/// <summary>
        /// Performs Monomorphization on the given compilation. If the keepAllIntrinsics parameter
        /// is set to true, then unused intrinsics will not be removed from the resulting compilation.
        /// </summary>
        public static QsCompilation Apply(QsCompilation compilation, bool keepAllIntrinsics = true)
        {
            var globals         = compilation.Namespaces.GlobalCallableResolutions();
            var concretizations = new List <QsCallable>();
            var concreteNames   = new Dictionary <ConcreteCallGraphNode, QsQualifiedName>();

            var nodes = new ConcreteCallGraph(compilation).Nodes
                        // Remove specialization information so that we only deal with the full callables.
                        .Select(n => new ConcreteCallGraphNode(n.CallableName, QsSpecializationKind.QsBody, n.ParamResolutions))
                        .ToImmutableHashSet();

            var getAccessModifiers = new GetAccessModifiers((typeName) => GetAccessModifier(compilation.Namespaces.GlobalTypeResolutions(), typeName));

            // Loop through the nodes, getting a list of concrete callables
            foreach (var node in nodes)
            {
                // If there is a call to an unknown callable, throw exception
                if (!globals.TryGetValue(node.CallableName, out QsCallable originalGlobal))
                {
                    throw new ArgumentException($"Couldn't find definition for callable: {node.CallableName}");
                }

                if (node.ParamResolutions.Any())
                {
                    // Get concrete name
                    var concreteName = UniqueVariableNames.PrependGuid(node.CallableName);

                    // Add to concrete name mapping
                    concreteNames[node] = concreteName;

                    // Generate the concrete version of the callable
                    var concrete = ReplaceTypeParamImplementations.Apply(originalGlobal, node.ParamResolutions, getAccessModifiers);
                    concretizations.Add(
                        concrete.WithFullName(oldName => concreteName)
                        .WithSpecializations(specs => specs.Select(spec => spec.WithParent(_ => concreteName)).ToImmutableArray()));
                }
                else
                {
                    concretizations.Add(originalGlobal);
                }
            }

            GetConcreteIdentifierFunc getConcreteIdentifier = (globalCallable, types) =>
                                                              GetConcreteIdentifier(concreteNames, globalCallable, types);

            var intrinsicCallableSet = globals
                                       .Where(kvp => kvp.Value.Specializations.Any(spec => spec.Implementation.IsIntrinsic))
                                       .Select(kvp => kvp.Key)
                                       .ToImmutableHashSet();

            var final = new List <QsCallable>();

            // Loop through concretizations, replacing all references to generics with their concrete counterparts
            foreach (var callable in concretizations)
            {
                final.Add(ReplaceTypeParamCalls.Apply(callable, getConcreteIdentifier, intrinsicCallableSet));
            }

            return(ResolveGenerics.Apply(compilation, final, intrinsicCallableSet, keepAllIntrinsics));
        }
Example #2
0
            private (QsCallable, ResolvedType) GenerateOperation(QsScope contents)
            {
                var newName = UniqueVariableNames.PrependGuid(this.CurrentCallable.Callable.FullName);

                var knownVariables = contents.KnownSymbols.Variables;

                var parameters = QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .NewQsTuple(knownVariables
                                                                                                 .Select(var => QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .NewQsTupleItem(new LocalVariableDeclaration <QsLocalSymbol>(
                                                                                                                                                                                        QsLocalSymbol.NewValidName(var.VariableName),
                                                                                                                                                                                        var.Type,
                                                                                                                                                                                        new InferredExpressionInformation(false, false),
                                                                                                                                                                                        var.Position,
                                                                                                                                                                                        var.Range)))
                                                                                                 .ToImmutableArray());

                var paramTypes = ResolvedType.New(ResolvedTypeKind.UnitType);

                if (knownVariables.Length == 1)
                {
                    paramTypes = knownVariables.First().Type;
                }
                else if (knownVariables.Length > 1)
                {
                    paramTypes = ResolvedType.New(ResolvedTypeKind.NewTupleType(knownVariables
                                                                                .Select(var => var.Type)
                                                                                .ToImmutableArray()));
                }

                var(signature, specializations) = this.MakeSpecializations(newName, paramTypes, SpecializationImplementation.NewProvided(parameters, contents));

                var generatedCallable = new QsCallable(
                    QsCallableKind.Operation,
                    newName,
                    ImmutableArray <QsDeclarationAttribute> .Empty,
                    new Modifiers(AccessModifier.Internal),
                    this.CurrentCallable.Callable.SourceFile,
                    QsNullable <QsLocation> .Null,
                    signature,
                    parameters,
                    specializations.ToImmutableArray(),
                    ImmutableArray <string> .Empty,
                    QsComments.Empty);

                // Change the origin of all type parameter references to use the new name and make all variables immutable
                generatedCallable = UpdateGeneratedOp.Apply(generatedCallable, knownVariables, this.CurrentCallable.Callable.FullName, newName);

                return(generatedCallable, signature.ArgumentType);
            }
Example #3
0
        private static Identifier GetConcreteIdentifier(
            Response currentResponse,
            Stack <Request> requests,
            List <Response> responses,
            Identifier.GlobalCallable globalCallable,
            ImmutableConcretion types)
        {
            QsQualifiedName concreteName = globalCallable.Item;

            var typesHashSet = ImmutableHashSet <KeyValuePair <Tuple <QsQualifiedName, NonNullable <string> >, ResolvedType> > .Empty;

            if (types != null && !types.IsEmpty)
            {
                typesHashSet = types.ToImmutableHashSet();
            }

            string name = null;

            // Check for recursive call
            if (currentResponse.OriginalName.Equals(globalCallable.Item) &&
                typesHashSet.SetEquals(currentResponse.TypeResolutions))
            {
                name = currentResponse.ConcreteCallable.FullName.Name.Value;
            }

            // Search requests for identifier
            if (name == null)
            {
                name = requests
                       .Where(req =>
                              req.OriginalName.Equals(globalCallable.Item) &&
                              typesHashSet.SetEquals(req.TypeResolutions))
                       .Select(req => req.ConcreteName.Name.Value)
                       .FirstOrDefault();
            }

            // Search responses for identifier
            if (name == null)
            {
                name = responses
                       .Where(res =>
                              res.OriginalName.Equals(globalCallable.Item) &&
                              typesHashSet.SetEquals(res.TypeResolutions))
                       .Select(res => res.ConcreteCallable.FullName.Name.Value)
                       .FirstOrDefault();
            }

            // If identifier can't be found, make a new request
            if (name == null)
            {
                // If this is not a generic, do not change the name
                if (!typesHashSet.IsEmpty)
                {
                    // Create new name
                    concreteName = UniqueVariableNames.PrependGuid(globalCallable.Item);
                }

                requests.Push(new Request()
                {
                    OriginalName    = globalCallable.Item,
                    TypeResolutions = types,
                    ConcreteName    = concreteName
                });
            }
            else
            {
                // If the identifier was found, update with the name
                concreteName = new QsQualifiedName(globalCallable.Item.Namespace, NonNullable <string> .New(name));
            }

            return(Identifier.NewGlobalCallable(concreteName));
        }