From 57d2b914ca727a3df725d6f3f51306af0e8880d3 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 6 Sep 2019 14:40:19 -0700 Subject: [PATCH 01/32] Added target skeleton --- QsCompiler.sln | 27 +++++++++++++++ src/QsCompiler/QsTargeting/Target.fs | 37 +++++++++++++++++++++ src/QsCompiler/QsTargeting/Targeting.fsproj | 20 +++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/QsCompiler/QsTargeting/Target.fs create mode 100644 src/QsCompiler/QsTargeting/Targeting.fsproj diff --git a/QsCompiler.sln b/QsCompiler.sln index 7a330f37f1..094bfb5548 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -44,6 +44,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Optimizations", "src\QsComp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B4A9484D-31FC-4A27-9E26-4C8DE3E02D77}" EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Targeting", "src\QsCompiler\QsTargeting\Targeting.fsproj", "{C4279E56-33ED-450A-B547-6752D6926052}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -234,6 +236,18 @@ Global {2E331781-F7ED-4EF1-8451-896636C6D93A}.Release|x64.Build.0 = Release|Any CPU {2E331781-F7ED-4EF1-8451-896636C6D93A}.Release|x86.ActiveCfg = Release|Any CPU {2E331781-F7ED-4EF1-8451-896636C6D93A}.Release|x86.Build.0 = Release|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x64.ActiveCfg = Debug|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x64.Build.0 = Debug|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x86.ActiveCfg = Debug|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x86.Build.0 = Debug|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|Any CPU.Build.0 = Release|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x64.ActiveCfg = Release|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x64.Build.0 = Release|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x86.ActiveCfg = Release|Any CPU + {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x86.Build.0 = Release|Any CPU {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -258,6 +272,18 @@ Global {31085984-3DA6-43C7-B0AA-CE62DC60BB56}.Release|x64.Build.0 = Release|Any CPU {31085984-3DA6-43C7-B0AA-CE62DC60BB56}.Release|x86.ActiveCfg = Release|Any CPU {31085984-3DA6-43C7-B0AA-CE62DC60BB56}.Release|x86.Build.0 = Release|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x64.ActiveCfg = Debug|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x64.Build.0 = Debug|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x86.ActiveCfg = Debug|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x86.Build.0 = Debug|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Release|Any CPU.Build.0 = Release|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Release|x64.ActiveCfg = Release|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Release|x64.Build.0 = Release|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Release|x86.ActiveCfg = Release|Any CPU + {C4279E56-33ED-450A-B547-6752D6926052}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -270,6 +296,7 @@ Global {D50583DF-FBEF-45EF-B523-70B2CDBE1DD1} = {76BA96DA-DC1E-4315-A3ED-5F0700A79812} {2E331781-F7ED-4EF1-8451-896636C6D93A} = {76BA96DA-DC1E-4315-A3ED-5F0700A79812} {D2E36476-A65F-4310-9C4C-B721BCC47B00} = {6077A717-50BF-4F87-B439-CA549AF6A4AE} + {A83A9BA2-A774-4F07-B801-5A4A73598F62} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/QsCompiler/QsTargeting/Target.fs b/src/QsCompiler/QsTargeting/Target.fs new file mode 100644 index 0000000000..5481b37bb0 --- /dev/null +++ b/src/QsCompiler/QsTargeting/Target.fs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.QsCompiler.Targeting + +open Microsoft.Quantum.QsCompiler.SymbolManagement +open Microsoft.VisualStudio.LanguageServer.Protocol +open System.Collections.Generic +open System.Threading +open Microsoft.Quantum.QsCompiler.SyntaxTree +open Microsoft.Quantum.QsCompiler.Transformations.Core + +type TargetCapabilities = + { + CanDoIf : bool + CanDoRepeat : bool + CanMeasureAndContinue : bool + } + +type internal TargetValidationTransformation(target : Target) = + inherit SyntaxTreeTransformation() + + let diagnostics = [] : Diagnostic list + + member this.Diagnostics with get () = new List(diagnostics) + +and Target(builtIns : NamespaceManager, capabilities : TargetCapabilities) = + member this.BuiltIns with get () = builtIns + + member this.Capabilities with get () = capabilities + + member this.ValidateSyntaxTree (ns : QsNamespace, cancellationToken : CancellationToken) : List = + let xformer = new TargetValidationTransformation(this) + + xformer.Transform ns |> ignore + + xformer.Diagnostics diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj new file mode 100644 index 0000000000..203e439f43 --- /dev/null +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -0,0 +1,20 @@ + + + + netstandard2.1 + + + + + + + + + + + + + + + + From 9de93fafc623f18e265f856c76f8966d85060ca2 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 6 Sep 2019 15:58:43 -0700 Subject: [PATCH 02/32] A bit more fleshed out and broken into more files --- src/QsCompiler/QsTargeting/Target.fs | 31 ++++++------ .../QsTargeting/TargetCapabilities.fs | 14 ++++++ src/QsCompiler/QsTargeting/Targeting.fsproj | 2 + .../QsTargeting/ValidatingTransformations.fs | 47 +++++++++++++++++++ 4 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 src/QsCompiler/QsTargeting/TargetCapabilities.fs create mode 100644 src/QsCompiler/QsTargeting/ValidatingTransformations.fs diff --git a/src/QsCompiler/QsTargeting/Target.fs b/src/QsCompiler/QsTargeting/Target.fs index 5481b37bb0..f6f68d48c7 100644 --- a/src/QsCompiler/QsTargeting/Target.fs +++ b/src/QsCompiler/QsTargeting/Target.fs @@ -4,33 +4,30 @@ namespace Microsoft.Quantum.QsCompiler.Targeting open Microsoft.Quantum.QsCompiler.SymbolManagement -open Microsoft.VisualStudio.LanguageServer.Protocol open System.Collections.Generic open System.Threading open Microsoft.Quantum.QsCompiler.SyntaxTree -open Microsoft.Quantum.QsCompiler.Transformations.Core +open Microsoft.Quantum.QsCompiler.Diagnostics -type TargetCapabilities = - { - CanDoIf : bool - CanDoRepeat : bool - CanMeasureAndContinue : bool - } +type Target(builtIns : NamespaceManager, capabilities : TargetCapabilities) = + member this.BuiltIns with get () = builtIns -type internal TargetValidationTransformation(target : Target) = - inherit SyntaxTreeTransformation() + member this.Capabilities with get () = capabilities - let diagnostics = [] : Diagnostic list + member this.ValidateCallable (callable : QsCallable) : List = + let xformer = new TVScopeTransformation(this.Capabilities) - member this.Diagnostics with get () = new List(diagnostics) + let processSpecialization (spec : QsSpecialization) = + match spec.Implementation with + | Provided(_, scope) -> xformer.Transform scope |> ignore + | _ -> () -and Target(builtIns : NamespaceManager, capabilities : TargetCapabilities) = - member this.BuiltIns with get () = builtIns + callable.Specializations |> Seq.iter processSpecialization - member this.Capabilities with get () = capabilities + xformer.Diagnostics - member this.ValidateSyntaxTree (ns : QsNamespace, cancellationToken : CancellationToken) : List = - let xformer = new TargetValidationTransformation(this) + member this.ValidateSyntaxTree (ns : QsNamespace, cancellationToken : CancellationToken) : List = + let xformer = new TVTreeTransformation(this.Capabilities) xformer.Transform ns |> ignore diff --git a/src/QsCompiler/QsTargeting/TargetCapabilities.fs b/src/QsCompiler/QsTargeting/TargetCapabilities.fs new file mode 100644 index 0000000000..2f4b3b7adf --- /dev/null +++ b/src/QsCompiler/QsTargeting/TargetCapabilities.fs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.QsCompiler.Targeting + +type TargetCapabilities = + { + CanDoIf : bool + CanDoRepeat : bool + CanMeasureAndContinue : bool + CanFail : bool + CanMessage : bool + CanCompute : bool + } diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj index 203e439f43..a523458e6e 100644 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -5,6 +5,8 @@ + + diff --git a/src/QsCompiler/QsTargeting/ValidatingTransformations.fs b/src/QsCompiler/QsTargeting/ValidatingTransformations.fs new file mode 100644 index 0000000000..ded494b94a --- /dev/null +++ b/src/QsCompiler/QsTargeting/ValidatingTransformations.fs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.QsCompiler.Targeting + +open Microsoft.Quantum.QsCompiler.SymbolManagement +open System.Collections.Generic +open Microsoft.Quantum.QsCompiler.SyntaxTree +open Microsoft.Quantum.QsCompiler.Transformations.Core +open Microsoft.Quantum.QsCompiler.Diagnostics + +type internal TVExpressionTransformation(capabilities : TargetCapabilities) = + inherit ExpressionTransformation() + +type internal TVStatementKindTransformation(capabilities : TargetCapabilities) = + inherit StatementKindTransformation() + + let scopeXformer = new TVScopeTransformation(capabilities) + let exprXformer = new TVExpressionTransformation(capabilities) + + let diagnostics = new List() + member this.Diagnostics with get () = diagnostics + + override this.ScopeTransformation x = scopeXformer.Transform x + override this.ExpressionTransformation x = exprXformer.Transform x + override this.TypeTransformation x = x + override this.LocationTransformation x = x + + override this.onFailStatement x = + if not capabilities.CanFail then + diagnostics.Add(DiagnosticItem.Error(ErrorCode.TargetExecutionFailed)) + base.onFailStatement x + +and internal TVScopeTransformation(capabilities : TargetCapabilities) = + inherit ScopeTransformation() + + let diagnostics = [] : DiagnosticItem list + + member this.Diagnostics with get () = new List(diagnostics) + +type internal TVTreeTransformation(capabilities : TargetCapabilities) = + inherit SyntaxTreeTransformation() + + let diagnostics = [] : DiagnosticItem list + + member this.Diagnostics with get () = new List(diagnostics) + From c25c544098c6955df69f1317859d39401fe80c63 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 13 Sep 2019 16:35:46 -0700 Subject: [PATCH 03/32] Initial change to use cpability levels --- .../CompilationManager/CompilationUnit.cs | 13 +++++----- .../CompilationManager/TypeChecking.cs | 2 +- src/QsCompiler/Core/ConstructorExtensions.fs | 1 + src/QsCompiler/DataStructures/SyntaxTree.fs | 4 +++ src/QsCompiler/QsTargeting/Target.fs | 26 ++++++------------- .../QsTargeting/TargetCapabilities.fs | 14 ---------- src/QsCompiler/QsTargeting/Targeting.fsproj | 1 - .../QsTargeting/ValidatingTransformations.fs | 17 +++++------- 8 files changed, 27 insertions(+), 51 deletions(-) delete mode 100644 src/QsCompiler/QsTargeting/TargetCapabilities.fs diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index f003544dc6..8d5927daf7 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -395,8 +395,8 @@ internal void UpdateCallables(IEnumerable updates) if (header.Kind.IsTypeConstructor) { var specLocation = new QsLocation(header.Position, header.SymbolRange); - var defaultSpec = new QsSpecialization(QsSpecializationKind.QsBody, header.QualifiedName, header.Attributes, header.SourceFile, specLocation, - QsNullable>.Null, header.Signature, SpecializationImplementation.Intrinsic, ImmutableArray.Empty, QsComments.Empty); + var defaultSpec = new QsSpecialization(QsSpecializationKind.QsBody, header.QualifiedName, header.Attributes, QsSpecialization.UnsetRequiredCapability, header.SourceFile, + specLocation, QsNullable>.Null, header.Signature, SpecializationImplementation.Intrinsic, ImmutableArray.Empty, QsComments.Empty); this.CompiledCallables[fullName] = new QsCallable(header.Kind, header.QualifiedName, header.Attributes, header.SourceFile, specLocation, header.Signature, header.ArgumentTuple, ImmutableArray.Create(defaultSpec), header.Documentation, QsComments.Empty); continue; @@ -418,8 +418,8 @@ internal void UpdateCallables(IEnumerable updates) var compiledSpec = compiledSpecs.Single(); var specLocation = new QsLocation(specHeader.Position, specHeader.HeaderRange); - return new QsSpecialization(compiledSpec.Kind, compiledSpec.Parent, compiledSpec.Attributes, compiledSpec.SourceFile, specLocation, - compiledSpec.TypeArguments, compiledSpec.Signature, compiledSpec.Implementation, compiledSpec.Documentation, compiledSpec.Comments); + return new QsSpecialization(compiledSpec.Kind, compiledSpec.Parent, compiledSpec.Attributes, QsSpecialization.UnsetRequiredCapability, compiledSpec.SourceFile, + specLocation, compiledSpec.TypeArguments, compiledSpec.Signature, compiledSpec.Implementation, compiledSpec.Documentation, compiledSpec.Comments); }) .Where(spec => spec != null).ToImmutableArray(); @@ -452,8 +452,9 @@ private QsCallable GetImportedCallable(CallableDeclarationHeader header) var specSignature = specHeader.Kind.IsQsControlled || specHeader.Kind.IsQsControlledAdjoint ? SyntaxGenerator.BuildControlled(header.Signature) : header.Signature; - return new QsSpecialization(specHeader.Kind, header.QualifiedName, specHeader.Attributes, specHeader.SourceFile, specLocation, - specHeader.TypeArguments, specSignature, implementation, specHeader.Documentation, QsComments.Empty); + return new QsSpecialization(specHeader.Kind, header.QualifiedName, specHeader.Attributes, QsSpecialization.UnsetRequiredCapability, + specHeader.SourceFile, specLocation, specHeader.TypeArguments, specSignature, implementation, specHeader.Documentation, + QsComments.Empty); }) .ToImmutableArray(); var location = new QsLocation(header.Position, header.SymbolRange); diff --git a/src/QsCompiler/CompilationManager/TypeChecking.cs b/src/QsCompiler/CompilationManager/TypeChecking.cs index 43ab1d720e..a22a3f24af 100644 --- a/src/QsCompiler/CompilationManager/TypeChecking.cs +++ b/src/QsCompiler/CompilationManager/TypeChecking.cs @@ -1226,7 +1226,7 @@ private static ImmutableArray BuildSpecializations QsSpecialization GetSpecialization(SpecializationDeclarationHeader spec, ResolvedSignature signature, SpecializationImplementation implementation, QsComments comments = null) => - new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, spec.SourceFile, null, + new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, QsSpecialization.UnsetRequiredCapability, spec.SourceFile, null, spec.TypeArguments, SyntaxGenerator.WithoutRangeInfo(signature), implementation, spec.Documentation, comments ?? QsComments.Empty); QsSpecialization BuildSpecialization(QsSpecializationKind kind, ResolvedSignature signature, QsSpecializationGeneratorKind gen, FragmentTree.TreeNode root, diff --git a/src/QsCompiler/Core/ConstructorExtensions.fs b/src/QsCompiler/Core/ConstructorExtensions.fs index cbd0b46ab0..c8539942b7 100644 --- a/src/QsCompiler/Core/ConstructorExtensions.fs +++ b/src/QsCompiler/Core/ConstructorExtensions.fs @@ -181,6 +181,7 @@ type QsSpecialization with Kind = kind Parent = parent Attributes = attributes + RequiredCapability = QsSpecialization.UnsetRequiredCapability SourceFile = source Location = location TypeArguments = typeArgs diff --git a/src/QsCompiler/DataStructures/SyntaxTree.fs b/src/QsCompiler/DataStructures/SyntaxTree.fs index dbff23d1fe..a36ab45bca 100644 --- a/src/QsCompiler/DataStructures/SyntaxTree.fs +++ b/src/QsCompiler/DataStructures/SyntaxTree.fs @@ -618,6 +618,8 @@ type QsSpecialization = { Parent : QsQualifiedName /// contains all attributes associated with the specialization Attributes : ImmutableArray + /// contains the minimum target capability level for this specialization + RequiredCapability : int /// identifier for the file the specialization is declared in (not necessarily the same as the one of the callable it extends) SourceFile : NonNullable /// Contains the location information for the declared specialization. @@ -639,6 +641,8 @@ type QsSpecialization = { member this.AddAttribute att = {this with Attributes = this.Attributes.Add att} member this.WithImplementation impl = {this with Implementation = impl} + static member UnsetRequiredCapability = -1 + /// describes a Q# function, operation, or type constructor type QsCallable = { diff --git a/src/QsCompiler/QsTargeting/Target.fs b/src/QsCompiler/QsTargeting/Target.fs index f6f68d48c7..0af39ba818 100644 --- a/src/QsCompiler/QsTargeting/Target.fs +++ b/src/QsCompiler/QsTargeting/Target.fs @@ -9,26 +9,16 @@ open System.Threading open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Diagnostics -type Target(builtIns : NamespaceManager, capabilities : TargetCapabilities) = +type Target(builtIns : NamespaceManager, capabilityLevel : int) = member this.BuiltIns with get () = builtIns - member this.Capabilities with get () = capabilities + member this.CapabilityLevel with get () = capabilityLevel - member this.ValidateCallable (callable : QsCallable) : List = - let xformer = new TVScopeTransformation(this.Capabilities) - - let processSpecialization (spec : QsSpecialization) = - match spec.Implementation with - | Provided(_, scope) -> xformer.Transform scope |> ignore - | _ -> () - - callable.Specializations |> Seq.iter processSpecialization - - xformer.Diagnostics + member this.ValidateSpecialization (spec : QsSpecialization) : List = + let diagnostics = new List() + if spec.RequiredCapability > this.CapabilityLevel + then diagnostics.Add(Error ErrorCode.UnexpectedCompilerException) + diagnostics member this.ValidateSyntaxTree (ns : QsNamespace, cancellationToken : CancellationToken) : List = - let xformer = new TVTreeTransformation(this.Capabilities) - - xformer.Transform ns |> ignore - - xformer.Diagnostics + new List() diff --git a/src/QsCompiler/QsTargeting/TargetCapabilities.fs b/src/QsCompiler/QsTargeting/TargetCapabilities.fs deleted file mode 100644 index 2f4b3b7adf..0000000000 --- a/src/QsCompiler/QsTargeting/TargetCapabilities.fs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.QsCompiler.Targeting - -type TargetCapabilities = - { - CanDoIf : bool - CanDoRepeat : bool - CanMeasureAndContinue : bool - CanFail : bool - CanMessage : bool - CanCompute : bool - } diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj index a523458e6e..2466249988 100644 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -5,7 +5,6 @@ - diff --git a/src/QsCompiler/QsTargeting/ValidatingTransformations.fs b/src/QsCompiler/QsTargeting/ValidatingTransformations.fs index ded494b94a..3ac21c18c5 100644 --- a/src/QsCompiler/QsTargeting/ValidatingTransformations.fs +++ b/src/QsCompiler/QsTargeting/ValidatingTransformations.fs @@ -9,14 +9,14 @@ open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.Core open Microsoft.Quantum.QsCompiler.Diagnostics -type internal TVExpressionTransformation(capabilities : TargetCapabilities) = +type internal TVExpressionXform() = inherit ExpressionTransformation() -type internal TVStatementKindTransformation(capabilities : TargetCapabilities) = +type internal TVStatementKindXform() = inherit StatementKindTransformation() - let scopeXformer = new TVScopeTransformation(capabilities) - let exprXformer = new TVExpressionTransformation(capabilities) + let scopeXformer = new TVScopeXform() + let exprXformer = new TVExpressionXform() let diagnostics = new List() member this.Diagnostics with get () = diagnostics @@ -26,19 +26,14 @@ type internal TVStatementKindTransformation(capabilities : TargetCapabilities) = override this.TypeTransformation x = x override this.LocationTransformation x = x - override this.onFailStatement x = - if not capabilities.CanFail then - diagnostics.Add(DiagnosticItem.Error(ErrorCode.TargetExecutionFailed)) - base.onFailStatement x - -and internal TVScopeTransformation(capabilities : TargetCapabilities) = +and internal TVScopeXform() = inherit ScopeTransformation() let diagnostics = [] : DiagnosticItem list member this.Diagnostics with get () = new List(diagnostics) -type internal TVTreeTransformation(capabilities : TargetCapabilities) = +type internal TVTreeXform() = inherit SyntaxTreeTransformation() let diagnostics = [] : DiagnosticItem list From dd680818fc2df609e3c7b2a6e40e9128d828374e Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Wed, 18 Sep 2019 15:43:45 -0700 Subject: [PATCH 04/32] Added more leveling infrastructure. The real work is still TBD. --- .../CompilationManager/CompilationUnit.cs | 16 +-- .../CompilationManager/TypeChecking.cs | 4 +- src/QsCompiler/Core/ConstructorExtensions.fs | 3 +- src/QsCompiler/DataStructures/SyntaxTree.fs | 22 +++- .../QsTargeting/CapabilityLeveler.fs | 115 ++++++++++++++++++ src/QsCompiler/QsTargeting/Target.fs | 2 +- src/QsCompiler/QsTargeting/Targeting.fsproj | 2 +- .../QsTargeting/ValidatingTransformations.fs | 42 ------- 8 files changed, 146 insertions(+), 60 deletions(-) create mode 100644 src/QsCompiler/QsTargeting/CapabilityLeveler.fs delete mode 100644 src/QsCompiler/QsTargeting/ValidatingTransformations.fs diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index 8d5927daf7..eeca08f519 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -395,8 +395,9 @@ internal void UpdateCallables(IEnumerable updates) if (header.Kind.IsTypeConstructor) { var specLocation = new QsLocation(header.Position, header.SymbolRange); - var defaultSpec = new QsSpecialization(QsSpecializationKind.QsBody, header.QualifiedName, header.Attributes, QsSpecialization.UnsetRequiredCapability, header.SourceFile, - specLocation, QsNullable>.Null, header.Signature, SpecializationImplementation.Intrinsic, ImmutableArray.Empty, QsComments.Empty); + var defaultSpec = new QsSpecialization(QsSpecializationKind.QsBody, header.QualifiedName, header.Attributes, CapabilityLevel.Unset, + CapabilityLevel.Unset, header.SourceFile, specLocation, QsNullable>.Null, header.Signature, + SpecializationImplementation.Intrinsic, ImmutableArray.Empty, QsComments.Empty); this.CompiledCallables[fullName] = new QsCallable(header.Kind, header.QualifiedName, header.Attributes, header.SourceFile, specLocation, header.Signature, header.ArgumentTuple, ImmutableArray.Create(defaultSpec), header.Documentation, QsComments.Empty); continue; @@ -418,8 +419,9 @@ internal void UpdateCallables(IEnumerable updates) var compiledSpec = compiledSpecs.Single(); var specLocation = new QsLocation(specHeader.Position, specHeader.HeaderRange); - return new QsSpecialization(compiledSpec.Kind, compiledSpec.Parent, compiledSpec.Attributes, QsSpecialization.UnsetRequiredCapability, compiledSpec.SourceFile, - specLocation, compiledSpec.TypeArguments, compiledSpec.Signature, compiledSpec.Implementation, compiledSpec.Documentation, compiledSpec.Comments); + return new QsSpecialization(compiledSpec.Kind, compiledSpec.Parent, compiledSpec.Attributes, CapabilityLevel.Unset, + CapabilityLevel.Unset, compiledSpec.SourceFile, specLocation, compiledSpec.TypeArguments, compiledSpec.Signature, + compiledSpec.Implementation, compiledSpec.Documentation, compiledSpec.Comments); }) .Where(spec => spec != null).ToImmutableArray(); @@ -452,9 +454,9 @@ private QsCallable GetImportedCallable(CallableDeclarationHeader header) var specSignature = specHeader.Kind.IsQsControlled || specHeader.Kind.IsQsControlledAdjoint ? SyntaxGenerator.BuildControlled(header.Signature) : header.Signature; - return new QsSpecialization(specHeader.Kind, header.QualifiedName, specHeader.Attributes, QsSpecialization.UnsetRequiredCapability, - specHeader.SourceFile, specLocation, specHeader.TypeArguments, specSignature, implementation, specHeader.Documentation, - QsComments.Empty); + return new QsSpecialization(specHeader.Kind, header.QualifiedName, specHeader.Attributes, CapabilityLevel.Unset, + CapabilityLevel.Unset, specHeader.SourceFile, specLocation, specHeader.TypeArguments, specSignature, + implementation, specHeader.Documentation, QsComments.Empty); }) .ToImmutableArray(); var location = new QsLocation(header.Position, header.SymbolRange); diff --git a/src/QsCompiler/CompilationManager/TypeChecking.cs b/src/QsCompiler/CompilationManager/TypeChecking.cs index a22a3f24af..d977e95c0b 100644 --- a/src/QsCompiler/CompilationManager/TypeChecking.cs +++ b/src/QsCompiler/CompilationManager/TypeChecking.cs @@ -1226,8 +1226,8 @@ private static ImmutableArray BuildSpecializations QsSpecialization GetSpecialization(SpecializationDeclarationHeader spec, ResolvedSignature signature, SpecializationImplementation implementation, QsComments comments = null) => - new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, QsSpecialization.UnsetRequiredCapability, spec.SourceFile, null, - spec.TypeArguments, SyntaxGenerator.WithoutRangeInfo(signature), implementation, spec.Documentation, comments ?? QsComments.Empty); + new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, CapabilityLevel.Unset, CapabilityLevel.Unset, + spec.SourceFile, null, spec.TypeArguments, SyntaxGenerator.WithoutRangeInfo(signature), implementation, spec.Documentation, comments ?? QsComments.Empty); QsSpecialization BuildSpecialization(QsSpecializationKind kind, ResolvedSignature signature, QsSpecializationGeneratorKind gen, FragmentTree.TreeNode root, Func>, QsCompilerDiagnostic[]>> buildArg, QsComments comments = null) diff --git a/src/QsCompiler/Core/ConstructorExtensions.fs b/src/QsCompiler/Core/ConstructorExtensions.fs index c8539942b7..7cb7abeb7c 100644 --- a/src/QsCompiler/Core/ConstructorExtensions.fs +++ b/src/QsCompiler/Core/ConstructorExtensions.fs @@ -181,7 +181,8 @@ type QsSpecialization with Kind = kind Parent = parent Attributes = attributes - RequiredCapability = QsSpecialization.UnsetRequiredCapability + RequiredCapability = CapabilityLevel.Unset + LocalRequiredCapability = CapabilityLevel.Unset SourceFile = source Location = location TypeArguments = typeArgs diff --git a/src/QsCompiler/DataStructures/SyntaxTree.fs b/src/QsCompiler/DataStructures/SyntaxTree.fs index a36ab45bca..f74d93274e 100644 --- a/src/QsCompiler/DataStructures/SyntaxTree.fs +++ b/src/QsCompiler/DataStructures/SyntaxTree.fs @@ -608,8 +608,18 @@ type SpecializationImplementation = | Generated of QsGeneratorDirective // Invert and Distribute will be replaced by Provided before sending to code gen -/// For each callable various specialization exist describing how it acts -/// depending on the type of the argument it is called with (type specializations), +/// Different targets provide different levels of Q# support. Some targets can execute any Q# code, +/// while others are very limited in the Q# constructs that they can process. +type CapabilityLevel = +| Minimal = 1 +| Basic = 2 +| Medium = 3 +| Advanced = 4 +| Full = 5 +| Unset = -1 + +/// For each callable various specialization exist describing how it acts +/// depending on the type of the argument it is called with (type specializations), /// and/or which functors are applied to the call. type QsSpecialization = { /// contains the functor specialization kind (specialization for body, adjoint, controlled, or controlled adjoint) @@ -618,8 +628,10 @@ type QsSpecialization = { Parent : QsQualifiedName /// contains all attributes associated with the specialization Attributes : ImmutableArray - /// contains the minimum target capability level for this specialization - RequiredCapability : int + /// contains the minimum target capability level for this specialization, including its entire call tree + RequiredCapability : CapabilityLevel + /// contains the minimum target capability level for this specialization's code, not including anything it calls + LocalRequiredCapability : CapabilityLevel /// identifier for the file the specialization is declared in (not necessarily the same as the one of the callable it extends) SourceFile : NonNullable /// Contains the location information for the declared specialization. @@ -641,8 +653,6 @@ type QsSpecialization = { member this.AddAttribute att = {this with Attributes = this.Attributes.Add att} member this.WithImplementation impl = {this with Implementation = impl} - static member UnsetRequiredCapability = -1 - /// describes a Q# function, operation, or type constructor type QsCallable = { diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs new file mode 100644 index 0000000000..7b156278ec --- /dev/null +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +module Microsoft.Quantum.QsCompiler.Targeting.CapabilityLeveler + +open Microsoft.Quantum.QsCompiler.SyntaxTree +open Microsoft.Quantum.QsCompiler.Transformations.Core +open System.Collections.Immutable +open Microsoft.Quantum.QsCompiler.DataTypes +open Microsoft.Quantum.QsCompiler +open Microsoft.Quantum.QsCompiler +open Microsoft.Quantum.QsCompiler.SyntaxTokens + +type internal CapabilityInfoHolder(context : QsNamespace seq) = + let mutable localLevel = CapabilityLevel.Minimal + let mutable calledLevel = CapabilityLevel.Minimal + let callables = context |> GlobalCallableResolutions + + member this.GetCallableLevel(name, modifier, types) = + match callables.TryGetValue(name) with + | true, callable -> + callable.Specializations |> Seq.filter (fun spec -> spec.Kind = modifier && spec.TypeArguments = types) + |> Seq.map (fun a -> a.RequiredCapability) + |> Seq.tryExactlyOne + | false, _ -> None + + member this.LocalLevel with get() = localLevel and set(n) = if int n > int localLevel then localLevel <- n + member this.CalledLevel with get() = calledLevel and set(n) = if int n > int calledLevel then calledLevel <- n + +type internal ExpressionKindLeveler(holder : CapabilityInfoHolder) = + inherit ExpressionKindTransformation() + + let exprXformer = new ExpressionLeveler(holder) + + override this.ExpressionTransformation x = exprXformer.Transform x + override this.TypeTransformation x = x + + override this.onOperationCall(ex1, ex2) = + base.onOperationCall(ex1, ex2) + +and internal ExpressionLeveler(holder : CapabilityInfoHolder) = + inherit ExpressionTransformation() + + let kindXformer = new ExpressionKindLeveler(holder) + +and internal StatementLeveler(holder : CapabilityInfoHolder) = + inherit StatementKindTransformation() + + let scopeXformer = new ScopeLeveler(holder) + let exprXformer = new ExpressionLeveler(holder) + + override this.ScopeTransformation x = scopeXformer.Transform x + override this.ExpressionTransformation x = exprXformer.Transform x + override this.TypeTransformation x = x + override this.LocationTransformation x = x + +and internal ScopeLeveler(holder : CapabilityInfoHolder) = + inherit ScopeTransformation() + + override this.StatementKind = upcast new StatementLeveler(holder) + +type TreeLeveler(context : QsNamespace seq) = + inherit SyntaxTreeTransformation() + + let mutable currentCallableLevel = None : (CapabilityLevel * CapabilityLevel) option + + let checkForLevelAttributes (attrs : QsDeclarationAttribute seq) = + let isLevelAttribute (a : QsDeclarationAttribute) = + match a.TypeId with + | Value udt -> udt.Namespace = BuiltIn.LevelAttribute.Namespace && udt.Name = BuiltIn.LevelAttribute.Name + | Null -> false + let getLevelFromArgument (a : QsDeclarationAttribute) = + match a.Argument.Expression with + | IntLiteral n -> let level = enum (int n) + Some (level, level) + | _ -> None + let levels = attrs |> Seq.filter isLevelAttribute |> List.ofSeq + match levels with + | [ level ] -> getLevelFromArgument level + | [] -> None + | _ -> None + + let transformSpecialization (spec : QsSpecialization) = + let computeLevelFromImplementation () = + match spec.Implementation with + | SpecializationImplementation.Provided (_, code) -> + // Compute the capability levels by walking the code + let holder = new CapabilityInfoHolder(context) + let xform = new ScopeLeveler(holder) + xform.Transform code |> ignore + Some (holder.LocalLevel, holder.CalledLevel) + | SpecializationImplementation.Intrinsic -> + Some (CapabilityLevel.Minimal, CapabilityLevel.Minimal) + | SpecializationImplementation.External -> + None + | SpecializationImplementation.Generated _ -> + // TODO: Find the "base" specialization and use it's levels + Some (CapabilityLevel.Unset, CapabilityLevel.Unset) + // If there is a Level attribute for this specific specialization, use it; otherwise, + // use the level from Level attribute for the containing callable, if any; as a last + // resort, check the actual implementation. + let local, called = spec.Attributes + |> checkForLevelAttributes + |> Option.orElse currentCallableLevel + |> Option.orElseWith computeLevelFromImplementation + |> Option.defaultValue (CapabilityLevel.Unset, CapabilityLevel.Unset) + { spec with LocalRequiredCapability = local; RequiredCapability = called } + + override this.onSpecializationImplementation spec = + transformSpecialization spec + + override this.beforeCallable callable = + currentCallableLevel <- checkForLevelAttributes callable.Attributes + base.beforeCallable callable + diff --git a/src/QsCompiler/QsTargeting/Target.fs b/src/QsCompiler/QsTargeting/Target.fs index 0af39ba818..64884ec757 100644 --- a/src/QsCompiler/QsTargeting/Target.fs +++ b/src/QsCompiler/QsTargeting/Target.fs @@ -9,7 +9,7 @@ open System.Threading open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Diagnostics -type Target(builtIns : NamespaceManager, capabilityLevel : int) = +type Target(builtIns : NamespaceManager, capabilityLevel : CapabilityLevel) = member this.BuiltIns with get () = builtIns member this.CapabilityLevel with get () = capabilityLevel diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj index 2466249988..63c3846c53 100644 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -5,7 +5,7 @@ - + diff --git a/src/QsCompiler/QsTargeting/ValidatingTransformations.fs b/src/QsCompiler/QsTargeting/ValidatingTransformations.fs deleted file mode 100644 index 3ac21c18c5..0000000000 --- a/src/QsCompiler/QsTargeting/ValidatingTransformations.fs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.QsCompiler.Targeting - -open Microsoft.Quantum.QsCompiler.SymbolManagement -open System.Collections.Generic -open Microsoft.Quantum.QsCompiler.SyntaxTree -open Microsoft.Quantum.QsCompiler.Transformations.Core -open Microsoft.Quantum.QsCompiler.Diagnostics - -type internal TVExpressionXform() = - inherit ExpressionTransformation() - -type internal TVStatementKindXform() = - inherit StatementKindTransformation() - - let scopeXformer = new TVScopeXform() - let exprXformer = new TVExpressionXform() - - let diagnostics = new List() - member this.Diagnostics with get () = diagnostics - - override this.ScopeTransformation x = scopeXformer.Transform x - override this.ExpressionTransformation x = exprXformer.Transform x - override this.TypeTransformation x = x - override this.LocationTransformation x = x - -and internal TVScopeXform() = - inherit ScopeTransformation() - - let diagnostics = [] : DiagnosticItem list - - member this.Diagnostics with get () = new List(diagnostics) - -type internal TVTreeXform() = - inherit SyntaxTreeTransformation() - - let diagnostics = [] : DiagnosticItem list - - member this.Diagnostics with get () = new List(diagnostics) - From fb14448aee7b58896bb83e6f1770541f0e89a1e2 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Thu, 19 Sep 2019 15:20:16 -0700 Subject: [PATCH 05/32] Lots more plumbing, getting close to gluing it all together --- src/QsCompiler/Core/Dependencies.fs | 5 + .../QsTargeting/CapabilityLeveler.fs | 97 ++++++++++++++++++- src/QsCompiler/QsTargeting/Targeting.fsproj | 3 +- 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/QsCompiler/Core/Dependencies.fs b/src/QsCompiler/Core/Dependencies.fs index b0752f0013..147d270e99 100644 --- a/src/QsCompiler/Core/Dependencies.fs +++ b/src/QsCompiler/Core/Dependencies.fs @@ -67,6 +67,11 @@ type BuiltIn = { TypeParameters = ImmutableArray.Empty } + static member LevelAttribute = { + Name = "Level" |> NonNullable.New + Namespace = BuiltIn.CoreNamespace + TypeParameters = ImmutableArray.Empty + } // "weak dependencies" in other namespaces (e.g. things used for code actions) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 7b156278ec..079ec59c83 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -6,10 +6,103 @@ module Microsoft.Quantum.QsCompiler.Targeting.CapabilityLeveler open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.Core open System.Collections.Immutable +open System.Collections.Generic +open System open Microsoft.Quantum.QsCompiler.DataTypes open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.SyntaxTokens +open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput + +type internal SpecializationKey = + { + QualifiedName : QsQualifiedName + Kind : QsSpecializationKind + TypeArgString : string + } + +type CapabilityLevelManager() = + let sep = '|' + let levels = new Dictionary() + let dependencies = new Dictionary>() + let keyTypes = new Dictionary() + + let SpecInfoToKey name kind (types : QsNullable>) = + let ResolvedTypeToString rt = + let exprTransformer = new ExpressionToQs() + let transformer = new ExpressionTypeToQs(exprTransformer) + transformer.Apply(rt) + let typeArgs = types.ValueOr (new ImmutableArray()) + |> Seq.map (fun t -> (t, ResolvedTypeToString t)) + typeArgs |> Seq.iter (fun (t, s) -> keyTypes.[s] <- t) + let typeArgString = typeArgs + |> Seq.map snd + |> String.concat (sep.ToString()) + { QualifiedName = name; Kind = kind; TypeArgString = typeArgString } + + let StringToTypeArray (ts : string) = + let lookupString s = + match keyTypes.TryGetValue(s) with + | true, t -> t + | false, _ -> ResolvedType.New(InvalidType) + let typeSequence = ts.Split(sep) |> Seq.map lookupString + if typeSequence |> Seq.isEmpty + then Null + else Value (typeSequence |> ImmutableArray.ToImmutableArray) + + let rec WalkDependencyTree root (accum : HashSet) = + match dependencies.TryGetValue(root) with + | true, next -> + next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum + | false, _ -> accum + + member this.GetSpecializationLevel(name, kind, types) = + let key = SpecInfoToKey name kind types + match levels.TryGetValue(key) with + | true, level -> level + | false, _ -> CapabilityLevel.Unset + + member this.SetSpecializationLevel(name, kind, types, level) = + let key = SpecInfoToKey name kind types + levels.[key] <- level + + member this.AddDependency(callerName, callerKind, callerTypes, calledName, calledKind, calledTypes) = + let callerKey = SpecInfoToKey callerName callerKind callerTypes + let calledKey = SpecInfoToKey calledName calledKind calledTypes + match dependencies.TryGetValue(callerKey) with + | true, deps -> deps.Add(calledKey) |> ignore + | false, _ -> let newDeps = new HashSet() + newDeps.Add(calledKey) |> ignore + dependencies.[callerKey] <- newDeps + + member this.FlushDependencies(callerName, callerKind, callerTypes) = + let key = SpecInfoToKey callerName callerKind callerTypes + dependencies.Remove(key) |> ignore + + member this.GetDependencies(callerName, callerKind, callerTypes) = + let key = SpecInfoToKey callerName callerKind callerTypes + match dependencies.TryGetValue(key) with + | true, deps -> + deps |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) + | false, _ -> Seq.empty + + member this.GetDependencyTree(callerName, callerKind, callerTypes) = + let key = SpecInfoToKey callerName callerKind callerTypes + WalkDependencyTree key (new HashSet(key |> Seq.singleton)) + |> Seq.filter (fun k -> k <> key) + |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) + + member this.GetDependencyLevel(callerName, callerKind, callerTypes) = + let getLevel k = + match levels.TryGetValue(k) with + | true, level -> level + | false, _ -> CapabilityLevel.Unset + let key = SpecInfoToKey callerName callerKind callerTypes + let deps = WalkDependencyTree key (new HashSet(key |> Seq.singleton)) + |> Seq.filter (fun k -> k <> key) + if Seq.isEmpty deps + then CapabilityLevel.Unset + else deps |> Seq.map getLevel |> Seq.max type internal CapabilityInfoHolder(context : QsNamespace seq) = let mutable localLevel = CapabilityLevel.Minimal @@ -24,8 +117,8 @@ type internal CapabilityInfoHolder(context : QsNamespace seq) = |> Seq.tryExactlyOne | false, _ -> None - member this.LocalLevel with get() = localLevel and set(n) = if int n > int localLevel then localLevel <- n - member this.CalledLevel with get() = calledLevel and set(n) = if int n > int calledLevel then calledLevel <- n + member this.LocalLevel with get() = localLevel and set(n) = if n > localLevel then localLevel <- n + member this.CalledLevel with get() = calledLevel and set(n) = if n > calledLevel then calledLevel <- n type internal ExpressionKindLeveler(holder : CapabilityInfoHolder) = inherit ExpressionKindTransformation() diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj index 63c3846c53..8637e93fb2 100644 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -5,7 +5,7 @@ - + @@ -16,6 +16,7 @@ + From 3ff24c40b3e2e77fb7bab5bf74779f8f4f5ae682 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 20 Sep 2019 15:14:44 -0700 Subject: [PATCH 06/32] Dependency tracking is done for now. Next step is to figure out levels based on the code, which will require levels to be defined. --- .../QsTargeting/CapabilityLeveler.fs | 213 +++++++++++------- 1 file changed, 133 insertions(+), 80 deletions(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 079ec59c83..919361f351 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -module Microsoft.Quantum.QsCompiler.Targeting.CapabilityLeveler +module Microsoft.Quantum.QsCompiler.Targeting.Leveler open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.Core @@ -14,14 +14,14 @@ open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput -type internal SpecializationKey = +type private SpecializationKey = { QualifiedName : QsQualifiedName Kind : QsSpecializationKind TypeArgString : string } -type CapabilityLevelManager() = +type private CapabilityLevelManager() = let sep = '|' let levels = new Dictionary() let dependencies = new Dictionary>() @@ -40,6 +40,9 @@ type CapabilityLevelManager() = |> String.concat (sep.ToString()) { QualifiedName = name; Kind = kind; TypeArgString = typeArgString } + let SpecToKey (spec : QsSpecialization) = + SpecInfoToKey spec.Parent spec.Kind spec.TypeArguments + let StringToTypeArray (ts : string) = let lookupString s = match keyTypes.TryGetValue(s) with @@ -50,93 +53,147 @@ type CapabilityLevelManager() = then Null else Value (typeSequence |> ImmutableArray.ToImmutableArray) + let RecordDependency callerKey calledKey = + match dependencies.TryGetValue(callerKey) with + | true, deps -> deps.Add(calledKey) |> ignore + | false, _ -> let newDeps = new HashSet() + newDeps.Add(calledKey) |> ignore + dependencies.[callerKey] <- newDeps + let rec WalkDependencyTree root (accum : HashSet) = match dependencies.TryGetValue(root) with | true, next -> next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum | false, _ -> accum - member this.GetSpecializationLevel(name, kind, types) = - let key = SpecInfoToKey name kind types + member this.GetSpecializationLevel(spec) = + let key = SpecToKey spec match levels.TryGetValue(key) with | true, level -> level | false, _ -> CapabilityLevel.Unset - member this.SetSpecializationLevel(name, kind, types, level) = - let key = SpecInfoToKey name kind types + member this.SetSpecializationLevel(spec, level) = + let key = SpecToKey spec levels.[key] <- level - member this.AddDependency(callerName, callerKind, callerTypes, calledName, calledKind, calledTypes) = - let callerKey = SpecInfoToKey callerName callerKind callerTypes - let calledKey = SpecInfoToKey calledName calledKind calledTypes - match dependencies.TryGetValue(callerKey) with - | true, deps -> deps.Add(calledKey) |> ignore - | false, _ -> let newDeps = new HashSet() - newDeps.Add(calledKey) |> ignore - dependencies.[callerKey] <- newDeps + member this.AddDependency(callerSpec, calledSpec) = + let callerKey = SpecToKey callerSpec + let calledKey = SpecToKey calledSpec + RecordDependency callerKey calledKey + + member this.AddDependency(callerSpec, calledName, calledKind, calledTypeArgs) = + let callerKey = SpecToKey callerSpec + let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs + RecordDependency callerKey calledKey + + member this.AddDependency(callerName, callerKind, callerTypeArgs, calledName, calledKind, calledTypeArgs) = + let callerKey = SpecInfoToKey callerName callerKind callerTypeArgs + let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs + RecordDependency callerKey calledKey - member this.FlushDependencies(callerName, callerKind, callerTypes) = - let key = SpecInfoToKey callerName callerKind callerTypes + member this.FlushDependencies(callerSpec) = + let key = SpecToKey callerSpec dependencies.Remove(key) |> ignore - member this.GetDependencies(callerName, callerKind, callerTypes) = - let key = SpecInfoToKey callerName callerKind callerTypes + member this.GetDependencies(callerSpec) = + let key = SpecToKey callerSpec match dependencies.TryGetValue(key) with | true, deps -> deps |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) | false, _ -> Seq.empty - member this.GetDependencyTree(callerName, callerKind, callerTypes) = - let key = SpecInfoToKey callerName callerKind callerTypes + member this.GetDependencyTree(callerSpec) = + let key = SpecToKey callerSpec WalkDependencyTree key (new HashSet(key |> Seq.singleton)) |> Seq.filter (fun k -> k <> key) |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) - member this.GetDependencyLevel(callerName, callerKind, callerTypes) = + member this.GetDependencyLevel(callerSpec) = let getLevel k = match levels.TryGetValue(k) with | true, level -> level | false, _ -> CapabilityLevel.Unset - let key = SpecInfoToKey callerName callerKind callerTypes + let key = SpecToKey callerSpec let deps = WalkDependencyTree key (new HashSet(key |> Seq.singleton)) |> Seq.filter (fun k -> k <> key) if Seq.isEmpty deps then CapabilityLevel.Unset else deps |> Seq.map getLevel |> Seq.max -type internal CapabilityInfoHolder(context : QsNamespace seq) = +let private manager = new CapabilityLevelManager() + +type private CapabilityInfoHolder(spec) = let mutable localLevel = CapabilityLevel.Minimal - let mutable calledLevel = CapabilityLevel.Minimal - let callables = context |> GlobalCallableResolutions - - member this.GetCallableLevel(name, modifier, types) = - match callables.TryGetValue(name) with - | true, callable -> - callable.Specializations |> Seq.filter (fun spec -> spec.Kind = modifier && spec.TypeArguments = types) - |> Seq.map (fun a -> a.RequiredCapability) - |> Seq.tryExactlyOne - | false, _ -> None member this.LocalLevel with get() = localLevel and set(n) = if n > localLevel then localLevel <- n - member this.CalledLevel with get() = calledLevel and set(n) = if n > calledLevel then calledLevel <- n -type internal ExpressionKindLeveler(holder : CapabilityInfoHolder) = + member this.Specialization with get() = spec + +type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = inherit ExpressionKindTransformation() let exprXformer = new ExpressionLeveler(holder) + let mutable inCall = false + let mutable adjoint = false + let mutable controlled = false + + member private this.HandleCallable method arg = + inCall <- true + adjoint <- false + controlled <- false + let method = this.ExpressionTransformation method + inCall <- false + let arg = this.ExpressionTransformation arg + CallLikeExpression(method, arg) override this.ExpressionTransformation x = exprXformer.Transform x override this.TypeTransformation x = x - override this.onOperationCall(ex1, ex2) = - base.onOperationCall(ex1, ex2) - -and internal ExpressionLeveler(holder : CapabilityInfoHolder) = + override this.onOperationCall(method, arg) = + this.HandleCallable method arg + + override this.onFunctionCall(method, arg) = + this.HandleCallable method arg + + override this.onAdjointApplication(ex) = + adjoint <- true + base.onAdjointApplication(ex) + + override this.onControlledApplication(ex) = + controlled <- true + base.onControlledApplication(ex) + + override this.onIdentifier(sym, typeArgs) = + match sym with + | GlobalCallable(name) -> + if inCall + then + let kind = match adjoint, controlled with + | false, false -> QsBody + | false, true -> QsControlled + | true, false -> QsAdjoint + | true, true -> QsControlledAdjoint + manager.AddDependency(holder.Specialization, name, kind, typeArgs) + else + // The callable is being used in a non-call context, such as being + /// assigned to a variable or passed as an argument to another callable, + // which means it could get a functor applied at some later time. + // We're conservative and add all 4 possible kinds. + manager.AddDependency(holder.Specialization, name, QsBody, typeArgs) + manager.AddDependency(holder.Specialization, name, QsControlled, typeArgs) + manager.AddDependency(holder.Specialization, name, QsAdjoint, typeArgs) + manager.AddDependency(holder.Specialization, name, QsControlledAdjoint, typeArgs) + | _ -> () + base.onIdentifier(sym, typeArgs) + +and private ExpressionLeveler(holder : CapabilityInfoHolder) = inherit ExpressionTransformation() let kindXformer = new ExpressionKindLeveler(holder) -and internal StatementLeveler(holder : CapabilityInfoHolder) = + override this.Kind = upcast kindXformer + +and private StatementLeveler(holder : CapabilityInfoHolder) = inherit StatementKindTransformation() let scopeXformer = new ScopeLeveler(holder) @@ -147,16 +204,12 @@ and internal StatementLeveler(holder : CapabilityInfoHolder) = override this.TypeTransformation x = x override this.LocationTransformation x = x -and internal ScopeLeveler(holder : CapabilityInfoHolder) = +and private ScopeLeveler(holder : CapabilityInfoHolder) = inherit ScopeTransformation() override this.StatementKind = upcast new StatementLeveler(holder) -type TreeLeveler(context : QsNamespace seq) = - inherit SyntaxTreeTransformation() - - let mutable currentCallableLevel = None : (CapabilityLevel * CapabilityLevel) option - +let ProcessSpecialization(callable : QsCallable, spec : QsSpecialization) = let checkForLevelAttributes (attrs : QsDeclarationAttribute seq) = let isLevelAttribute (a : QsDeclarationAttribute) = match a.TypeId with @@ -165,44 +218,44 @@ type TreeLeveler(context : QsNamespace seq) = let getLevelFromArgument (a : QsDeclarationAttribute) = match a.Argument.Expression with | IntLiteral n -> let level = enum (int n) - Some (level, level) + Some level | _ -> None let levels = attrs |> Seq.filter isLevelAttribute |> List.ofSeq match levels with | [ level ] -> getLevelFromArgument level | [] -> None | _ -> None + let computeLevelFromImplementation () = + match spec.Implementation with + | SpecializationImplementation.Provided (_, code) -> + // Compute the capability levels by walking the code + let holder = new CapabilityInfoHolder(spec) + let xform = new ScopeLeveler(holder) + xform.Transform code |> ignore + Some holder.LocalLevel + | SpecializationImplementation.Intrinsic -> + Some CapabilityLevel.Minimal + | SpecializationImplementation.External -> + None + | SpecializationImplementation.Generated _ -> + // TODO: Find the "base" specialization and use it's level + Some CapabilityLevel.Unset + // We always have to walk the implementation in order to reset call dependencies, + // even if the local level is set by an attribute. + manager.FlushDependencies(spec) + let levelFromImplementation = computeLevelFromImplementation() + // Now we can get the max level of called routines + let calledLevel = manager.GetDependencyLevel(spec) + + // If there is a Level attribute for this specific specialization, use it; otherwise, + // use the level from Level attribute for the containing callable, if any; as a last + // resort, check the actual implementation. + let localLevel = checkForLevelAttributes spec.Attributes + |> Option.orElse (checkForLevelAttributes callable.Attributes) + |> Option.orElse levelFromImplementation + |> Option.defaultValue CapabilityLevel.Unset + manager.SetSpecializationLevel(spec, localLevel) + + (localLevel, calledLevel) - let transformSpecialization (spec : QsSpecialization) = - let computeLevelFromImplementation () = - match spec.Implementation with - | SpecializationImplementation.Provided (_, code) -> - // Compute the capability levels by walking the code - let holder = new CapabilityInfoHolder(context) - let xform = new ScopeLeveler(holder) - xform.Transform code |> ignore - Some (holder.LocalLevel, holder.CalledLevel) - | SpecializationImplementation.Intrinsic -> - Some (CapabilityLevel.Minimal, CapabilityLevel.Minimal) - | SpecializationImplementation.External -> - None - | SpecializationImplementation.Generated _ -> - // TODO: Find the "base" specialization and use it's levels - Some (CapabilityLevel.Unset, CapabilityLevel.Unset) - // If there is a Level attribute for this specific specialization, use it; otherwise, - // use the level from Level attribute for the containing callable, if any; as a last - // resort, check the actual implementation. - let local, called = spec.Attributes - |> checkForLevelAttributes - |> Option.orElse currentCallableLevel - |> Option.orElseWith computeLevelFromImplementation - |> Option.defaultValue (CapabilityLevel.Unset, CapabilityLevel.Unset) - { spec with LocalRequiredCapability = local; RequiredCapability = called } - - override this.onSpecializationImplementation spec = - transformSpecialization spec - - override this.beforeCallable callable = - currentCallableLevel <- checkForLevelAttributes callable.Attributes - base.beforeCallable callable From 22ad65833a29069b88ca68a9eeb5968f195683f7 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 27 Sep 2019 09:55:27 -0700 Subject: [PATCH 07/32] Started on actual levels --- .../Core/ExpressionTransformation.fs | 3 +- .../QsTargeting/CapabilityLeveler.fs | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/QsCompiler/Core/ExpressionTransformation.fs b/src/QsCompiler/Core/ExpressionTransformation.fs index 7942c73547..b51723fcf4 100644 --- a/src/QsCompiler/Core/ExpressionTransformation.fs +++ b/src/QsCompiler/Core/ExpressionTransformation.fs @@ -189,7 +189,8 @@ type ExpressionKindTransformation(?enable) = | ExpressionType.Operation _ -> this.onOperationCall (method, arg) | _ -> this.onFunctionCall (method, arg) - member this.Transform kind = + abstract member Transform : ExpressionKind -> ExpressionKind + default this.Transform kind = if not enable then kind else match kind with | Identifier (sym, tArgs) -> this.onIdentifier (sym, tArgs) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 919361f351..3aa7249a72 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -186,6 +186,47 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = | _ -> () base.onIdentifier(sym, typeArgs) + override this.Transform(kind) = + match kind with + | UnwrapApplication _ + | ValueTuple _ + | ArrayItem _ + | NamedItem _ + | ValueArray _ + | NewArray _ + | IntLiteral _ + | BigIntLiteral _ + | DoubleLiteral _ + | BoolLiteral _ + | StringLiteral _ + | RangeLiteral _ + | CopyAndUpdate _ + | CONDITIONAL _ + | EQ _ + | NEQ _ + | LT _ + | LTE _ + | GT _ + | GTE _ + | AND _ + | OR _ + | ADD _ + | SUB _ + | MUL _ + | DIV _ + | POW _ + | MOD _ + | LSHIFT _ + | RSHIFT _ + | BXOR _ + | BOR _ + | BAND _ + | NOT _ + | NEG _ + | BNOT _ -> holder.LocalLevel <- CapabilityLevel.Medium + | _ -> () + base.Transform(kind) + and private ExpressionLeveler(holder : CapabilityInfoHolder) = inherit ExpressionTransformation() From 9feb55bddb27dbe3d483671092c4609af67aac3e Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 27 Sep 2019 14:26:47 -0700 Subject: [PATCH 08/32] Couple of changes. Next step is to figure out how to handle quantum-ness of expressions in `if` statements. --- src/QsCompiler/QsTargeting/CapabilityLeveler.fs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 3aa7249a72..c89a8b0e04 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -234,7 +234,7 @@ and private ExpressionLeveler(holder : CapabilityInfoHolder) = override this.Kind = upcast kindXformer -and private StatementLeveler(holder : CapabilityInfoHolder) = +type private StatementLeveler(holder : CapabilityInfoHolder) = inherit StatementKindTransformation() let scopeXformer = new ScopeLeveler(holder) @@ -245,6 +245,10 @@ and private StatementLeveler(holder : CapabilityInfoHolder) = override this.TypeTransformation x = x override this.LocationTransformation x = x + override this.onRepeatStatement(s) = + holder.LocalLevel <- CapabilityLevel.Advanced + base.onRepeatStatement(s) + and private ScopeLeveler(holder : CapabilityInfoHolder) = inherit ScopeTransformation() From beef94de68a46520e4f16229fc0db0c6a9a348b6 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Thu, 3 Oct 2019 15:45:41 -0700 Subject: [PATCH 09/32] WIP: Working on expression checking for if statements. --- .../QsTargeting/CapabilityLeveler.fs | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index c89a8b0e04..8dda9076a9 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -3,16 +3,15 @@ module Microsoft.Quantum.QsCompiler.Targeting.Leveler +open Microsoft.Quantum.QsCompiler +open Microsoft.Quantum.QsCompiler.DataTypes +open Microsoft.Quantum.QsCompiler.SyntaxExtensions +open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.Core +open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput open System.Collections.Immutable open System.Collections.Generic -open System -open Microsoft.Quantum.QsCompiler.DataTypes -open Microsoft.Quantum.QsCompiler -open Microsoft.Quantum.QsCompiler -open Microsoft.Quantum.QsCompiler.SyntaxTokens -open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput type private SpecializationKey = { @@ -231,6 +230,9 @@ and private ExpressionLeveler(holder : CapabilityInfoHolder) = inherit ExpressionTransformation() let kindXformer = new ExpressionKindLeveler(holder) + let mutable isSimpleResultTest = true + + member this.IsSimpleResultTest with get() = isSimpleResultTest and set(value) = isSimpleResultTest <- value override this.Kind = upcast kindXformer @@ -241,10 +243,24 @@ type private StatementLeveler(holder : CapabilityInfoHolder) = let exprXformer = new ExpressionLeveler(holder) override this.ScopeTransformation x = scopeXformer.Transform x - override this.ExpressionTransformation x = exprXformer.Transform x + override this.ExpressionTransformation x = + exprXformer.IsSimpleResultTest <- true + exprXformer.Transform x override this.TypeTransformation x = x override this.LocationTransformation x = x + override this.onConditionalStatement(stm) = + let processCase (condition, block : QsPositionedBlock) = + let location = block.Location + let comments = block.Comments + let expr = this.ExpressionTransformation condition + if not exprXformer.IsSimpleResultTest then holder.LocalLevel <- CapabilityLevel.Medium + let body = this.ScopeTransformation block.Body + expr, QsPositionedBlock.New comments location body + let cases = stm.ConditionalBlocks |> Seq.map processCase + let defaultCase = stm.Default |> QsNullable<_>.Map (fun b -> this.onPositionedBlock (None, b) |> snd) + QsConditionalStatement.New (cases, defaultCase) |> QsConditionalStatement + override this.onRepeatStatement(s) = holder.LocalLevel <- CapabilityLevel.Advanced base.onRepeatStatement(s) From 71a4968cb5016675b29988413d409a303b271b23 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 4 Oct 2019 13:01:37 -0700 Subject: [PATCH 10/32] Basic checks in place. Time to start thinking about tests... --- .../QsTargeting/CapabilityLeveler.fs | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 8dda9076a9..d087802513 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -120,6 +120,9 @@ type private CapabilityLevelManager() = else deps |> Seq.map getLevel |> Seq.max let private manager = new CapabilityLevelManager() + +let private isResult ex = + match ex.ResolvedType.Resolution with | Result -> true | _ -> false type private CapabilityInfoHolder(spec) = let mutable localLevel = CapabilityLevel.Minimal @@ -135,6 +138,9 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = let mutable inCall = false let mutable adjoint = false let mutable controlled = false + let mutable isSimpleResultTest = true + + member this.IsSimpleResultTest with get() = isSimpleResultTest and set(value) = isSimpleResultTest <- value member private this.HandleCallable method arg = inCall <- true @@ -201,14 +207,12 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = | RangeLiteral _ | CopyAndUpdate _ | CONDITIONAL _ - | EQ _ | NEQ _ | LT _ | LTE _ | GT _ | GTE _ | AND _ - | OR _ | ADD _ | SUB _ | MUL _ @@ -222,7 +226,13 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = | BAND _ | NOT _ | NEG _ - | BNOT _ -> holder.LocalLevel <- CapabilityLevel.Medium + | BNOT _ -> + holder.LocalLevel <- CapabilityLevel.Medium + | OR _ -> + isSimpleResultTest <- false + | EQ (ex1, ex2) -> + if not (isResult ex1 && isResult ex2) + then isSimpleResultTest <- false | _ -> () base.Transform(kind) @@ -230,11 +240,11 @@ and private ExpressionLeveler(holder : CapabilityInfoHolder) = inherit ExpressionTransformation() let kindXformer = new ExpressionKindLeveler(holder) - let mutable isSimpleResultTest = true - member this.IsSimpleResultTest with get() = isSimpleResultTest and set(value) = isSimpleResultTest <- value + override this.Kind = upcast kindXformer - override this.Kind = upcast kindXformer + member this.IsSimpleResultTest with get() = kindXformer.IsSimpleResultTest + and set(v) = kindXformer.IsSimpleResultTest <- v type private StatementLeveler(holder : CapabilityInfoHolder) = inherit StatementKindTransformation() @@ -251,12 +261,12 @@ type private StatementLeveler(holder : CapabilityInfoHolder) = override this.onConditionalStatement(stm) = let processCase (condition, block : QsPositionedBlock) = - let location = block.Location - let comments = block.Comments let expr = this.ExpressionTransformation condition - if not exprXformer.IsSimpleResultTest then holder.LocalLevel <- CapabilityLevel.Medium + if not exprXformer.IsSimpleResultTest + then holder.LocalLevel <- CapabilityLevel.Medium + else holder.LocalLevel <- CapabilityLevel.Basic let body = this.ScopeTransformation block.Body - expr, QsPositionedBlock.New comments location body + expr, QsPositionedBlock.New block.Comments block.Location body let cases = stm.ConditionalBlocks |> Seq.map processCase let defaultCase = stm.Default |> QsNullable<_>.Map (fun b -> this.onPositionedBlock (None, b) |> snd) QsConditionalStatement.New (cases, defaultCase) |> QsConditionalStatement @@ -265,6 +275,22 @@ type private StatementLeveler(holder : CapabilityInfoHolder) = holder.LocalLevel <- CapabilityLevel.Advanced base.onRepeatStatement(s) + override this.onWhileStatement(s) = + holder.LocalLevel <- CapabilityLevel.Advanced + base.onWhileStatement(s) + + override this.onValueUpdate(s) = + holder.LocalLevel <- CapabilityLevel.Advanced + base.onValueUpdate(s) + + override this.onVariableDeclaration(s) = + if s.Kind = QsBindingKind.MutableBinding + then holder.LocalLevel <- CapabilityLevel.Advanced + else + if not (isResult s.Rhs) + then holder.LocalLevel <- CapabilityLevel.Advanced + base.onVariableDeclaration(s) + and private ScopeLeveler(holder : CapabilityInfoHolder) = inherit ScopeTransformation() From 8476dd7e7ecc3c1984008d5875d31b109b9edf48 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Tue, 15 Oct 2019 15:58:38 -0700 Subject: [PATCH 11/32] WIP -- restructuring to work on a syntax tree, and starting to add unit tests --- .../QsTargeting/CapabilityLeveler.fs | 39 +++++++++++++- .../Tests.Compiler/CapabilityLevelerTests.fs | 47 +++++++++++++++++ .../Tests.Compiler/TestFiles/test-03.qs | 52 +++++++++++++++++++ .../Tests.Compiler/Tests.Compiler.fsproj | 11 ++++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs create mode 100644 src/QsCompiler/Tests.Compiler/TestFiles/test-03.qs diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index d087802513..6935db88fe 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -65,6 +65,11 @@ type private CapabilityLevelManager() = next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum | false, _ -> accum + member this.Reset () = + levels.Clear() + dependencies.Clear() + keyTypes.Clear() + member this.GetSpecializationLevel(spec) = let key = SpecToKey spec match levels.TryGetValue(key) with @@ -124,6 +129,15 @@ let private manager = new CapabilityLevelManager() let private isResult ex = match ex.ResolvedType.Resolution with | Result -> true | _ -> false +let private isQubitType (t : ResolvedType) = + match t.Resolution with | Qubit -> true | _ -> false + +let private isQubit ex = + ex.ResolvedType |> isQubitType + +let private isQubitArray ex = + match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false + type private CapabilityInfoHolder(spec) = let mutable localLevel = CapabilityLevel.Minimal @@ -195,7 +209,6 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = match kind with | UnwrapApplication _ | ValueTuple _ - | ArrayItem _ | NamedItem _ | ValueArray _ | NewArray _ @@ -233,6 +246,9 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = | EQ (ex1, ex2) -> if not (isResult ex1 && isResult ex2) then isSimpleResultTest <- false + | ArrayItem (arr, idx) -> + if not (isQubitArray arr) + then holder.LocalLevel <- CapabilityLevel.Medium | _ -> () base.Transform(kind) @@ -345,4 +361,23 @@ let ProcessSpecialization(callable : QsCallable, spec : QsSpecialization) = (localLevel, calledLevel) - +type TreeLeveler() = + inherit SyntaxTreeTransformation() + + do + manager.Reset() + + let mutable spec = None : QsSpecialization option + + override this.Scope + with get() = + match spec with + | Some s -> + let holder = new CapabilityInfoHolder(s) + let xform = new ScopeLeveler(holder) + upcast xform + | None -> failwith "Scope outside of a specialization" + + override this.onSpecializationImplementation(s) = + spec <- Some s + base.onSpecializationImplementation(s) \ No newline at end of file diff --git a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs new file mode 100644 index 0000000000..2cf6251230 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +module Microsoft.Quantum.QsCompiler.Testing.CapabilityLevelerTests + +open System +open System.Collections.Immutable +open System.IO +open System.Linq +open Microsoft.Quantum.QsCompiler +open Microsoft.Quantum.QsCompiler.CompilationBuilder +open Microsoft.Quantum.QsCompiler.DataTypes +open Microsoft.Quantum.QsCompiler.SyntaxTree +open Microsoft.Quantum.QsCompiler.Transformations +open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput +open Xunit + +// Utilities for testing operation capability level setting and the corresponding infrastructure + +let private buildSyntaxTree path code = + let fileId = new Uri(path) + let compilationUnit = new CompilationUnitManager(fun ex -> failwith ex.Message) + let file = CompilationUnitManager.InitializeFileManager(fileId, code) + compilationUnit.AddOrUpdateSourceFileAsync file |> ignore // spawns a task that modifies the current compilation + let mutable syntaxTree = compilationUnit.GetSyntaxTree() // will wait for any current tasks to finish + //FunctorGeneration.GenerateFunctorSpecializations(syntaxTree, &syntaxTree) |> ignore + syntaxTree + +let private buildSyntaxTreeFromFile fileName = + let path = Path.Combine(Path.GetFullPath ".", "TestFiles", fileName) + path |> File.ReadAllText |> buildSyntaxTree path + +//let private + +let private getOperationLevel tree opName = + let matchOperation opName (e : QsNamespaceElement) = + match e with + | QsCallable c when c.FullName.Name.Value = opName -> + Some c + | _ -> None + let findOperation (ns : QsNamespace) opName = + ns.Elements |> Seq.tryPick (matchOperation opName) + tree |> Seq.tryPick (findOperation opName) + + +//////////////////////////////// tests ////////////////////////////////// + diff --git a/src/QsCompiler/Tests.Compiler/TestFiles/test-03.qs b/src/QsCompiler/Tests.Compiler/TestFiles/test-03.qs new file mode 100644 index 0000000000..5237da43b7 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestFiles/test-03.qs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Tests for capability leveling + +namespace Microsoft.Quantum.Testing { + // This should be level 1 since it's intrinsic. + operation M (q : Qubit) : Result + { + body intrinsic; + } + + // This should be level 1 since it's intrinsic. + operation H (q : Qubit) : Unit + { + body intrinsic; + } + + // This should be level 1 since everything it does is safe. + operation Level1 () : Unit + { + using (q = Qubit()) + { + return M(q); + } + } + + // This should be level 2 because it has a branch on a measurement result. + operation Level2 () : Unit + { + using (q = Qubit()) + { + if (M(q) == One) + { + H(q); + } + } + } + + // This should be level 5 because it has classical computation. + operation Level5 (d : Double) : Double + { + return 1.0/d; + } + + // This should be level 4 because of the attribute. + @Level(4) + operation Level4 () : Unit + { + + } +} diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj index 6fbe8cc4cd..02b558820b 100644 --- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj +++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj @@ -109,6 +109,16 @@ PreserveNewest + + Never + + + Never + + + Never + + @@ -127,6 +137,7 @@ + From 8e47f079c77b404cd0e99aa2a783a09322ce6848 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Wed, 16 Oct 2019 14:04:29 -0700 Subject: [PATCH 12/32] The transformations are restructured and cleaned up, and no more hidden state (everything is wrapped in the top-level transformation). Still tests to add, as well as a few TODOs left in the code. --- .../CompilationManager/CompilationUnit.cs | 10 +- .../CompilationManager/TypeChecking.cs | 4 +- src/QsCompiler/Core/ConstructorExtensions.fs | 1 - src/QsCompiler/DataStructures/SyntaxTree.fs | 4 +- .../QsTargeting/CapabilityLeveler.fs | 147 ++++++++++-------- 5 files changed, 90 insertions(+), 76 deletions(-) diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index eeca08f519..685d9d8a03 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -396,8 +396,8 @@ internal void UpdateCallables(IEnumerable updates) { var specLocation = new QsLocation(header.Position, header.SymbolRange); var defaultSpec = new QsSpecialization(QsSpecializationKind.QsBody, header.QualifiedName, header.Attributes, CapabilityLevel.Unset, - CapabilityLevel.Unset, header.SourceFile, specLocation, QsNullable>.Null, header.Signature, - SpecializationImplementation.Intrinsic, ImmutableArray.Empty, QsComments.Empty); + header.SourceFile, specLocation, QsNullable>.Null, header.Signature, SpecializationImplementation.Intrinsic, + ImmutableArray.Empty, QsComments.Empty); this.CompiledCallables[fullName] = new QsCallable(header.Kind, header.QualifiedName, header.Attributes, header.SourceFile, specLocation, header.Signature, header.ArgumentTuple, ImmutableArray.Create(defaultSpec), header.Documentation, QsComments.Empty); continue; @@ -420,8 +420,8 @@ internal void UpdateCallables(IEnumerable updates) var compiledSpec = compiledSpecs.Single(); var specLocation = new QsLocation(specHeader.Position, specHeader.HeaderRange); return new QsSpecialization(compiledSpec.Kind, compiledSpec.Parent, compiledSpec.Attributes, CapabilityLevel.Unset, - CapabilityLevel.Unset, compiledSpec.SourceFile, specLocation, compiledSpec.TypeArguments, compiledSpec.Signature, - compiledSpec.Implementation, compiledSpec.Documentation, compiledSpec.Comments); + compiledSpec.SourceFile, specLocation, compiledSpec.TypeArguments, compiledSpec.Signature, compiledSpec.Implementation, + compiledSpec.Documentation, compiledSpec.Comments); }) .Where(spec => spec != null).ToImmutableArray(); @@ -455,7 +455,7 @@ private QsCallable GetImportedCallable(CallableDeclarationHeader header) ? SyntaxGenerator.BuildControlled(header.Signature) : header.Signature; return new QsSpecialization(specHeader.Kind, header.QualifiedName, specHeader.Attributes, CapabilityLevel.Unset, - CapabilityLevel.Unset, specHeader.SourceFile, specLocation, specHeader.TypeArguments, specSignature, + specHeader.SourceFile, specLocation, specHeader.TypeArguments, specSignature, implementation, specHeader.Documentation, QsComments.Empty); }) .ToImmutableArray(); diff --git a/src/QsCompiler/CompilationManager/TypeChecking.cs b/src/QsCompiler/CompilationManager/TypeChecking.cs index d977e95c0b..571d5bc345 100644 --- a/src/QsCompiler/CompilationManager/TypeChecking.cs +++ b/src/QsCompiler/CompilationManager/TypeChecking.cs @@ -1226,8 +1226,8 @@ private static ImmutableArray BuildSpecializations QsSpecialization GetSpecialization(SpecializationDeclarationHeader spec, ResolvedSignature signature, SpecializationImplementation implementation, QsComments comments = null) => - new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, CapabilityLevel.Unset, CapabilityLevel.Unset, - spec.SourceFile, null, spec.TypeArguments, SyntaxGenerator.WithoutRangeInfo(signature), implementation, spec.Documentation, comments ?? QsComments.Empty); + new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, CapabilityLevel.Unset, spec.SourceFile, null, + spec.TypeArguments, SyntaxGenerator.WithoutRangeInfo(signature), implementation, spec.Documentation, comments ?? QsComments.Empty); QsSpecialization BuildSpecialization(QsSpecializationKind kind, ResolvedSignature signature, QsSpecializationGeneratorKind gen, FragmentTree.TreeNode root, Func>, QsCompilerDiagnostic[]>> buildArg, QsComments comments = null) diff --git a/src/QsCompiler/Core/ConstructorExtensions.fs b/src/QsCompiler/Core/ConstructorExtensions.fs index 7cb7abeb7c..5a1329f78a 100644 --- a/src/QsCompiler/Core/ConstructorExtensions.fs +++ b/src/QsCompiler/Core/ConstructorExtensions.fs @@ -182,7 +182,6 @@ type QsSpecialization with Parent = parent Attributes = attributes RequiredCapability = CapabilityLevel.Unset - LocalRequiredCapability = CapabilityLevel.Unset SourceFile = source Location = location TypeArguments = typeArgs diff --git a/src/QsCompiler/DataStructures/SyntaxTree.fs b/src/QsCompiler/DataStructures/SyntaxTree.fs index f74d93274e..a44ad32892 100644 --- a/src/QsCompiler/DataStructures/SyntaxTree.fs +++ b/src/QsCompiler/DataStructures/SyntaxTree.fs @@ -628,10 +628,8 @@ type QsSpecialization = { Parent : QsQualifiedName /// contains all attributes associated with the specialization Attributes : ImmutableArray - /// contains the minimum target capability level for this specialization, including its entire call tree - RequiredCapability : CapabilityLevel /// contains the minimum target capability level for this specialization's code, not including anything it calls - LocalRequiredCapability : CapabilityLevel + RequiredCapability : CapabilityLevel /// identifier for the file the specialization is declared in (not necessarily the same as the one of the callable it extends) SourceFile : NonNullable /// Contains the location information for the declared specialization. diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 6935db88fe..2f0087a34f 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -65,11 +65,6 @@ type private CapabilityLevelManager() = next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum | false, _ -> accum - member this.Reset () = - levels.Clear() - dependencies.Clear() - keyTypes.Clear() - member this.GetSpecializationLevel(spec) = let key = SpecToKey spec match levels.TryGetValue(key) with @@ -124,8 +119,6 @@ type private CapabilityLevelManager() = then CapabilityLevel.Unset else deps |> Seq.map getLevel |> Seq.max -let private manager = new CapabilityLevelManager() - let private isResult ex = match ex.ResolvedType.Resolution with | Result -> true | _ -> false @@ -138,13 +131,15 @@ let private isQubit ex = let private isQubitArray ex = match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false -type private CapabilityInfoHolder(spec) = - let mutable localLevel = CapabilityLevel.Minimal +type private CapabilityInfoHolder(spec, manager : CapabilityLevelManager) = + let mutable localLevel = CapabilityLevel.Unset member this.LocalLevel with get() = localLevel and set(n) = if n > localLevel then localLevel <- n member this.Specialization with get() = spec + member this.Manager = manager + type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = inherit ExpressionKindTransformation() @@ -156,7 +151,7 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = member this.IsSimpleResultTest with get() = isSimpleResultTest and set(value) = isSimpleResultTest <- value - member private this.HandleCallable method arg = + member private this.HandleCall method arg = inCall <- true adjoint <- false controlled <- false @@ -169,10 +164,10 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = override this.TypeTransformation x = x override this.onOperationCall(method, arg) = - this.HandleCallable method arg + this.HandleCall method arg override this.onFunctionCall(method, arg) = - this.HandleCallable method arg + this.HandleCall method arg override this.onAdjointApplication(ex) = adjoint <- true @@ -192,16 +187,16 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = | false, true -> QsControlled | true, false -> QsAdjoint | true, true -> QsControlledAdjoint - manager.AddDependency(holder.Specialization, name, kind, typeArgs) + holder.Manager.AddDependency(holder.Specialization, name, kind, typeArgs) else // The callable is being used in a non-call context, such as being /// assigned to a variable or passed as an argument to another callable, // which means it could get a functor applied at some later time. // We're conservative and add all 4 possible kinds. - manager.AddDependency(holder.Specialization, name, QsBody, typeArgs) - manager.AddDependency(holder.Specialization, name, QsControlled, typeArgs) - manager.AddDependency(holder.Specialization, name, QsAdjoint, typeArgs) - manager.AddDependency(holder.Specialization, name, QsControlledAdjoint, typeArgs) + holder.Manager.AddDependency(holder.Specialization, name, QsBody, typeArgs) + holder.Manager.AddDependency(holder.Specialization, name, QsControlled, typeArgs) + holder.Manager.AddDependency(holder.Specialization, name, QsAdjoint, typeArgs) + holder.Manager.AddDependency(holder.Specialization, name, QsControlledAdjoint, typeArgs) | _ -> () base.onIdentifier(sym, typeArgs) @@ -312,7 +307,15 @@ and private ScopeLeveler(holder : CapabilityInfoHolder) = override this.StatementKind = upcast new StatementLeveler(holder) -let ProcessSpecialization(callable : QsCallable, spec : QsSpecialization) = + member this.Holder with get() = holder + +/// This syntax tree transformer fills in the CapabilityLevel fields in specializations, +/// based on information gathered by the associated scope and other transformations. +type TreeLeveler() = + inherit SyntaxTreeTransformation() + + // Checks to see if a callable or specialization has a developer-specified capability level, + // which overrides the level computed from the code if it is present.7682 let checkForLevelAttributes (attrs : QsDeclarationAttribute seq) = let isLevelAttribute (a : QsDeclarationAttribute) = match a.TypeId with @@ -328,56 +331,70 @@ let ProcessSpecialization(callable : QsCallable, spec : QsSpecialization) = | [ level ] -> getLevelFromArgument level | [] -> None | _ -> None - let computeLevelFromImplementation () = - match spec.Implementation with - | SpecializationImplementation.Provided (_, code) -> - // Compute the capability levels by walking the code - let holder = new CapabilityInfoHolder(spec) - let xform = new ScopeLeveler(holder) - xform.Transform code |> ignore - Some holder.LocalLevel - | SpecializationImplementation.Intrinsic -> - Some CapabilityLevel.Minimal - | SpecializationImplementation.External -> - None - | SpecializationImplementation.Generated _ -> - // TODO: Find the "base" specialization and use it's level - Some CapabilityLevel.Unset - // We always have to walk the implementation in order to reset call dependencies, - // even if the local level is set by an attribute. - manager.FlushDependencies(spec) - let levelFromImplementation = computeLevelFromImplementation() - // Now we can get the max level of called routines - let calledLevel = manager.GetDependencyLevel(spec) - - // If there is a Level attribute for this specific specialization, use it; otherwise, - // use the level from Level attribute for the containing callable, if any; as a last - // resort, check the actual implementation. - let localLevel = checkForLevelAttributes spec.Attributes - |> Option.orElse (checkForLevelAttributes callable.Attributes) - |> Option.orElse levelFromImplementation - |> Option.defaultValue CapabilityLevel.Unset - manager.SetSpecializationLevel(spec, localLevel) - - (localLevel, calledLevel) -type TreeLeveler() = - inherit SyntaxTreeTransformation() - - do - manager.Reset() + let manager = new CapabilityLevelManager() let mutable spec = None : QsSpecialization option - override this.Scope - with get() = - match spec with - | Some s -> - let holder = new CapabilityInfoHolder(s) - let xform = new ScopeLeveler(holder) - upcast xform - | None -> failwith "Scope outside of a specialization" + let mutable scopeXform = None : ScopeLeveler option + + let mutable currentOperationLevel = None : CapabilityLevel option + + override this.Scope with get() = upcast scopeXform.Value + + override this.beforeCallable(c) = + currentOperationLevel <- c.Attributes |> checkForLevelAttributes + base.beforeCallable(c) override this.onSpecializationImplementation(s) = - spec <- Some s - base.onSpecializationImplementation(s) \ No newline at end of file + let holder = new CapabilityInfoHolder(s, manager) + let xform = new ScopeLeveler(holder) + scopeXform <- Some xform + let result = base.onSpecializationImplementation(s) + let level = s.Attributes |> checkForLevelAttributes + |> Option.orElse currentOperationLevel + |> Option.defaultValue holder.LocalLevel + manager.SetSpecializationLevel(s, level) + { result with RequiredCapability = level } + + // TODO: For generated specializations, we need to find the appropriate "body" declaration + // and copy the required capability from that to the generated specialization. + + override this.onIntrinsicImplementation() = + scopeXform |> Option.iter (fun x -> x.Holder.LocalLevel <- CapabilityLevel.Minimal) + base.onIntrinsicImplementation() + + override this.Transform(ns : QsNamespace) = + let xformed = base.Transform ns + // We have to do this after we've checked all of the callables. + // Even so, there are potential issues from inter-namespace calls. + // TODO: figure out how to be safe against inter-namespace calls, given that + // namespaces may be processed in any order. + // Note that F# doesn't like ns |> base.Transform -- it complains about this usage + // of "base". + xformed |> this.PostProcess + + /// Update required levels based on full call trees. + /// We have to do this after we've checked all of the callables. + /// Even so, there are potential issues from inter-namespace calls. + /// TODO: figure out how to be safe against inter-namespace calls, given that + /// namespaces may be processed in any order. + member this.PostProcess(ns : QsNamespace) = + let processElement qse = + let processSpecialization (s : QsSpecialization) = + if s.Attributes |> checkForLevelAttributes |> Option.isNone + then + let calledLevel = manager.GetDependencyLevel(s) + if calledLevel > s.RequiredCapability + then { s with RequiredCapability = calledLevel } + else s + else s + match qse with + | QsCallable c when c.Attributes |> checkForLevelAttributes |> Option.isNone -> + let specs = c.Specializations |> Seq.map processSpecialization + QsCallable (QsCallable.New c.Kind (c.SourceFile, c.Location) + (c.FullName, c.Attributes, c.ArgumentTuple, c.Signature, + specs, c.Documentation, c.Comments)) + | _ -> qse + let elems = ns.Elements |> Seq.map processElement + QsNamespace.New(ns.Name, elems, ns.Documentation) From 06e457b03d2eaf0c8f5c6179cfbf76a5609c00d3 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Thu, 31 Oct 2019 17:12:39 -0700 Subject: [PATCH 13/32] WIP -- tests crashing --- .../QsTargeting/CapabilityLeveler.fs | 23 +++++++++++------ src/QsCompiler/QsTargeting/Targeting.fsproj | 2 +- .../Tests.Compiler/CapabilityLevelerTests.fs | 25 +++++++++++++++---- .../CapabilityLevels.qs} | 0 .../Tests.Compiler/Tests.Compiler.fsproj | 5 +++- 5 files changed, 41 insertions(+), 14 deletions(-) rename src/QsCompiler/Tests.Compiler/{TestFiles/test-03.qs => TestCases/CapabilityLevels.qs} (100%) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 2f0087a34f..387d53310e 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -31,12 +31,16 @@ type private CapabilityLevelManager() = let exprTransformer = new ExpressionToQs() let transformer = new ExpressionTypeToQs(exprTransformer) transformer.Apply(rt) - let typeArgs = types.ValueOr (new ImmutableArray()) - |> Seq.map (fun t -> (t, ResolvedTypeToString t)) - typeArgs |> Seq.iter (fun (t, s) -> keyTypes.[s] <- t) - let typeArgString = typeArgs - |> Seq.map snd + let getArgString (args : ImmutableArray) = + if args.IsDefaultOrEmpty + then "" + else + let typeArgs = args |> Seq.map (fun t -> (t, ResolvedTypeToString t)) + typeArgs |> Seq.iter (fun (t, s) -> keyTypes.[s] <- t) + typeArgs |> Seq.map snd |> String.concat (sep.ToString()) + let typeArgString = types |> QsNullable<_>.Map getArgString + |> fun n -> n.ValueOr "" { QualifiedName = name; Kind = kind; TypeArgString = typeArgString } let SpecToKey (spec : QsSpecialization) = @@ -264,6 +268,7 @@ type private StatementLeveler(holder : CapabilityInfoHolder) = let exprXformer = new ExpressionLeveler(holder) override this.ScopeTransformation x = scopeXformer.Transform x + override this.ExpressionTransformation x = exprXformer.IsSimpleResultTest <- true exprXformer.Transform x @@ -305,7 +310,9 @@ type private StatementLeveler(holder : CapabilityInfoHolder) = and private ScopeLeveler(holder : CapabilityInfoHolder) = inherit ScopeTransformation() - override this.StatementKind = upcast new StatementLeveler(holder) + let kindXformer = new StatementLeveler(holder) + + override this.StatementKind = upcast kindXformer member this.Holder with get() = holder @@ -340,10 +347,12 @@ type TreeLeveler() = let mutable currentOperationLevel = None : CapabilityLevel option - override this.Scope with get() = upcast scopeXform.Value + override this.Scope with get() = scopeXform |> Option.map (fun x -> x :> ScopeTransformation) + |> Option.defaultWith (fun () -> new ScopeTransformation()) override this.beforeCallable(c) = currentOperationLevel <- c.Attributes |> checkForLevelAttributes + System.Console.WriteLine("About to process callable " + c.FullName.Name.Value) base.beforeCallable(c) override this.onSpecializationImplementation(s) = diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj index 8637e93fb2..86bcb078f3 100644 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -1,7 +1,7 @@  - netstandard2.1 + netcoreapp3.0 diff --git a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs index 2cf6251230..118e658c62 100644 --- a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs +++ b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs @@ -11,23 +11,25 @@ open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.CompilationBuilder open Microsoft.Quantum.QsCompiler.DataTypes open Microsoft.Quantum.QsCompiler.SyntaxTree +open Microsoft.Quantum.QsCompiler.Targeting.Leveler open Microsoft.Quantum.QsCompiler.Transformations open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput open Xunit // Utilities for testing operation capability level setting and the corresponding infrastructure +let out = File.CreateText("C:\\Users\\ageller\\Source\\Repos\\debug.log") +System.Console.SetOut(out) + let private buildSyntaxTree path code = let fileId = new Uri(path) let compilationUnit = new CompilationUnitManager(fun ex -> failwith ex.Message) let file = CompilationUnitManager.InitializeFileManager(fileId, code) compilationUnit.AddOrUpdateSourceFileAsync file |> ignore // spawns a task that modifies the current compilation - let mutable syntaxTree = compilationUnit.GetSyntaxTree() // will wait for any current tasks to finish - //FunctorGeneration.GenerateFunctorSpecializations(syntaxTree, &syntaxTree) |> ignore - syntaxTree + compilationUnit.GetSyntaxTree() // will wait for any current tasks to finish let private buildSyntaxTreeFromFile fileName = - let path = Path.Combine(Path.GetFullPath ".", "TestFiles", fileName) + let path = Path.Combine(Path.GetFullPath ".", "TestCases", fileName + ".qs") path |> File.ReadAllText |> buildSyntaxTree path //let private @@ -38,10 +40,23 @@ let private getOperationLevel tree opName = | QsCallable c when c.FullName.Name.Value = opName -> Some c | _ -> None - let findOperation (ns : QsNamespace) opName = + let findOperation opName (ns : QsNamespace) = ns.Elements |> Seq.tryPick (matchOperation opName) + let getOperationBodyLevel (c : QsCallable) = + c.Specializations |> Seq.tryFind (fun s -> s.Kind = QsSpecializationKind.QsBody) + |> Option.map (fun s -> s.RequiredCapability) + |> Option.defaultValue CapabilityLevel.Unset tree |> Seq.tryPick (findOperation opName) + |> Option.defaultWith (fun () -> failwithf "Operation %A not found" opName) + |> getOperationBodyLevel //////////////////////////////// tests ////////////////////////////////// +[] +let ``capability leveling tests`` () = + let leveler = new TreeLeveler() + let syntaxTree = buildSyntaxTreeFromFile "CapabilityLevels" |> Seq.map leveler.Transform + + Assert.Equal(CapabilityLevel.Minimal, getOperationLevel syntaxTree "M") + () \ No newline at end of file diff --git a/src/QsCompiler/Tests.Compiler/TestFiles/test-03.qs b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs similarity index 100% rename from src/QsCompiler/Tests.Compiler/TestFiles/test-03.qs rename to src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj index 02b558820b..47a9233407 100644 --- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj +++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj @@ -118,7 +118,9 @@ Never - + + PreserveNewest + @@ -152,6 +154,7 @@ + false From 6aaba49a0e3d129fc52c86a90766127c15192f35 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 1 Nov 2019 13:19:23 -0700 Subject: [PATCH 14/32] First test case passes!! --- .../QsTargeting/CapabilityLeveler.fs | 18 ++++++++---------- .../Tests.Compiler/CapabilityLevelerTests.fs | 8 ++++---- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 387d53310e..95a4b2fe1e 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -144,10 +144,9 @@ type private CapabilityInfoHolder(spec, manager : CapabilityLevelManager) = member this.Manager = manager -type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = +type private ExpressionKindLeveler(exprXformer : ExpressionLeveler, holder : CapabilityInfoHolder) = inherit ExpressionKindTransformation() - let exprXformer = new ExpressionLeveler(holder) let mutable inCall = false let mutable adjoint = false let mutable controlled = false @@ -251,20 +250,19 @@ type private ExpressionKindLeveler(holder : CapabilityInfoHolder) = | _ -> () base.Transform(kind) -and private ExpressionLeveler(holder : CapabilityInfoHolder) = +and private ExpressionLeveler(holder : CapabilityInfoHolder) as this = inherit ExpressionTransformation() - let kindXformer = new ExpressionKindLeveler(holder) + let kindXformer = new ExpressionKindLeveler(this, holder) override this.Kind = upcast kindXformer member this.IsSimpleResultTest with get() = kindXformer.IsSimpleResultTest and set(v) = kindXformer.IsSimpleResultTest <- v -type private StatementLeveler(holder : CapabilityInfoHolder) = +type private StatementLeveler(scopeXformer : ScopeLeveler, holder : CapabilityInfoHolder) = inherit StatementKindTransformation() - let scopeXformer = new ScopeLeveler(holder) let exprXformer = new ExpressionLeveler(holder) override this.ScopeTransformation x = scopeXformer.Transform x @@ -307,10 +305,10 @@ type private StatementLeveler(holder : CapabilityInfoHolder) = then holder.LocalLevel <- CapabilityLevel.Advanced base.onVariableDeclaration(s) -and private ScopeLeveler(holder : CapabilityInfoHolder) = +and private ScopeLeveler(holder : CapabilityInfoHolder) as this = inherit ScopeTransformation() - let kindXformer = new StatementLeveler(holder) + let kindXformer = new StatementLeveler(this, holder) override this.StatementKind = upcast kindXformer @@ -352,8 +350,8 @@ type TreeLeveler() = override this.beforeCallable(c) = currentOperationLevel <- c.Attributes |> checkForLevelAttributes - System.Console.WriteLine("About to process callable " + c.FullName.Name.Value) - base.beforeCallable(c) + let result = base.beforeCallable(c) + result override this.onSpecializationImplementation(s) = let holder = new CapabilityInfoHolder(s, manager) diff --git a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs index 118e658c62..bff1e38381 100644 --- a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs +++ b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs @@ -18,9 +18,6 @@ open Xunit // Utilities for testing operation capability level setting and the corresponding infrastructure -let out = File.CreateText("C:\\Users\\ageller\\Source\\Repos\\debug.log") -System.Console.SetOut(out) - let private buildSyntaxTree path code = let fileId = new Uri(path) let compilationUnit = new CompilationUnitManager(fun ex -> failwith ex.Message) @@ -56,7 +53,10 @@ let private getOperationLevel tree opName = [] let ``capability leveling tests`` () = let leveler = new TreeLeveler() + let syntaxTree = buildSyntaxTreeFromFile "CapabilityLevels" |> Seq.map leveler.Transform - Assert.Equal(CapabilityLevel.Minimal, getOperationLevel syntaxTree "M") + let mLevel = getOperationLevel syntaxTree "M" + Assert.Equal(CapabilityLevel.Minimal, mLevel) + () \ No newline at end of file From 2f8fe9d133a9caa886ddc42d4d2d9213cc667a1e Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 1 Nov 2019 14:05:05 -0700 Subject: [PATCH 15/32] Almost all test cases working --- src/QsCompiler/QsTargeting/CapabilityLeveler.fs | 2 +- .../Tests.Compiler/CapabilityLevelerTests.fs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 95a4b2fe1e..b5f37dc02f 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -136,7 +136,7 @@ let private isQubitArray ex = match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false type private CapabilityInfoHolder(spec, manager : CapabilityLevelManager) = - let mutable localLevel = CapabilityLevel.Unset + let mutable localLevel = CapabilityLevel.Minimal member this.LocalLevel with get() = localLevel and set(n) = if n > localLevel then localLevel <- n diff --git a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs index bff1e38381..2a09be94e9 100644 --- a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs +++ b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs @@ -59,4 +59,19 @@ let ``capability leveling tests`` () = let mLevel = getOperationLevel syntaxTree "M" Assert.Equal(CapabilityLevel.Minimal, mLevel) + let hLevel = getOperationLevel syntaxTree "H" + Assert.Equal(CapabilityLevel.Minimal, hLevel) + + let level1Level = getOperationLevel syntaxTree "Level1" + Assert.Equal(CapabilityLevel.Minimal, level1Level) + + let level2Level = getOperationLevel syntaxTree "Level2" + Assert.Equal(CapabilityLevel.Basic, level2Level) + + let level4Level = getOperationLevel syntaxTree "Level4" + Assert.Equal(CapabilityLevel.Advanced, level4Level) + + let level5Level = getOperationLevel syntaxTree "Level5" + Assert.Equal(CapabilityLevel.Full, level5Level) + () \ No newline at end of file From 5da40138a7842915c13bc12e1a35e1c23cfdc805 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Fri, 1 Nov 2019 18:16:29 -0700 Subject: [PATCH 16/32] TRying to get the Level attribute recognized... --- .../Tests.Compiler/TestCases/CapabilityLevels.qs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs index 5237da43b7..d11f19d5d7 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs @@ -3,6 +3,15 @@ // Tests for capability leveling +namespace Microsoft.Quantum.Core { // or whatever namespace you expect it in - Core seems like the right choice + + @Attribute() + newtype Level = Int; + + @Attribute() + newtype Attribute = Unit; +} + namespace Microsoft.Quantum.Testing { // This should be level 1 since it's intrinsic. operation M (q : Qubit) : Result From 9608598417d7d8efbb450c3d2539aab1af7aceb4 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Mon, 4 Nov 2019 08:16:13 -0800 Subject: [PATCH 17/32] Got the attribute working with help from Bettina, now all tests pass! --- src/QsCompiler/QsTargeting/CapabilityLeveler.fs | 7 +++++++ src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs | 2 +- .../Tests.Compiler/TestCases/CapabilityLevels.qs | 7 ++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index b5f37dc02f..e551dfc508 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -330,6 +330,13 @@ type TreeLeveler() = match a.Argument.Expression with | IntLiteral n -> let level = enum (int n) Some level + | ValueTuple args -> if args.Length = 1 + then + match args.[0].Expression with + | IntLiteral n -> let level = enum (int n) + Some level + | _ -> None + else None | _ -> None let levels = attrs |> Seq.filter isLevelAttribute |> List.ofSeq match levels with diff --git a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs index 2a09be94e9..45bf9ffc3b 100644 --- a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs +++ b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs @@ -72,6 +72,6 @@ let ``capability leveling tests`` () = Assert.Equal(CapabilityLevel.Advanced, level4Level) let level5Level = getOperationLevel syntaxTree "Level5" - Assert.Equal(CapabilityLevel.Full, level5Level) + Assert.Equal(CapabilityLevel.Medium, level5Level) () \ No newline at end of file diff --git a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs index d11f19d5d7..e108cf838f 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs @@ -3,8 +3,8 @@ // Tests for capability leveling -namespace Microsoft.Quantum.Core { // or whatever namespace you expect it in - Core seems like the right choice - +namespace Microsoft.Quantum.Core +{ @Attribute() newtype Level = Int; @@ -12,7 +12,8 @@ namespace Microsoft.Quantum.Core { // or whatever namespace you expect it in - C newtype Attribute = Unit; } -namespace Microsoft.Quantum.Testing { +namespace Microsoft.Quantum.Testing +{ // This should be level 1 since it's intrinsic. operation M (q : Qubit) : Result { From d1cb52303abc37e0af75eea00753cf64b212c027 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Tue, 5 Nov 2019 08:33:22 -0800 Subject: [PATCH 18/32] FIxed test name and comments --- src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs | 2 +- src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs index 45bf9ffc3b..c0836fb048 100644 --- a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs +++ b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs @@ -71,7 +71,7 @@ let ``capability leveling tests`` () = let level4Level = getOperationLevel syntaxTree "Level4" Assert.Equal(CapabilityLevel.Advanced, level4Level) - let level5Level = getOperationLevel syntaxTree "Level5" + let level5Level = getOperationLevel syntaxTree "Level3" Assert.Equal(CapabilityLevel.Medium, level5Level) () \ No newline at end of file diff --git a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs index e108cf838f..23746ca2af 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs @@ -47,8 +47,8 @@ namespace Microsoft.Quantum.Testing } } - // This should be level 5 because it has classical computation. - operation Level5 (d : Double) : Double + // This should be level 3 because it has classical computation. + operation Level3 (d : Double) : Double { return 1.0/d; } From 5958c02ba2f37b4601e7a68eefdba409127b9ad9 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Tue, 5 Nov 2019 14:49:54 -0800 Subject: [PATCH 19/32] Initial versions of walkers, compiling cleanly --- src/QsCompiler/Core/Core.fsproj | 3 + src/QsCompiler/Core/ExpressionWalker.fs | 454 +++++++++++++++++++++ src/QsCompiler/Core/StatementWalker.fs | 164 ++++++++ src/QsCompiler/Core/TreeWalker.fs | 196 +++++++++ src/QsCompiler/DataStructures/DataTypes.fs | 5 + 5 files changed, 822 insertions(+) create mode 100644 src/QsCompiler/Core/ExpressionWalker.fs create mode 100644 src/QsCompiler/Core/StatementWalker.fs create mode 100644 src/QsCompiler/Core/TreeWalker.fs diff --git a/src/QsCompiler/Core/Core.fsproj b/src/QsCompiler/Core/Core.fsproj index 363ce5f65f..ebe43db7ad 100644 --- a/src/QsCompiler/Core/Core.fsproj +++ b/src/QsCompiler/Core/Core.fsproj @@ -17,6 +17,9 @@ + + + diff --git a/src/QsCompiler/Core/ExpressionWalker.fs b/src/QsCompiler/Core/ExpressionWalker.fs new file mode 100644 index 0000000000..32ab5194d4 --- /dev/null +++ b/src/QsCompiler/Core/ExpressionWalker.fs @@ -0,0 +1,454 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.QsCompiler.Transformations.Core + +open System.Collections.Immutable +open System.Numerics +open Microsoft.Quantum.QsCompiler.DataTypes +open Microsoft.Quantum.QsCompiler.SyntaxExtensions +open Microsoft.Quantum.QsCompiler.SyntaxTokens +open Microsoft.Quantum.QsCompiler.SyntaxTree + +//type private ExpressionKind = QsExpressionKind +//type private ExpressionType = QsTypeKind + + +/// Convention: +/// All methods starting with "on" implement the walk for an expression of a certain kind. +/// All methods starting with "before" group a set of statements, and are called before walking the set +/// even if the corresponding walk routine (starting with "on") is overridden. +/// +/// These classes differ from the "*Transformation" classes in that these classes visit every node in the +/// syntax tree, but don't create a new syntax tree, while the Transformation classes generate a new (or +/// at least partially new) tree from the old one. +/// Effectively, the Transformation classes implement fold, while the Walker classes implement iter. +[] +type ExpressionKindWalker(?enable) = + let enable = defaultArg enable true + + abstract member ExpressionWalker : TypedExpression -> unit + abstract member TypeWalker : ResolvedType -> unit + + abstract member beforeCallLike : TypedExpression * TypedExpression -> unit + default this.beforeCallLike (method, arg) = () + + abstract member beforeFunctorApplication : TypedExpression -> unit + default this.beforeFunctorApplication ex = () + + abstract member beforeModifierApplication : TypedExpression -> unit + default this.beforeModifierApplication ex = () + + abstract member beforeBinaryOperatorExpression : TypedExpression * TypedExpression -> unit + default this.beforeBinaryOperatorExpression (lhs, rhs) = () + + abstract member beforeUnaryOperatorExpression : TypedExpression -> unit + default this.beforeUnaryOperatorExpression ex = () + + + abstract member onIdentifier : Identifier * QsNullable> -> unit + default this.onIdentifier (sym, tArgs) = tArgs |> QsNullable<_>.Iter (fun ts -> (ts |> Seq.iter this.TypeWalker)) + + abstract member onOperationCall : TypedExpression * TypedExpression -> unit + default this.onOperationCall (method, arg) = + this.ExpressionWalker method + this.ExpressionWalker arg + + abstract member onFunctionCall : TypedExpression * TypedExpression -> unit + default this.onFunctionCall (method, arg) = + this.ExpressionWalker method + this.ExpressionWalker arg + + abstract member onPartialApplication : TypedExpression * TypedExpression -> unit + default this.onPartialApplication (method, arg) = + this.ExpressionWalker method + this.ExpressionWalker arg + + abstract member onAdjointApplication : TypedExpression -> unit + default this.onAdjointApplication ex = this.ExpressionWalker ex + + abstract member onControlledApplication : TypedExpression -> unit + default this.onControlledApplication ex = this.ExpressionWalker ex + + abstract member onUnwrapApplication : TypedExpression -> unit + default this.onUnwrapApplication ex = this.ExpressionWalker ex + + abstract member onUnitValue : unit -> unit + default this.onUnitValue () = () + + abstract member onMissingExpression : unit -> unit + default this.onMissingExpression () = () + + abstract member onInvalidExpression : unit -> unit + default this.onInvalidExpression () = () + + abstract member onValueTuple : ImmutableArray -> unit + default this.onValueTuple vs = vs |> Seq.iter this.ExpressionWalker + + abstract member onArrayItem : TypedExpression * TypedExpression -> unit + default this.onArrayItem (arr, idx) = + this.ExpressionWalker arr + this.ExpressionWalker idx + + abstract member onNamedItem : TypedExpression * Identifier -> unit + default this.onNamedItem (ex, acc) = this.ExpressionWalker ex + + abstract member onValueArray : ImmutableArray -> unit + default this.onValueArray vs = vs |> Seq.iter this.ExpressionWalker + + abstract member onNewArray : ResolvedType * TypedExpression -> unit + default this.onNewArray (bt, idx) = + this.TypeWalker bt + this.ExpressionWalker idx + + abstract member onIntLiteral : int64 -> unit + default this.onIntLiteral i = () + + abstract member onBigIntLiteral : BigInteger -> unit + default this.onBigIntLiteral b = () + + abstract member onDoubleLiteral : double -> unit + default this.onDoubleLiteral d = () + + abstract member onBoolLiteral : bool -> unit + default this.onBoolLiteral b = () + + abstract member onResultLiteral : QsResult -> unit + default this.onResultLiteral r = () + + abstract member onPauliLiteral : QsPauli -> unit + default this.onPauliLiteral p = () + + abstract member onStringLiteral : NonNullable * ImmutableArray -> unit + default this.onStringLiteral (s, exs) = exs |> Seq.iter this.ExpressionWalker + + abstract member onRangeLiteral : TypedExpression * TypedExpression -> unit + default this.onRangeLiteral (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onCopyAndUpdateExpression : TypedExpression * TypedExpression * TypedExpression -> unit + default this.onCopyAndUpdateExpression (lhs, accEx, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker accEx + this.ExpressionWalker rhs + + abstract member onConditionalExpression : TypedExpression * TypedExpression * TypedExpression -> unit + default this.onConditionalExpression (cond, ifTrue, ifFalse) = + this.ExpressionWalker cond + this.ExpressionWalker ifTrue + this.ExpressionWalker ifFalse + + abstract member onEquality : TypedExpression * TypedExpression -> unit + default this.onEquality (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onInequality : TypedExpression * TypedExpression -> unit + default this.onInequality (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onLessThan : TypedExpression * TypedExpression -> unit + default this.onLessThan (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onLessThanOrEqual : TypedExpression * TypedExpression -> unit + default this.onLessThanOrEqual (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onGreaterThan : TypedExpression * TypedExpression -> unit + default this.onGreaterThan (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onGreaterThanOrEqual : TypedExpression * TypedExpression -> unit + default this.onGreaterThanOrEqual (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onLogicalAnd : TypedExpression * TypedExpression -> unit + default this.onLogicalAnd (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onLogicalOr : TypedExpression * TypedExpression -> unit + default this.onLogicalOr (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onAddition : TypedExpression * TypedExpression -> unit + default this.onAddition (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onSubtraction : TypedExpression * TypedExpression -> unit + default this.onSubtraction (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onMultiplication : TypedExpression * TypedExpression -> unit + default this.onMultiplication (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onDivision : TypedExpression * TypedExpression -> unit + default this.onDivision (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onExponentiate : TypedExpression * TypedExpression -> unit + default this.onExponentiate (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onModulo : TypedExpression * TypedExpression -> unit + default this.onModulo (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onLeftShift : TypedExpression * TypedExpression -> unit + default this.onLeftShift (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onRightShift : TypedExpression * TypedExpression -> unit + default this.onRightShift (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onBitwiseExclusiveOr : TypedExpression * TypedExpression -> unit + default this.onBitwiseExclusiveOr (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onBitwiseOr : TypedExpression * TypedExpression -> unit + default this.onBitwiseOr (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onBitwiseAnd : TypedExpression * TypedExpression -> unit + default this.onBitwiseAnd (lhs, rhs) = + this.ExpressionWalker lhs + this.ExpressionWalker rhs + + abstract member onLogicalNot : TypedExpression -> unit + default this.onLogicalNot ex = this.ExpressionWalker ex + + abstract member onNegative : TypedExpression -> unit + default this.onNegative ex = this.ExpressionWalker ex + + abstract member onBitwiseNot : TypedExpression -> unit + default this.onBitwiseNot ex = this.ExpressionWalker ex + + + member private this.dispatchCallLikeExpression (method, arg) = + match method.ResolvedType.Resolution with + | _ when TypedExpression.IsPartialApplication (CallLikeExpression (method, arg)) -> this.onPartialApplication (method, arg) + | ExpressionType.Operation _ -> this.onOperationCall (method, arg) + | _ -> this.onFunctionCall (method, arg) + + abstract member Walk : ExpressionKind -> unit + default this.Walk kind = + if not enable then () else + match kind with + | Identifier (sym, tArgs) -> this.onIdentifier (sym, tArgs) + | CallLikeExpression (method,arg) -> this.beforeCallLike (method, arg) + this.dispatchCallLikeExpression (method, arg) + | AdjointApplication ex -> this.beforeFunctorApplication ex + this.beforeModifierApplication ex + this.onAdjointApplication ex + | ControlledApplication ex -> this.beforeFunctorApplication ex + this.beforeModifierApplication ex + this.onControlledApplication ex + | UnwrapApplication ex -> this.beforeModifierApplication ex + this.onUnwrapApplication ex + | UnitValue -> this.onUnitValue () + | MissingExpr -> this.onMissingExpression () + | InvalidExpr -> this.onInvalidExpression () + | ValueTuple vs -> this.onValueTuple vs + | ArrayItem (arr, idx) -> this.onArrayItem (arr, idx) + | NamedItem (ex, acc) -> this.onNamedItem (ex, acc) + | ValueArray vs -> this.onValueArray vs + | NewArray (bt, idx) -> this.onNewArray (bt, idx) + | IntLiteral i -> this.onIntLiteral i + | BigIntLiteral b -> this.onBigIntLiteral b + | DoubleLiteral d -> this.onDoubleLiteral d + | BoolLiteral b -> this.onBoolLiteral b + | ResultLiteral r -> this.onResultLiteral r + | PauliLiteral p -> this.onPauliLiteral p + | StringLiteral (s, exs) -> this.onStringLiteral (s, exs) + | RangeLiteral (lhs, rhs) -> this.onRangeLiteral (lhs, rhs) + | CopyAndUpdate (lhs, accEx, rhs) -> this.onCopyAndUpdateExpression (lhs, accEx, rhs) + | CONDITIONAL (cond, ifTrue, ifFalse) -> this.onConditionalExpression (cond, ifTrue, ifFalse) + | EQ (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onEquality (lhs, rhs) + | NEQ (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onInequality (lhs, rhs) + | LT (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onLessThan (lhs, rhs) + | LTE (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onLessThanOrEqual (lhs, rhs) + | GT (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onGreaterThan (lhs, rhs) + | GTE (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onGreaterThanOrEqual (lhs, rhs) + | AND (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onLogicalAnd (lhs, rhs) + | OR (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onLogicalOr (lhs, rhs) + | ADD (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onAddition (lhs, rhs) + | SUB (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onSubtraction (lhs, rhs) + | MUL (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onMultiplication (lhs, rhs) + | DIV (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onDivision (lhs, rhs) + | POW (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onExponentiate (lhs, rhs) + | MOD (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onModulo (lhs, rhs) + | LSHIFT (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onLeftShift (lhs, rhs) + | RSHIFT (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onRightShift (lhs, rhs) + | BXOR (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onBitwiseExclusiveOr (lhs, rhs) + | BOR (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onBitwiseOr (lhs, rhs) + | BAND (lhs,rhs) -> this.beforeBinaryOperatorExpression (lhs, rhs) + this.onBitwiseAnd (lhs, rhs) + | NOT ex -> this.beforeUnaryOperatorExpression ex + this.onLogicalNot ex + | NEG ex -> this.beforeUnaryOperatorExpression ex + this.onNegative ex + | BNOT ex -> this.beforeUnaryOperatorExpression ex + this.onBitwiseNot ex + + +and ExpressionTypeWalker(?enable) = + let enable = defaultArg enable true + + abstract member onRangeInformation : QsRangeInfo -> unit + default this.onRangeInformation r =() + + abstract member onCharacteristicsExpression : ResolvedCharacteristics -> unit + default this.onCharacteristicsExpression fs = () + + abstract member onCallableInformation : CallableInformation -> unit + default this.onCallableInformation opInfo = + this.onCharacteristicsExpression opInfo.Characteristics + + abstract member onUserDefinedType : UserDefinedType -> unit + default this.onUserDefinedType udt = + this.onRangeInformation udt.Range + + abstract member onTypeParameter : QsTypeParameter -> unit + default this.onTypeParameter tp = + this.onRangeInformation tp.Range + + abstract member onUnitType : unit -> unit + default this.onUnitType () = () + + abstract member onOperation : (ResolvedType * ResolvedType) * CallableInformation -> unit + default this.onOperation ((it, ot), info) = + this.Walk it + this.Walk ot + this.onCallableInformation info + + abstract member onFunction : ResolvedType * ResolvedType -> unit + default this.onFunction (it, ot) = + this.Walk it + this.Walk ot + + abstract member onTupleType : ImmutableArray -> unit + default this.onTupleType ts = ts |> Seq.iter this.Walk + + abstract member onArrayType : ResolvedType -> unit + default this.onArrayType b = this.Walk b + + abstract member onQubit : unit -> unit + default this.onQubit () = () + + abstract member onMissingType : unit -> unit + default this.onMissingType () = () + + abstract member onInvalidType : unit -> unit + default this.onInvalidType () = () + + abstract member onInt : unit -> unit + default this.onInt () = () + + abstract member onBigInt : unit -> unit + default this.onBigInt () = () + + abstract member onDouble : unit -> unit + default this.onDouble () = () + + abstract member onBool : unit -> unit + default this.onBool () = () + + abstract member onString : unit -> unit + default this.onString () = () + + abstract member onResult : unit -> unit + default this.onResult () = () + + abstract member onPauli : unit -> unit + default this.onPauli () = () + + abstract member onRange : unit -> unit + default this.onRange () = () + + member this.Walk (t : ResolvedType) = + if not enable then () else + match t.Resolution with + | ExpressionType.UnitType -> this.onUnitType () + | ExpressionType.Operation ((it, ot), fs) -> this.onOperation ((it, ot), fs) + | ExpressionType.Function (it, ot) -> this.onFunction (it, ot) + | ExpressionType.TupleType ts -> this.onTupleType ts + | ExpressionType.ArrayType b -> this.onArrayType b + | ExpressionType.UserDefinedType udt -> this.onUserDefinedType udt + | ExpressionType.TypeParameter tp -> this.onTypeParameter tp + | ExpressionType.Qubit -> this.onQubit () + | ExpressionType.MissingType -> this.onMissingType () + | ExpressionType.InvalidType -> this.onInvalidType () + | ExpressionType.Int -> this.onInt () + | ExpressionType.BigInt -> this.onBigInt () + | ExpressionType.Double -> this.onDouble () + | ExpressionType.Bool -> this.onBool () + | ExpressionType.String -> this.onString () + | ExpressionType.Result -> this.onResult () + | ExpressionType.Pauli -> this.onPauli () + | ExpressionType.Range -> this.onRange () + + +and ExpressionWalker(?enableKindWalkers) = + let enableKind = defaultArg enableKindWalkers true + let typeWalker = new ExpressionTypeWalker() + + abstract member Kind : ExpressionKindWalker + default this.Kind = { + new ExpressionKindWalker (enableKind) with + override x.ExpressionWalker ex = this.Walk ex + override x.TypeWalker t = this.Type.Walk t + } + + abstract member Type : ExpressionTypeWalker + default this.Type = typeWalker + + abstract member onRangeInformation : QsNullable -> unit + default this.onRangeInformation r = () + + abstract member onExpressionInformation : InferredExpressionInformation -> unit + default this.onExpressionInformation info = () + + abstract member Walk : TypedExpression -> unit + default this.Walk (ex : TypedExpression) = + this.onRangeInformation ex.Range + this.Kind.Walk ex.Expression + this.Type.Walk ex.ResolvedType + this.onExpressionInformation ex.InferredInformation diff --git a/src/QsCompiler/Core/StatementWalker.fs b/src/QsCompiler/Core/StatementWalker.fs new file mode 100644 index 0000000000..1d86f27436 --- /dev/null +++ b/src/QsCompiler/Core/StatementWalker.fs @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.QsCompiler.Transformations.Core + +open Microsoft.Quantum.QsCompiler.DataTypes +open Microsoft.Quantum.QsCompiler.SyntaxTokens +open Microsoft.Quantum.QsCompiler.SyntaxTree + + +/// Convention: +/// All methods starting with "on" implement the walk for an expression of a certain kind. +/// All methods starting with "before" group a set of statements, and are called before walking the set +/// even if the corresponding walk routine (starting with "on") is overridden. +/// +/// These classes differ from the "*Transformation" classes in that these classes visit every node in the +/// syntax tree, but don't create a new syntax tree, while the Transformation classes generate a new (or +/// at least partially new) tree from the old one. +/// Effectively, the Transformation classes implement fold, while the Walker classes implement iter. +[] +type StatementKindWalker(?enable) = + let enable = defaultArg enable true + + abstract member ScopeWalker : QsScope -> unit + abstract member ExpressionWalker : TypedExpression -> unit + abstract member TypeWalker : ResolvedType -> unit + abstract member LocationWalker : QsNullable -> unit + + abstract member onQubitInitializer : ResolvedInitializer -> unit + default this.onQubitInitializer init = + match init.Resolution with + | SingleQubitAllocation -> () + | QubitRegisterAllocation ex -> this.ExpressionWalker ex + | QubitTupleAllocation is -> is |> Seq.iter this.onQubitInitializer + | InvalidInitializer -> () + + abstract member beforeVariableDeclaration : SymbolTuple -> unit + default this.beforeVariableDeclaration syms = () + + abstract member onSymbolTuple : SymbolTuple -> unit + default this.onSymbolTuple syms = () + + + abstract member onExpressionStatement : TypedExpression -> unit + default this.onExpressionStatement ex = this.ExpressionWalker ex + + abstract member onReturnStatement : TypedExpression -> unit + default this.onReturnStatement ex = this.ExpressionWalker ex + + abstract member onFailStatement : TypedExpression -> unit + default this.onFailStatement ex = this.ExpressionWalker ex + + abstract member onVariableDeclaration : QsBinding -> unit + default this.onVariableDeclaration stm = + this.ExpressionWalker stm.Rhs + this.onSymbolTuple stm.Lhs + + abstract member onValueUpdate : QsValueUpdate -> unit + default this.onValueUpdate stm = + this.ExpressionWalker stm.Rhs + this.ExpressionWalker stm.Lhs + + abstract member onPositionedBlock : TypedExpression option * QsPositionedBlock -> unit + default this.onPositionedBlock (intro : TypedExpression option, block : QsPositionedBlock) = + this.LocationWalker block.Location + intro |> Option.iter this.ExpressionWalker + this.ScopeWalker block.Body + + abstract member onConditionalStatement : QsConditionalStatement -> unit + default this.onConditionalStatement stm = + stm.ConditionalBlocks |> Seq.iter (fun (c, b) -> this.onPositionedBlock (Some c, b)) + stm.Default |> QsNullable<_>.Iter (fun b -> this.onPositionedBlock (None, b)) + + abstract member onForStatement : QsForStatement -> unit + default this.onForStatement stm = + this.ExpressionWalker stm.IterationValues + fst stm.LoopItem |> this.onSymbolTuple + this.TypeWalker (snd stm.LoopItem) + this.ScopeWalker stm.Body + + abstract member onWhileStatement : QsWhileStatement -> unit + default this.onWhileStatement stm = + this.ExpressionWalker stm.Condition + this.ScopeWalker stm.Body + + abstract member onRepeatStatement : QsRepeatStatement -> unit + default this.onRepeatStatement stm = + this.onPositionedBlock (None, stm.RepeatBlock) + this.onPositionedBlock (Some stm.SuccessCondition, stm.FixupBlock) + + abstract member onConjugation : QsConjugation -> unit + default this.onConjugation stm = + this.onPositionedBlock (None, stm.OuterTransformation) + this.onPositionedBlock (None, stm.InnerTransformation) + + abstract member onQubitScope : QsQubitScope -> unit + default this.onQubitScope (stm : QsQubitScope) = + this.onQubitInitializer stm.Binding.Rhs + this.onSymbolTuple stm.Binding.Lhs + this.ScopeWalker stm.Body + + abstract member onAllocateQubits : QsQubitScope -> unit + default this.onAllocateQubits stm = this.onQubitScope stm + + abstract member onBorrowQubits : QsQubitScope -> unit + default this.onBorrowQubits stm = this.onQubitScope stm + + + member private this.dispatchQubitScope (stm : QsQubitScope) = + match stm.Kind with + | Allocate -> this.onAllocateQubits stm + | Borrow -> this.onBorrowQubits stm + + abstract member Walk : QsStatementKind -> unit + default this.Walk kind = + let beforeBinding (stm : QsBinding) = this.beforeVariableDeclaration stm.Lhs + let beforeForStatement (stm : QsForStatement) = this.beforeVariableDeclaration (fst stm.LoopItem) + let beforeQubitScope (stm : QsQubitScope) = this.beforeVariableDeclaration stm.Binding.Lhs + + if not enable then () else + match kind with + | QsExpressionStatement ex -> this.onExpressionStatement ex + | QsReturnStatement ex -> this.onReturnStatement ex + | QsFailStatement ex -> this.onFailStatement ex + | QsVariableDeclaration stm -> beforeBinding stm + this.onVariableDeclaration stm + | QsValueUpdate stm -> this.onValueUpdate stm + | QsConditionalStatement stm -> this.onConditionalStatement stm + | QsForStatement stm -> beforeForStatement stm + this.onForStatement stm + | QsWhileStatement stm -> this.onWhileStatement stm + | QsRepeatStatement stm -> this.onRepeatStatement stm + | QsConjugation stm -> this.onConjugation stm + | QsQubitScope stm -> beforeQubitScope stm + this.dispatchQubitScope stm + + +and ScopeWalker(?enableStatementKindWalkers) = + let enableStatementKind = defaultArg enableStatementKindWalkers true + let expressionsWalker = new ExpressionWalker() + + abstract member Expression : ExpressionWalker + default this.Expression = expressionsWalker + + abstract member StatementKind : StatementKindWalker + default this.StatementKind = { + new StatementKindWalker (enableStatementKind) with + override x.ScopeWalker s = this.Walk s + override x.ExpressionWalker ex = this.Expression.Walk ex + override x.TypeWalker t = this.Expression.Type.Walk t + override x.LocationWalker l = this.onLocation l + } + + abstract member onLocation : QsNullable -> unit + default this.onLocation loc = () + + abstract member onStatement : QsStatement -> unit + default this.onStatement stm = + this.onLocation stm.Location + this.StatementKind.Walk stm.Statement + + abstract member Walk : QsScope -> unit + default this.Walk scope = + scope.Statements |> Seq.iter this.onStatement diff --git a/src/QsCompiler/Core/TreeWalker.fs b/src/QsCompiler/Core/TreeWalker.fs new file mode 100644 index 0000000000..fd2c6acc05 --- /dev/null +++ b/src/QsCompiler/Core/TreeWalker.fs @@ -0,0 +1,196 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.QsCompiler.Transformations.Core + +open System.Collections.Immutable +open System.Linq +open Microsoft.Quantum.QsCompiler.DataTypes +open Microsoft.Quantum.QsCompiler.SyntaxTokens +open Microsoft.Quantum.QsCompiler.SyntaxTree + +// This are inherited here from TreeTransformation.fs; kept here as comments for documentation. +//type QsArgumentTuple = QsTuple> + + +/// Convention: +/// All methods starting with "on" implement the walk for an expression of a certain kind. +/// All methods starting with "before" group a set of statements, and are called before walking the set +/// even if the corresponding walk routine (starting with "on") is overridden. +/// +/// These classes differ from the "*Transformation" classes in that these classes visit every node in the +/// syntax tree, but don't create a new syntax tree, while the Transformation classes generate a new (or +/// at least partially new) tree from the old one. +/// Effectively, the Transformation classes implement fold, while the Walker classes implement iter. +type SyntaxTreeWalker() = + let scopeWalker = new ScopeWalker() + + abstract member Scope : ScopeWalker + default this.Scope = scopeWalker + + + abstract member beforeNamespaceElement : QsNamespaceElement -> unit + default this.beforeNamespaceElement e = () + + abstract member beforeCallable : QsCallable -> unit + default this.beforeCallable c = () + + abstract member beforeSpecialization : QsSpecialization -> unit + default this.beforeSpecialization spec = () + + abstract member beforeSpecializationImplementation : SpecializationImplementation -> unit + default this.beforeSpecializationImplementation impl = () + + abstract member beforeGeneratedImplementation : QsGeneratorDirective -> unit + default this.beforeGeneratedImplementation dir = () + + + abstract member onLocation : QsLocation -> unit + default this.onLocation l = () + + abstract member onDocumentation : ImmutableArray -> unit + default this.onDocumentation doc = () + + abstract member onSourceFile : NonNullable -> unit + default this.onSourceFile f = () + + abstract member onTypeItems : QsTuple -> unit + default this.onTypeItems tItem = + match tItem with + | QsTuple items -> items |> Seq.iter this.onTypeItems + | QsTupleItem (Anonymous itemType) -> this.Scope.Expression.Type.Walk itemType + | QsTupleItem (Named item) -> this.Scope.Expression.Type.Walk item.Type + + abstract member onArgumentTuple : QsArgumentTuple -> unit + default this.onArgumentTuple arg = + match arg with + | QsTuple items -> items |> Seq.iter this.onArgumentTuple + | QsTupleItem item -> this.Scope.Expression.Type.Walk item.Type + + abstract member onSignature : ResolvedSignature -> unit + default this.onSignature (s : ResolvedSignature) = + this.Scope.Expression.Type.Walk s.ArgumentType + this.Scope.Expression.Type.Walk s.ReturnType + this.Scope.Expression.Type.onCallableInformation s.Information + + + abstract member onExternalImplementation : unit -> unit + default this.onExternalImplementation () = () + + abstract member onIntrinsicImplementation : unit -> unit + default this.onIntrinsicImplementation () = () + + abstract member onProvidedImplementation : QsArgumentTuple * QsScope -> unit + default this.onProvidedImplementation (argTuple, body) = + this.onArgumentTuple argTuple + this.Scope.Walk body + + abstract member onSelfInverseDirective : unit -> unit + default this.onSelfInverseDirective () = () + + abstract member onInvertDirective : unit -> unit + default this.onInvertDirective () = () + + abstract member onDistributeDirective : unit -> unit + default this.onDistributeDirective () = () + + abstract member onInvalidGeneratorDirective : unit -> unit + default this.onInvalidGeneratorDirective () = () + + member this.dispatchGeneratedImplementation (dir : QsGeneratorDirective) = + this.beforeGeneratedImplementation dir + match dir with + | SelfInverse -> this.onSelfInverseDirective () + | Invert -> this.onInvertDirective() + | Distribute -> this.onDistributeDirective() + | InvalidGenerator -> this.onInvalidGeneratorDirective() + + member this.dispatchSpecializationImplementation (impl : SpecializationImplementation) = + this.beforeSpecializationImplementation impl + match impl with + | External -> this.onExternalImplementation() + | Intrinsic -> this.onIntrinsicImplementation() + | Generated dir -> this.dispatchGeneratedImplementation dir + | Provided (argTuple, body) -> this.onProvidedImplementation (argTuple, body) + + + abstract member onSpecializationImplementation : QsSpecialization -> unit + default this.onSpecializationImplementation (spec : QsSpecialization) = + this.onSourceFile spec.SourceFile + this.onLocation spec.Location + spec.Attributes |> Seq.iter this.onAttribute + spec.TypeArguments |> QsNullable<_>.Iter (fun args -> (args |> Seq.iter this.Scope.Expression.Type.Walk)) + this.onSignature spec.Signature + this.dispatchSpecializationImplementation spec.Implementation + this.onDocumentation spec.Documentation + + abstract member onBodySpecialization : QsSpecialization -> unit + default this.onBodySpecialization spec = this.onSpecializationImplementation spec + + abstract member onAdjointSpecialization : QsSpecialization -> unit + default this.onAdjointSpecialization spec = this.onSpecializationImplementation spec + + abstract member onControlledSpecialization : QsSpecialization -> unit + default this.onControlledSpecialization spec = this.onSpecializationImplementation spec + + abstract member onControlledAdjointSpecialization : QsSpecialization -> unit + default this.onControlledAdjointSpecialization spec = this.onSpecializationImplementation spec + + member this.dispatchSpecialization (spec : QsSpecialization) = + this.beforeSpecialization spec + match spec.Kind with + | QsSpecializationKind.QsBody -> this.onBodySpecialization spec + | QsSpecializationKind.QsAdjoint -> this.onAdjointSpecialization spec + | QsSpecializationKind.QsControlled -> this.onControlledSpecialization spec + | QsSpecializationKind.QsControlledAdjoint -> this.onControlledAdjointSpecialization spec + + + abstract member onType : QsCustomType -> unit + default this.onType t = + this.onSourceFile t.SourceFile + this.onLocation t.Location + t.Attributes |> Seq.iter this.onAttribute + this.Scope.Expression.Type.Walk t.Type + this.onTypeItems t.TypeItems + this.onDocumentation t.Documentation + + abstract member onCallableImplementation : QsCallable -> unit + default this.onCallableImplementation (c : QsCallable) = + this.onSourceFile c.SourceFile + this.onLocation c.Location + c.Attributes |> Seq.iter this.onAttribute + this.onSignature c.Signature + this.onArgumentTuple c.ArgumentTuple + c.Specializations |> Seq.iter this.dispatchSpecialization + this.onDocumentation c.Documentation + + abstract member onOperation : QsCallable -> unit + default this.onOperation c = this.onCallableImplementation c + + abstract member onFunction : QsCallable -> unit + default this.onFunction c = this.onCallableImplementation c + + abstract member onTypeConstructor : QsCallable -> unit + default this.onTypeConstructor c = this.onCallableImplementation c + + member this.dispatchCallable (c : QsCallable) = + this.beforeCallable c + match c.Kind with + | QsCallableKind.Function -> this.onFunction c + | QsCallableKind.Operation -> this.onOperation c + | QsCallableKind.TypeConstructor -> this.onTypeConstructor c + + + abstract member onAttribute : QsDeclarationAttribute -> unit + default this.onAttribute att = () + + member this.dispatchNamespaceElement element = + this.beforeNamespaceElement element + match element with + | QsCustomType t -> t |> this.onType + | QsCallable c -> c |> this.dispatchCallable + + abstract member Walk : QsNamespace -> unit + default this.Walk ns = + ns.Documentation.AsEnumerable() |> Seq.iter (fun grouping -> grouping |> Seq.iter this.onDocumentation) + ns.Elements |> Seq.iter this.dispatchNamespaceElement diff --git a/src/QsCompiler/DataStructures/DataTypes.fs b/src/QsCompiler/DataStructures/DataTypes.fs index c8fe8ab318..92b86673ed 100644 --- a/src/QsCompiler/DataStructures/DataTypes.fs +++ b/src/QsCompiler/DataStructures/DataTypes.fs @@ -19,6 +19,11 @@ type QsNullable<'T> = // to avoid having to include the F# core in the C# part o | Null -> Null | Value v -> Value (fct v) + /// If the given nullable has a value, applies the given function to it. + static member Iter fct = function + | Null -> () + | Value v -> fct v + /// If the given nullable has a value, applies (fct fallback) to it and returns the result, /// and returns fallback otherwise. static member Fold fct fallback = function From b6f8163257b565ce56350b22e25f3b213dbc68e1 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Tue, 5 Nov 2019 15:12:20 -0800 Subject: [PATCH 20/32] Stole a transformation test to use as a walker test --- .../Tests.Compiler/TransformationTests.fs | 15 +- .../Transformations/WalkerDefinitions.cs | 207 ++++++++++++++++++ 2 files changed, 214 insertions(+), 8 deletions(-) create mode 100644 src/QsCompiler/Transformations/WalkerDefinitions.cs diff --git a/src/QsCompiler/Tests.Compiler/TransformationTests.fs b/src/QsCompiler/Tests.Compiler/TransformationTests.fs index fe04481fcb..ae304aa929 100644 --- a/src/QsCompiler/Tests.Compiler/TransformationTests.fs +++ b/src/QsCompiler/Tests.Compiler/TransformationTests.fs @@ -27,7 +27,7 @@ type private Counter () = member val ifsCount = 0 with get, set type private StatementKindCounter(stm, counter : Counter) = - inherit StatementKindTransformation(stm) + inherit StatementKindWalker(stm) override this.onConditionalStatement (node:QsConditionalStatement) = counter.ifsCount <- counter.ifsCount + 1 @@ -38,30 +38,29 @@ type private StatementKindCounter(stm, counter : Counter) = base.onForStatement node and private StatementCounter(counter) = - inherit ScopeTransformation + inherit ScopeWalker (Func<_,_>(fun s -> new StatementKindCounter(s :?> StatementCounter, counter)), new ExpressionCounter(counter)) and private ExpressionKindCounter(ex, counter : Counter) = - inherit ExpressionKindTransformation(ex) + inherit ExpressionKindWalker(ex) override this.beforeCallLike (op,args) = counter.callsCount <- counter.callsCount + 1 - (op,args) + base.beforeCallLike (op, args) and private ExpressionCounter(counter) = - inherit ExpressionTransformation + inherit ExpressionWalker (new Func<_,_>(fun e -> new ExpressionKindCounter(e :?> ExpressionCounter, counter))) type private SyntaxCounter(counter) = - inherit SyntaxTreeTransformation(new StatementCounter(counter)) + inherit SyntaxTreeWalker(new StatementCounter(counter)) override this.beforeCallable (node:QsCallable) = match node.Kind with | Operation -> counter.opsCount <- counter.opsCount + 1 | Function -> counter.funCount <- counter.funCount + 1 | TypeConstructor -> () - node override this.onType (udt:QsCustomType) = counter.udtCount <- counter.udtCount + 1 @@ -84,7 +83,7 @@ let private buildSyntaxTree code = let ``basic walk`` () = let tree = Path.Combine(Path.GetFullPath ".", "TestCases", "Transformation.qs") |> File.ReadAllText |> buildSyntaxTree let counter = new Counter() - tree |> Seq.map (SyntaxCounter(counter)).Transform |> Seq.toList |> ignore + tree |> Seq.iter (SyntaxCounter(counter)).Walk Assert.Equal (4, counter.udtCount) Assert.Equal (1, counter.funCount) diff --git a/src/QsCompiler/Transformations/WalkerDefinitions.cs b/src/QsCompiler/Transformations/WalkerDefinitions.cs new file mode 100644 index 0000000000..90c4eb1c65 --- /dev/null +++ b/src/QsCompiler/Transformations/WalkerDefinitions.cs @@ -0,0 +1,207 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Quantum.QsCompiler.DataTypes; +using Microsoft.Quantum.QsCompiler.SyntaxTree; + + +namespace Microsoft.Quantum.QsCompiler.Transformations +{ + // syntax tree walkers + + public class SyntaxTreeWalker : + Core.SyntaxTreeWalker + where S : Core.ScopeWalker + { + public readonly S _Scope; + public override Core.ScopeWalker Scope => this._Scope ?? base.Scope; + + public SyntaxTreeWalker(S scope) : + base() => + this._Scope = scope; + } + + + // scope walkers + + /// + /// Base class for all StatementKindWalkers. + /// + public class StatementKindWalker : + Core.StatementKindWalker + where S : Core.ScopeWalker + { + public readonly S _Scope; + + public StatementKindWalker(S scope) : + base(true) => + this._Scope = scope ?? throw new ArgumentNullException(nameof(scope)); + + public override void ScopeWalker(QsScope value) => + this._Scope.Walk(value); + + public override void ExpressionWalker(TypedExpression value) => + this._Scope.Expression.Walk(value); + + public override void TypeWalker(ResolvedType value) => + this._Scope.Expression.Type.Walk(value); + + public override void LocationWalker(QsNullable value) => + this._Scope.onLocation(value); + } + + /// + /// Base class for all ScopeWalkers. + /// + public class ScopeWalker : + Core.ScopeWalker + where K : Core.StatementKindWalker + where E : Core.ExpressionWalker + { + public readonly K _StatementKind; + private readonly Core.StatementKindWalker DefaultStatementKind; + public override Core.StatementKindWalker StatementKind => _StatementKind ?? DefaultStatementKind; + + public readonly E _Expression; + private readonly Core.ExpressionWalker DefaultExpression; + public override Core.ExpressionWalker Expression => _Expression ?? DefaultExpression; + + public ScopeWalker(Func, K> statementKind, E expression) : + base(expression != null) // default kind Walkers are enabled only if there are expression Walkers + { + this.DefaultStatementKind = base.StatementKind; + this._StatementKind = statementKind?.Invoke(this); + + this.DefaultExpression = new NoExpressionWalkers(); // disable by default + this._Expression = expression; + } + } + + /// + /// Given an expression Walker, Walk applies the given Walker to all expressions in a scope. + /// + public class ScopeWalker : + ScopeWalker + where E : Core.ExpressionWalker + { + public ScopeWalker(E expression) : + base(null, expression) + { } + } + + /// + /// Does not do any Walkers, and can be use as no-op if a ScopeWalker is required as argument. + /// + public class NoScopeWalkers : + ScopeWalker + { + public NoScopeWalkers() : + base(null) + { } + + public override void Walk(QsScope scope) {} + } + + + // expression Walkers + + /// + /// Base class for all ExpressionTypeWalkers. + /// + public class ExpressionTypeWalker : + Core.ExpressionTypeWalker + where E : Core.ExpressionWalker + { + public readonly E _Expression; + + public ExpressionTypeWalker(E expression) : + base(true) => + this._Expression = expression ?? throw new ArgumentNullException(nameof(expression)); + } + + /// + /// Base class for all ExpressionKindWalkers. + /// + public class ExpressionKindWalker : + Core.ExpressionKindWalker + where E : Core.ExpressionWalker + { + public readonly E _Expression; + + public ExpressionKindWalker(E expression) : + base(true) => + this._Expression = expression ?? throw new ArgumentNullException(nameof(expression)); + + public override void ExpressionWalker(TypedExpression value) => + this._Expression.Walk(value); + + public override void TypeWalker(ResolvedType value) => + this._Expression.Type.Walk(value); + } + + /// + /// Base class for all ExpressionWalkers. + /// + public class ExpressionWalker : + Core.ExpressionWalker + where K : Core.ExpressionKindWalker + where T : Core.ExpressionTypeWalker + { + public readonly K _Kind; + private readonly Core.ExpressionKindWalker DefaultKind; + public override Core.ExpressionKindWalker Kind => _Kind ?? DefaultKind; + + public readonly T _Type; + private readonly Core.ExpressionTypeWalker DefaultType; + public override Core.ExpressionTypeWalker Type => _Type ?? DefaultType; + + public ExpressionWalker(Func, K> kind, Func, T> type) : + base(false) // disable Walkers by default + { + this.DefaultKind = base.Kind; + this._Kind = kind?.Invoke(this); + + this.DefaultType = new Core.ExpressionTypeWalker(false); // disabled by default + this._Type = type?.Invoke(this); + } + } + + /// + /// Given an expression kind Walker, Walk applies the given Walker to the Kind of every expression. + /// + public class ExpressionWalker : + ExpressionWalker + where K : Core.ExpressionKindWalker + { + public ExpressionWalker(Func, K> kind) : + base(kind, null) + { } + } + + /// + /// ExpressionWalker where expression kind Walkers are set to their default - + /// i.e. subexpressions are walked, but no Walker is done on the kind itself. + /// + public class DefaultExpressionWalker : + ExpressionWalker> + { + public DefaultExpressionWalker() : + base(e => new ExpressionKindWalker(e as DefaultExpressionWalker)) + { } + } + + /// + /// Disables all expression Walkers, and can be use as no-op if an ExpressionWalker is required as argument. + /// + public class NoExpressionWalkers : + ExpressionWalker + { + public NoExpressionWalkers() : + base(null) + { } + + public override void Walk(TypedExpression ex) { } + } +} + From efa2f80a28d4b752eb38ea8671724ca375f6e80d Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Tue, 5 Nov 2019 15:59:47 -0800 Subject: [PATCH 21/32] Refactored into the leveler (a transformation) and a call graph building walker. The leveler could be a transform on top and a walker below; not clear how much this would gain. --- src/QsCompiler/QsTargeting/CallGraphWalker.fs | 239 ++++++++++++++++++ .../QsTargeting/CapabilityLeveler.fs | 213 ++-------------- src/QsCompiler/QsTargeting/Targeting.fsproj | 1 + 3 files changed, 263 insertions(+), 190 deletions(-) create mode 100644 src/QsCompiler/QsTargeting/CallGraphWalker.fs diff --git a/src/QsCompiler/QsTargeting/CallGraphWalker.fs b/src/QsCompiler/QsTargeting/CallGraphWalker.fs new file mode 100644 index 0000000000..929bdade4e --- /dev/null +++ b/src/QsCompiler/QsTargeting/CallGraphWalker.fs @@ -0,0 +1,239 @@ +module Microsoft.Quantum.QsCompiler.Targeting.CallGraphWalker + +open Microsoft.Quantum.QsCompiler +open Microsoft.Quantum.QsCompiler.DataTypes +open Microsoft.Quantum.QsCompiler.SyntaxExtensions +open Microsoft.Quantum.QsCompiler.SyntaxTokens +open Microsoft.Quantum.QsCompiler.SyntaxTree +open Microsoft.Quantum.QsCompiler.Transformations.Core +open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput +open System.Collections.Immutable +open System.Collections.Generic + +type private SpecializationKey = + { + QualifiedName : QsQualifiedName + Kind : QsSpecializationKind + TypeArgString : string + } + +type CallGraph() = + let sep = '|' + let levels = new Dictionary() + let dependencies = new Dictionary>() + let keyTypes = new Dictionary() + + let SpecInfoToKey name kind (types : QsNullable>) = + let ResolvedTypeToString rt = + let exprTransformer = new ExpressionToQs() + let transformer = new ExpressionTypeToQs(exprTransformer) + transformer.Apply(rt) + let getArgString (args : ImmutableArray) = + if args.IsDefaultOrEmpty + then "" + else + let typeArgs = args |> Seq.map (fun t -> (t, ResolvedTypeToString t)) + typeArgs |> Seq.iter (fun (t, s) -> keyTypes.[s] <- t) + typeArgs |> Seq.map snd + |> String.concat (sep.ToString()) + let typeArgString = types |> QsNullable<_>.Map getArgString + |> fun n -> n.ValueOr "" + { QualifiedName = name; Kind = kind; TypeArgString = typeArgString } + + let SpecToKey (spec : QsSpecialization) = + SpecInfoToKey spec.Parent spec.Kind spec.TypeArguments + + let StringToTypeArray (ts : string) = + let lookupString s = + match keyTypes.TryGetValue(s) with + | true, t -> t + | false, _ -> ResolvedType.New(InvalidType) + let typeSequence = ts.Split(sep) |> Seq.map lookupString + if typeSequence |> Seq.isEmpty + then Null + else Value (typeSequence |> ImmutableArray.ToImmutableArray) + + let RecordDependency callerKey calledKey = + match dependencies.TryGetValue(callerKey) with + | true, deps -> deps.Add(calledKey) |> ignore + | false, _ -> let newDeps = new HashSet() + newDeps.Add(calledKey) |> ignore + dependencies.[callerKey] <- newDeps + + let rec WalkDependencyTree root (accum : HashSet) = + match dependencies.TryGetValue(root) with + | true, next -> + next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum + | false, _ -> accum + + member this.GetSpecializationLevel(spec) = + let key = SpecToKey spec + match levels.TryGetValue(key) with + | true, level -> level + | false, _ -> CapabilityLevel.Unset + + member this.SetSpecializationLevel(spec, level) = + let key = SpecToKey spec + levels.[key] <- level + + member this.AddDependency(callerSpec, calledSpec) = + let callerKey = SpecToKey callerSpec + let calledKey = SpecToKey calledSpec + RecordDependency callerKey calledKey + + member this.AddDependency(callerSpec, calledName, calledKind, calledTypeArgs) = + let callerKey = SpecToKey callerSpec + let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs + RecordDependency callerKey calledKey + + member this.AddDependency(callerName, callerKind, callerTypeArgs, calledName, calledKind, calledTypeArgs) = + let callerKey = SpecInfoToKey callerName callerKind callerTypeArgs + let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs + RecordDependency callerKey calledKey + + member this.FlushDependencies(callerSpec) = + let key = SpecToKey callerSpec + dependencies.Remove(key) |> ignore + + member this.GetDependencies(callerSpec) = + let key = SpecToKey callerSpec + match dependencies.TryGetValue(key) with + | true, deps -> + deps |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) + | false, _ -> Seq.empty + + member this.GetDependencyTree(callerSpec) = + let key = SpecToKey callerSpec + WalkDependencyTree key (new HashSet(key |> Seq.singleton)) + |> Seq.filter (fun k -> k <> key) + |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) + + member this.GetDependencyLevel(callerSpec) = + let getLevel k = + match levels.TryGetValue(k) with + | true, level -> level + | false, _ -> CapabilityLevel.Unset + let key = SpecToKey callerSpec + let deps = WalkDependencyTree key (new HashSet(key |> Seq.singleton)) + |> Seq.filter (fun k -> k <> key) + if Seq.isEmpty deps + then CapabilityLevel.Unset + else deps |> Seq.map getLevel |> Seq.max + +let private isResult ex = + match ex.ResolvedType.Resolution with | Result -> true | _ -> false + +let private isQubitType (t : ResolvedType) = + match t.Resolution with | Qubit -> true | _ -> false + +let private isQubit ex = + ex.ResolvedType |> isQubitType + +let private isQubitArray ex = + match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false + +type private ExpressionKindGraphBuilder(exprXformer : ExpressionGraphBuilder, graph : CallGraph, + spec : QsSpecialization) = + inherit ExpressionKindWalker() + + let mutable inCall = false + let mutable adjoint = false + let mutable controlled = false + + override this.ExpressionWalker x = exprXformer.Walk x + override this.TypeWalker x = () + + member private this.HandleCall method arg = + inCall <- true + adjoint <- false + controlled <- false + this.ExpressionWalker method + inCall <- false + this.ExpressionWalker arg + + override this.onOperationCall(method, arg) = + this.HandleCall method arg + + override this.onFunctionCall(method, arg) = + this.HandleCall method arg + + override this.onAdjointApplication(ex) = + adjoint <- true + base.onAdjointApplication(ex) + + override this.onControlledApplication(ex) = + controlled <- true + base.onControlledApplication(ex) + + override this.onIdentifier(sym, typeArgs) = + match sym with + | GlobalCallable(name) -> + if inCall + then + let kind = match adjoint, controlled with + | false, false -> QsBody + | false, true -> QsControlled + | true, false -> QsAdjoint + | true, true -> QsControlledAdjoint + graph.AddDependency(spec, name, kind, typeArgs) + else + // The callable is being used in a non-call context, such as being + /// assigned to a variable or passed as an argument to another callable, + // which means it could get a functor applied at some later time. + // We're conservative and add all 4 possible kinds. + graph.AddDependency(spec, name, QsBody, typeArgs) + graph.AddDependency(spec, name, QsControlled, typeArgs) + graph.AddDependency(spec, name, QsAdjoint, typeArgs) + graph.AddDependency(spec, name, QsControlledAdjoint, typeArgs) + | _ -> () + base.onIdentifier(sym, typeArgs) + +and private ExpressionGraphBuilder(graph : CallGraph, spec : QsSpecialization) as this = + inherit ExpressionWalker() + + let kindXformer = new ExpressionKindGraphBuilder(this, graph, spec) + + override this.Kind = upcast kindXformer + +type private StatementGraphBuilder(scopeXformer : ScopeGraphBuilder, graph : CallGraph, + spec : QsSpecialization) = + inherit StatementKindWalker() + + let exprXformer = new ExpressionGraphBuilder(graph, spec) + + override this.ScopeWalker x = scopeXformer.Walk x + + override this.ExpressionWalker x = exprXformer.Walk x + override this.TypeWalker x = () + override this.LocationWalker x = () + +and private ScopeGraphBuilder(graph : CallGraph, spec : QsSpecialization) as this = + inherit ScopeWalker() + + let kindXformer = new StatementGraphBuilder(this, graph, spec) + + override this.StatementKind = upcast kindXformer + + member this.Holder with get() = graph + +/// This syntax tree transformer fills in the CapabilityLevel fields in specializations, +/// based on information gathered by the associated scope and other transformations. +type TreeGraphBuilder() = + inherit SyntaxTreeWalker() + + let graph = new CallGraph() + + let mutable spec = None : QsSpecialization option + + let mutable scopeXform = None : ScopeGraphBuilder option + + let mutable currentOperationLevel = None : CapabilityLevel option + + override this.Scope with get() = scopeXform |> Option.map (fun x -> x :> ScopeWalker) + |> Option.defaultWith (fun () -> new ScopeWalker()) + + override this.onSpecializationImplementation(s) = + let xform = new ScopeGraphBuilder(graph, s) + scopeXform <- Some xform + base.onSpecializationImplementation(s) + diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index e551dfc508..d65ff47330 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -9,119 +9,6 @@ open Microsoft.Quantum.QsCompiler.SyntaxExtensions open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.Core -open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput -open System.Collections.Immutable -open System.Collections.Generic - -type private SpecializationKey = - { - QualifiedName : QsQualifiedName - Kind : QsSpecializationKind - TypeArgString : string - } - -type private CapabilityLevelManager() = - let sep = '|' - let levels = new Dictionary() - let dependencies = new Dictionary>() - let keyTypes = new Dictionary() - - let SpecInfoToKey name kind (types : QsNullable>) = - let ResolvedTypeToString rt = - let exprTransformer = new ExpressionToQs() - let transformer = new ExpressionTypeToQs(exprTransformer) - transformer.Apply(rt) - let getArgString (args : ImmutableArray) = - if args.IsDefaultOrEmpty - then "" - else - let typeArgs = args |> Seq.map (fun t -> (t, ResolvedTypeToString t)) - typeArgs |> Seq.iter (fun (t, s) -> keyTypes.[s] <- t) - typeArgs |> Seq.map snd - |> String.concat (sep.ToString()) - let typeArgString = types |> QsNullable<_>.Map getArgString - |> fun n -> n.ValueOr "" - { QualifiedName = name; Kind = kind; TypeArgString = typeArgString } - - let SpecToKey (spec : QsSpecialization) = - SpecInfoToKey spec.Parent spec.Kind spec.TypeArguments - - let StringToTypeArray (ts : string) = - let lookupString s = - match keyTypes.TryGetValue(s) with - | true, t -> t - | false, _ -> ResolvedType.New(InvalidType) - let typeSequence = ts.Split(sep) |> Seq.map lookupString - if typeSequence |> Seq.isEmpty - then Null - else Value (typeSequence |> ImmutableArray.ToImmutableArray) - - let RecordDependency callerKey calledKey = - match dependencies.TryGetValue(callerKey) with - | true, deps -> deps.Add(calledKey) |> ignore - | false, _ -> let newDeps = new HashSet() - newDeps.Add(calledKey) |> ignore - dependencies.[callerKey] <- newDeps - - let rec WalkDependencyTree root (accum : HashSet) = - match dependencies.TryGetValue(root) with - | true, next -> - next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum - | false, _ -> accum - - member this.GetSpecializationLevel(spec) = - let key = SpecToKey spec - match levels.TryGetValue(key) with - | true, level -> level - | false, _ -> CapabilityLevel.Unset - - member this.SetSpecializationLevel(spec, level) = - let key = SpecToKey spec - levels.[key] <- level - - member this.AddDependency(callerSpec, calledSpec) = - let callerKey = SpecToKey callerSpec - let calledKey = SpecToKey calledSpec - RecordDependency callerKey calledKey - - member this.AddDependency(callerSpec, calledName, calledKind, calledTypeArgs) = - let callerKey = SpecToKey callerSpec - let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs - RecordDependency callerKey calledKey - - member this.AddDependency(callerName, callerKind, callerTypeArgs, calledName, calledKind, calledTypeArgs) = - let callerKey = SpecInfoToKey callerName callerKind callerTypeArgs - let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs - RecordDependency callerKey calledKey - - member this.FlushDependencies(callerSpec) = - let key = SpecToKey callerSpec - dependencies.Remove(key) |> ignore - - member this.GetDependencies(callerSpec) = - let key = SpecToKey callerSpec - match dependencies.TryGetValue(key) with - | true, deps -> - deps |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) - | false, _ -> Seq.empty - - member this.GetDependencyTree(callerSpec) = - let key = SpecToKey callerSpec - WalkDependencyTree key (new HashSet(key |> Seq.singleton)) - |> Seq.filter (fun k -> k <> key) - |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) - - member this.GetDependencyLevel(callerSpec) = - let getLevel k = - match levels.TryGetValue(k) with - | true, level -> level - | false, _ -> CapabilityLevel.Unset - let key = SpecToKey callerSpec - let deps = WalkDependencyTree key (new HashSet(key |> Seq.singleton)) - |> Seq.filter (fun k -> k <> key) - if Seq.isEmpty deps - then CapabilityLevel.Unset - else deps |> Seq.map getLevel |> Seq.max let private isResult ex = match ex.ResolvedType.Resolution with | Result -> true | _ -> false @@ -135,74 +22,23 @@ let private isQubit ex = let private isQubitArray ex = match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false -type private CapabilityInfoHolder(spec, manager : CapabilityLevelManager) = +type private CapabilityInfoHolder(spec) = let mutable localLevel = CapabilityLevel.Minimal member this.LocalLevel with get() = localLevel and set(n) = if n > localLevel then localLevel <- n member this.Specialization with get() = spec - member this.Manager = manager - type private ExpressionKindLeveler(exprXformer : ExpressionLeveler, holder : CapabilityInfoHolder) = inherit ExpressionKindTransformation() - let mutable inCall = false - let mutable adjoint = false - let mutable controlled = false let mutable isSimpleResultTest = true member this.IsSimpleResultTest with get() = isSimpleResultTest and set(value) = isSimpleResultTest <- value - member private this.HandleCall method arg = - inCall <- true - adjoint <- false - controlled <- false - let method = this.ExpressionTransformation method - inCall <- false - let arg = this.ExpressionTransformation arg - CallLikeExpression(method, arg) - override this.ExpressionTransformation x = exprXformer.Transform x override this.TypeTransformation x = x - override this.onOperationCall(method, arg) = - this.HandleCall method arg - - override this.onFunctionCall(method, arg) = - this.HandleCall method arg - - override this.onAdjointApplication(ex) = - adjoint <- true - base.onAdjointApplication(ex) - - override this.onControlledApplication(ex) = - controlled <- true - base.onControlledApplication(ex) - - override this.onIdentifier(sym, typeArgs) = - match sym with - | GlobalCallable(name) -> - if inCall - then - let kind = match adjoint, controlled with - | false, false -> QsBody - | false, true -> QsControlled - | true, false -> QsAdjoint - | true, true -> QsControlledAdjoint - holder.Manager.AddDependency(holder.Specialization, name, kind, typeArgs) - else - // The callable is being used in a non-call context, such as being - /// assigned to a variable or passed as an argument to another callable, - // which means it could get a functor applied at some later time. - // We're conservative and add all 4 possible kinds. - holder.Manager.AddDependency(holder.Specialization, name, QsBody, typeArgs) - holder.Manager.AddDependency(holder.Specialization, name, QsControlled, typeArgs) - holder.Manager.AddDependency(holder.Specialization, name, QsAdjoint, typeArgs) - holder.Manager.AddDependency(holder.Specialization, name, QsControlledAdjoint, typeArgs) - | _ -> () - base.onIdentifier(sym, typeArgs) - override this.Transform(kind) = match kind with | UnwrapApplication _ @@ -320,7 +156,7 @@ type TreeLeveler() = inherit SyntaxTreeTransformation() // Checks to see if a callable or specialization has a developer-specified capability level, - // which overrides the level computed from the code if it is present.7682 + // which overrides the level computed from the code if it is present. let checkForLevelAttributes (attrs : QsDeclarationAttribute seq) = let isLevelAttribute (a : QsDeclarationAttribute) = match a.TypeId with @@ -344,8 +180,6 @@ type TreeLeveler() = | [] -> None | _ -> None - let manager = new CapabilityLevelManager() - let mutable spec = None : QsSpecialization option let mutable scopeXform = None : ScopeLeveler option @@ -361,14 +195,13 @@ type TreeLeveler() = result override this.onSpecializationImplementation(s) = - let holder = new CapabilityInfoHolder(s, manager) + let holder = new CapabilityInfoHolder(s) let xform = new ScopeLeveler(holder) scopeXform <- Some xform let result = base.onSpecializationImplementation(s) let level = s.Attributes |> checkForLevelAttributes |> Option.orElse currentOperationLevel |> Option.defaultValue holder.LocalLevel - manager.SetSpecializationLevel(s, level) { result with RequiredCapability = level } // TODO: For generated specializations, we need to find the appropriate "body" declaration @@ -386,29 +219,29 @@ type TreeLeveler() = // namespaces may be processed in any order. // Note that F# doesn't like ns |> base.Transform -- it complains about this usage // of "base". - xformed |> this.PostProcess + xformed // |> this.PostProcess /// Update required levels based on full call trees. /// We have to do this after we've checked all of the callables. /// Even so, there are potential issues from inter-namespace calls. /// TODO: figure out how to be safe against inter-namespace calls, given that /// namespaces may be processed in any order. - member this.PostProcess(ns : QsNamespace) = - let processElement qse = - let processSpecialization (s : QsSpecialization) = - if s.Attributes |> checkForLevelAttributes |> Option.isNone - then - let calledLevel = manager.GetDependencyLevel(s) - if calledLevel > s.RequiredCapability - then { s with RequiredCapability = calledLevel } - else s - else s - match qse with - | QsCallable c when c.Attributes |> checkForLevelAttributes |> Option.isNone -> - let specs = c.Specializations |> Seq.map processSpecialization - QsCallable (QsCallable.New c.Kind (c.SourceFile, c.Location) - (c.FullName, c.Attributes, c.ArgumentTuple, c.Signature, - specs, c.Documentation, c.Comments)) - | _ -> qse - let elems = ns.Elements |> Seq.map processElement - QsNamespace.New(ns.Name, elems, ns.Documentation) + //member this.PostProcess(ns : QsNamespace) = + // let processElement qse = + // let processSpecialization (s : QsSpecialization) = + // if s.Attributes |> checkForLevelAttributes |> Option.isNone + // then + // let calledLevel = manager.GetDependencyLevel(s) + // if calledLevel > s.RequiredCapability + // then { s with RequiredCapability = calledLevel } + // else s + // else s + // match qse with + // | QsCallable c when c.Attributes |> checkForLevelAttributes |> Option.isNone -> + // let specs = c.Specializations |> Seq.map processSpecialization + // QsCallable (QsCallable.New c.Kind (c.SourceFile, c.Location) + // (c.FullName, c.Attributes, c.ArgumentTuple, c.Signature, + // specs, c.Documentation, c.Comments)) + // | _ -> qse + // let elems = ns.Elements |> Seq.map processElement + // QsNamespace.New(ns.Name, elems, ns.Documentation) diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj index 86bcb078f3..5588f42b60 100644 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -6,6 +6,7 @@ + From 5721a45866d8bed264ea296d040a4559853a9c28 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Wed, 6 Nov 2019 10:38:39 -0800 Subject: [PATCH 22/32] Refactored to make the leveler more efficient by walking the implementation of specializations, rather than transforming them, avoiding a bunch of copying and allocation. --- .../QsTargeting/CapabilityLeveler.fs | 86 +++++++++---------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index d65ff47330..3b3ca51f24 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -5,41 +5,40 @@ module Microsoft.Quantum.QsCompiler.Targeting.Leveler open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.DataTypes -open Microsoft.Quantum.QsCompiler.SyntaxExtensions open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.Quantum.QsCompiler.Transformations.Core +// Some useful utility routines let private isResult ex = match ex.ResolvedType.Resolution with | Result -> true | _ -> false let private isQubitType (t : ResolvedType) = match t.Resolution with | Qubit -> true | _ -> false -let private isQubit ex = - ex.ResolvedType |> isQubitType - let private isQubitArray ex = match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false -type private CapabilityInfoHolder(spec) = +/// Tiny wrapper around a mutable capability level. +/// The reason for using this class, rather than a simple ref, is the logic in the setter; +/// that allows us to always just set the value, rather than have the test logic throughout the code. +type private CapabilityInfoHolder() = let mutable localLevel = CapabilityLevel.Minimal member this.LocalLevel with get() = localLevel and set(n) = if n > localLevel then localLevel <- n - member this.Specialization with get() = spec - +/// Walker for setting capability levels based on expression details. type private ExpressionKindLeveler(exprXformer : ExpressionLeveler, holder : CapabilityInfoHolder) = - inherit ExpressionKindTransformation() + inherit ExpressionKindWalker() let mutable isSimpleResultTest = true member this.IsSimpleResultTest with get() = isSimpleResultTest and set(value) = isSimpleResultTest <- value - override this.ExpressionTransformation x = exprXformer.Transform x - override this.TypeTransformation x = x + override this.ExpressionWalker x = exprXformer.Walk x + override this.TypeWalker x = () - override this.Transform(kind) = + override this.Walk(kind) = match kind with | UnwrapApplication _ | ValueTuple _ @@ -84,10 +83,11 @@ type private ExpressionKindLeveler(exprXformer : ExpressionLeveler, holder : Cap if not (isQubitArray arr) then holder.LocalLevel <- CapabilityLevel.Medium | _ -> () - base.Transform(kind) + base.Walk(kind) +/// Walker for setting capability levels based on expressions. and private ExpressionLeveler(holder : CapabilityInfoHolder) as this = - inherit ExpressionTransformation() + inherit ExpressionWalker() let kindXformer = new ExpressionKindLeveler(this, holder) @@ -96,30 +96,29 @@ and private ExpressionLeveler(holder : CapabilityInfoHolder) as this = member this.IsSimpleResultTest with get() = kindXformer.IsSimpleResultTest and set(v) = kindXformer.IsSimpleResultTest <- v +/// Walker for setting capability levels based on statements. type private StatementLeveler(scopeXformer : ScopeLeveler, holder : CapabilityInfoHolder) = - inherit StatementKindTransformation() + inherit StatementKindWalker() let exprXformer = new ExpressionLeveler(holder) - override this.ScopeTransformation x = scopeXformer.Transform x + override this.ScopeWalker x = scopeXformer.Walk x - override this.ExpressionTransformation x = + override this.ExpressionWalker x = exprXformer.IsSimpleResultTest <- true - exprXformer.Transform x - override this.TypeTransformation x = x - override this.LocationTransformation x = x + exprXformer.Walk x + override this.TypeWalker x = () + override this.LocationWalker x = () override this.onConditionalStatement(stm) = let processCase (condition, block : QsPositionedBlock) = - let expr = this.ExpressionTransformation condition + this.ExpressionWalker condition if not exprXformer.IsSimpleResultTest then holder.LocalLevel <- CapabilityLevel.Medium else holder.LocalLevel <- CapabilityLevel.Basic - let body = this.ScopeTransformation block.Body - expr, QsPositionedBlock.New block.Comments block.Location body - let cases = stm.ConditionalBlocks |> Seq.map processCase - let defaultCase = stm.Default |> QsNullable<_>.Map (fun b -> this.onPositionedBlock (None, b) |> snd) - QsConditionalStatement.New (cases, defaultCase) |> QsConditionalStatement + this.ScopeWalker block.Body + stm.ConditionalBlocks |> Seq.iter processCase + stm.Default |> QsNullable<_>.Iter (fun b -> this.onPositionedBlock (None, b)) override this.onRepeatStatement(s) = holder.LocalLevel <- CapabilityLevel.Advanced @@ -141,8 +140,9 @@ type private StatementLeveler(scopeXformer : ScopeLeveler, holder : CapabilityIn then holder.LocalLevel <- CapabilityLevel.Advanced base.onVariableDeclaration(s) +/// Walker for setting capability levels based on scopes. and private ScopeLeveler(holder : CapabilityInfoHolder) as this = - inherit ScopeTransformation() + inherit ScopeWalker() let kindXformer = new StatementLeveler(this, holder) @@ -151,7 +151,7 @@ and private ScopeLeveler(holder : CapabilityInfoHolder) as this = member this.Holder with get() = holder /// This syntax tree transformer fills in the CapabilityLevel fields in specializations, -/// based on information gathered by the associated scope and other transformations. +/// based on information gathered by the associated scope and other walkers. type TreeLeveler() = inherit SyntaxTreeTransformation() @@ -180,14 +180,9 @@ type TreeLeveler() = | [] -> None | _ -> None - let mutable spec = None : QsSpecialization option - - let mutable scopeXform = None : ScopeLeveler option - let mutable currentOperationLevel = None : CapabilityLevel option - override this.Scope with get() = scopeXform |> Option.map (fun x -> x :> ScopeTransformation) - |> Option.defaultWith (fun () -> new ScopeTransformation()) + override this.Scope with get() = new ScopeTransformation() override this.beforeCallable(c) = currentOperationLevel <- c.Attributes |> checkForLevelAttributes @@ -195,21 +190,22 @@ type TreeLeveler() = result override this.onSpecializationImplementation(s) = - let holder = new CapabilityInfoHolder(s) - let xform = new ScopeLeveler(holder) - scopeXform <- Some xform - let result = base.onSpecializationImplementation(s) - let level = s.Attributes |> checkForLevelAttributes - |> Option.orElse currentOperationLevel - |> Option.defaultValue holder.LocalLevel - { result with RequiredCapability = level } - + let codeLevel = match s.Implementation with + | Intrinsic -> CapabilityLevel.Minimal + | External -> CapabilityLevel.Unset + | Generated _ -> CapabilityLevel.Unset // TODO: For generated specializations, we need to find the appropriate "body" declaration // and copy the required capability from that to the generated specialization. + | Provided (_, scope) -> + let holder = new CapabilityInfoHolder() + let xform = new ScopeLeveler(holder) + xform.Walk(scope) + holder.LocalLevel + let level = s.Attributes |> checkForLevelAttributes + |> Option.orElse currentOperationLevel + |> Option.defaultValue codeLevel + if level <> s.RequiredCapability then { s with RequiredCapability = level } else s - override this.onIntrinsicImplementation() = - scopeXform |> Option.iter (fun x -> x.Holder.LocalLevel <- CapabilityLevel.Minimal) - base.onIntrinsicImplementation() override this.Transform(ns : QsNamespace) = let xformed = base.Transform ns From 9e3b10d77adfe108b45536fc9be6abd6cd99a0ae Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Wed, 6 Nov 2019 13:04:29 -0800 Subject: [PATCH 23/32] Removing a file that's not needed yet --- src/QsCompiler/QsTargeting/Target.fs | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 src/QsCompiler/QsTargeting/Target.fs diff --git a/src/QsCompiler/QsTargeting/Target.fs b/src/QsCompiler/QsTargeting/Target.fs deleted file mode 100644 index 64884ec757..0000000000 --- a/src/QsCompiler/QsTargeting/Target.fs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.QsCompiler.Targeting - -open Microsoft.Quantum.QsCompiler.SymbolManagement -open System.Collections.Generic -open System.Threading -open Microsoft.Quantum.QsCompiler.SyntaxTree -open Microsoft.Quantum.QsCompiler.Diagnostics - -type Target(builtIns : NamespaceManager, capabilityLevel : CapabilityLevel) = - member this.BuiltIns with get () = builtIns - - member this.CapabilityLevel with get () = capabilityLevel - - member this.ValidateSpecialization (spec : QsSpecialization) : List = - let diagnostics = new List() - if spec.RequiredCapability > this.CapabilityLevel - then diagnostics.Add(Error ErrorCode.UnexpectedCompilerException) - diagnostics - - member this.ValidateSyntaxTree (ns : QsNamespace, cancellationToken : CancellationToken) : List = - new List() From f460a42918c60eaf7ba65d94b1b1d950c4988f09 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Wed, 6 Nov 2019 14:52:37 -0800 Subject: [PATCH 24/32] Cleaned up some refactoring cruft --- src/QsCompiler/QsTargeting/CallGraphWalker.fs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/QsCompiler/QsTargeting/CallGraphWalker.fs b/src/QsCompiler/QsTargeting/CallGraphWalker.fs index 929bdade4e..2950c37389 100644 --- a/src/QsCompiler/QsTargeting/CallGraphWalker.fs +++ b/src/QsCompiler/QsTargeting/CallGraphWalker.fs @@ -120,18 +120,6 @@ type CallGraph() = then CapabilityLevel.Unset else deps |> Seq.map getLevel |> Seq.max -let private isResult ex = - match ex.ResolvedType.Resolution with | Result -> true | _ -> false - -let private isQubitType (t : ResolvedType) = - match t.Resolution with | Qubit -> true | _ -> false - -let private isQubit ex = - ex.ResolvedType |> isQubitType - -let private isQubitArray ex = - match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false - type private ExpressionKindGraphBuilder(exprXformer : ExpressionGraphBuilder, graph : CallGraph, spec : QsSpecialization) = inherit ExpressionKindWalker() @@ -214,8 +202,6 @@ and private ScopeGraphBuilder(graph : CallGraph, spec : QsSpecialization) as thi override this.StatementKind = upcast kindXformer - member this.Holder with get() = graph - /// This syntax tree transformer fills in the CapabilityLevel fields in specializations, /// based on information gathered by the associated scope and other transformations. type TreeGraphBuilder() = @@ -223,12 +209,8 @@ type TreeGraphBuilder() = let graph = new CallGraph() - let mutable spec = None : QsSpecialization option - let mutable scopeXform = None : ScopeGraphBuilder option - let mutable currentOperationLevel = None : CapabilityLevel option - override this.Scope with get() = scopeXform |> Option.map (fun x -> x :> ScopeWalker) |> Option.defaultWith (fun () -> new ScopeWalker()) @@ -237,3 +219,4 @@ type TreeGraphBuilder() = scopeXform <- Some xform base.onSpecializationImplementation(s) + member this.CallGraph with get() = graph From 2ffa3d8ed1b05a3a01328c27f79d0e4602daea68 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Thu, 7 Nov 2019 13:24:31 -0800 Subject: [PATCH 25/32] Removed deleted file from project file --- src/QsCompiler/QsTargeting/Targeting.fsproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj index 5588f42b60..e837b7ccb2 100644 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ b/src/QsCompiler/QsTargeting/Targeting.fsproj @@ -7,7 +7,6 @@ - From 87065e5996526bfd9d87cdca818118bf68b779bb Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Thu, 7 Nov 2019 15:20:54 -0800 Subject: [PATCH 26/32] Removed an obsolete reference from the solution file --- QsCompiler.sln | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/QsCompiler.sln b/QsCompiler.sln index 094bfb5548..07fb83c6a9 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -236,18 +236,6 @@ Global {2E331781-F7ED-4EF1-8451-896636C6D93A}.Release|x64.Build.0 = Release|Any CPU {2E331781-F7ED-4EF1-8451-896636C6D93A}.Release|x86.ActiveCfg = Release|Any CPU {2E331781-F7ED-4EF1-8451-896636C6D93A}.Release|x86.Build.0 = Release|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x64.ActiveCfg = Debug|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x64.Build.0 = Debug|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x86.ActiveCfg = Debug|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Debug|x86.Build.0 = Debug|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|Any CPU.Build.0 = Release|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x64.ActiveCfg = Release|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x64.Build.0 = Release|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x86.ActiveCfg = Release|Any CPU - {A83A9BA2-A774-4F07-B801-5A4A73598F62}.Release|x86.Build.0 = Release|Any CPU {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -296,7 +284,6 @@ Global {D50583DF-FBEF-45EF-B523-70B2CDBE1DD1} = {76BA96DA-DC1E-4315-A3ED-5F0700A79812} {2E331781-F7ED-4EF1-8451-896636C6D93A} = {76BA96DA-DC1E-4315-A3ED-5F0700A79812} {D2E36476-A65F-4310-9C4C-B721BCC47B00} = {6077A717-50BF-4F87-B439-CA549AF6A4AE} - {A83A9BA2-A774-4F07-B801-5A4A73598F62} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} {DDAA35BF-7BFC-431F-9F7E-182F01DAEB3F} = {D2E36476-A65F-4310-9C4C-B721BCC47B00} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution From a4dd9b1ad1c6711f0177b72cb94b527776537558 Mon Sep 17 00:00:00 2001 From: Alan Geller Date: Tue, 12 Nov 2019 17:22:10 -0800 Subject: [PATCH 27/32] WIP, cleaning up --- src/QsCompiler/DataStructures/SyntaxTree.fs | 30 ++++++------- src/QsCompiler/QsTargeting/CallGraphWalker.fs | 26 +++--------- .../QsTargeting/CapabilityLeveler.fs | 42 +++---------------- 3 files changed, 26 insertions(+), 72 deletions(-) diff --git a/src/QsCompiler/DataStructures/SyntaxTree.fs b/src/QsCompiler/DataStructures/SyntaxTree.fs index a44ad32892..ab516a49bf 100644 --- a/src/QsCompiler/DataStructures/SyntaxTree.fs +++ b/src/QsCompiler/DataStructures/SyntaxTree.fs @@ -241,21 +241,35 @@ type ResolvedCharacteristics = private { | None -> Null +/// Different targets provide different levels of Q# support. Some targets can execute any Q# code, +/// while others are very limited in the Q# constructs that they can process. +type CapabilityLevel = +| Minimal = 1 +| Basic = 2 +| Medium = 3 +| Advanced = 4 +| Full = 5 +| Unset = -1 + + /// used to represent information on Q# operations and expressions thereof generated and/or tracked during compilation type InferredCallableInformation = { /// indicates whether the callable is a self-adjoint operation IsSelfAdjoint : bool /// indicates whether the callable is intrinsic, i.e. implemented by the target machine IsIntrinsic : bool + /// contains the minimum target capability level required to execute this specialization's code, not including anything it calls + RequiredCapabilityLevel : CapabilityLevel } with - static member NoInformation = {IsSelfAdjoint = false; IsIntrinsic = false} + static member NoInformation = {IsSelfAdjoint = false; IsIntrinsic = false; RequiredCapabilityLevel = CapabilityLevel.Unset} /// Determines the information that was inferred for all given items. static member Common (infos : InferredCallableInformation seq) = let allAreIntrinsic = infos |> Seq.map (fun info -> info.IsIntrinsic) |> Seq.contains false |> not let allAreSelfAdjoint = infos |> Seq.map (fun info -> info.IsSelfAdjoint) |> Seq.contains false |> not - {IsIntrinsic = allAreIntrinsic; IsSelfAdjoint = allAreSelfAdjoint} + let requiredLevel = infos |> Seq.map (fun info -> info.RequiredCapabilityLevel) |> Seq.max + {IsIntrinsic = allAreIntrinsic; IsSelfAdjoint = allAreSelfAdjoint; RequiredCapabilityLevel = requiredLevel} /// Contains information associated with a fully resolved operation type. @@ -608,16 +622,6 @@ type SpecializationImplementation = | Generated of QsGeneratorDirective // Invert and Distribute will be replaced by Provided before sending to code gen -/// Different targets provide different levels of Q# support. Some targets can execute any Q# code, -/// while others are very limited in the Q# constructs that they can process. -type CapabilityLevel = -| Minimal = 1 -| Basic = 2 -| Medium = 3 -| Advanced = 4 -| Full = 5 -| Unset = -1 - /// For each callable various specialization exist describing how it acts /// depending on the type of the argument it is called with (type specializations), /// and/or which functors are applied to the call. @@ -628,8 +632,6 @@ type QsSpecialization = { Parent : QsQualifiedName /// contains all attributes associated with the specialization Attributes : ImmutableArray - /// contains the minimum target capability level for this specialization's code, not including anything it calls - RequiredCapability : CapabilityLevel /// identifier for the file the specialization is declared in (not necessarily the same as the one of the callable it extends) SourceFile : NonNullable /// Contains the location information for the declared specialization. diff --git a/src/QsCompiler/QsTargeting/CallGraphWalker.fs b/src/QsCompiler/QsTargeting/CallGraphWalker.fs index 2950c37389..8ff67800bf 100644 --- a/src/QsCompiler/QsTargeting/CallGraphWalker.fs +++ b/src/QsCompiler/QsTargeting/CallGraphWalker.fs @@ -17,6 +17,7 @@ type private SpecializationKey = TypeArgString : string } + type CallGraph() = let sep = '|' let levels = new Dictionary() @@ -66,16 +67,6 @@ type CallGraph() = next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum | false, _ -> accum - member this.GetSpecializationLevel(spec) = - let key = SpecToKey spec - match levels.TryGetValue(key) with - | true, level -> level - | false, _ -> CapabilityLevel.Unset - - member this.SetSpecializationLevel(spec, level) = - let key = SpecToKey spec - levels.[key] <- level - member this.AddDependency(callerSpec, calledSpec) = let callerKey = SpecToKey callerSpec let calledKey = SpecToKey calledSpec @@ -108,17 +99,6 @@ type CallGraph() = |> Seq.filter (fun k -> k <> key) |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) - member this.GetDependencyLevel(callerSpec) = - let getLevel k = - match levels.TryGetValue(k) with - | true, level -> level - | false, _ -> CapabilityLevel.Unset - let key = SpecToKey callerSpec - let deps = WalkDependencyTree key (new HashSet(key |> Seq.singleton)) - |> Seq.filter (fun k -> k <> key) - if Seq.isEmpty deps - then CapabilityLevel.Unset - else deps |> Seq.map getLevel |> Seq.max type private ExpressionKindGraphBuilder(exprXformer : ExpressionGraphBuilder, graph : CallGraph, spec : QsSpecialization) = @@ -176,6 +156,7 @@ type private ExpressionKindGraphBuilder(exprXformer : ExpressionGraphBuilder, gr | _ -> () base.onIdentifier(sym, typeArgs) + and private ExpressionGraphBuilder(graph : CallGraph, spec : QsSpecialization) as this = inherit ExpressionWalker() @@ -183,6 +164,7 @@ and private ExpressionGraphBuilder(graph : CallGraph, spec : QsSpecialization) a override this.Kind = upcast kindXformer + type private StatementGraphBuilder(scopeXformer : ScopeGraphBuilder, graph : CallGraph, spec : QsSpecialization) = inherit StatementKindWalker() @@ -195,6 +177,7 @@ type private StatementGraphBuilder(scopeXformer : ScopeGraphBuilder, graph : Cal override this.TypeWalker x = () override this.LocationWalker x = () + and private ScopeGraphBuilder(graph : CallGraph, spec : QsSpecialization) as this = inherit ScopeWalker() @@ -202,6 +185,7 @@ and private ScopeGraphBuilder(graph : CallGraph, spec : QsSpecialization) as thi override this.StatementKind = upcast kindXformer + /// This syntax tree transformer fills in the CapabilityLevel fields in specializations, /// based on information gathered by the associated scope and other transformations. type TreeGraphBuilder() = diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs index 3b3ca51f24..17765706ad 100644 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs @@ -196,6 +196,8 @@ type TreeLeveler() = | Generated _ -> CapabilityLevel.Unset // TODO: For generated specializations, we need to find the appropriate "body" declaration // and copy the required capability from that to the generated specialization. + // If the body hasn't been processed yet, then process it right away, use the result here, + // and remember the result for later use so we don't compute it twice. | Provided (_, scope) -> let holder = new CapabilityInfoHolder() let xform = new ScopeLeveler(holder) @@ -204,40 +206,6 @@ type TreeLeveler() = let level = s.Attributes |> checkForLevelAttributes |> Option.orElse currentOperationLevel |> Option.defaultValue codeLevel - if level <> s.RequiredCapability then { s with RequiredCapability = level } else s - - - override this.Transform(ns : QsNamespace) = - let xformed = base.Transform ns - // We have to do this after we've checked all of the callables. - // Even so, there are potential issues from inter-namespace calls. - // TODO: figure out how to be safe against inter-namespace calls, given that - // namespaces may be processed in any order. - // Note that F# doesn't like ns |> base.Transform -- it complains about this usage - // of "base". - xformed // |> this.PostProcess - - /// Update required levels based on full call trees. - /// We have to do this after we've checked all of the callables. - /// Even so, there are potential issues from inter-namespace calls. - /// TODO: figure out how to be safe against inter-namespace calls, given that - /// namespaces may be processed in any order. - //member this.PostProcess(ns : QsNamespace) = - // let processElement qse = - // let processSpecialization (s : QsSpecialization) = - // if s.Attributes |> checkForLevelAttributes |> Option.isNone - // then - // let calledLevel = manager.GetDependencyLevel(s) - // if calledLevel > s.RequiredCapability - // then { s with RequiredCapability = calledLevel } - // else s - // else s - // match qse with - // | QsCallable c when c.Attributes |> checkForLevelAttributes |> Option.isNone -> - // let specs = c.Specializations |> Seq.map processSpecialization - // QsCallable (QsCallable.New c.Kind (c.SourceFile, c.Location) - // (c.FullName, c.Attributes, c.ArgumentTuple, c.Signature, - // specs, c.Documentation, c.Comments)) - // | _ -> qse - // let elems = ns.Elements |> Seq.map processElement - // QsNamespace.New(ns.Name, elems, ns.Documentation) + if level <> s.Signature.Information.InferredInformation.RequiredCapabilityLevel + then { s with Signature = { s.Signature with Information = { s.Signature.Information with InferredInformation = { s.Signature.Information.InferredInformation with RequiredCapabilityLevel = level } } }} + else s From 9abf5debcc0d127d3dd30af5fd3e3c42cc43c9b9 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Nov 2019 13:56:01 -0800 Subject: [PATCH 28/32] Removed CallGraph walker and CapabilityLeveler --- QsCompiler.sln | 14 ---- .../CompilationManager/CompilationUnit.cs | 6 +- .../CompilationManager/TypeChecking.cs | 2 +- src/QsCompiler/Core/ConstructorExtensions.fs | 1 - src/QsCompiler/Core/Dependencies.fs | 6 -- src/QsCompiler/DataStructures/SyntaxTree.fs | 22 +----- .../Tests.Compiler/CapabilityLevelerTests.fs | 77 ------------------- .../TestCases/CapabilityLevels.qs | 62 --------------- .../Tests.Compiler/Tests.Compiler.fsproj | 5 -- 9 files changed, 8 insertions(+), 187 deletions(-) delete mode 100644 src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs delete mode 100644 src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs diff --git a/QsCompiler.sln b/QsCompiler.sln index 07fb83c6a9..7a330f37f1 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -44,8 +44,6 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Optimizations", "src\QsComp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B4A9484D-31FC-4A27-9E26-4C8DE3E02D77}" EndProject -Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Targeting", "src\QsCompiler\QsTargeting\Targeting.fsproj", "{C4279E56-33ED-450A-B547-6752D6926052}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -260,18 +258,6 @@ Global {31085984-3DA6-43C7-B0AA-CE62DC60BB56}.Release|x64.Build.0 = Release|Any CPU {31085984-3DA6-43C7-B0AA-CE62DC60BB56}.Release|x86.ActiveCfg = Release|Any CPU {31085984-3DA6-43C7-B0AA-CE62DC60BB56}.Release|x86.Build.0 = Release|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x64.ActiveCfg = Debug|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x64.Build.0 = Debug|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x86.ActiveCfg = Debug|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Debug|x86.Build.0 = Debug|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Release|Any CPU.Build.0 = Release|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Release|x64.ActiveCfg = Release|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Release|x64.Build.0 = Release|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Release|x86.ActiveCfg = Release|Any CPU - {C4279E56-33ED-450A-B547-6752D6926052}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index 685d9d8a03..63cb21fa98 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -395,7 +395,7 @@ internal void UpdateCallables(IEnumerable updates) if (header.Kind.IsTypeConstructor) { var specLocation = new QsLocation(header.Position, header.SymbolRange); - var defaultSpec = new QsSpecialization(QsSpecializationKind.QsBody, header.QualifiedName, header.Attributes, CapabilityLevel.Unset, + var defaultSpec = new QsSpecialization(QsSpecializationKind.QsBody, header.QualifiedName, header.Attributes, header.SourceFile, specLocation, QsNullable>.Null, header.Signature, SpecializationImplementation.Intrinsic, ImmutableArray.Empty, QsComments.Empty); this.CompiledCallables[fullName] = new QsCallable(header.Kind, header.QualifiedName, header.Attributes, header.SourceFile, specLocation, @@ -419,7 +419,7 @@ internal void UpdateCallables(IEnumerable updates) var compiledSpec = compiledSpecs.Single(); var specLocation = new QsLocation(specHeader.Position, specHeader.HeaderRange); - return new QsSpecialization(compiledSpec.Kind, compiledSpec.Parent, compiledSpec.Attributes, CapabilityLevel.Unset, + return new QsSpecialization(compiledSpec.Kind, compiledSpec.Parent, compiledSpec.Attributes, compiledSpec.SourceFile, specLocation, compiledSpec.TypeArguments, compiledSpec.Signature, compiledSpec.Implementation, compiledSpec.Documentation, compiledSpec.Comments); }) @@ -454,7 +454,7 @@ private QsCallable GetImportedCallable(CallableDeclarationHeader header) var specSignature = specHeader.Kind.IsQsControlled || specHeader.Kind.IsQsControlledAdjoint ? SyntaxGenerator.BuildControlled(header.Signature) : header.Signature; - return new QsSpecialization(specHeader.Kind, header.QualifiedName, specHeader.Attributes, CapabilityLevel.Unset, + return new QsSpecialization(specHeader.Kind, header.QualifiedName, specHeader.Attributes, specHeader.SourceFile, specLocation, specHeader.TypeArguments, specSignature, implementation, specHeader.Documentation, QsComments.Empty); }) diff --git a/src/QsCompiler/CompilationManager/TypeChecking.cs b/src/QsCompiler/CompilationManager/TypeChecking.cs index 571d5bc345..a5c51e1c01 100644 --- a/src/QsCompiler/CompilationManager/TypeChecking.cs +++ b/src/QsCompiler/CompilationManager/TypeChecking.cs @@ -1226,7 +1226,7 @@ private static ImmutableArray BuildSpecializations QsSpecialization GetSpecialization(SpecializationDeclarationHeader spec, ResolvedSignature signature, SpecializationImplementation implementation, QsComments comments = null) => - new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, CapabilityLevel.Unset, spec.SourceFile, null, + new QsSpecialization(spec.Kind, spec.Parent, spec.Attributes, spec.SourceFile, null, spec.TypeArguments, SyntaxGenerator.WithoutRangeInfo(signature), implementation, spec.Documentation, comments ?? QsComments.Empty); QsSpecialization BuildSpecialization(QsSpecializationKind kind, ResolvedSignature signature, QsSpecializationGeneratorKind gen, FragmentTree.TreeNode root, diff --git a/src/QsCompiler/Core/ConstructorExtensions.fs b/src/QsCompiler/Core/ConstructorExtensions.fs index 5a1329f78a..cbd0b46ab0 100644 --- a/src/QsCompiler/Core/ConstructorExtensions.fs +++ b/src/QsCompiler/Core/ConstructorExtensions.fs @@ -181,7 +181,6 @@ type QsSpecialization with Kind = kind Parent = parent Attributes = attributes - RequiredCapability = CapabilityLevel.Unset SourceFile = source Location = location TypeArguments = typeArgs diff --git a/src/QsCompiler/Core/Dependencies.fs b/src/QsCompiler/Core/Dependencies.fs index 147d270e99..b594cdc22a 100644 --- a/src/QsCompiler/Core/Dependencies.fs +++ b/src/QsCompiler/Core/Dependencies.fs @@ -67,12 +67,6 @@ type BuiltIn = { TypeParameters = ImmutableArray.Empty } - static member LevelAttribute = { - Name = "Level" |> NonNullable.New - Namespace = BuiltIn.CoreNamespace - TypeParameters = ImmutableArray.Empty - } - // "weak dependencies" in other namespaces (e.g. things used for code actions) static member IndexRange = { diff --git a/src/QsCompiler/DataStructures/SyntaxTree.fs b/src/QsCompiler/DataStructures/SyntaxTree.fs index ab516a49bf..8ecb77e306 100644 --- a/src/QsCompiler/DataStructures/SyntaxTree.fs +++ b/src/QsCompiler/DataStructures/SyntaxTree.fs @@ -241,35 +241,21 @@ type ResolvedCharacteristics = private { | None -> Null -/// Different targets provide different levels of Q# support. Some targets can execute any Q# code, -/// while others are very limited in the Q# constructs that they can process. -type CapabilityLevel = -| Minimal = 1 -| Basic = 2 -| Medium = 3 -| Advanced = 4 -| Full = 5 -| Unset = -1 - - /// used to represent information on Q# operations and expressions thereof generated and/or tracked during compilation type InferredCallableInformation = { /// indicates whether the callable is a self-adjoint operation IsSelfAdjoint : bool /// indicates whether the callable is intrinsic, i.e. implemented by the target machine IsIntrinsic : bool - /// contains the minimum target capability level required to execute this specialization's code, not including anything it calls - RequiredCapabilityLevel : CapabilityLevel } with - static member NoInformation = {IsSelfAdjoint = false; IsIntrinsic = false; RequiredCapabilityLevel = CapabilityLevel.Unset} + static member NoInformation = {IsSelfAdjoint = false; IsIntrinsic = false;} /// Determines the information that was inferred for all given items. static member Common (infos : InferredCallableInformation seq) = let allAreIntrinsic = infos |> Seq.map (fun info -> info.IsIntrinsic) |> Seq.contains false |> not let allAreSelfAdjoint = infos |> Seq.map (fun info -> info.IsSelfAdjoint) |> Seq.contains false |> not - let requiredLevel = infos |> Seq.map (fun info -> info.RequiredCapabilityLevel) |> Seq.max - {IsIntrinsic = allAreIntrinsic; IsSelfAdjoint = allAreSelfAdjoint; RequiredCapabilityLevel = requiredLevel} + {IsIntrinsic = allAreIntrinsic; IsSelfAdjoint = allAreSelfAdjoint;} /// Contains information associated with a fully resolved operation type. @@ -622,8 +608,8 @@ type SpecializationImplementation = | Generated of QsGeneratorDirective // Invert and Distribute will be replaced by Provided before sending to code gen -/// For each callable various specialization exist describing how it acts -/// depending on the type of the argument it is called with (type specializations), +/// For each callable various specialization exist describing how it acts +/// depending on the type of the argument it is called with (type specializations), /// and/or which functors are applied to the call. type QsSpecialization = { /// contains the functor specialization kind (specialization for body, adjoint, controlled, or controlled adjoint) diff --git a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs b/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs deleted file mode 100644 index c0836fb048..0000000000 --- a/src/QsCompiler/Tests.Compiler/CapabilityLevelerTests.fs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -module Microsoft.Quantum.QsCompiler.Testing.CapabilityLevelerTests - -open System -open System.Collections.Immutable -open System.IO -open System.Linq -open Microsoft.Quantum.QsCompiler -open Microsoft.Quantum.QsCompiler.CompilationBuilder -open Microsoft.Quantum.QsCompiler.DataTypes -open Microsoft.Quantum.QsCompiler.SyntaxTree -open Microsoft.Quantum.QsCompiler.Targeting.Leveler -open Microsoft.Quantum.QsCompiler.Transformations -open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput -open Xunit - -// Utilities for testing operation capability level setting and the corresponding infrastructure - -let private buildSyntaxTree path code = - let fileId = new Uri(path) - let compilationUnit = new CompilationUnitManager(fun ex -> failwith ex.Message) - let file = CompilationUnitManager.InitializeFileManager(fileId, code) - compilationUnit.AddOrUpdateSourceFileAsync file |> ignore // spawns a task that modifies the current compilation - compilationUnit.GetSyntaxTree() // will wait for any current tasks to finish - -let private buildSyntaxTreeFromFile fileName = - let path = Path.Combine(Path.GetFullPath ".", "TestCases", fileName + ".qs") - path |> File.ReadAllText |> buildSyntaxTree path - -//let private - -let private getOperationLevel tree opName = - let matchOperation opName (e : QsNamespaceElement) = - match e with - | QsCallable c when c.FullName.Name.Value = opName -> - Some c - | _ -> None - let findOperation opName (ns : QsNamespace) = - ns.Elements |> Seq.tryPick (matchOperation opName) - let getOperationBodyLevel (c : QsCallable) = - c.Specializations |> Seq.tryFind (fun s -> s.Kind = QsSpecializationKind.QsBody) - |> Option.map (fun s -> s.RequiredCapability) - |> Option.defaultValue CapabilityLevel.Unset - tree |> Seq.tryPick (findOperation opName) - |> Option.defaultWith (fun () -> failwithf "Operation %A not found" opName) - |> getOperationBodyLevel - - -//////////////////////////////// tests ////////////////////////////////// - -[] -let ``capability leveling tests`` () = - let leveler = new TreeLeveler() - - let syntaxTree = buildSyntaxTreeFromFile "CapabilityLevels" |> Seq.map leveler.Transform - - let mLevel = getOperationLevel syntaxTree "M" - Assert.Equal(CapabilityLevel.Minimal, mLevel) - - let hLevel = getOperationLevel syntaxTree "H" - Assert.Equal(CapabilityLevel.Minimal, hLevel) - - let level1Level = getOperationLevel syntaxTree "Level1" - Assert.Equal(CapabilityLevel.Minimal, level1Level) - - let level2Level = getOperationLevel syntaxTree "Level2" - Assert.Equal(CapabilityLevel.Basic, level2Level) - - let level4Level = getOperationLevel syntaxTree "Level4" - Assert.Equal(CapabilityLevel.Advanced, level4Level) - - let level5Level = getOperationLevel syntaxTree "Level3" - Assert.Equal(CapabilityLevel.Medium, level5Level) - - () \ No newline at end of file diff --git a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs b/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs deleted file mode 100644 index 23746ca2af..0000000000 --- a/src/QsCompiler/Tests.Compiler/TestCases/CapabilityLevels.qs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// Tests for capability leveling - -namespace Microsoft.Quantum.Core -{ - @Attribute() - newtype Level = Int; - - @Attribute() - newtype Attribute = Unit; -} - -namespace Microsoft.Quantum.Testing -{ - // This should be level 1 since it's intrinsic. - operation M (q : Qubit) : Result - { - body intrinsic; - } - - // This should be level 1 since it's intrinsic. - operation H (q : Qubit) : Unit - { - body intrinsic; - } - - // This should be level 1 since everything it does is safe. - operation Level1 () : Unit - { - using (q = Qubit()) - { - return M(q); - } - } - - // This should be level 2 because it has a branch on a measurement result. - operation Level2 () : Unit - { - using (q = Qubit()) - { - if (M(q) == One) - { - H(q); - } - } - } - - // This should be level 3 because it has classical computation. - operation Level3 (d : Double) : Double - { - return 1.0/d; - } - - // This should be level 4 because of the attribute. - @Level(4) - operation Level4 () : Unit - { - - } -} diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj index 47a9233407..38ee33672f 100644 --- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj +++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj @@ -118,9 +118,6 @@ Never - - PreserveNewest - @@ -139,7 +136,6 @@ - @@ -154,7 +150,6 @@ - false From a99f5cb240f0b29cffc13e97d937ae8dcd0fab02 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Nov 2019 14:28:58 -0800 Subject: [PATCH 29/32] Remove the files. --- src/QsCompiler/QsTargeting/CallGraphWalker.fs | 206 ----------------- .../QsTargeting/CapabilityLeveler.fs | 211 ------------------ src/QsCompiler/QsTargeting/Targeting.fsproj | 22 -- 3 files changed, 439 deletions(-) delete mode 100644 src/QsCompiler/QsTargeting/CallGraphWalker.fs delete mode 100644 src/QsCompiler/QsTargeting/CapabilityLeveler.fs delete mode 100644 src/QsCompiler/QsTargeting/Targeting.fsproj diff --git a/src/QsCompiler/QsTargeting/CallGraphWalker.fs b/src/QsCompiler/QsTargeting/CallGraphWalker.fs deleted file mode 100644 index 8ff67800bf..0000000000 --- a/src/QsCompiler/QsTargeting/CallGraphWalker.fs +++ /dev/null @@ -1,206 +0,0 @@ -module Microsoft.Quantum.QsCompiler.Targeting.CallGraphWalker - -open Microsoft.Quantum.QsCompiler -open Microsoft.Quantum.QsCompiler.DataTypes -open Microsoft.Quantum.QsCompiler.SyntaxExtensions -open Microsoft.Quantum.QsCompiler.SyntaxTokens -open Microsoft.Quantum.QsCompiler.SyntaxTree -open Microsoft.Quantum.QsCompiler.Transformations.Core -open Microsoft.Quantum.QsCompiler.Transformations.QsCodeOutput -open System.Collections.Immutable -open System.Collections.Generic - -type private SpecializationKey = - { - QualifiedName : QsQualifiedName - Kind : QsSpecializationKind - TypeArgString : string - } - - -type CallGraph() = - let sep = '|' - let levels = new Dictionary() - let dependencies = new Dictionary>() - let keyTypes = new Dictionary() - - let SpecInfoToKey name kind (types : QsNullable>) = - let ResolvedTypeToString rt = - let exprTransformer = new ExpressionToQs() - let transformer = new ExpressionTypeToQs(exprTransformer) - transformer.Apply(rt) - let getArgString (args : ImmutableArray) = - if args.IsDefaultOrEmpty - then "" - else - let typeArgs = args |> Seq.map (fun t -> (t, ResolvedTypeToString t)) - typeArgs |> Seq.iter (fun (t, s) -> keyTypes.[s] <- t) - typeArgs |> Seq.map snd - |> String.concat (sep.ToString()) - let typeArgString = types |> QsNullable<_>.Map getArgString - |> fun n -> n.ValueOr "" - { QualifiedName = name; Kind = kind; TypeArgString = typeArgString } - - let SpecToKey (spec : QsSpecialization) = - SpecInfoToKey spec.Parent spec.Kind spec.TypeArguments - - let StringToTypeArray (ts : string) = - let lookupString s = - match keyTypes.TryGetValue(s) with - | true, t -> t - | false, _ -> ResolvedType.New(InvalidType) - let typeSequence = ts.Split(sep) |> Seq.map lookupString - if typeSequence |> Seq.isEmpty - then Null - else Value (typeSequence |> ImmutableArray.ToImmutableArray) - - let RecordDependency callerKey calledKey = - match dependencies.TryGetValue(callerKey) with - | true, deps -> deps.Add(calledKey) |> ignore - | false, _ -> let newDeps = new HashSet() - newDeps.Add(calledKey) |> ignore - dependencies.[callerKey] <- newDeps - - let rec WalkDependencyTree root (accum : HashSet) = - match dependencies.TryGetValue(root) with - | true, next -> - next |> Seq.fold (fun (a : HashSet) k -> if a.Add(k) then WalkDependencyTree k a else a) accum - | false, _ -> accum - - member this.AddDependency(callerSpec, calledSpec) = - let callerKey = SpecToKey callerSpec - let calledKey = SpecToKey calledSpec - RecordDependency callerKey calledKey - - member this.AddDependency(callerSpec, calledName, calledKind, calledTypeArgs) = - let callerKey = SpecToKey callerSpec - let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs - RecordDependency callerKey calledKey - - member this.AddDependency(callerName, callerKind, callerTypeArgs, calledName, calledKind, calledTypeArgs) = - let callerKey = SpecInfoToKey callerName callerKind callerTypeArgs - let calledKey = SpecInfoToKey calledName calledKind calledTypeArgs - RecordDependency callerKey calledKey - - member this.FlushDependencies(callerSpec) = - let key = SpecToKey callerSpec - dependencies.Remove(key) |> ignore - - member this.GetDependencies(callerSpec) = - let key = SpecToKey callerSpec - match dependencies.TryGetValue(key) with - | true, deps -> - deps |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) - | false, _ -> Seq.empty - - member this.GetDependencyTree(callerSpec) = - let key = SpecToKey callerSpec - WalkDependencyTree key (new HashSet(key |> Seq.singleton)) - |> Seq.filter (fun k -> k <> key) - |> Seq.map (fun key -> (key.QualifiedName, key.Kind, key.TypeArgString |> StringToTypeArray)) - - -type private ExpressionKindGraphBuilder(exprXformer : ExpressionGraphBuilder, graph : CallGraph, - spec : QsSpecialization) = - inherit ExpressionKindWalker() - - let mutable inCall = false - let mutable adjoint = false - let mutable controlled = false - - override this.ExpressionWalker x = exprXformer.Walk x - override this.TypeWalker x = () - - member private this.HandleCall method arg = - inCall <- true - adjoint <- false - controlled <- false - this.ExpressionWalker method - inCall <- false - this.ExpressionWalker arg - - override this.onOperationCall(method, arg) = - this.HandleCall method arg - - override this.onFunctionCall(method, arg) = - this.HandleCall method arg - - override this.onAdjointApplication(ex) = - adjoint <- true - base.onAdjointApplication(ex) - - override this.onControlledApplication(ex) = - controlled <- true - base.onControlledApplication(ex) - - override this.onIdentifier(sym, typeArgs) = - match sym with - | GlobalCallable(name) -> - if inCall - then - let kind = match adjoint, controlled with - | false, false -> QsBody - | false, true -> QsControlled - | true, false -> QsAdjoint - | true, true -> QsControlledAdjoint - graph.AddDependency(spec, name, kind, typeArgs) - else - // The callable is being used in a non-call context, such as being - /// assigned to a variable or passed as an argument to another callable, - // which means it could get a functor applied at some later time. - // We're conservative and add all 4 possible kinds. - graph.AddDependency(spec, name, QsBody, typeArgs) - graph.AddDependency(spec, name, QsControlled, typeArgs) - graph.AddDependency(spec, name, QsAdjoint, typeArgs) - graph.AddDependency(spec, name, QsControlledAdjoint, typeArgs) - | _ -> () - base.onIdentifier(sym, typeArgs) - - -and private ExpressionGraphBuilder(graph : CallGraph, spec : QsSpecialization) as this = - inherit ExpressionWalker() - - let kindXformer = new ExpressionKindGraphBuilder(this, graph, spec) - - override this.Kind = upcast kindXformer - - -type private StatementGraphBuilder(scopeXformer : ScopeGraphBuilder, graph : CallGraph, - spec : QsSpecialization) = - inherit StatementKindWalker() - - let exprXformer = new ExpressionGraphBuilder(graph, spec) - - override this.ScopeWalker x = scopeXformer.Walk x - - override this.ExpressionWalker x = exprXformer.Walk x - override this.TypeWalker x = () - override this.LocationWalker x = () - - -and private ScopeGraphBuilder(graph : CallGraph, spec : QsSpecialization) as this = - inherit ScopeWalker() - - let kindXformer = new StatementGraphBuilder(this, graph, spec) - - override this.StatementKind = upcast kindXformer - - -/// This syntax tree transformer fills in the CapabilityLevel fields in specializations, -/// based on information gathered by the associated scope and other transformations. -type TreeGraphBuilder() = - inherit SyntaxTreeWalker() - - let graph = new CallGraph() - - let mutable scopeXform = None : ScopeGraphBuilder option - - override this.Scope with get() = scopeXform |> Option.map (fun x -> x :> ScopeWalker) - |> Option.defaultWith (fun () -> new ScopeWalker()) - - override this.onSpecializationImplementation(s) = - let xform = new ScopeGraphBuilder(graph, s) - scopeXform <- Some xform - base.onSpecializationImplementation(s) - - member this.CallGraph with get() = graph diff --git a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs b/src/QsCompiler/QsTargeting/CapabilityLeveler.fs deleted file mode 100644 index 17765706ad..0000000000 --- a/src/QsCompiler/QsTargeting/CapabilityLeveler.fs +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -module Microsoft.Quantum.QsCompiler.Targeting.Leveler - -open Microsoft.Quantum.QsCompiler -open Microsoft.Quantum.QsCompiler.DataTypes -open Microsoft.Quantum.QsCompiler.SyntaxTokens -open Microsoft.Quantum.QsCompiler.SyntaxTree -open Microsoft.Quantum.QsCompiler.Transformations.Core - -// Some useful utility routines -let private isResult ex = - match ex.ResolvedType.Resolution with | Result -> true | _ -> false - -let private isQubitType (t : ResolvedType) = - match t.Resolution with | Qubit -> true | _ -> false - -let private isQubitArray ex = - match ex.ResolvedType.Resolution with | ArrayType t when isQubitType t -> true | _ -> false - -/// Tiny wrapper around a mutable capability level. -/// The reason for using this class, rather than a simple ref, is the logic in the setter; -/// that allows us to always just set the value, rather than have the test logic throughout the code. -type private CapabilityInfoHolder() = - let mutable localLevel = CapabilityLevel.Minimal - - member this.LocalLevel with get() = localLevel and set(n) = if n > localLevel then localLevel <- n - -/// Walker for setting capability levels based on expression details. -type private ExpressionKindLeveler(exprXformer : ExpressionLeveler, holder : CapabilityInfoHolder) = - inherit ExpressionKindWalker() - - let mutable isSimpleResultTest = true - - member this.IsSimpleResultTest with get() = isSimpleResultTest and set(value) = isSimpleResultTest <- value - - override this.ExpressionWalker x = exprXformer.Walk x - override this.TypeWalker x = () - - override this.Walk(kind) = - match kind with - | UnwrapApplication _ - | ValueTuple _ - | NamedItem _ - | ValueArray _ - | NewArray _ - | IntLiteral _ - | BigIntLiteral _ - | DoubleLiteral _ - | BoolLiteral _ - | StringLiteral _ - | RangeLiteral _ - | CopyAndUpdate _ - | CONDITIONAL _ - | NEQ _ - | LT _ - | LTE _ - | GT _ - | GTE _ - | AND _ - | ADD _ - | SUB _ - | MUL _ - | DIV _ - | POW _ - | MOD _ - | LSHIFT _ - | RSHIFT _ - | BXOR _ - | BOR _ - | BAND _ - | NOT _ - | NEG _ - | BNOT _ -> - holder.LocalLevel <- CapabilityLevel.Medium - | OR _ -> - isSimpleResultTest <- false - | EQ (ex1, ex2) -> - if not (isResult ex1 && isResult ex2) - then isSimpleResultTest <- false - | ArrayItem (arr, idx) -> - if not (isQubitArray arr) - then holder.LocalLevel <- CapabilityLevel.Medium - | _ -> () - base.Walk(kind) - -/// Walker for setting capability levels based on expressions. -and private ExpressionLeveler(holder : CapabilityInfoHolder) as this = - inherit ExpressionWalker() - - let kindXformer = new ExpressionKindLeveler(this, holder) - - override this.Kind = upcast kindXformer - - member this.IsSimpleResultTest with get() = kindXformer.IsSimpleResultTest - and set(v) = kindXformer.IsSimpleResultTest <- v - -/// Walker for setting capability levels based on statements. -type private StatementLeveler(scopeXformer : ScopeLeveler, holder : CapabilityInfoHolder) = - inherit StatementKindWalker() - - let exprXformer = new ExpressionLeveler(holder) - - override this.ScopeWalker x = scopeXformer.Walk x - - override this.ExpressionWalker x = - exprXformer.IsSimpleResultTest <- true - exprXformer.Walk x - override this.TypeWalker x = () - override this.LocationWalker x = () - - override this.onConditionalStatement(stm) = - let processCase (condition, block : QsPositionedBlock) = - this.ExpressionWalker condition - if not exprXformer.IsSimpleResultTest - then holder.LocalLevel <- CapabilityLevel.Medium - else holder.LocalLevel <- CapabilityLevel.Basic - this.ScopeWalker block.Body - stm.ConditionalBlocks |> Seq.iter processCase - stm.Default |> QsNullable<_>.Iter (fun b -> this.onPositionedBlock (None, b)) - - override this.onRepeatStatement(s) = - holder.LocalLevel <- CapabilityLevel.Advanced - base.onRepeatStatement(s) - - override this.onWhileStatement(s) = - holder.LocalLevel <- CapabilityLevel.Advanced - base.onWhileStatement(s) - - override this.onValueUpdate(s) = - holder.LocalLevel <- CapabilityLevel.Advanced - base.onValueUpdate(s) - - override this.onVariableDeclaration(s) = - if s.Kind = QsBindingKind.MutableBinding - then holder.LocalLevel <- CapabilityLevel.Advanced - else - if not (isResult s.Rhs) - then holder.LocalLevel <- CapabilityLevel.Advanced - base.onVariableDeclaration(s) - -/// Walker for setting capability levels based on scopes. -and private ScopeLeveler(holder : CapabilityInfoHolder) as this = - inherit ScopeWalker() - - let kindXformer = new StatementLeveler(this, holder) - - override this.StatementKind = upcast kindXformer - - member this.Holder with get() = holder - -/// This syntax tree transformer fills in the CapabilityLevel fields in specializations, -/// based on information gathered by the associated scope and other walkers. -type TreeLeveler() = - inherit SyntaxTreeTransformation() - - // Checks to see if a callable or specialization has a developer-specified capability level, - // which overrides the level computed from the code if it is present. - let checkForLevelAttributes (attrs : QsDeclarationAttribute seq) = - let isLevelAttribute (a : QsDeclarationAttribute) = - match a.TypeId with - | Value udt -> udt.Namespace = BuiltIn.LevelAttribute.Namespace && udt.Name = BuiltIn.LevelAttribute.Name - | Null -> false - let getLevelFromArgument (a : QsDeclarationAttribute) = - match a.Argument.Expression with - | IntLiteral n -> let level = enum (int n) - Some level - | ValueTuple args -> if args.Length = 1 - then - match args.[0].Expression with - | IntLiteral n -> let level = enum (int n) - Some level - | _ -> None - else None - | _ -> None - let levels = attrs |> Seq.filter isLevelAttribute |> List.ofSeq - match levels with - | [ level ] -> getLevelFromArgument level - | [] -> None - | _ -> None - - let mutable currentOperationLevel = None : CapabilityLevel option - - override this.Scope with get() = new ScopeTransformation() - - override this.beforeCallable(c) = - currentOperationLevel <- c.Attributes |> checkForLevelAttributes - let result = base.beforeCallable(c) - result - - override this.onSpecializationImplementation(s) = - let codeLevel = match s.Implementation with - | Intrinsic -> CapabilityLevel.Minimal - | External -> CapabilityLevel.Unset - | Generated _ -> CapabilityLevel.Unset - // TODO: For generated specializations, we need to find the appropriate "body" declaration - // and copy the required capability from that to the generated specialization. - // If the body hasn't been processed yet, then process it right away, use the result here, - // and remember the result for later use so we don't compute it twice. - | Provided (_, scope) -> - let holder = new CapabilityInfoHolder() - let xform = new ScopeLeveler(holder) - xform.Walk(scope) - holder.LocalLevel - let level = s.Attributes |> checkForLevelAttributes - |> Option.orElse currentOperationLevel - |> Option.defaultValue codeLevel - if level <> s.Signature.Information.InferredInformation.RequiredCapabilityLevel - then { s with Signature = { s.Signature with Information = { s.Signature.Information with InferredInformation = { s.Signature.Information.InferredInformation with RequiredCapabilityLevel = level } } }} - else s diff --git a/src/QsCompiler/QsTargeting/Targeting.fsproj b/src/QsCompiler/QsTargeting/Targeting.fsproj deleted file mode 100644 index e837b7ccb2..0000000000 --- a/src/QsCompiler/QsTargeting/Targeting.fsproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - netcoreapp3.0 - - - - - - - - - - - - - - - - - - From 8b3f4bed2d2efd94419033d34236b43787079f42 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 14 Nov 2019 14:34:42 -0800 Subject: [PATCH 30/32] Addressed PR comments --- src/QsCompiler/Core/Dependencies.fs | 1 + src/QsCompiler/Core/ExpressionWalker.fs | 3 --- src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj | 9 --------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/QsCompiler/Core/Dependencies.fs b/src/QsCompiler/Core/Dependencies.fs index b594cdc22a..b0752f0013 100644 --- a/src/QsCompiler/Core/Dependencies.fs +++ b/src/QsCompiler/Core/Dependencies.fs @@ -67,6 +67,7 @@ type BuiltIn = { TypeParameters = ImmutableArray.Empty } + // "weak dependencies" in other namespaces (e.g. things used for code actions) static member IndexRange = { diff --git a/src/QsCompiler/Core/ExpressionWalker.fs b/src/QsCompiler/Core/ExpressionWalker.fs index 32ab5194d4..ccaa4a85de 100644 --- a/src/QsCompiler/Core/ExpressionWalker.fs +++ b/src/QsCompiler/Core/ExpressionWalker.fs @@ -10,9 +10,6 @@ open Microsoft.Quantum.QsCompiler.SyntaxExtensions open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree -//type private ExpressionKind = QsExpressionKind -//type private ExpressionType = QsTypeKind - /// Convention: /// All methods starting with "on" implement the walk for an expression of a certain kind. diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj index 38ee33672f..6fbe8cc4cd 100644 --- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj +++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj @@ -109,15 +109,6 @@ PreserveNewest - - Never - - - Never - - - Never - From 934e79c93d64747d2de5d4170687e06bb1fe8542 Mon Sep 17 00:00:00 2001 From: bettinaheim <34236215+bettinaheim@users.noreply.github.com> Date: Fri, 15 Nov 2019 09:18:49 -0800 Subject: [PATCH 31/32] Update src/QsCompiler/Core/TreeWalker.fs --- src/QsCompiler/Core/TreeWalker.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/QsCompiler/Core/TreeWalker.fs b/src/QsCompiler/Core/TreeWalker.fs index fd2c6acc05..50e00053f5 100644 --- a/src/QsCompiler/Core/TreeWalker.fs +++ b/src/QsCompiler/Core/TreeWalker.fs @@ -9,7 +9,6 @@ open Microsoft.Quantum.QsCompiler.DataTypes open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree -// This are inherited here from TreeTransformation.fs; kept here as comments for documentation. //type QsArgumentTuple = QsTuple> From 7f4bfd62aced41fefdd82b3b9fb7b966690b61f6 Mon Sep 17 00:00:00 2001 From: bettinaheim <34236215+bettinaheim@users.noreply.github.com> Date: Fri, 15 Nov 2019 09:18:58 -0800 Subject: [PATCH 32/32] Update src/QsCompiler/Core/TreeWalker.fs --- src/QsCompiler/Core/TreeWalker.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/QsCompiler/Core/TreeWalker.fs b/src/QsCompiler/Core/TreeWalker.fs index 50e00053f5..cdd89b9c50 100644 --- a/src/QsCompiler/Core/TreeWalker.fs +++ b/src/QsCompiler/Core/TreeWalker.fs @@ -9,7 +9,6 @@ open Microsoft.Quantum.QsCompiler.DataTypes open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree -//type QsArgumentTuple = QsTuple> /// Convention: