/// <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)); }
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); }
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)); }