diff --git a/.gitignore b/.gitignore index 77a2c5708e..db0688c2ef 100644 --- a/.gitignore +++ b/.gitignore @@ -342,7 +342,6 @@ ASALocalRun/ src/ProjectTemplates/Quantum.App1/Quantum.App1.csproj src/ProjectTemplates/Quantum.Library1/Quantum.Library1.csproj src/ProjectTemplates/Quantum.Test1/Quantum.Test1.csproj -src/QsCompiler/LanguageServer/TemporaryProject.cs src/QuantumSdk/DefaultItems/DefaultItems.props src/ProjectTemplates/Quantum.App1/.template.config/template.json src/ProjectTemplates/Quantum.Library1/.template.config/template.json @@ -366,3 +365,6 @@ src/ProjectTemplates/Quantum.Test1/.template.config/template.json src/QsCompiler/QirGeneration/QirGeneration.nuspec /examples/QIR/Development/qir/* /examples/QIR/Development/build + +# MSBuild logs +MSBuild_Logs/ diff --git a/QsCompiler.sln b/QsCompiler.sln index 6e4a63a022..f369337299 100644 --- a/QsCompiler.sln +++ b/QsCompiler.sln @@ -65,6 +65,14 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Tests.CSharpGeneration", "s EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeGeneration", "CodeGeneration", "{160AABCE-2317-4695-815C-D3B3F88BE780}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Formatter", "Formatter", "{755A6971-AD80-4519-A64E-0333B89C1E9D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Parser", "src\QsFmt\Parser\Parser.csproj", "{005C0AEB-829A-4DD2-9A5D-973A9E351AF5}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Formatter", "src\QsFmt\Formatter\Formatter.fsproj", "{4D1F507F-7382-4F5B-9923-58398A565D8B}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "App", "src\QsFmt\App\App.fsproj", "{AD350766-EE10-4DE3-A834-129D026487FB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -387,6 +395,42 @@ Global {23020BC1-8D69-40E1-A6BB-DB5D28247A7F}.Release|x64.Build.0 = Release|Any CPU {23020BC1-8D69-40E1-A6BB-DB5D28247A7F}.Release|x86.ActiveCfg = Release|Any CPU {23020BC1-8D69-40E1-A6BB-DB5D28247A7F}.Release|x86.Build.0 = Release|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Debug|x64.ActiveCfg = Debug|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Debug|x64.Build.0 = Debug|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Debug|x86.ActiveCfg = Debug|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Debug|x86.Build.0 = Debug|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Release|Any CPU.Build.0 = Release|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Release|x64.ActiveCfg = Release|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Release|x64.Build.0 = Release|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Release|x86.ActiveCfg = Release|Any CPU + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5}.Release|x86.Build.0 = Release|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Debug|x64.ActiveCfg = Debug|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Debug|x64.Build.0 = Debug|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Debug|x86.ActiveCfg = Debug|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Debug|x86.Build.0 = Debug|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Release|Any CPU.Build.0 = Release|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Release|x64.ActiveCfg = Release|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Release|x64.Build.0 = Release|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Release|x86.ActiveCfg = Release|Any CPU + {4D1F507F-7382-4F5B-9923-58398A565D8B}.Release|x86.Build.0 = Release|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Debug|x64.ActiveCfg = Debug|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Debug|x64.Build.0 = Debug|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Debug|x86.ActiveCfg = Debug|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Debug|x86.Build.0 = Debug|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Release|Any CPU.Build.0 = Release|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Release|x64.ActiveCfg = Release|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Release|x64.Build.0 = Release|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Release|x86.ActiveCfg = Release|Any CPU + {AD350766-EE10-4DE3-A834-129D026487FB}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -407,6 +451,9 @@ Global {2BCE252C-DCE8-48A6-B08C-E5DDD753506C} = {160AABCE-2317-4695-815C-D3B3F88BE780} {B08BB875-89AF-4194-AC13-D8FB8290B54E} = {B4A9484D-31FC-4A27-9E26-4C8DE3E02D77} {23020BC1-8D69-40E1-A6BB-DB5D28247A7F} = {B4A9484D-31FC-4A27-9E26-4C8DE3E02D77} + {005C0AEB-829A-4DD2-9A5D-973A9E351AF5} = {755A6971-AD80-4519-A64E-0333B89C1E9D} + {4D1F507F-7382-4F5B-9923-58398A565D8B} = {755A6971-AD80-4519-A64E-0333B89C1E9D} + {AD350766-EE10-4DE3-A834-129D026487FB} = {755A6971-AD80-4519-A64E-0333B89C1E9D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B921C36B-4574-4025-8FE3-E5BD2D3D2B81} diff --git a/QsFmt.sln b/QsFmt.sln index 345a97b8f8..12e4a7d425 100644 --- a/QsFmt.sln +++ b/QsFmt.sln @@ -9,14 +9,9 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Formatter", "src\QsFmt\Form EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "App", "src\QsFmt\App\App.fsproj", "{68F54AEE-C852-4FFA-831D-5BA741BE893E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4399BDF1-685A-4373-8748-142C835A52D6}" - ProjectSection(SolutionItems) = preProject - README.md = src\QsFmt\README.md - EndProjectSection +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Formatter.Tests", "src\QsFmt\Formatter.Tests\Formatter.Tests.fsproj", "{FC9E2BEC-F15F-4818-B0E1-805EA554269E}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Formatter.Tests", "src\QsFmt\Formatter.Tests\Formatter.Tests.fsproj", "{FC9E2BEC-F15F-4818-B0E1-805EA554269E}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "App.Tests", "src\QsFmt\App.Tests\App.Tests.fsproj", "{E00FA726-F852-4D14-90F8-1B0E3E08D822}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "App.Tests", "src\QsFmt\App.Tests\App.Tests.fsproj", "{E00FA726-F852-4D14-90F8-1B0E3E08D822}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/README.md b/README.md index ba43e8d56e..50e63c0e30 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ If you edit the [Microsoft.Quantum.Sdk](./src/QuantumSdk) as part of your change ``` dotnet publish src/QuantumSdk/Tools/Tools.sln -c Debug dotnet publish src/QsCompiler/CommandLineTool/CommandLineTool.csproj -c Debug +dotnet publish src/QsFmt/App/App.fsproj -c Debug nuget.exe pack src/QuantumSdk/QuantumSdk.nuspec -Version 1.0.0 -Properties Configuration=Debug ``` Move the created .nupkg file into your [local NuGet folder](https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds). You can now use the package to build any Q# project by opening the project file in a text editor, and editing the Sdk version number in the first line to be diff --git a/build/manifest.ps1 b/build/manifest.ps1 index 2e47fe5a27..58dbca40db 100644 --- a/build/manifest.ps1 +++ b/build/manifest.ps1 @@ -56,6 +56,7 @@ $artifacts = @{ ".\src\QsCompiler\LlvmBindings\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.LlvmBindings.dll", ".\src\QsCompiler\Transformations\bin\$Env:BUILD_CONFIGURATION\netstandard2.1\Microsoft.Quantum.QsTransformations.dll", ".\src\QsCompiler\CommandLineTool\bin\$Env:BUILD_CONFIGURATION\netcoreapp3.1\qsc.dll", + ".\src\QsFmt\App\bin\$Env:BUILD_CONFIGURATION\netcoreapp3.1\qsfmt.dll", ".\src\QuantumSdk\Tools\BuildConfiguration\bin\$Env:BUILD_CONFIGURATION\netcoreapp3.1\Microsoft.Quantum.Sdk.BuildConfiguration.dll", ".\src\QuantumSdk\Tools\DefaultEntryPoint\bin\$Env:BUILD_CONFIGURATION\netcoreapp3.1\Microsoft.Quantum.Sdk.DefaultEntryPoint.Generation.dll" ) | ForEach-Object { Join-Path $PSScriptRoot (Join-Path ".." $_) }; diff --git a/build/pack.ps1 b/build/pack.ps1 index 7d86455a05..76557d57b2 100644 --- a/build/pack.ps1 +++ b/build/pack.ps1 @@ -89,6 +89,7 @@ Publish-One '../src/QsCompiler/CommandLineTool/CommandLineTool.csproj' Publish-One '../src/QsCompiler/LlvmBindings/LlvmBindings.csproj' Publish-One '../src/QuantumSdk/Tools/BuildConfiguration/BuildConfiguration.csproj' Publish-One '../src/QuantumSdk/Tools/DefaultEntryPoint/DefaultEntryPoint.csproj' +Publish-One '../src/QsFmt/App/App.fsproj' Pack-One '../src/QsCompiler/Compiler/Compiler.csproj' '-IncludeReferencedProjects' Pack-One '../src/QsCompiler/QirGeneration/QirGeneration.csproj' diff --git a/src/QsCompiler/CompilationManager/CompilationUnit.cs b/src/QsCompiler/CompilationManager/CompilationUnit.cs index 701ee78ce8..6ac64fa192 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnit.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnit.cs @@ -315,18 +315,14 @@ public class CompilationUnit : IReaderWriterLock, IDisposable internal NamespaceManager GlobalSymbols { get; private set; } + internal ProjectProperties BuildProperties { get; } + private readonly Dictionary compiledCallables; private readonly Dictionary compiledTypes; private readonly ReaderWriterLockSlim syncRoot; private readonly HashSet dependentLocks; - internal RuntimeCapability RuntimeCapability { get; } - - internal bool IsExecutable { get; } - - internal string ProcessorArchitecture { get; } - /// public void Dispose() { @@ -338,9 +334,7 @@ public void Dispose() /// with registered as dependent locks if not null. /// internal CompilationUnit( - RuntimeCapability capability, - bool isExecutable, - string processorArchitecture, + ProjectProperties projectProperties, References? externals = null, IEnumerable? dependentLocks = null) { @@ -350,16 +344,19 @@ internal CompilationUnit( this.syncRoot = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); this.dependentLocks = new HashSet(dependentLocks); - this.RuntimeCapability = capability; - this.IsExecutable = isExecutable; - this.ProcessorArchitecture = processorArchitecture; - this.compiledCallables = new Dictionary(); this.compiledTypes = new Dictionary(); this.Externals = externals; + this.BuildProperties = projectProperties; this.GlobalSymbols = this.CreateGlobalSymbols(); } + /// + internal CompilationUnit(CompilationUnit compilationUnit, IEnumerable? dependentLocks = null) + : this(compilationUnit.BuildProperties, compilationUnit.Externals, dependentLocks ?? compilationUnit.dependentLocks) + { + } + /// /// Creates a new instance of the namespace manager for global symbols. /// @@ -369,8 +366,8 @@ internal CompilationUnit( this.Externals.Declarations.Values.SelectMany(h => h.Specializations.Select(t => Tuple.Create(t.Item1, t.Item2))), this.Externals.Declarations.Values.SelectMany(h => h.Types), - this.RuntimeCapability, - this.IsExecutable); + this.BuildProperties.RuntimeCapability, + this.BuildProperties.IsExecutable); /// /// Replaces to match . diff --git a/src/QsCompiler/CompilationManager/CompilationUnitManager.cs b/src/QsCompiler/CompilationManager/CompilationUnitManager.cs index e28b5c22ae..96d0f0f45b 100644 --- a/src/QsCompiler/CompilationManager/CompilationUnitManager.cs +++ b/src/QsCompiler/CompilationManager/CompilationUnitManager.cs @@ -6,10 +6,12 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Quantum.QsCompiler.CompilationBuilder.DataStructures; +using Microsoft.Quantum.QsCompiler.ReservedKeywords; using Microsoft.Quantum.QsCompiler.SyntaxProcessing; using Microsoft.Quantum.QsCompiler.SyntaxTokens; using Microsoft.Quantum.QsCompiler.SyntaxTree; @@ -50,6 +52,11 @@ public class CompilationUnitManager : IDisposable /// public Action PublishDiagnostics { get; } + /// + /// General purpose logging routine. + /// + public Action Log { get; } + /// /// Null if a global type checking has been queued but is not yet running. /// If not null, then a global type checking may be running and can be cancelled via this token source. @@ -73,23 +80,44 @@ public class CompilationUnitManager : IDisposable /// If provided, called whenever diagnostics within a file have changed and are ready for publishing. /// public CompilationUnitManager( + ProjectProperties buildProperties, Action? exceptionLogger = null, + Action? log = null, Action? publishDiagnostics = null, - bool syntaxCheckOnly = false, - RuntimeCapability? capability = null, - bool isExecutable = false, - string processorArchitecture = "Unspecified") + bool syntaxCheckOnly = false) { this.EnableVerification = !syntaxCheckOnly; - this.compilationUnit = new CompilationUnit(capability ?? RuntimeCapability.FullComputation, isExecutable, processorArchitecture); + this.compilationUnit = new CompilationUnit(buildProperties); this.fileContentManagers = new ConcurrentDictionary(); this.changedFiles = new ManagedHashSet(new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion)); this.PublishDiagnostics = publishDiagnostics ?? (_ => { }); + this.Log = log ?? ((_, __) => { }); this.LogException = exceptionLogger ?? Console.Error.WriteLine; this.Processing = new ProcessingQueue(this.LogException); this.waitForTypeCheck = new CancellationTokenSource(); } + [Obsolete("Use CompilationUnitManager(ProjectProperties, Action{Exception}?, Action{PublishDiagnosticParams}?, bool) instead.")] + public CompilationUnitManager( + Action? exceptionLogger = null, + Action? publishDiagnostics = null, + bool syntaxCheckOnly = false, + RuntimeCapability? capability = null, + bool isExecutable = false, + string? processorArchitecture = null) + : this( + new ProjectProperties(ImmutableDictionary.CreateRange(new[] + { + new KeyValuePair(MSBuildProperties.ResolvedRuntimeCapabilities, capability?.Name), + new KeyValuePair(MSBuildProperties.ResolvedProcessorArchitecture, processorArchitecture), + new KeyValuePair(MSBuildProperties.ResolvedQsharpOutputType, isExecutable ? AssemblyConstants.QsharpExe : AssemblyConstants.QsharpLibrary), + })), + exceptionLogger, + null, + publishDiagnostics) + { + } + /// /// Cancels any asynchronously running ongoing global type checking. After all currently queued tasks /// have finished, locks all processing, flushes the unprocessed changes in each source file, @@ -581,12 +609,7 @@ private Task SpawnGlobalTypeCheckingAsync(bool runSynchronously = false) // work with a separate compilation unit instance such that processing of all further edits can go on in parallel var sourceFiles = this.fileContentManagers.Values.OrderBy(m => m.FileName); this.changedFiles.RemoveAll(f => sourceFiles.Any(m => m.FileName == f)); - var compilation = new CompilationUnit( - this.compilationUnit.RuntimeCapability, - this.compilationUnit.IsExecutable, - this.compilationUnit.ProcessorArchitecture, - this.compilationUnit.Externals, - sourceFiles.Select(file => file.SyncRoot)); + var compilation = new CompilationUnit(this.compilationUnit, sourceFiles.Select(file => file.SyncRoot)); var content = compilation.UpdateGlobalSymbolsFor(sourceFiles); foreach (var file in sourceFiles) { @@ -781,6 +804,86 @@ private void TypeCheckFile(string fileId, CancellationToken cancellationToken) return success ? edit : null; } + /// + /// Returns the edits to format the file according to the specified settings. + /// + /// + /// Returns null if some parameters are unspecified (null), + /// or if the specified file is not listed as source file + /// + public TextEdit[]? Formatting(TextDocumentIdentifier? textDocument, bool format = true, bool update = true, int timeout = 3000) + { + var verb = + update && format ? "update-and-format" : + update ? "update" : + format ? "format" : + null; + + var qsFmtExe = this.compilationUnit.BuildProperties.QsFmtExe; + var sdkPath = this.compilationUnit.BuildProperties.SdkPath; + + var fmtCommand = qsFmtExe?.Split(); + (string command, string dllPath) = fmtCommand != null && fmtCommand.Length > 0 + ? (fmtCommand[0], string.Join(" ", fmtCommand[1..])) + : ("dotnet", Path.Combine(sdkPath ?? "", "tools", "qsfmt", "qsfmt.dll")); + + // It is possible for File.Exists/Directory.Exists to return false for both dllPath and sdkPath + // despite that the command can indeed be successfully executed. + if (verb == null) + { + return null; + } + + TextEdit[]? FormatFile(FileContentManager file) + { + var tempFile = Path.ChangeExtension(Path.GetTempFileName(), ".qs"); + var currentContent = file.GetFileContent(); + File.WriteAllText(tempFile, currentContent); + + // The exit code is selected looking at this: https://tldp.org/LDP/abs/html/exitcodes.html + // Code 130 usually indicates "Script terminated by Control-C", and seem appropriate in this case. + var exitCodeOnTimeout = 130; + var commandArgs = $"{dllPath} {verb} --input {tempFile}"; + this.Log($"Invoking {verb} command: {command} {commandArgs}", MessageType.Info); + var succeeded = + ProcessRunner.Run(command, commandArgs, out var _, out var errstream, out var exitCode, out var ex, timeout: timeout, exitCodeOnTimeOut: exitCodeOnTimeout) + && exitCode == 0 && ex == null; + + if (succeeded) + { + var range = DataTypes.Range.Create(DataTypes.Position.Zero, file.End()); + var edit = new TextEdit { Range = range.ToLsp(), NewText = File.ReadAllText(tempFile) }; + File.Delete(tempFile); + return new[] { edit }; + } + else if (exitCode == exitCodeOnTimeout) + { + this.Log($"{verb} command timed out.", MessageType.Info); + } + else if (ex != null) + { + if (qsFmtExe == null && this.compilationUnit.BuildProperties.SdkVersion > new Version(0, 21)) + { + this.LogException(ex); + } + } + else + { + this.Log($"Unknown error during {verb} (exit code {exitCode}): \n{errstream}", MessageType.Error); + } + + return null; + } + + var succeeded = this.Processing.QueueForExecution( + () => this.FileQuery( + textDocument, + (file, _) => FormatFile(file), + suppressExceptionLogging: false), // since the operation is blocking, no exceptions should occur + out var edits); + return succeeded ? edits : null; + } + // routines related to providing information for non-blocking editor commands // -> these commands need to be responsive and therefore won't wait for any processing to finish // -> if the query cannot be processed immediately, they simply return null diff --git a/src/QsCompiler/CompilationManager/EditorSupport/CodeActions.cs b/src/QsCompiler/CompilationManager/EditorSupport/CodeActions.cs index 06103e21a7..bd8ff29324 100644 --- a/src/QsCompiler/CompilationManager/EditorSupport/CodeActions.cs +++ b/src/QsCompiler/CompilationManager/EditorSupport/CodeActions.cs @@ -28,7 +28,7 @@ internal static class SuggestedEdits /// /// Returns for as a . /// - private static WorkspaceEdit GetWorkspaceEdit(this FileContentManager file, params TextEdit[] edits) + internal static WorkspaceEdit GetWorkspaceEdit(this FileContentManager file, params TextEdit[] edits) { var versionedFileId = new VersionedTextDocumentIdentifier { Uri = file.Uri, Version = file.Version ?? 1 }; return new WorkspaceEdit diff --git a/src/QsCompiler/CompilationManager/EditorSupport/EditorCommands.cs b/src/QsCompiler/CompilationManager/EditorSupport/EditorCommands.cs index 4ccbf2efae..6cb1ed114e 100644 --- a/src/QsCompiler/CompilationManager/EditorSupport/EditorCommands.cs +++ b/src/QsCompiler/CompilationManager/EditorSupport/EditorCommands.cs @@ -150,7 +150,7 @@ internal static class EditorCommands /// /// Returns null if any of the given arguments is null or if suitable edits cannot be determined. /// - public static ILookup? CodeActions(this FileContentManager file, CompilationUnit compilation, Range? range, CodeActionContext? context) + public static IEnumerable<(string, WorkspaceEdit)>? CodeActions(this FileContentManager file, CompilationUnit compilation, Range? range, CodeActionContext? context) { if (range?.Start is null || range.End is null || !file.ContainsRange(range)) { @@ -165,8 +165,7 @@ internal static class EditorCommands .Concat(file.IndexRangeSuggestions(compilation, range)) .Concat(file.UnreachableCodeSuggestions(diagnostics)) .Concat(file.DocCommentSuggestions(range)) - .Concat(file.BindingSuggestions(compilation, diagnostics)) - .ToLookup(s => s.Item1, s => s.Item2); + .Concat(file.BindingSuggestions(compilation, diagnostics)); } /// diff --git a/src/QsCompiler/CompilationManager/FileContentManager.cs b/src/QsCompiler/CompilationManager/FileContentManager.cs index fe925300dc..2cdd403d33 100644 --- a/src/QsCompiler/CompilationManager/FileContentManager.cs +++ b/src/QsCompiler/CompilationManager/FileContentManager.cs @@ -1147,13 +1147,29 @@ internal void ReplaceFileContent(string text) } } + /// + /// Forces the processing of all currently queued changes, and return the current file content. + /// + internal string GetFileContent() + { + this.SyncRoot.EnterUpgradeableReadLock(); + try + { + this.Flush(); + return string.Concat(this.content.Get().Select(line => line.Text)); + } + finally + { + this.SyncRoot.ExitUpgradeableReadLock(); + } + } + /// /// Forces the processing of all currently queued changes. /// /// /// Does *NOT* call with the update. /// - /// internal void Flush() { this.timer.Stop(); diff --git a/src/QsCompiler/Compiler/Process.cs b/src/QsCompiler/CompilationManager/Process.cs similarity index 65% rename from src/QsCompiler/Compiler/Process.cs rename to src/QsCompiler/CompilationManager/Process.cs index e79c679c2c..7606abc33a 100644 --- a/src/QsCompiler/Compiler/Process.cs +++ b/src/QsCompiler/CompilationManager/Process.cs @@ -18,59 +18,57 @@ public static class ProcessRunner /// public static bool Run(Process process, StringBuilder output, StringBuilder error, out Exception? ex, int timeout) { - using (var outputWaitHandle = new AutoResetEvent(false)) - using (var errorWaitHandle = new AutoResetEvent(false)) + using var outputWaitHandle = new AutoResetEvent(false); + using var errorWaitHandle = new AutoResetEvent(false); + void AddOutput(object sender, DataReceivedEventArgs e) { - void AddOutput(object sender, DataReceivedEventArgs e) + if (e.Data == null) { - if (e.Data == null) - { - outputWaitHandle.Set(); - } - else - { - output.AppendLine(e.Data); - } + outputWaitHandle.Set(); } - - void AddError(object sender, DataReceivedEventArgs e) + else { - if (e.Data == null) - { - errorWaitHandle.Set(); - } - else - { - error.AppendLine(e.Data); - } + output.AppendLine(e.Data); } + } - process.OutputDataReceived += AddOutput; - process.ErrorDataReceived += AddError; - - try - { - ex = null; - process.Start(); - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); - return process.WaitForExit(timeout) - && outputWaitHandle.WaitOne() - && errorWaitHandle.WaitOne(); - } - catch (Exception e) + void AddError(object sender, DataReceivedEventArgs e) + { + if (e.Data == null) { - ex = e; + errorWaitHandle.Set(); } - finally + else { - // unsubscribe such that the AutoResetEvents are not accessed after disposing - process.OutputDataReceived -= AddOutput; - process.ErrorDataReceived -= AddError; + error.AppendLine(e.Data); } + } + + process.OutputDataReceived += AddOutput; + process.ErrorDataReceived += AddError; - return ex == null; + try + { + ex = null; + process.Start(); + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + return process.WaitForExit(timeout) + && outputWaitHandle.WaitOne() + && errorWaitHandle.WaitOne(); + } + catch (Exception e) + { + ex = e; } + finally + { + // unsubscribe such that the AutoResetEvents are not accessed after disposing + process.OutputDataReceived -= AddOutput; + process.ErrorDataReceived -= AddError; + } + + return ex == null; } /// @@ -89,7 +87,8 @@ public static bool Run( out int exitCode, out Exception? ex, IDictionary? envVariables = null, - int timeout = 10000) + int timeout = 10000, + int exitCodeOnTimeOut = 1) { var process = new Process(); process.StartInfo = new ProcessStartInfo @@ -114,7 +113,7 @@ public static bool Run( try { var exited = Run(process, outstream, errstream, out ex, timeout); - exitCode = process.ExitCode; + exitCode = process.HasExited ? process.ExitCode : exitCodeOnTimeOut; return exited; } finally diff --git a/src/QsCompiler/CompilationManager/ProjectManager.cs b/src/QsCompiler/CompilationManager/ProjectManager.cs index f2b608c462..917f2c5dab 100644 --- a/src/QsCompiler/CompilationManager/ProjectManager.cs +++ b/src/QsCompiler/CompilationManager/ProjectManager.cs @@ -11,40 +11,109 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.Quantum.QsCompiler.Diagnostics; +using Microsoft.Quantum.QsCompiler.ReservedKeywords; using Microsoft.Quantum.QsCompiler.Transformations; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.Quantum.QsCompiler.CompilationBuilder { - internal class ProjectProperties + /// + /// Represents project properties defined in the project file. + /// + public class ProjectProperties { - public string Version { get; } + private static readonly Version DefaultAssemblyVersion = + Assembly.GetExecutingAssembly().GetName().Version; - public string OutputPath { get; } + /// + /// Returns the value specified by , + /// or the language version that corresponding to this compiler version if no valid value is specified. + /// + public Version LanguageVersion => + this.BuildProperties.TryGetValue(MSBuildProperties.QsharpLangVersion, out var versionProp) + && Version.TryParse(versionProp, out Version version) + ? version + : new Version(DefaultAssemblyVersion.Major, DefaultAssemblyVersion.Minor); - public RuntimeCapability RuntimeCapability { get; } + /// + /// Returns the value specified by , + /// or null if no valid value is specified. + /// + public Version? SdkVersion => + this.BuildProperties.TryGetValue(MSBuildProperties.QuantumSdkVersion, out var versionProp) + && Version.TryParse(versionProp, out Version version) + ? version + : null; - public bool IsExecutable { get; } + /// + /// Returns the value specified by , + /// or an empty string if no value is specified. + /// + public string SdkPath => + this.BuildProperties.TryGetValue(MSBuildProperties.QuantumSdkPath, out var path) + ? path ?? string.Empty + : string.Empty; - public string ProcessorArchitecture { get; } + /// + /// Returns the value specified by , + /// or an empty string if no value is specified. + /// + public string DllOutputPath => + this.BuildProperties.TryGetValue(MSBuildProperties.TargetPath, out var path) + ? path ?? string.Empty + : string.Empty; - public bool ExposeReferencesViaTestNames { get; } + /// + /// Returns the value specified by , + /// or if no valid value is specified. + /// + public RuntimeCapability RuntimeCapability => + this.BuildProperties.TryGetValue(MSBuildProperties.ResolvedRuntimeCapabilities, out var capability) + ? RuntimeCapability.TryParse(capability).ValueOr(RuntimeCapability.FullComputation) + : RuntimeCapability.FullComputation; - public ProjectProperties( - string version, - string outputPath, - RuntimeCapability runtimeCapability, - bool isExecutable, - string processorArchitecture, - bool loadTestNames) - { - this.Version = version ?? ""; - this.OutputPath = outputPath; - this.RuntimeCapability = runtimeCapability; - this.IsExecutable = isExecutable; - this.ProcessorArchitecture = processorArchitecture; - this.ExposeReferencesViaTestNames = loadTestNames; - } + /// + /// Returns the value specified by , + /// or an user friendly string indicating and unspecified processor architecture if no value is specified. + /// + public string ProcessorArchitecture => + this.BuildProperties.TryGetValue(MSBuildProperties.ResolvedProcessorArchitecture, out var architecture) + && !string.IsNullOrEmpty(architecture) + ? architecture + : "Unspecified"; + + /// + /// Returns true if the indicates that + /// the project is an executable project opposed to a library. + /// + public bool IsExecutable => + this.BuildProperties.TryGetValue(MSBuildProperties.ResolvedQsharpOutputType, out var outputType) + && AssemblyConstants.QsharpExe.Equals(outputType, StringComparison.OrdinalIgnoreCase); + + /// + /// Returns true if the indicates that + /// declarations should be loaded via a test name specified by an attribute. + /// + internal bool ExposeReferencesViaTestNames => + this.BuildProperties.TryGetValue(MSBuildProperties.ExposeReferencesViaTestNames, out var exposeViaTestNames) + && "true".Equals(exposeViaTestNames, StringComparison.OrdinalIgnoreCase); + + /// + /// Returns the value specified by , + /// or an empty string if no value is specified. + /// + internal string QsFmtExe => + this.BuildProperties.TryGetValue(MSBuildProperties.QsFmtExe, out var path) + ? path ?? string.Empty + : string.Empty; + + private ImmutableDictionary BuildProperties { get; } + + public static ProjectProperties Empty => + new ProjectProperties(ImmutableDictionary.Empty); + + public ProjectProperties(IDictionary buildProperties) => + this.BuildProperties = buildProperties.ToImmutableDictionary(); } public class ProjectInformation @@ -59,21 +128,29 @@ public class ProjectInformation public ImmutableArray References { get; } - internal static ProjectInformation Empty( - string version, - string outputPath, - RuntimeCapability capability) => + internal static ProjectInformation Empty(string outputPath) => new ProjectInformation( - version, - outputPath, - capability, - false, - "Unspecified", - false, Enumerable.Empty(), Enumerable.Empty(), - Enumerable.Empty()); + Enumerable.Empty(), + ImmutableDictionary.CreateRange(new[] + { + new KeyValuePair(MSBuildProperties.TargetPath, outputPath), + })); + + public ProjectInformation( + IEnumerable sourceFiles, + IEnumerable projectReferences, + IEnumerable references, + IDictionary buildProperties) + { + this.Properties = new ProjectProperties(buildProperties); + this.SourceFiles = sourceFiles.ToImmutableArray(); + this.ProjectReferences = projectReferences.ToImmutableArray(); + this.References = references.ToImmutableArray(); + } + [Obsolete] public ProjectInformation( string version, string outputPath, @@ -85,8 +162,15 @@ public ProjectInformation( IEnumerable projectReferences, IEnumerable references) { - this.Properties = new ProjectProperties( - version, outputPath, runtimeCapability, isExecutable, processorArchitecture, loadTestNames); + var buildProperties = ImmutableDictionary.CreateBuilder(); + buildProperties.Add(MSBuildProperties.QsharpLangVersion, version); + buildProperties.Add(MSBuildProperties.TargetPath, outputPath); + buildProperties.Add(MSBuildProperties.ResolvedRuntimeCapabilities, runtimeCapability.Name); + buildProperties.Add(MSBuildProperties.ResolvedQsharpOutputType, isExecutable ? AssemblyConstants.QsharpExe : AssemblyConstants.QsharpLibrary); + buildProperties.Add(MSBuildProperties.ResolvedProcessorArchitecture, processorArchitecture); + buildProperties.Add(MSBuildProperties.ExposeReferencesViaTestNames, loadTestNames ? "true" : "false"); + + this.Properties = new ProjectProperties(buildProperties); this.SourceFiles = sourceFiles.ToImmutableArray(); this.ProjectReferences = projectReferences.ToImmutableArray(); this.References = references.ToImmutableArray(); @@ -189,25 +273,19 @@ internal Project( this.Properties = projectInfo.Properties; this.SetProjectInformation(projectInfo); - var version = Version.TryParse(projectInfo.Properties.Version, out Version v) ? v : null; - if (projectInfo.Properties.Version.Equals("Latest", StringComparison.InvariantCultureIgnoreCase)) - { - version = new Version(0, 3); - } - - var ignore = version == null || version < new Version(0, 3) ? true : false; + var version = projectInfo.Properties.LanguageVersion; + var ignore = version == null || version < new Version(0, 3); // We track the file contents for unsupported projects in case the files are migrated to newer projects while editing, // but we don't do any semantic verification, and we don't publish diagnostics for them. this.processing = new ProcessingQueue(onException); + this.log = log ?? ((msg, severity) => Console.WriteLine($"{severity}: {msg}")); this.Manager = new CompilationUnitManager( + this.Properties, onException, + ignore ? null : this.log, ignore ? null : publishDiagnostics, - syntaxCheckOnly: ignore, - this.Properties.RuntimeCapability, - this.Properties.IsExecutable, - this.Properties.ProcessorArchitecture); - this.log = log ?? ((msg, severity) => Console.WriteLine($"{severity}: {msg}")); + syntaxCheckOnly: ignore); this.loadedSourceFiles = ImmutableHashSet.Empty; this.loadedReferences = References.Empty; @@ -226,7 +304,7 @@ private void SetProjectInformation(ProjectInformation projectInfo) this.Properties = projectInfo.Properties; this.isLoaded = false; - var outputPath = projectInfo.Properties.OutputPath; + var outputPath = projectInfo.Properties.DllOutputPath; try { outputPath = Path.GetFullPath(outputPath); @@ -730,7 +808,7 @@ public ProjectManager(Action? exceptionLogger, Action(); - this.defaultManager = new CompilationUnitManager(exceptionLogger, publishDiagnostics, syntaxCheckOnly: true); + this.defaultManager = new CompilationUnitManager(ProjectProperties.Empty, exceptionLogger, log, publishDiagnostics, syntaxCheckOnly: true); this.publishDiagnostics = publishDiagnostics; this.logException = exceptionLogger; this.log = log; @@ -814,7 +892,8 @@ private Action, Task> MigrateToDefaultManager(Func projectFiles, ProjectInformation.Loader projectLoader, - Func? openInEditor = null) + Func? openInEditor = null, + bool enableLazyLoading = true) { openInEditor ??= _ => null; @@ -840,7 +919,7 @@ public Task LoadProjectsAsync( continue; } - if (project.ContainsAnySourceFiles(uri => openInEditor(uri) != null)) + if (!enableLazyLoading || project.ContainsAnySourceFiles(uri => openInEditor(uri) != null)) { project.LoadProjectAsync(outputPaths, this.MigrateToProject(openInEditor), null); } @@ -873,9 +952,7 @@ public Task ProjectChangedOnDiskAsync( null, this.MigrateToDefaultManager(openInEditor), ProjectInformation.Empty( - "Latest", - existing.OutputPath?.LocalPath ?? throw new Exception("Missing output path."), - RuntimeCapability.FullComputation)) + existing.OutputPath?.LocalPath ?? throw new Exception("Missing output path."))) ?.Wait(); // does need to block, or the call to the DefaultManager in ManagerTaskAsync needs to be adapted if (existing != null) { @@ -1041,7 +1118,7 @@ public Task ManagerTaskAsync(Uri file, Action exec // TextDocumentEdit | CreateFile | RenameFile | DeleteFile. // Note that the SumType struct is defined in the LSP client, // and works by defining explicit cast operators for each case. - IEnumerable> CastToSumType(SumType[]>? editCollection) => + static IEnumerable> CastToSumType(SumType[]>? editCollection) => editCollection switch { { } edits => edits.Match( @@ -1068,6 +1145,26 @@ IEnumerable> CastT // -> these commands need to be responsive and therefore won't wait for any processing to finish // -> if the query cannot be processed immediately, they simply return null + /// + /// Returns the edits to format the file according to the specified settings. + /// + /// + /// Returns null if some parameters are unspecified (null), + /// or if the specified file is not listed as source file + /// + public TextEdit[]? Formatting(DocumentFormattingParams? param) + { + var manager = this.Manager(param?.TextDocument?.Uri); + var edits = manager?.Formatting(param?.TextDocument, format: true, update: true, timeout: 10000); // Formatting flushes unprocessed text changes + + if (manager != null && edits == null) + { + this.log?.Invoke("Failed to format document. Formatter may be unavailable.", MessageType.Info); + } + + return edits; + } + /// /// Returns the source file and position where the item at the given position is declared at, /// if such a declaration exists, and returns null otherwise. @@ -1169,9 +1266,43 @@ IEnumerable> CastT /// Fails silently without logging anything if an exception occurs upon evaluating the query /// (occasional failures are to be expected as the evaluation is a readonly query running in parallel to the ongoing processing). /// - public ILookup? CodeActions(CodeActionParams? param) => + public IEnumerable? CodeActions(CodeActionParams? param) => this.Manager(param?.TextDocument?.Uri)?.FileQuery( - param?.TextDocument, (file, c) => file.CodeActions(c, param?.Range?.ToQSharp(), param?.Context), suppressExceptionLogging: true); + param?.TextDocument, + (file, c) => + { + var codeActionSuggestions = file.CodeActions(c, param?.Range?.ToQSharp(), param?.Context); + var diagnostics = param?.Context?.Diagnostics; + if (diagnostics != null && diagnostics.Any(DiagnosticTools.WarningType( + WarningCode.DeprecatedTupleBrackets, + WarningCode.DeprecatedUnitType, + WarningCode.DeprecatedQubitBindingKeyword, + WarningCode.DeprecatedANDoperator, + WarningCode.DeprecatedNOToperator, + WarningCode.DeprecatedORoperator, + WarningCode.DeprecatedNewArray))) + { + var formattingEdits = this.Manager( + param?.TextDocument?.Uri)?.Formatting(param?.TextDocument, update: true, format: false, timeout: 2000); + if (formattingEdits != null) + { + codeActionSuggestions = codeActionSuggestions.Append( + ("Update deprecated syntax in file.", file.GetWorkspaceEdit(formattingEdits))); + } + } + + return codeActionSuggestions + .ToLookup(s => s.Item1, s => s.Item2) + .SelectMany(vs => vs.Select(v => CreateAction(vs.Key, v))); + + static CodeAction CreateAction(string title, WorkspaceEdit edit) => + new CodeAction + { + Title = title, + Edit = edit, + }; + }, + suppressExceptionLogging: true); /// /// Returns a list of suggested completion items for the given location. diff --git a/src/QsCompiler/CompilationManager/TypeChecking.cs b/src/QsCompiler/CompilationManager/TypeChecking.cs index 341c432c79..ff7705618b 100644 --- a/src/QsCompiler/CompilationManager/TypeChecking.cs +++ b/src/QsCompiler/CompilationManager/TypeChecking.cs @@ -1666,8 +1666,8 @@ QsSpecialization BuildSpecialization( var requiredFunctorSupport = RequiredFunctorSupport(kind, GetDirective).ToImmutableHashSet(); var context = ScopeContext.Create( compilation.GlobalSymbols, - compilation.RuntimeCapability, - compilation.ProcessorArchitecture, + compilation.BuildProperties.RuntimeCapability, + compilation.BuildProperties.ProcessorArchitecture, spec); implementation = BuildUserDefinedImplementation( root, spec.Source.AssemblyOrCodeFile, arg, requiredFunctorSupport, context, diagnostics); diff --git a/src/QsCompiler/Compiler/CompilationLoader.cs b/src/QsCompiler/Compiler/CompilationLoader.cs index ddf004104e..5debc43d65 100644 --- a/src/QsCompiler/Compiler/CompilationLoader.cs +++ b/src/QsCompiler/Compiler/CompilationLoader.cs @@ -529,14 +529,16 @@ public CompilationLoader(SourceLoader loadSources, ReferenceLoader loadReference PerformanceTracking.TaskStart(PerformanceTracking.Task.Build); this.compilationStatus.Validation = Status.Succeeded; var files = CompilationUnitManager.InitializeFileManagers(sourceFiles, null, this.OnCompilerException); // do *not* live track (i.e. use publishing) here! + var processorArchitecture = this.config.AssemblyConstants?.GetValueOrDefault(AssemblyConstants.ProcessorArchitecture); + var buildProperties = ImmutableDictionary.CreateBuilder(); + buildProperties.Add(MSBuildProperties.ResolvedRuntimeCapabilities, this.config.RuntimeCapability?.Name); + buildProperties.Add(MSBuildProperties.ResolvedQsharpOutputType, this.config.IsExecutable ? AssemblyConstants.QsharpExe : AssemblyConstants.QsharpLibrary); + buildProperties.Add(MSBuildProperties.ResolvedProcessorArchitecture, processorArchitecture); + var compilationManager = new CompilationUnitManager( - this.OnCompilerException, - capability: this.config.RuntimeCapability, - isExecutable: this.config.IsExecutable, - processorArchitecture: string.IsNullOrWhiteSpace(processorArchitecture) - ? "Unspecified" - : processorArchitecture); + new ProjectProperties(buildProperties), + this.OnCompilerException); compilationManager.UpdateReferencesAsync(references); compilationManager.AddOrUpdateSourceFilesAsync(files); this.VerifiedCompilation = compilationManager.Build(); diff --git a/src/QsCompiler/DataStructures/Diagnostics.fs b/src/QsCompiler/DataStructures/Diagnostics.fs index 50e77301e3..e4476b0977 100644 --- a/src/QsCompiler/DataStructures/Diagnostics.fs +++ b/src/QsCompiler/DataStructures/Diagnostics.fs @@ -369,6 +369,7 @@ type WarningCode = | [] UseOfUnderscorePattern = 3305 | DeprecatedTupleBrackets = 3306 | DeprecatedQubitBindingKeyword = 3307 + | DeprecatedNewArray = 3308 | DeprecatedRUSloopInFunction = 4001 | DiscardingItemInAssignment = 5001 @@ -954,6 +955,8 @@ type DiagnosticItem = | WarningCode.DeprecatedQubitBindingKeyword -> "The \"{0}\" keyword has been replaced with \"{1}\", and qubits may now be allocated without a block. " + "Consider \"{1} q = Qubit();\" or \"{1} q = Qubit() {{ ... }}\"." + | WarningCode.DeprecatedNewArray -> + "Deprecated syntax. Use [] to construct an empty array, or [x, size = n] to construct an array of x repeated n times." | WarningCode.DeprecatedRUSloopInFunction -> "The use of repeat-until-success-loops within functions may not be supported in the future. Please use a while-loop instead." diff --git a/src/QsCompiler/DataStructures/ReservedKeywords.fs b/src/QsCompiler/DataStructures/ReservedKeywords.fs index 53b7c7f2f4..5c2da35c21 100644 --- a/src/QsCompiler/DataStructures/ReservedKeywords.fs +++ b/src/QsCompiler/DataStructures/ReservedKeywords.fs @@ -238,9 +238,22 @@ module GeneratedAttributes = let Namespace = "Microsoft.Quantum.QsCompiler.Metadata.Attributes" let LoadedViaTestNameInsteadOf = "__LoadedViaTestNameInsteadOf__" -/// contains project specific settings specified during Q# compilation +/// contains project properties defined in the project file and used by MSBuild +module MSBuildProperties = + let QuantumSdkPath = "QuantumSdkPath" + let QsharpLangVersion = "QSharpLangVersion" + let QuantumSdkVersion = "QuantumSdkVersion" + let TargetPath = "TargetPath" + let ResolvedProcessorArchitecture = "ResolvedProcessorArchitecture" + let ResolvedRuntimeCapabilities = "ResolvedRuntimeCapabilities" + let ResolvedQsharpOutputType = "ResolvedQSharpOutputType" + let ExposeReferencesViaTestNames = "ExposeReferencesViaTestNames" + let QsFmtExe = "QsFmtExe" + let QscExe = "QscExe" + +/// contains project specific settings specified that can be accessed by rewrite steps during Q# compilation module AssemblyConstants = - let OutputPath = "OutputPath" + let OutputPath = "OutputPath" // defined by the CompilationLoader let AssemblyName = "AssemblyName" let QsharpOutputType = "QSharpOutputType" let QsharpExe = "QSharpExe" diff --git a/src/QsCompiler/DataStructures/RuntimeCapability.fs b/src/QsCompiler/DataStructures/RuntimeCapability.fs index 9661c411fc..9535b51abe 100644 --- a/src/QsCompiler/DataStructures/RuntimeCapability.fs +++ b/src/QsCompiler/DataStructures/RuntimeCapability.fs @@ -59,6 +59,12 @@ type RuntimeCapability = | "Unknown" -> Value FullComputation | _ -> Null + member this.Name = + match this with + | BasicQuantumFunctionality -> "BasicQuantumFunctionality" + | BasicMeasurementFeedback -> "BasicMeasurementFeedback" + | FullComputation -> "FullComputation" + // TODO: RELEASE 2021-04: Remove RuntimeCapabilitiesExtensions. [] [] diff --git a/src/QsCompiler/LanguageServer/EditorState.cs b/src/QsCompiler/LanguageServer/EditorState.cs index 450a5a880d..74023dee72 100644 --- a/src/QsCompiler/LanguageServer/EditorState.cs +++ b/src/QsCompiler/LanguageServer/EditorState.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -11,6 +12,7 @@ using Microsoft.Build.Execution; using Microsoft.Quantum.QsCompiler; using Microsoft.Quantum.QsCompiler.CompilationBuilder; +using Microsoft.Quantum.QsCompiler.ReservedKeywords; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.Quantum.QsLanguageServer @@ -28,7 +30,6 @@ internal class EditorState : IDisposable private readonly Action publish; private readonly Action, Dictionary> sendTelemetry; - private readonly Action? onTemporaryProjectLoaded; /// /// needed to determine if the reality of a source file that has changed on disk is indeed given by the content on disk, @@ -60,8 +61,7 @@ internal EditorState( Action? publishDiagnostics, Action, Dictionary>? sendTelemetry, Action? log, - Action? onException, - Action? onTemporaryProjectLoaded) + Action? onException) { this.ignoreEditorUpdatesForFiles = new ConcurrentDictionary(); this.sendTelemetry = sendTelemetry ?? ((eventName, properties, measurements) => { }); @@ -86,7 +86,6 @@ internal EditorState( this.projectLoader = projectLoader; this.projects = new ProjectManager(onException, log, this.publish); - this.onTemporaryProjectLoaded = onTemporaryProjectLoaded; } /// @@ -120,64 +119,41 @@ internal bool QsProjectLoader(Uri projectFile, [NotNullWhen(true)] out ProjectIn return false; } - var outputDir = projectInstance.GetPropertyValue("OutputPath"); - var targetFile = projectInstance.GetPropertyValue("TargetFileName"); - var outputPath = Path.Combine(projectInstance.Directory, outputDir, targetFile); - - var processorArchitecture = projectInstance.GetPropertyValue("ResolvedProcessorArchitecture"); - var resRuntimeCapability = projectInstance.GetPropertyValue("ResolvedRuntimeCapabilities"); - var runtimeCapability = RuntimeCapability.TryParse(resRuntimeCapability).ValueOr(RuntimeCapability.FullComputation); - + // project item groups var sourceFiles = GetItemsByType(projectInstance, "QSharpCompile"); - var csharpFiles = GetItemsByType(projectInstance, "Compile").Where(file => !file.EndsWith(".g.cs")); var projectReferences = GetItemsByType(projectInstance, "ProjectReference"); var references = GetItemsByType(projectInstance, "Reference"); - var version = projectInstance.GetPropertyValue("QSharpLangVersion"); - var isExecutable = "QSharpExe".Equals(projectInstance.GetPropertyValue("ResolvedQSharpOutputType"), StringComparison.OrdinalIgnoreCase); - var loadTestNames = "true".Equals(projectInstance.GetPropertyValue("ExposeReferencesViaTestNames"), StringComparison.OrdinalIgnoreCase); + // telemetry data var defaultSimulator = projectInstance.GetPropertyValue("DefaultSimulator")?.Trim(); - + var csharpFiles = GetItemsByType(projectInstance, "Compile").Where(file => !file.EndsWith(".g.cs")); var telemetryMeas = new Dictionary(); telemetryMeas["sources"] = sourceFiles.Count(); telemetryMeas["csharpfiles"] = csharpFiles.Count(); telemetryProps["defaultSimulator"] = defaultSimulator; this.sendTelemetry("project-load", telemetryProps, telemetryMeas); // does not send anything unless the corresponding flag is defined upon compilation - info = new ProjectInformation( - version, - outputPath, - runtimeCapability, - isExecutable, - string.IsNullOrWhiteSpace(processorArchitecture) ? "Unspecified" : processorArchitecture, - loadTestNames, - sourceFiles, - projectReferences, - references); - return true; - } - internal Uri QsTemporaryProjectLoader(Uri sourceFileUri, string? sdkVersion) - { - var sourceFolderPath = Path.GetDirectoryName(sourceFileUri.LocalPath) ?? ""; - var projectFileName = string.Join( - "_x2f_", // arbitrary string to help avoid collisions - sourceFolderPath - .Replace("_", "_x5f_") // arbitrary string to help avoid collisions - .Split(Path.GetInvalidFileNameChars())); - var projectFolderPath = Directory.CreateDirectory(Path.Combine( - Path.GetTempPath(), - "qsharp", - projectFileName)).FullName; - var projectFilePath = Path.Combine(projectFolderPath, $"generated.csproj"); - using (var outputFile = new StreamWriter(projectFilePath)) - { - outputFile.WriteLine( - TemporaryProject.GetFileContents( - compilationScope: Path.Combine(sourceFolderPath, "*.qs"), - sdkVersion: sdkVersion)); - } + // project properties + void AddProperty(IDictionary props, string property) => + props.Add(property, projectInstance.GetPropertyValue(property)); + + var buildProperties = ImmutableDictionary.CreateBuilder(); + AddProperty(buildProperties, MSBuildProperties.TargetPath); + AddProperty(buildProperties, MSBuildProperties.ResolvedProcessorArchitecture); + AddProperty(buildProperties, MSBuildProperties.QuantumSdkPath); + AddProperty(buildProperties, MSBuildProperties.QuantumSdkVersion); + AddProperty(buildProperties, MSBuildProperties.QsharpLangVersion); + AddProperty(buildProperties, MSBuildProperties.ResolvedRuntimeCapabilities); + AddProperty(buildProperties, MSBuildProperties.ResolvedQsharpOutputType); + AddProperty(buildProperties, MSBuildProperties.ExposeReferencesViaTestNames); + AddProperty(buildProperties, MSBuildProperties.QsFmtExe); - return new Uri(projectFilePath); + info = new ProjectInformation( + sourceFiles: sourceFiles, + projectReferences: projectReferences, + references: references, + buildProperties); + return true; } /// @@ -411,6 +387,15 @@ internal Task CloseFileAsync(TextDocumentIdentifier textDocument, Action ValidFileUri(param?.TextDocument?.Uri) && !this.IgnoreFile(param?.TextDocument?.Uri) ? this.projects.Rename(param, versionedChanges) : null; + /// + /// Returns the edits to format the file according to the specified settings. + /// Returns null if the specified uri is not a valid file uri, + /// or the given file is listed as to be ignored, + /// or if some parameters are unspecified (null). + /// + public TextEdit[]? Formatting(DocumentFormattingParams param) => + ValidFileUri(param?.TextDocument?.Uri) && !this.IgnoreFile(param?.TextDocument?.Uri) ? this.projects.Formatting(param) : null; + /// /// Returns the source file and position where the item at the given position is declared at, /// if such a declaration exists, and returns the given position and file otherwise. @@ -472,7 +457,7 @@ internal Task CloseFileAsync(TextDocumentIdentifier textDocument, Action - public ILookup? CodeActions(CodeActionParams param) => + public IEnumerable? CodeActions(CodeActionParams param) => ValidFileUri(param?.TextDocument?.Uri) && !this.IgnoreFile(param?.TextDocument?.Uri) ? this.projects.CodeActions(param) : null; /// diff --git a/src/QsCompiler/LanguageServer/LanguageServer.cs b/src/QsCompiler/LanguageServer/LanguageServer.cs index fd4d61edd7..f0e6ea5e9f 100644 --- a/src/QsCompiler/LanguageServer/LanguageServer.cs +++ b/src/QsCompiler/LanguageServer/LanguageServer.cs @@ -100,8 +100,7 @@ void ProcessFileEvents(IEnumerable e) => diagnostics => this.PublishDiagnosticsAsync(diagnostics), (name, props, meas) => this.SendTelemetryAsync(name, props, meas), this.LogToWindow, - this.OnInternalError, - this.OnTemporaryProjectLoaded); + this.OnInternalError); this.waitForInit.Set(); } @@ -214,9 +213,6 @@ internal void OnInternalError(Exception ex) } } - private void OnTemporaryProjectLoaded(Uri projectUri) => - this.fileWatcher.ListenAsync(Path.GetDirectoryName(projectUri.LocalPath), false, null, "*.csproj").Wait(); - /* jsonrpc methods for initialization and shut down */ private Task InitializeWorkspaceAsync(ImmutableDictionary> folders) @@ -292,6 +288,7 @@ public object Initialize(JToken arg) capabilities.WorkspaceSymbolProvider = false; capabilities.RenameProvider = true; capabilities.HoverProvider = true; + capabilities.DocumentFormattingProvider = true; capabilities.DocumentHighlightProvider = true; capabilities.SignatureHelpProvider.TriggerCharacters = new[] { "(", "," }; capabilities.ExecuteCommandProvider.Commands = new[] { CommandIds.ApplyEdit }; // do not declare internal capabilities @@ -421,6 +418,33 @@ public Task OnTextDocumentChangedAsync(JToken arg) } } + [JsonRpcMethod(Methods.TextDocumentFormattingName)] + public object OnFormatting(JToken arg) + { + if (this.waitForInit != null) + { + return ProtocolError.AwaitingInitialization; + } + + var param = Utils.TryJTokenAs(arg); + if (param == null) + { + throw new JsonSerializationException($"Expected parameters for {Methods.TextDocumentFormattingName}, but got null."); + } + + try + { + return + QsCompilerError.RaiseOnFailure( + () => this.editorState.Formatting(param) ?? Array.Empty(), + "Formatting threw an exception"); + } + catch + { + return Array.Empty(); + } + } + [JsonRpcMethod(Methods.TextDocumentDefinitionName)] public object OnTextDocumentDefinition(JToken arg) { @@ -660,15 +684,6 @@ public object OnTextDocumentSymbol(JToken arg) // list all symbols found in a gi [JsonRpcMethod(Methods.TextDocumentCodeActionName)] public object OnCodeAction(JToken arg) { - CodeAction CreateAction(string title, WorkspaceEdit edit) - { - return new CodeAction - { - Title = title, - Edit = edit, - }; - } - if (this.waitForInit != null) { return ProtocolError.AwaitingInitialization; @@ -685,9 +700,7 @@ CodeAction CreateAction(string title, WorkspaceEdit edit) { return QsCompilerError.RaiseOnFailure( - () => this.editorState.CodeActions(param) - ?.SelectMany(vs => vs.Select(v => CreateAction(vs.Key, v))) - ?? Enumerable.Empty(), + () => this.editorState.CodeActions(param) ?? Enumerable.Empty(), "CodeAction threw an exception") .ToArray(); } diff --git a/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template b/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template deleted file mode 100644 index 13d6aad7ec..0000000000 --- a/src/QsCompiler/LanguageServer/TemporaryProject.cs.v.template +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.QsLanguageServer -{ - internal static class TemporaryProject - { - internal static string GetFileContents(string compilationScope, string? sdkVersion = null) => $@" - - - netstandard2.1 - - - - - "; - } -} diff --git a/src/QsCompiler/TestProjects/TestProjects.sln b/src/QsCompiler/TestProjects/TestProjects.sln index a2e0503b96..64c34cffbd 100644 --- a/src/QsCompiler/TestProjects/TestProjects.sln +++ b/src/QsCompiler/TestProjects/TestProjects.sln @@ -29,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "test12", "test12\test12.csp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "test13", "test13\test13.csproj", "{3EDCBFE8-4EAD-4B2A-A899-10511A5721D3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "test15", "test15\test15.csproj", "{956FE0B5-CDBA-4865-BBCC-3AF72FC7C791}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -87,6 +89,10 @@ Global {3EDCBFE8-4EAD-4B2A-A899-10511A5721D3}.Debug|Any CPU.Build.0 = Debug|Any CPU {3EDCBFE8-4EAD-4B2A-A899-10511A5721D3}.Release|Any CPU.ActiveCfg = Release|Any CPU {3EDCBFE8-4EAD-4B2A-A899-10511A5721D3}.Release|Any CPU.Build.0 = Release|Any CPU + {956FE0B5-CDBA-4865-BBCC-3AF72FC7C791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {956FE0B5-CDBA-4865-BBCC-3AF72FC7C791}.Debug|Any CPU.Build.0 = Debug|Any CPU + {956FE0B5-CDBA-4865-BBCC-3AF72FC7C791}.Release|Any CPU.ActiveCfg = Release|Any CPU + {956FE0B5-CDBA-4865-BBCC-3AF72FC7C791}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/QsCompiler/TestProjects/test12/Operation12a.qs b/src/QsCompiler/TestProjects/test12/Operation12a.qs index 0ac71dec42..1999004ced 100644 --- a/src/QsCompiler/TestProjects/test12/Operation12a.qs +++ b/src/QsCompiler/TestProjects/test12/Operation12a.qs @@ -5,6 +5,6 @@ namespace test3 { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Intrinsic; - operation Operation3a () : Unit { + operation Operation12a () : () { } } diff --git a/src/QsCompiler/TestProjects/test12/Operation12b.qs b/src/QsCompiler/TestProjects/test12/Operation12b.qs index 2d434f82e3..c87cc79e38 100644 --- a/src/QsCompiler/TestProjects/test12/Operation12b.qs +++ b/src/QsCompiler/TestProjects/test12/Operation12b.qs @@ -5,6 +5,6 @@ namespace test3 { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Intrinsic; - operation Operation3b () : Unit { + operation Operation12b () : Unit { } } diff --git a/src/QsCompiler/TestProjects/test12/format/Formatted.qs b/src/QsCompiler/TestProjects/test12/format/Formatted.qs new file mode 100644 index 0000000000..f715c04ff9 --- /dev/null +++ b/src/QsCompiler/TestProjects/test12/format/Formatted.qs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests { + + operation Test() : Unit { + let arr = [0, size = 10]; + for i in 1 .. 10 { + } + } +} diff --git a/src/QsCompiler/TestProjects/test12/format/Unformatted.qs b/src/QsCompiler/TestProjects/test12/format/Unformatted.qs new file mode 100644 index 0000000000..f8cdd0a64c --- /dev/null +++ b/src/QsCompiler/TestProjects/test12/format/Unformatted.qs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests { + + operation Test() : () { + let arr = new Int[10]; + for (i in 1 .. 10) { + } + } +} diff --git a/src/QsCompiler/TestProjects/test12/test12.csproj b/src/QsCompiler/TestProjects/test12/test12.csproj index ab491aa32a..5253aff4c0 100644 --- a/src/QsCompiler/TestProjects/test12/test12.csproj +++ b/src/QsCompiler/TestProjects/test12/test12.csproj @@ -1,11 +1,11 @@ - + + netstandard2.1 - x64 - - + + diff --git a/src/QsCompiler/TestProjects/test15/README.md b/src/QsCompiler/TestProjects/test15/README.md new file mode 100644 index 0000000000..39362c17f4 --- /dev/null +++ b/src/QsCompiler/TestProjects/test15/README.md @@ -0,0 +1 @@ +This is a valid Q# app using the formatter source code. diff --git a/src/QsCompiler/TestProjects/test15/format/Formatted.qs b/src/QsCompiler/TestProjects/test15/format/Formatted.qs new file mode 100644 index 0000000000..006cfc4799 --- /dev/null +++ b/src/QsCompiler/TestProjects/test15/format/Formatted.qs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests { + + @EntryPoint() + operation Test() : Unit { + let arr = [0, size = 10]; + for i in 1 .. 10 { + } + } +} diff --git a/src/QsCompiler/TestProjects/test15/format/Unformatted.qs b/src/QsCompiler/TestProjects/test15/format/Unformatted.qs new file mode 100644 index 0000000000..7c8de6c5da --- /dev/null +++ b/src/QsCompiler/TestProjects/test15/format/Unformatted.qs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Tests { + + @EntryPoint() + operation Test() : () { + let arr = new Int[10]; + for (i in 1 .. 10) { + } + } +} diff --git a/src/QsCompiler/TestProjects/test15/test15.csproj b/src/QsCompiler/TestProjects/test15/test15.csproj new file mode 100644 index 0000000000..6ee168a3bb --- /dev/null +++ b/src/QsCompiler/TestProjects/test15/test15.csproj @@ -0,0 +1,16 @@ + + + + Exe + netcoreapp3.1 + + + + dotnet $(MSBuildProjectDirectory)/../../qsfmt/qsfmt.dll + + + + + + + diff --git a/src/QsCompiler/Tests.CSharpGeneration/SimulationCodeTests.fs b/src/QsCompiler/Tests.CSharpGeneration/SimulationCodeTests.fs index 0e2a5c9492..c6492816af 100644 --- a/src/QsCompiler/Tests.CSharpGeneration/SimulationCodeTests.fs +++ b/src/QsCompiler/Tests.CSharpGeneration/SimulationCodeTests.fs @@ -114,7 +114,14 @@ namespace N1 let file = CompilationUnitManager.InitializeFileManager(fileId, File.ReadAllText fileName) mgr.AddOrUpdateSourceFileAsync file |> ignore // TODO: catch compilation errors and fail - let mgr = new CompilationUnitManager(null, (fun ps -> ps.Diagnostics |> Array.iter addError)) + let mgr = + new CompilationUnitManager( + ProjectProperties.Empty, + (fun ex -> raise ex), + (fun msg _ -> printf "%s" msg), + (fun (ps: PublishDiagnosticParams) -> ps.Diagnostics |> Array.iter addError) + ) + files |> List.iter (addSourceFile mgr) try diff --git a/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs b/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs index 60d67d1cbf..bfa56e5677 100644 --- a/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs +++ b/src/QsCompiler/Tests.Compiler/AccessModifierTests.fs @@ -27,8 +27,12 @@ type AccessModifierTests() = [] member this.Types() = - this.Expect "TypeUseOK" [] - this.Expect "TypeReferenceInternalInaccessible" [ Error ErrorCode.InaccessibleType ] + this.Expect "TypeUseOK" (Warning WarningCode.DeprecatedNewArray |> List.replicate 3) + + this.Expect + "TypeReferenceInternalInaccessible" + [ Error ErrorCode.InaccessibleType; Warning WarningCode.DeprecatedNewArray ] + this.Expect "TypeConstructorReferenceInternalInaccessible" [ Error ErrorCode.InaccessibleCallable ] [] diff --git a/src/QsCompiler/Tests.Compiler/CallGraphTests.fs b/src/QsCompiler/Tests.Compiler/CallGraphTests.fs index fc1dbdecd5..8d9152276c 100644 --- a/src/QsCompiler/Tests.Compiler/CallGraphTests.fs +++ b/src/QsCompiler/Tests.Compiler/CallGraphTests.fs @@ -9,7 +9,6 @@ open System.IO open System.Linq open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.CompilationBuilder -open Microsoft.Quantum.QsCompiler.DataTypes open Microsoft.Quantum.QsCompiler.DependencyAnalysis open Microsoft.Quantum.QsCompiler.Diagnostics open Microsoft.Quantum.QsCompiler.ReservedKeywords @@ -21,16 +20,12 @@ open Xunit.Abstractions type CallGraphTests(output: ITestOutputHelper) = - let compilationManager = new CompilationUnitManager(new Action(fun ex -> failwith ex.Message)) + let compilationManager = new CompilationUnitManager(ProjectProperties.Empty, (fun ex -> failwith ex.Message)) let compilationManagerExe = - new CompilationUnitManager( - Action<_>(fun ex -> failwith ex.Message), - null, - false, - FullComputation, - isExecutable = true - ) + let props = ImmutableDictionary.CreateBuilder() + props.Add(MSBuildProperties.ResolvedQsharpOutputType, AssemblyConstants.QsharpExe) + new CompilationUnitManager(new ProjectProperties(props), (fun ex -> failwith ex.Message)) let getTempFile () = new Uri(Path.GetFullPath(Path.GetRandomFileName())) diff --git a/src/QsCompiler/Tests.Compiler/ClassicalControlTests.fs b/src/QsCompiler/Tests.Compiler/ClassicalControlTests.fs index ae943dfac6..4e52a75824 100644 --- a/src/QsCompiler/Tests.Compiler/ClassicalControlTests.fs +++ b/src/QsCompiler/Tests.Compiler/ClassicalControlTests.fs @@ -18,7 +18,7 @@ open Xunit type ClassicalControlTests() = - let compilationManager = new CompilationUnitManager(new Action(fun ex -> failwith ex.Message)) + let compilationManager = new CompilationUnitManager(ProjectProperties.Empty, (fun ex -> failwith ex.Message)) let getTempFile () = new Uri(Path.GetFullPath(Path.GetRandomFileName())) diff --git a/src/QsCompiler/Tests.Compiler/CompilationLoaderTests.fs b/src/QsCompiler/Tests.Compiler/CompilationLoaderTests.fs index c4daf53cb3..be72b66b70 100644 --- a/src/QsCompiler/Tests.Compiler/CompilationLoaderTests.fs +++ b/src/QsCompiler/Tests.Compiler/CompilationLoaderTests.fs @@ -36,7 +36,7 @@ type CompilationLoaderTests(output: ITestOutputHelper) = /// Compiles a snippet of Q# source code. /// let compileQSharp source = - use compilationManager = new CompilationUnitManager() + use compilationManager = new CompilationUnitManager(ProjectProperties.Empty) let fileManager uri content = CompilationUnitManager.InitializeFileManager(uri, content) diff --git a/src/QsCompiler/Tests.Compiler/GlobalVerificationTests.fs b/src/QsCompiler/Tests.Compiler/GlobalVerificationTests.fs index 585d659e1e..e1b57eab2a 100644 --- a/src/QsCompiler/Tests.Compiler/GlobalVerificationTests.fs +++ b/src/QsCompiler/Tests.Compiler/GlobalVerificationTests.fs @@ -35,12 +35,12 @@ type GlobalVerificationTests() = this.Expect "LocalNamespaceShortNames1" [] this.Expect "LocalNamespaceShortNames2" [] this.Expect "LocalNamespaceShortNames3" [ Error ErrorCode.UnknownType ] - this.Expect "LocalNamespaceShortNames4" [ Error ErrorCode.UnknownType ] + this.Expect "LocalNamespaceShortNames4" [ Error ErrorCode.UnknownType; Warning WarningCode.DeprecatedNewArray ] this.Expect "LocalNamespaceShortNames5" [ Error ErrorCode.UnknownIdentifier ] this.Expect "LocalNamespaceShortNames6" [ Error ErrorCode.TypeMismatch; Error ErrorCode.TypeMismatch ] this.Expect "LocalNamespaceShortNames7" [ Error ErrorCode.UnknownIdentifier ] this.Expect "LocalNamespaceShortNames8" [] - this.Expect "LocalNamespaceShortNames9" [] + this.Expect "LocalNamespaceShortNames9" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "LocalNamespaceShortNames10" [] this.Expect "LocalNamespaceShortNames11" [ Error ErrorCode.UnknownType; Error ErrorCode.UnknownIdentifier ] this.Expect "LocalNamespaceShortNames12" [ Error ErrorCode.UnknownIdentifier ] @@ -53,7 +53,7 @@ type GlobalVerificationTests() = this.Expect "LocalNamespaceShortNames19" [] this.Expect "LocalNamespaceShortNames20" [] this.Expect "LocalNamespaceShortNames21" [] - this.Expect "LocalNamespaceShortNames22" [] + this.Expect "LocalNamespaceShortNames22" (Warning WarningCode.DeprecatedNewArray |> List.replicate 2) this.Expect "LocalNamespaceShortNames23" [] this.Expect "LocalNamespaceShortNames24" [] @@ -533,7 +533,7 @@ type GlobalVerificationTests() = this.Expect "ValidAttributes1" [] this.Expect "ValidAttributes2" [] this.Expect "ValidAttributes3" [] - this.Expect "ValidAttributes4" [] + this.Expect "ValidAttributes4" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "ValidAttributes5" [] this.Expect "ValidAttributes6" [] this.Expect "ValidAttributes7" [] @@ -555,7 +555,14 @@ type GlobalVerificationTests() = this.Expect "InvalidAttributes5" [ Error ErrorCode.UnknownTypeInNamespace ] this.Expect "InvalidAttributes6" [ Error ErrorCode.AttributeArgumentTypeMismatch ] this.Expect "InvalidAttributes7" [ Error ErrorCode.InvalidAttributeArgument ] - this.Expect "InvalidAttributes8" [ Error ErrorCode.ArgumentOfUserDefinedTypeInAttribute ] + + this.Expect + "InvalidAttributes8" + [ + Error ErrorCode.ArgumentOfUserDefinedTypeInAttribute + Warning WarningCode.DeprecatedNewArray + ] + this.Expect "InvalidAttributes9" [ Error ErrorCode.MisplacedDeclarationAttribute ] this.Expect "InvalidAttributes10" [ Error ErrorCode.MisplacedDeclarationAttribute ] this.Expect "InvalidAttributes11" [ Error ErrorCode.MisplacedDeclarationAttribute ] diff --git a/src/QsCompiler/Tests.Compiler/LinkingTests.fs b/src/QsCompiler/Tests.Compiler/LinkingTests.fs index 81b4c0048c..b77bbc9082 100644 --- a/src/QsCompiler/Tests.Compiler/LinkingTests.fs +++ b/src/QsCompiler/Tests.Compiler/LinkingTests.fs @@ -7,6 +7,7 @@ open Microsoft.Quantum.QsCompiler open Microsoft.Quantum.QsCompiler.CompilationBuilder open Microsoft.Quantum.QsCompiler.DataTypes open Microsoft.Quantum.QsCompiler.Diagnostics +open Microsoft.Quantum.QsCompiler.ReservedKeywords open Microsoft.Quantum.QsCompiler.SyntaxExtensions open Microsoft.Quantum.QsCompiler.SyntaxTokens open Microsoft.Quantum.QsCompiler.SyntaxTree @@ -27,7 +28,9 @@ type LinkingTests() = inherit CompilerTests(LinkingTests.Compile()) let compilationManager = - new CompilationUnitManager(new Action(fun ex -> failwith ex.Message), isExecutable = true) + let props = ImmutableDictionary.CreateBuilder() + props.Add(MSBuildProperties.ResolvedQsharpOutputType, AssemblyConstants.QsharpExe) + new CompilationUnitManager(new ProjectProperties(props), (fun ex -> failwith ex.Message)) // The file name needs to end in ".qs" so that it isn't ignored by the References.Headers class during the internal renaming tests. let getTempFile () = @@ -118,7 +121,7 @@ type LinkingTests() = compilation member private this.BuildReference(source: string, content) = - let comp = this.BuildContent(new CompilationUnitManager(), content) + let comp = this.BuildContent(new CompilationUnitManager(ProjectProperties.Empty), content) Assert.Empty(comp.Diagnostics() |> Seq.filter (fun d -> d.Severity = Nullable DiagnosticSeverity.Error)) struct (source, comp.BuiltCompilation.Namespaces) @@ -171,7 +174,7 @@ type LinkingTests() = /// been renamed across the compilation unit. member private this.RunInternalRenamingTest num renamed notRenamed = let chunks = LinkingTests.ReadAndChunkSourceFile "InternalRenaming.qs" - let manager = new CompilationUnitManager() + let manager = new CompilationUnitManager(ProjectProperties.Empty) let addOrUpdateSourceFile filePath = getManager (new Uri(filePath)) (File.ReadAllText filePath) @@ -465,12 +468,12 @@ type LinkingTests() = let tests = LinkingTests.ReadAndChunkSourceFile "EntryPointDiagnostics.qs" + let props = ImmutableDictionary.CreateBuilder() + props.Add(MSBuildProperties.ResolvedQsharpOutputType, AssemblyConstants.QsharpExe) + props.Add(MSBuildProperties.ResolvedRuntimeCapabilities, BasicQuantumFunctionality.Name) + let compilationManager = - new CompilationUnitManager( - Action<_>(fun ex -> failwith ex.Message), - isExecutable = true, - capability = BasicQuantumFunctionality - ) + new CompilationUnitManager(new ProjectProperties(props), Action<_>(fun (ex: exn) -> failwith ex.Message)) let addOrUpdateSourceFile filePath = getManager (new Uri(filePath)) (File.ReadAllText filePath) @@ -612,7 +615,7 @@ type LinkingTests() = [] member this.``Group internal specializations by source file``() = let chunks = LinkingTests.ReadAndChunkSourceFile "InternalRenaming.qs" - let manager = new CompilationUnitManager() + let manager = new CompilationUnitManager(ProjectProperties.Empty) let sourceCompilation = this.BuildContent(manager, chunks.[7]) diff --git a/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs b/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs index 58a0245e11..a3d0273f10 100644 --- a/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs +++ b/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs @@ -47,25 +47,25 @@ type LocalVerificationTests() = this.Expect "TypeArgumentsInference6" [] this.Expect "TypeArgumentsInference7" [] - this.Expect "TypeArgumentsInference8" [] - this.Expect "TypeArgumentsInference9" [] + this.Expect "TypeArgumentsInference8" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "TypeArgumentsInference9" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "TypeArgumentsInference10" [] this.Expect "TypeArgumentsInference11" [] this.Expect "TypeArgumentsInference12" [] this.Expect "TypeArgumentsInference13" [] this.Expect "TypeArgumentsInference14" [] this.Expect "TypeArgumentsInference15" [] - this.Expect "TypeArgumentsInference16" [] - this.Expect "TypeArgumentsInference17" [] - this.Expect "TypeArgumentsInference18" [] + this.Expect "TypeArgumentsInference16" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "TypeArgumentsInference17" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "TypeArgumentsInference18" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "TypeArgumentsInference19" [] this.Expect "TypeArgumentsInference20" [] this.Expect "TypeArgumentsInference21" [ Error ErrorCode.TypeMismatch ] this.Expect "TypeArgumentsInference22" [ Error ErrorCode.TypeMismatch ] this.Expect "TypeArgumentsInference23" [] this.Expect "TypeArgumentsInference24" [] - this.Expect "TypeArgumentsInference25" [] - this.Expect "TypeArgumentsInference26" [] + this.Expect "TypeArgumentsInference25" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "TypeArgumentsInference26" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "TypeArgumentsInference27" [ Error ErrorCode.TypeMismatch ] this.Expect "TypeArgumentsInference28" [ Error ErrorCode.TypeMismatch ] this.Expect "TypeArgumentsInference29" [ Error ErrorCode.InvalidCyclicTypeParameterResolution ] @@ -88,8 +88,8 @@ type LocalVerificationTests() = this.Expect "TypeArgumentsInference33" [ Error ErrorCode.TypeMismatch ] this.Expect "TypeArgumentsInference34" [] this.Expect "TypeArgumentsInference35" [] - this.Expect "TypeArgumentsInference36" [] - this.Expect "TypeArgumentsInference37" [] + this.Expect "TypeArgumentsInference36" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "TypeArgumentsInference37" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "TypeArgumentsInference38" [ Error ErrorCode.TypeMismatch ] this.Expect "TypeArgumentsInference39" [ Error ErrorCode.TypeMismatch ] this.Expect "TypeArgumentsInference40" [] @@ -134,10 +134,10 @@ type LocalVerificationTests() = this.Expect "VariableDeclaration15" [] this.Expect "VariableDeclaration16" [] - this.Expect "VariableDeclaration17" [] - this.Expect "VariableDeclaration18" [] - this.Expect "VariableDeclaration19" [] - this.Expect "VariableDeclaration20" [] + this.Expect "VariableDeclaration17" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "VariableDeclaration18" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "VariableDeclaration19" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "VariableDeclaration20" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "VariableDeclaration21" [] this.Expect "VariableDeclaration22" [] this.Expect "VariableDeclaration23" [] @@ -157,7 +157,7 @@ type LocalVerificationTests() = this.Expect "CopyAndUpdateArray1" [] this.Expect "CopyAndUpdateArray2" [] this.Expect "CopyAndUpdateArray3" [] - this.Expect "CopyAndUpdateArray4" [] + this.Expect "CopyAndUpdateArray4" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "CopyAndUpdateArray5" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] this.Expect "CopyAndUpdateArray6" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] this.Expect "CopyAndUpdateArray7" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] @@ -179,11 +179,23 @@ type LocalVerificationTests() = this.Expect "UpdateAndReassign3" [] this.Expect "UpdateAndReassign4" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] this.Expect "UpdateAndReassign5" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] - this.Expect "UpdateAndReassign6" [] - this.Expect "UpdateAndReassign7" [] - this.Expect "UpdateAndReassign8" [] - this.Expect "UpdateAndReassign9" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] - this.Expect "UpdateAndReassign10" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] + this.Expect "UpdateAndReassign6" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "UpdateAndReassign7" [ Warning WarningCode.DeprecatedNewArray ] + this.Expect "UpdateAndReassign8" [ Warning WarningCode.DeprecatedNewArray ] + + this.Expect + "UpdateAndReassign9" + [ + Error ErrorCode.TypeMismatchInCopyAndUpdateExpr + Warning WarningCode.DeprecatedNewArray + ] + + this.Expect + "UpdateAndReassign10" + [ + Error ErrorCode.TypeMismatchInCopyAndUpdateExpr + Warning WarningCode.DeprecatedNewArray + ] [] @@ -234,7 +246,7 @@ type LocalVerificationTests() = this.Expect "ItemAccess16" [] this.Expect "ItemAccess17" [] this.Expect "ItemAccess18" [] - this.Expect "ItemAccess19" [] + this.Expect "ItemAccess19" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "ItemAccess20" [] @@ -255,22 +267,29 @@ type LocalVerificationTests() = Error ErrorCode.TypeMismatchInCopyAndUpdateExpr ] - this.Expect "ItemUpdate9" [] + this.Expect "ItemUpdate9" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "ItemUpdate10" [ Error ErrorCode.InvalidIdentifierExprInUpdate Error ErrorCode.ExcessContinuation + Warning WarningCode.DeprecatedNewArray ] - this.Expect "ItemUpdate11" [ Error ErrorCode.UpdateOfArrayItemExpr ] + this.Expect + "ItemUpdate11" + [ + Error ErrorCode.UpdateOfArrayItemExpr + Warning WarningCode.DeprecatedNewArray + ] this.Expect "ItemUpdate12" [ Error ErrorCode.TypeMismatchInCopyAndUpdateExpr Error ErrorCode.TypeMismatchInCopyAndUpdateExpr + Warning WarningCode.DeprecatedNewArray ] this.Expect "ItemUpdate13" [] @@ -294,7 +313,7 @@ type LocalVerificationTests() = this.Expect "ItemUpdate18" [ Error ErrorCode.MissingFunctorForAutoGeneration ] this.Expect "ItemUpdate19" [ Error ErrorCode.MissingFunctorForAutoGeneration ] this.Expect "ItemUpdate20" [] - this.Expect "ItemUpdate21" [] + this.Expect "ItemUpdate21" [ Warning WarningCode.DeprecatedNewArray ] this.Expect "ItemUpdate22" [] @@ -374,7 +393,13 @@ type LocalVerificationTests() = this.Expect "UsingDepAttrInDepCall" [ Warning WarningCode.DeprecationWithoutRedirect ] this.Expect "UsingDepTypeInDepCall" [ Warning WarningCode.DeprecationWithoutRedirect ] - this.Expect "UsingDeprecatedType1" [ Warning WarningCode.DeprecationWithoutRedirect ] + this.Expect + "UsingDeprecatedType1" + [ + Warning WarningCode.DeprecationWithoutRedirect + Warning WarningCode.DeprecatedNewArray + ] + this.Expect "UsingDeprecatedType2" [ Warning WarningCode.DeprecationWithoutRedirect ] this.Expect "UsingDeprecatedType3" [ Warning WarningCode.DeprecationWithoutRedirect ] @@ -392,7 +417,13 @@ type LocalVerificationTests() = Warning WarningCode.DeprecationWithoutRedirect ] - this.Expect "UsingRenamedType1" [ Warning WarningCode.DeprecationWithRedirect ] + this.Expect + "UsingRenamedType1" + [ + Warning WarningCode.DeprecationWithRedirect + Warning WarningCode.DeprecatedNewArray + ] + this.Expect "UsingRenamedType2" [ Warning WarningCode.DeprecationWithRedirect ] this.Expect "UsingRenamedType3" [ Warning WarningCode.DeprecationWithRedirect ] diff --git a/src/QsCompiler/Tests.Compiler/OptimizationTests.fs b/src/QsCompiler/Tests.Compiler/OptimizationTests.fs index 88f20c6b1e..20c9aa7296 100644 --- a/src/QsCompiler/Tests.Compiler/OptimizationTests.fs +++ b/src/QsCompiler/Tests.Compiler/OptimizationTests.fs @@ -15,7 +15,7 @@ open Xunit /// Given a string of valid Q# code, outputs the AST and the callables dictionary let private buildCompilation code = let fileId = new Uri(Path.GetFullPath "test-file.qs") - let compilationUnit = new CompilationUnitManager(fun ex -> failwith ex.Message) + let compilationUnit = new CompilationUnitManager(ProjectProperties.Empty, (fun ex -> failwith ex.Message)) let file = CompilationUnitManager.InitializeFileManager(fileId, code) // spawns a task that modifies the current compilation compilationUnit.AddOrUpdateSourceFileAsync file |> ignore diff --git a/src/QsCompiler/Tests.Compiler/SyntaxTests.fs b/src/QsCompiler/Tests.Compiler/SyntaxTests.fs index 4c5b8ffb63..816440e452 100644 --- a/src/QsCompiler/Tests.Compiler/SyntaxTests.fs +++ b/src/QsCompiler/Tests.Compiler/SyntaxTests.fs @@ -889,12 +889,16 @@ let ``Function type tests`` () = "new (Int -> Int)[0]", true, toNewArray (toTupleType [ Function(toType Int, toType Int) |> toType ]) (toInt 0), - [] + [ Warning WarningCode.DeprecatedNewArray ] "new Int -> Int[0]", true, toNewArray (Function(toType Int, toType Int) |> toType) (toInt 0), - [ Error ErrorCode.MissingLTupleBracket; Error ErrorCode.MissingRTupleBracket ] + [ + Error ErrorCode.MissingLTupleBracket + Error ErrorCode.MissingRTupleBracket + Warning WarningCode.DeprecatedNewArray + ] ] |> List.iter testExpr @@ -986,45 +990,86 @@ let ``Operation type tests`` () = "new (Qubit => Unit is Adj)[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType adjSet ]) (toInt 0), - [] + [ Warning WarningCode.DeprecatedNewArray ] "new Qubit => Unit is Adj[0]", true, toNewArray (toOpType qubitType unitType adjSet) (toInt 0), - [ Error ErrorCode.MissingLTupleBracket; Error ErrorCode.MissingRTupleBracket ] + [ + Error ErrorCode.MissingLTupleBracket + Error ErrorCode.MissingRTupleBracket + Warning WarningCode.DeprecatedNewArray + ] - "new (Qubit => Unit) is Adj[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] + "new (Qubit => Unit) is Adj[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit : Adjoint)[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType emptySet ]) (toInt 0), - [ Error ErrorCode.ExcessContinuation ] + [ Error ErrorCode.ExcessContinuation; Warning WarningCode.DeprecatedNewArray ] - "new Qubit => Unit : Adjoint[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] - "new (Qubit => Unit) : Adjoint[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] + "new Qubit => Unit : Adjoint[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] + "new (Qubit => Unit) : Adjoint[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit : Adj)[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType emptySet ]) (toInt 0), - [ Error ErrorCode.ExcessContinuation ] + [ Error ErrorCode.ExcessContinuation; Warning WarningCode.DeprecatedNewArray ] - "new Qubit => Unit : Adj[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] - "new (Qubit => Unit) : Adj[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] + "new Qubit => Unit : Adj[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] + "new (Qubit => Unit) : Adj[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit is Adj + Ctl)[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType adjCtlSet ]) (toInt 0), - [] + [ Warning WarningCode.DeprecatedNewArray ] "new Qubit => Unit is Adj + Ctl[0]", true, toNewArray (toOpType qubitType unitType adjCtlSet) (toInt 0), - [ Error ErrorCode.MissingLTupleBracket; Error ErrorCode.MissingRTupleBracket ] + [ + Error ErrorCode.MissingLTupleBracket + Error ErrorCode.MissingRTupleBracket + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit) is Adj + Ctl[0]", true, toExpr InvalidExpr, - [ Error ErrorCode.InvalidConstructorExpression ] + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit : Adjoint, Controlled)[0]", true, @@ -1032,25 +1077,47 @@ let ``Operation type tests`` () = (toTupleType [ toOpType qubitType unitType emptySet toType InvalidType ]) (toInt 0), - [ Error ErrorCode.ExcessContinuation; Error ErrorCode.InvalidType ] + [ + Error ErrorCode.ExcessContinuation + Error ErrorCode.InvalidType + Warning WarningCode.DeprecatedNewArray + ] "new Qubit => Unit : Adjoint, Controlled[0]", true, toExpr InvalidExpr, - [ Error ErrorCode.InvalidConstructorExpression ] + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit) : Adjoint, Controlled[0]", true, toExpr InvalidExpr, - [ Error ErrorCode.InvalidConstructorExpression ] + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit : Adj + Ctl)[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType emptySet ]) (toInt 0), - [ Error ErrorCode.ExcessContinuation ] + [ Error ErrorCode.ExcessContinuation; Warning WarningCode.DeprecatedNewArray ] - "new Qubit => Unit : Adj + Ctl[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] - "new (Qubit => Unit) : Adj + Ctl[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] + "new Qubit => Unit : Adj + Ctl[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] + "new (Qubit => Unit) : Adj + Ctl[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit : Adj, Ctl)[0]", true, @@ -1058,10 +1125,26 @@ let ``Operation type tests`` () = (toTupleType [ toOpType qubitType unitType emptySet toType InvalidType ]) (toInt 0), - [ Error ErrorCode.ExcessContinuation; Error ErrorCode.InvalidType ] + [ + Error ErrorCode.ExcessContinuation + Error ErrorCode.InvalidType + Warning WarningCode.DeprecatedNewArray + ] - "new Qubit => Unit : Adj, Ctl[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] - "new (Qubit => Unit) : Adj, Ctl[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] + "new Qubit => Unit : Adj, Ctl[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] + "new (Qubit => Unit) : Adj, Ctl[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit is Adj, Ctl)[0]", true, @@ -1069,50 +1152,68 @@ let ``Operation type tests`` () = (toTupleType [ toOpType qubitType unitType adjSet toType InvalidType ]) (toInt 0), - [ Error ErrorCode.InvalidType ] + [ Error ErrorCode.InvalidType; Warning WarningCode.DeprecatedNewArray ] - "new Qubit => Unit is Adj, Ctl[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] - "new (Qubit => Unit) is Adj, Ctl[0]", true, toExpr InvalidExpr, [ Error ErrorCode.InvalidConstructorExpression ] + "new Qubit => Unit is Adj, Ctl[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] + "new (Qubit => Unit) is Adj, Ctl[0]", + true, + toExpr InvalidExpr, + [ + Error ErrorCode.InvalidConstructorExpression + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit is (Adj + Ctl))[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType adjCtlSet ]) (toInt 0), - [] + [ Warning WarningCode.DeprecatedNewArray ] "new (Qubit => Unit is ((Adj) + (Ctl)))[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType adjCtlSet ]) (toInt 0), - [] + [ Warning WarningCode.DeprecatedNewArray ] "new (Qubit => Unit is (Adj + Ctl _))[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType adjCtlSet ]) (toInt 0), - [ Error ErrorCode.ExcessContinuation ] + [ Error ErrorCode.ExcessContinuation; Warning WarningCode.DeprecatedNewArray ] "new (Qubit => Unit is ())[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType (toCharacteristicsExpr InvalidSetExpr) ]) (toInt 0), - [ Error ErrorCode.MissingOperationCharacteristics ] + [ + Error ErrorCode.MissingOperationCharacteristics + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit is (Adj + (Ctl + )))[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType (toCharacteristicsExpr InvalidSetExpr) ]) (toInt 0), - [ Error ErrorCode.InvalidOperationCharacteristics ] + [ + Error ErrorCode.InvalidOperationCharacteristics + Warning WarningCode.DeprecatedNewArray + ] "new (Qubit => Unit is MySet)[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType (toCharacteristicsExpr InvalidSetExpr) ]) (toInt 0), - [ Error ErrorCode.UnknownSetName ] + [ Error ErrorCode.UnknownSetName; Warning WarningCode.DeprecatedNewArray ] "new (Qubit => Unit is Adj + MySet)[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType (toCharacteristicsExpr InvalidSetExpr) ]) (toInt 0), - [ Error ErrorCode.UnknownSetName ] + [ Error ErrorCode.UnknownSetName; Warning WarningCode.DeprecatedNewArray ] "new (Qubit => Unit is (Adj + MySet))[0]", true, toNewArray (toTupleType [ toOpType qubitType unitType (toCharacteristicsExpr InvalidSetExpr) ]) (toInt 0), - [ Error ErrorCode.UnknownSetName ] + [ Error ErrorCode.UnknownSetName; Warning WarningCode.DeprecatedNewArray ] ] |> List.iter testExpr diff --git a/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/LoggingBasedTests.qs b/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/LoggingBasedTests.qs index d07ed13cb6..8404ec6fc9 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/LoggingBasedTests.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/LoggingBasedTests.qs @@ -25,7 +25,7 @@ namespace Microsoft.Quantum.Testing.ExecutionTests { // tests related to auto-generation of functor specializations for operations involving conjugations - operation SpecGenForConjugations () : Unit + operation SpecGenForConjugations () : Unit is Adj + Ctl { within { @@ -64,11 +64,11 @@ namespace Microsoft.Quantum.Testing.ExecutionTests { } operation ConjugationsInControlled () : Unit { - Controlled SpecGenForConjugations(new Qubit[0], ()); + Controlled SpecGenForConjugations([], ()); } operation ConjugationsInControlledAdjoint () : Unit { - Controlled Adjoint SpecGenForConjugations(new Qubit[0], ()); + Controlled Adjoint SpecGenForConjugations([], ()); } diff --git a/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/Packaging.qs b/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/Packaging.qs index f7c979ad95..6451b1673a 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/Packaging.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/ExecutionTests/Packaging.qs @@ -1,20 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -namespace Microsoft.Quantum.Testing.ExecutionTests -{ +namespace Microsoft.Quantum.Testing.ExecutionTests { open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Testing; - operation PackageAndProjectReference () : Unit { Message("Welcome to Q#!"); Log(1, "Go check out https://docs.microsoft.com/azure/quantum."); } operation TypeInReferencedProject () : Unit { - mutable arr = new Complex[1]; - set arr w/= 0 <- Complex(1.,0.); + let arr = [Complex(1., 0.)]; Message($"{arr}"); } } diff --git a/src/QsCompiler/Tests.Compiler/TestCases/FunctorGeneration.qs b/src/QsCompiler/Tests.Compiler/TestCases/FunctorGeneration.qs index ea5f174b11..f2966fca7f 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/FunctorGeneration.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/FunctorGeneration.qs @@ -156,14 +156,14 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation ControlledAdjointGenDirective10 (q : Qubit) : Unit { body (...) { } adjoint (...) { } - controlled adjoint self; + controlled adjoint self; controlled auto; } operation ControlledAdjointGenDirective11 (q : Qubit) : Unit { body (...) { } adjoint invert; - controlled adjoint self; + controlled adjoint self; controlled auto; } @@ -291,30 +291,30 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { // checking that functor support is verified for local variables and partial application as well operation VariableNeedsFunctorSupport1 (q : Qubit) : Unit { - body (...) { + body (...) { let op = Controllable; - op(q); + op(q); } adjoint auto; } operation VariableNeedsFunctorSupport2 (q : Qubit) : Unit { - body (...) { + body (...) { let op = Adjointable; - op(q); + op(q); } controlled auto; } operation VariableNeedsFunctorSupport3 (q : Qubit) : Unit { - body (...) { + body (...) { (Controllable(_))(q); } adjoint auto; } operation VariableNeedsFunctorSupport4 (q : Qubit) : Unit { - body (...) { + body (...) { (Adjointable(_))(q); } controlled auto; @@ -322,30 +322,30 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation VariableWithFunctorSupport1 (q : Qubit) : Unit { - body (...) { + body (...) { let op = Controllable; - op(q); + op(q); } controlled auto; } operation VariableWithFunctorSupport2 (q : Qubit) : Unit { - body (...) { + body (...) { let op = Adjointable; - op(q); + op(q); } adjoint auto; } operation VariableWithFunctorSupport3 (q : Qubit) : Unit { - body (...) { + body (...) { (Controllable(_))(q); } controlled auto; } operation VariableWithFunctorSupport4 (q : Qubit) : Unit { - body (...) { + body (...) { (Adjointable(_))(q); } adjoint auto; @@ -401,7 +401,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation NeedsFunctorSupport10 (q : Qubit) : Unit { - body (...) { + body (...) { within { Controllable(q); } apply {} } @@ -409,7 +409,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation NeedsFunctorSupport11 (q : Qubit) : Unit { - body (...) { + body (...) { within { } apply { Operation(q); } } @@ -417,7 +417,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation NeedsFunctorSupport12 (q : Qubit) : Unit { - body (...) { + body (...) { within { } apply { Operation(q); } } @@ -425,7 +425,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation NeedsFunctorSupport13 (q : Qubit) : Unit { - body (...) { + body (...) { within { } apply { Controllable(q); } } @@ -445,7 +445,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation NeedsFunctorSupport16(q : Qubit) : Unit { body (...) { within { Operation(q); } - apply { } + apply { } } adjoint self; } @@ -453,7 +453,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation NeedsFunctorSupport17(q : Qubit) : Unit is Adj { within { Controllable(q); } - apply { } + apply { } } @@ -520,7 +520,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation FunctorSupport13 (q : Qubit) : Unit { - body (...) { + body (...) { within { Adjointable(q); } apply {} } @@ -528,7 +528,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation FunctorSupport14 (q : Qubit) : Unit { - body (...) { + body (...) { within { Adjointable(q); } apply {} } @@ -536,7 +536,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation FunctorSupport15 (q : Qubit) : Unit { - body (...) { + body (...) { within {} apply { Operation(q); } } @@ -614,9 +614,9 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation InvalidAutoInversion1(q : Qubit) : Unit { body (...) { - return (); + return (); } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion2(q : Qubit) : Unit { @@ -625,21 +625,21 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { until (true) fixup {} } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion3(q : Qubit) : Unit { body (...) { set _ = 1; } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion4(q : Qubit) : Unit { body (...) { if (true) { return (); } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion5(q : Qubit) : Unit { @@ -650,21 +650,21 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { fixup {} } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion6(q : Qubit) : Unit { body (...) { if (true) { set _ = 1; } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion7(q : Qubit) : Unit { body (...) { for i in 1..10 { return (); } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion8(q : Qubit) : Unit { @@ -675,21 +675,21 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { fixup {} } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion9(q : Qubit) : Unit { body (...) { for i in 1..10 { set _ = 1; } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion10(q : Qubit) : Unit { body (...) { use c = Qubit() { return (); } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion11(q : Qubit) : Unit { @@ -700,21 +700,21 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { fixup {} } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion12(q : Qubit) : Unit { body (...) { use c = Qubit() { set _ = 1; } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion13(q : Qubit) : Unit { body (...) { borrow c = Qubit() { return (); } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion14(q : Qubit) : Unit { @@ -725,14 +725,14 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { fixup {} } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion15(q : Qubit) : Unit { body (...) { borrow c = Qubit() { set _ = 1; } } - adjoint auto; + adjoint auto; } operation InvalidAutoInversion16(q : Qubit) : Unit { @@ -756,7 +756,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation ValidInversion1(q : Qubit) : Unit { body (...) { - return (); + return (); } adjoint self; } @@ -767,7 +767,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { until (true) fixup {} } - adjoint self; + adjoint self; } operation ValidInversion3(q : Qubit) : Unit { @@ -775,15 +775,15 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { mutable foo = 0; set foo = 1; } - adjoint self; + adjoint self; } operation ValidInversion4(q : Qubit) : Unit { body (...) { - // NOTE: this is ok because, opposed to a return-statement, + // NOTE: this is ok because, opposed to a return-statement, // there is no way modify control flow in a meaningful way using a fail // (the computation fails either way albeit potentially a bit earlier rather than later) - fail "not yet implemented"; + fail "not yet implemented"; } adjoint auto; } @@ -848,7 +848,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation WithInvalidQuantumDependency5 (q : Qubit) : Unit { body (...) { - for i in CoinFlip() ? new Int[0] | new Int[1] {} + for i in CoinFlip() ? [] | [0] {} } adjoint auto; } @@ -929,7 +929,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation InvalidControlled2 (q : Qubit) : Unit { body (...) { - for i in CoinFlip() ? new Int[0] | new Int[1] {} + for i in CoinFlip() ? [] | [0] {} } controlled auto; } @@ -951,42 +951,42 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation ValidControlled1 (q : Qubit) : Unit { body (...) { - let _ = Controllable (q); + let _ = Controllable (q); } controlled auto; } operation ValidControlled2 (q : Qubit) : Unit { body (...) { - mutable _ = Controllable (q); + mutable _ = Controllable (q); } controlled auto; } operation ValidControlled3 (q : Qubit) : Unit { body (...) { - set _ = Controllable (q); + set _ = Controllable (q); } controlled auto; } operation ValidControlled4 (q : Qubit) : Unit { body (...) { - return Controllable(q); + return Controllable(q); } controlled auto; } operation ValidControlled5 (q : Qubit) : Unit { body (...) { - fail $"{Controllable (q)}"; + fail $"{Controllable (q)}"; } controlled auto; } operation ValidControlled6 (q : Qubit) : Unit { body (...) { - if (true) { Controllable(q); } + if (true) { Controllable(q); } } controlled auto; } @@ -1063,7 +1063,7 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { controlled auto; controlled adjoint invert; } - + operation ValidControlledAdjointGeneration1 (q : Qubit) : Unit { body (...) { Operation (q); } @@ -1194,51 +1194,51 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { operation AutoAdjSpec () : Unit { - adjoint auto; + adjoint auto; } operation InvertAdjSpec () : Unit { - adjoint invert; + adjoint invert; } operation SelfAdjSpec () : Unit { - adjoint self; + adjoint self; } operation AutoCtlSpec () : Unit { controlled auto; - } + } operation DistrCtlSpec () : Unit { - controlled distribute; + controlled distribute; } operation CtlAffAutoAdjSpec () : Unit is Ctl { - adjoint auto; + adjoint auto; } operation CtlAffInvertAdjSpec () : Unit is Ctl { - adjoint invert; + adjoint invert; } operation CtlAffSelfAdjSpec () : Unit is Ctl { - adjoint self; + adjoint self; } operation AdjAffAutoCtlSpec () : Unit is Adj { controlled auto; - } + } operation AdjAffDistrCtlSpec () : Unit is Adj { - controlled distribute; + controlled distribute; } // operation characteristics expressions operation OperationCharacteristics1 (qs : Qubit[]) : Unit { - NoAffiliation(); - AdjAffiliation(); + NoAffiliation(); + AdjAffiliation(); CtlAffiliation(); CtlAdjAffiliation(); AdjCtlAffiliation(); @@ -1251,96 +1251,96 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { Adjoint AdjCtlAffiliation(); Adjoint AdjViaIntersection(); Controlled CtlAffiliation(qs, ()); - Controlled CtlAdjAffiliation(qs, ()); - Controlled AdjCtlAffiliation(qs, ()); - Controlled CtlViaIntersection(qs, ()); + Controlled CtlAdjAffiliation(qs, ()); + Controlled AdjCtlAffiliation(qs, ()); + Controlled CtlViaIntersection(qs, ()); } operation OperationCharacteristics2 (qs : Qubit[]) : Unit { - Adjoint NoAffiliation(); + Adjoint NoAffiliation(); } operation OperationCharacteristics3 (qs : Qubit[]) : Unit { - Controlled NoAffiliation((), qs); + Controlled NoAffiliation((), qs); } operation OperationCharacteristics4 (qs : Qubit[]) : Unit { - Controlled AdjAffiliation((), qs); + Controlled AdjAffiliation((), qs); } operation OperationCharacteristics5 (qs : Qubit[]) : Unit { - Adjoint CtlAffiliation(); + Adjoint CtlAffiliation(); } operation OperationCharacteristics6 (qs : Qubit[]) : Unit { - Adjoint AdjCtlIntersection(); + Adjoint AdjCtlIntersection(); } operation OperationCharacteristics7 (qs : Qubit[]) : Unit { - Adjoint CtlAdjIntersection(); + Adjoint CtlAdjIntersection(); } operation OperationCharacteristics8 (qs : Qubit[]) : Unit { - Adjoint CtlViaIntersection(); + Adjoint CtlViaIntersection(); } operation OperationCharacteristics9 (qs : Qubit[]) : Unit { - Controlled AdjCtlIntersection(qs, ()); + Controlled AdjCtlIntersection(qs, ()); } operation OperationCharacteristics10 (qs : Qubit[]) : Unit { - Controlled CtlAdjIntersection(qs, ()); + Controlled CtlAdjIntersection(qs, ()); } operation OperationCharacteristics11 (qs : Qubit[]) : Unit { - Controlled AdjViaIntersection(qs, ()); + Controlled AdjViaIntersection(qs, ()); } operation OperationCharacteristics12 (qs : Qubit[]) : Unit { - Adjoint EmptyIntersection1(); + Adjoint EmptyIntersection1(); } operation OperationCharacteristics13 (qs : Qubit[]) : Unit { - Adjoint EmptyIntersection2(); + Adjoint EmptyIntersection2(); } operation OperationCharacteristics14 (qs : Qubit[]) : Unit { - Controlled EmptyIntersection1(qs, ()); + Controlled EmptyIntersection1(qs, ()); } operation OperationCharacteristics15 (qs : Qubit[]) : Unit { - Controlled EmptyIntersection2(qs, ()); + Controlled EmptyIntersection2(qs, ()); } operation OperationCharacteristics16 (qs : Qubit[]) : Unit { - CtlAffAutoAdjSpec(); - CtlAffInvertAdjSpec(); + CtlAffAutoAdjSpec(); + CtlAffInvertAdjSpec(); CtlAffSelfAdjSpec(); Adjoint CtlAffAutoAdjSpec(); Adjoint CtlAffInvertAdjSpec(); Adjoint CtlAffSelfAdjSpec(); - Controlled CtlAffAutoAdjSpec(qs, ()); - Controlled CtlAffInvertAdjSpec(qs, ()); - Controlled CtlAffSelfAdjSpec(qs, ()); + Controlled CtlAffAutoAdjSpec(qs, ()); + Controlled CtlAffInvertAdjSpec(qs, ()); + Controlled CtlAffSelfAdjSpec(qs, ()); } operation OperationCharacteristics17 (qs : Qubit[]) : Unit { - AdjAffAutoCtlSpec(); + AdjAffAutoCtlSpec(); AdjAffDistrCtlSpec(); Adjoint AdjAffAutoCtlSpec(); Adjoint AdjAffDistrCtlSpec(); - Controlled AdjAffAutoCtlSpec(qs, ()); - Controlled AdjAffDistrCtlSpec(qs, ()); + Controlled AdjAffAutoCtlSpec(qs, ()); + Controlled AdjAffDistrCtlSpec(qs, ()); } operation OperationCharacteristics18 (qs : Qubit[]) : Unit { - AutoCtlSpec(); + AutoCtlSpec(); DistrCtlSpec(); - AutoAdjSpec(); - InvertAdjSpec(); + AutoAdjSpec(); + InvertAdjSpec(); SelfAdjSpec(); - Controlled AutoCtlSpec(qs, ()); - Controlled DistrCtlSpec(qs, ()); + Controlled AutoCtlSpec(qs, ()); + Controlled DistrCtlSpec(qs, ()); Adjoint AutoAdjSpec(); Adjoint InvertAdjSpec(); Adjoint SelfAdjSpec(); @@ -1355,15 +1355,15 @@ namespace Microsoft.Quantum.Testing.FunctorGeneration { } operation OperationCharacteristics21 (qs : Qubit[]) : Unit { - Controlled AutoAdjSpec(qs, ()); + Controlled AutoAdjSpec(qs, ()); } operation OperationCharacteristics22 (qs : Qubit[]) : Unit { - Controlled InvertAdjSpec(qs, ()); + Controlled InvertAdjSpec(qs, ()); } operation OperationCharacteristics23 (qs : Qubit[]) : Unit { - Controlled SelfAdjSpec(qs, ()); + Controlled SelfAdjSpec(qs, ()); } } diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LocalVerification.qs b/src/QsCompiler/Tests.Compiler/TestCases/LocalVerification.qs index ae83d16960..d0f34986e2 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LocalVerification.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LocalVerification.qs @@ -43,13 +43,13 @@ namespace Microsoft.Quantum.Testing.LocalVerification { } operation TypeArgumentsInference6<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new ('T => Unit)[0]; + mutable arr = []; set arr = [TypeArgumentsInference6(1, _)]; arr[0](arg); } operation TypeArgumentsInference7<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new ('T => Unit)[0]; + mutable arr = []; set arr += [TypeArgumentsInference7(1, _)]; arr[0](arg); } @@ -69,7 +69,7 @@ namespace Microsoft.Quantum.Testing.LocalVerification { } operation TypeArgumentsInference10<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new (Int => Unit)[0]; + mutable arr = []; set arr += [TypeArgumentsInference12(_, arg), TypeArgumentsInference12(_, "")]; arr[0](cnt - 1); } @@ -94,14 +94,14 @@ namespace Microsoft.Quantum.Testing.LocalVerification { } operation TypeArgumentsInference14<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new (Int => Unit)[0]; + mutable arr = []; set arr = [TypeArgumentsInference14(_, PauliX)]; set arr = [TypeArgumentsInference14(_, arg)]; arr[0](cnt - 1); } operation TypeArgumentsInference15<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new (Int => Unit)[0]; + mutable arr = []; set arr += [TypeArgumentsInference15(_, PauliX)]; set arr += [TypeArgumentsInference15(_, arg)]; arr[1](cnt - 1); @@ -300,7 +300,7 @@ namespace Microsoft.Quantum.Testing.LocalVerification { } operation VariableDeclaration13<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new ((Int, 'T) => Unit)[0]; + mutable arr = []; set arr += [VariableDeclaration12]; arr[0](cnt - 1, arg); } @@ -312,13 +312,13 @@ namespace Microsoft.Quantum.Testing.LocalVerification { } operation VariableDeclaration15<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new ((Int, 'T) => Unit)[0]; + mutable arr = []; set arr = [VariableDeclaration15]; arr[0](cnt - 1, arg); } operation VariableDeclaration16<'T>(cnt: Int, arg : 'T) : Unit { - mutable arr = new ((Int, 'T) => Unit)[0]; + mutable arr = []; set arr += [VariableDeclaration16]; arr[0](cnt - 1, arg); } @@ -351,7 +351,7 @@ namespace Microsoft.Quantum.Testing.LocalVerification { let tuple = (1, (VariableDeclaration21, "")); let a1 = [VariableDeclaration21]; mutable a2 = [VariableDeclaration21]; - mutable arr = new ((Int, Double) => Unit)[0]; + mutable arr = []; set arr = [VariableDeclaration21]; set arr += [VariableDeclaration21]; set arr w/= 0 <- VariableDeclaration21; @@ -442,7 +442,7 @@ namespace Microsoft.Quantum.Testing.LocalVerification { } function CopyAndUpdateArray3 (arr : Int[][]) : Int[][] { - return arr w/ 0 <- new Int[10]; + return arr w/ 0 <- [0, size = 10]; } function CopyAndUpdateArray4<'T> (arr : 'T[]) : 'T[] { @@ -527,27 +527,27 @@ namespace Microsoft.Quantum.Testing.LocalVerification { // update-and-reassign array function UpdateAndReassign1 () : Unit { - mutable arr = new Int[10]; + mutable arr = [0, size = 10]; set arr w/= 1 <- 0; } function UpdateAndReassign2 () : Unit { - mutable arr = new Int[10]; + mutable arr = [0, size = 10]; set arr w/= 0 .. 2 <- [0,0,0]; } function UpdateAndReassign3 () : Unit { - mutable arr = new Int[10]; + mutable arr = [0, size = 10]; set arr w/= 0 .. Length(arr)-1 <- arr w/ 0 <- 1; } function UpdateAndReassign4 () : Unit { - mutable arr = new Int[10]; + mutable arr = [0, size = 10]; set arr w/= 1 <- 0.; } function UpdateAndReassign5 () : Unit { - mutable arr = new Int[10]; + mutable arr = [0, size = 10]; set arr w/= 0 .. Length(arr) <- 1 .. Length(arr); } @@ -634,12 +634,12 @@ namespace Microsoft.Quantum.Testing.LocalVerification { } function ApplyAndReassign9 () : Unit { - mutable a = new Int[10]; + mutable a = [0, size = 10]; set a[0] = 1; } function ApplyAndReassign10 () : Unit { - mutable a = new Int[10]; + mutable a = [0, size = 10]; set a[0] += 1; } @@ -691,7 +691,7 @@ namespace Microsoft.Quantum.Testing.LocalVerification { fail "length mismatch"; } - mutable res = new (Int,Int,Int)[0]; + mutable res = []; for (i1, i2) in arg2::Name { set res += [(i1, i2, arg1::Name[Length(res)])]; } @@ -814,8 +814,8 @@ namespace Microsoft.Quantum.Testing.LocalVerification { function ItemUpdate9 () : Unit { mutable arr = new ArrayType10[5]; for i in 0..4 { - mutable item = arr[i] w/ Phase <- new Int[10]; - set item w/= Const <- new Double[10]; + mutable item = arr[i] w/ Phase <- [0, size = 10]; + set item w/= Const <- [0.0, size = 10]; set arr w/= i <- item; } } @@ -823,7 +823,7 @@ namespace Microsoft.Quantum.Testing.LocalVerification { function ItemUpdate10 () : Unit { mutable arr = new ArrayType10[5]; for i in 0..4 { - mutable item = arr[i] w/ Phase <- new Int[10]; + mutable item = arr[i] w/ Phase <- [0, size = 10]; set item::Phase w/= 0 <- 1; } } @@ -831,7 +831,7 @@ namespace Microsoft.Quantum.Testing.LocalVerification { function ItemUpdate11 () : Unit { mutable arr = new ArrayType10[5]; for i in 0..4 { - set arr[i] w/= Phase <- new Int[10]; + set arr[i] w/= Phase <- [0, size = 10]; } } diff --git a/src/QsCompiler/Tests.Compiler/TestUtils/SetupVerificationTests.fs b/src/QsCompiler/Tests.Compiler/TestUtils/SetupVerificationTests.fs index c21eb671dc..dcf2781d93 100644 --- a/src/QsCompiler/Tests.Compiler/TestUtils/SetupVerificationTests.fs +++ b/src/QsCompiler/Tests.Compiler/TestUtils/SetupVerificationTests.fs @@ -15,6 +15,7 @@ open Microsoft.Quantum.QsCompiler.Diagnostics open Microsoft.Quantum.QsCompiler.SyntaxTree open Microsoft.VisualStudio.LanguageServer.Protocol open Xunit +open Microsoft.Quantum.QsCompiler.ReservedKeywords type CompilerTests(compilation: CompilationUnitManager.Compilation) = @@ -149,8 +150,10 @@ type CompilerTests(compilation: CompilationUnitManager.Compilation) = let references = defaultArg references [] let capability = defaultArg capability FullComputation let paths = fileNames |> Seq.map (fun file -> Path.Combine(srcFolder, file) |> Path.GetFullPath) + let props = ImmutableDictionary.CreateBuilder() + props.Add(MSBuildProperties.ResolvedRuntimeCapabilities, capability.Name) let mutable exceptions = [] - use manager = new CompilationUnitManager((fun e -> exceptions <- e :: exceptions), capability = capability) + use manager = new CompilationUnitManager(new ProjectProperties(props), (fun e -> exceptions <- e :: exceptions)) paths.ToImmutableDictionary(Uri, File.ReadAllText) |> CompilationUnitManager.InitializeFileManagers diff --git a/src/QsCompiler/Tests.Compiler/TransformationTests.fs b/src/QsCompiler/Tests.Compiler/TransformationTests.fs index b23145aa35..cec6cd5e2b 100644 --- a/src/QsCompiler/Tests.Compiler/TransformationTests.fs +++ b/src/QsCompiler/Tests.Compiler/TransformationTests.fs @@ -76,7 +76,7 @@ and private SyntaxCounterExpressionKinds(parent: SyntaxCounter) = let private buildSyntaxTree code = let fileId = new Uri(Path.GetFullPath "test-file.qs") - let compilationUnit = new CompilationUnitManager(fun ex -> failwith ex.Message) + let compilationUnit = new CompilationUnitManager(ProjectProperties.Empty, (fun ex -> failwith ex.Message)) let file = CompilationUnitManager.InitializeFileManager(fileId, code) // spawns a task that modifies the current compilation compilationUnit.AddOrUpdateSourceFileAsync file |> ignore diff --git a/src/QsCompiler/Tests.Compiler/TypeCheckingTests.fs b/src/QsCompiler/Tests.Compiler/TypeCheckingTests.fs index 742fc83817..b4433e13dc 100644 --- a/src/QsCompiler/Tests.Compiler/TypeCheckingTests.fs +++ b/src/QsCompiler/Tests.Compiler/TypeCheckingTests.fs @@ -91,12 +91,12 @@ type TypeCheckingTests() = [] member this.Variance() = - this.Expect "Variance1" [] - this.Expect "Variance2" [ Error ErrorCode.TypeMismatch ] - this.Expect "Variance3" [ Error ErrorCode.TypeMismatch ] - this.Expect "Variance4" [ Error ErrorCode.TypeMismatch ] - this.Expect "Variance5" [ Error ErrorCode.TypeMismatch ] - this.Expect "Variance6" [ Error ErrorCode.TypeMismatch ] + this.Expect "Variance1" (Warning WarningCode.DeprecatedNewArray |> List.replicate 5) + this.Expect "Variance2" [ Error ErrorCode.TypeMismatch; Warning WarningCode.DeprecatedNewArray ] + this.Expect "Variance3" [ Error ErrorCode.TypeMismatch; Warning WarningCode.DeprecatedNewArray ] + this.Expect "Variance4" [ Error ErrorCode.TypeMismatch; Warning WarningCode.DeprecatedNewArray ] + this.Expect "Variance5" [ Error ErrorCode.TypeMismatch; Warning WarningCode.DeprecatedNewArray ] + this.Expect "Variance6" [ Error ErrorCode.TypeMismatch; Warning WarningCode.DeprecatedNewArray ] this.Expect "Variance7" @@ -137,10 +137,32 @@ type TypeCheckingTests() = [] member this.``Common base type``() = - this.Expect "CommonBaseType1" [] - this.Expect "CommonBaseType2" [ Error ErrorCode.TypeIntersectionMismatch ] - this.Expect "CommonBaseType3" [ Error ErrorCode.TypeIntersectionMismatch ] - this.Expect "CommonBaseType4" [ Error ErrorCode.TypeMismatchInReturn ] + this.Expect "CommonBaseType1" (Warning WarningCode.DeprecatedNewArray |> List.replicate 2) + + this.Expect + "CommonBaseType2" + [ + Error ErrorCode.TypeIntersectionMismatch + Warning WarningCode.DeprecatedNewArray + Warning WarningCode.DeprecatedNewArray + ] + + this.Expect + "CommonBaseType3" + [ + Error ErrorCode.TypeIntersectionMismatch + Warning WarningCode.DeprecatedNewArray + Warning WarningCode.DeprecatedNewArray + ] + + this.Expect + "CommonBaseType4" + [ + Error ErrorCode.TypeMismatchInReturn + Warning WarningCode.DeprecatedNewArray + Warning WarningCode.DeprecatedNewArray + ] + this.Expect "CommonBaseType5" [] this.Expect "CommonBaseType6" [] this.Expect "CommonBaseType7" [] @@ -155,9 +177,30 @@ type TypeCheckingTests() = this.Expect "CommonBaseType16" [ Error ErrorCode.TypeIntersectionMismatch ] this.Expect "CommonBaseType17" [] this.Expect "CommonBaseType18" [] - this.Expect "CommonBaseType19" [ Warning WarningCode.UnusedTypeParam ] - this.Expect "CommonBaseType20" [ Error ErrorCode.TypeIntersectionMismatch ] - this.Expect "CommonBaseType21" [] + + this.Expect + "CommonBaseType19" + [ + Warning WarningCode.UnusedTypeParam + Warning WarningCode.DeprecatedNewArray + Warning WarningCode.DeprecatedNewArray + ] + + this.Expect + "CommonBaseType20" + [ + Error ErrorCode.TypeIntersectionMismatch + Warning WarningCode.DeprecatedNewArray + Warning WarningCode.DeprecatedNewArray + ] + + this.Expect + "CommonBaseType21" + [ + Warning WarningCode.DeprecatedNewArray + Warning WarningCode.DeprecatedNewArray + ] + this.Expect "CommonBaseType22" [] this.Expect "CommonBaseType23" [] this.Expect "CommonBaseType24" [] @@ -221,7 +264,7 @@ type TypeCheckingTests() = member this.``Argument matching``() = this.Expect "MatchArgument1" [] this.Expect "MatchArgument2" [] - this.Expect "MatchArgument3" [] + this.Expect "MatchArgument3" (Warning WarningCode.DeprecatedNewArray |> List.replicate 2) this.Expect "MatchArgument4" [] this.Expect "MatchArgument5" [] this.Expect "MatchArgument6" [] diff --git a/src/QsCompiler/Tests.Compiler/TypeParameterTests.fs b/src/QsCompiler/Tests.Compiler/TypeParameterTests.fs index 5af12f13de..3f8160f318 100644 --- a/src/QsCompiler/Tests.Compiler/TypeParameterTests.fs +++ b/src/QsCompiler/Tests.Compiler/TypeParameterTests.fs @@ -67,7 +67,7 @@ type TypeParameterTests() = let success = CheckCombinedResolution expected resolutions Assert.False(success, "Combining type resolutions should have failed.") - let compilationManager = new CompilationUnitManager(new Action(fun ex -> failwith ex.Message)) + let compilationManager = new CompilationUnitManager(ProjectProperties.Empty, (fun ex -> failwith ex.Message)) let getTempFile () = new Uri(Path.GetFullPath(Path.GetRandomFileName())) diff --git a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs index 35385e95a6..3b18ee3cdd 100644 --- a/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs +++ b/src/QsCompiler/Tests.LanguageServer/ProjectLoaderTests.cs @@ -39,11 +39,13 @@ private static string ProjectFileName(string project) => private static string SourceFileName(string project, string fileName) => Path.Combine("TestProjects", project, fileName); - private (string, ProjectInformation?) Context(string project) + internal static Uri ProjectUri(string project) => + new Uri(Path.GetFullPath(ProjectFileName(project))); + + internal static (Uri, ProjectInformation?) Context(string project) { - var relativePath = ProjectFileName(project); - var uri = new Uri(Path.GetFullPath(relativePath)); - return (uri.LocalPath, CompilationContext.Load(uri)); + var uri = ProjectUri(project); + return (uri, CompilationContext.Load(uri)); } [TestMethod] @@ -74,7 +76,7 @@ public void SupportedTargetFrameworks() [TestMethod] public void FindProjectTargetFramework() { - void CompareFramework(string project, string? expected) + static void CompareFramework(string project, string? expected) { var projectFileName = ProjectFileName(project); var props = new ProjectLoader().DesignTimeBuildProperties(projectFileName, out var _, (x, y) => (y.Contains('.') ? 1 : 0) - (x.Contains('.') ? 1 : 0)); @@ -122,7 +124,7 @@ public void LoadNonQSharpProjects() foreach (var project in invalidProjects) { - var (_, context) = this.Context(project); + var (_, context) = Context(project); Assert.IsNull(context); } } @@ -130,11 +132,11 @@ public void LoadNonQSharpProjects() [TestMethod] public void LoadOutdatedQSharpProject() { - var (projectFile, context) = this.Context("test9"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test9"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test9.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test9.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); var qsFiles = new string[] { @@ -150,11 +152,11 @@ public void LoadOutdatedQSharpProject() [TestMethod] public void LoadQSharpCoreLibraries() { - var (projectFile, context) = this.Context("test3"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test3"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test3.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test3.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); var qsFiles = new string[] { @@ -169,21 +171,23 @@ public void LoadQSharpCoreLibraries() Assert.IsFalse(context.UsesXunitHelper()); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); - (projectFile, context) = this.Context("test12"); - projDir = Path.GetDirectoryName(projectFile) ?? ""; + (projectFile, context) = Context("test12"); + projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test12.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test12.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); qsFiles = new string[] { + Path.Combine(projDir, "format", "Unformatted.qs"), Path.Combine(projDir, "Operation12a.qs"), Path.Combine(projDir, "Operation12b.qs"), Path.Combine(projDir, "sub1", "Operation12b.qs"), Path.Combine(projDir, "sub1", "sub2", "Operation12a.qs"), }; - Assert.IsTrue(context.UsesIntrinsics()); + Assert.IsTrue(context.UsesQSharpCore()); + Assert.IsFalse(context.UsesIntrinsics()); Assert.IsTrue(context.UsesCanon()); Assert.IsFalse(context.UsesXunitHelper()); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); @@ -192,11 +196,11 @@ public void LoadQSharpCoreLibraries() [TestMethod] public void LoadQSharpFrameworkLibrary() { - var (projectFile, context) = this.Context("test7"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test7"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test7.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test7.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); var qsFiles = new string[] { @@ -212,11 +216,11 @@ public void LoadQSharpFrameworkLibrary() [TestMethod] public void LoadQSharpConsoleApps() { - var (projectFile, context) = this.Context("test4"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test4"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test4.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test4.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); var qsFiles = new string[] { @@ -229,11 +233,11 @@ public void LoadQSharpConsoleApps() Assert.IsTrue(context.UsesProject("test3.csproj")); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); - (projectFile, context) = this.Context("test10"); - projDir = Path.GetDirectoryName(projectFile) ?? ""; + (projectFile, context) = Context("test10"); + projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test10.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test10.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); qsFiles = new string[] { @@ -244,11 +248,11 @@ public void LoadQSharpConsoleApps() Assert.IsTrue(context.UsesCanon()); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); - (projectFile, context) = this.Context("test11"); - projDir = Path.GetDirectoryName(projectFile) ?? ""; + (projectFile, context) = Context("test11"); + projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test11.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test11.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); qsFiles = new string[] { @@ -263,11 +267,11 @@ public void LoadQSharpConsoleApps() [TestMethod] public void LoadQSharpUnitTest() { - var (projectFile, context) = this.Context("test5"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test5"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test5.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test5.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); var qsFiles = new string[] { @@ -287,11 +291,11 @@ public void LoadQSharpUnitTest() [TestMethod] public void LoadQSharpMultiFrameworkLibrary() { - var (projectFile, context) = this.Context("test6"); - var projDir = Path.GetDirectoryName(projectFile) ?? ""; + var (projectFile, context) = Context("test6"); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; Assert.IsNotNull(context); - Assert.AreEqual("test6.dll", Path.GetFileName(context!.Properties.OutputPath)); - Assert.IsTrue((Path.GetDirectoryName(context.Properties.OutputPath) ?? "").StartsWith(projDir)); + Assert.AreEqual("test6.dll", Path.GetFileName(context!.Properties.DllOutputPath)); + Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir)); var qsFiles = new string[] { @@ -306,20 +310,6 @@ public void LoadQSharpMultiFrameworkLibrary() Assert.IsTrue(context.UsesProject("test3.csproj")); CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray()); } - - [TestMethod] - public void LoadQSharpTemporaryProject() - { - var sourceFile = Path.GetFullPath(SourceFileName("test14", "Operation14.qs")); - var projectUri = CompilationContext.CreateTemporaryProject(new Uri(sourceFile), "0.12.20072031"); - Assert.IsNotNull(projectUri); - - var qsFiles = new string[] { sourceFile }; - var projectInformation = CompilationContext.Load(projectUri); - Assert.IsNotNull(projectInformation); - Assert.IsTrue(projectInformation!.UsesCanon()); - CollectionAssert.AreEquivalent(qsFiles, projectInformation!.SourceFiles.ToArray()); - } } internal static class CompilationContext @@ -327,13 +317,11 @@ internal static class CompilationContext private static void LogOutput(string msg, MessageType level) => Console.WriteLine($"[{level}]: {msg}"); - internal static ProjectInformation? Load(Uri projectFile) => - new EditorState(new ProjectLoader(LogOutput), null, null, null, null, null) - .QsProjectLoader(projectFile, out var loaded) ? loaded : null; + internal static EditorState Editor => + new EditorState(new ProjectLoader(LogOutput), null, null, null, null); - internal static Uri CreateTemporaryProject(Uri sourceFile, string sdkVersion) => - new EditorState(new ProjectLoader(LogOutput), null, null, null, null, null) - .QsTemporaryProjectLoader(sourceFile, sdkVersion); + internal static ProjectInformation? Load(Uri projectFile) => + Editor.QsProjectLoader(projectFile, out var loaded) ? loaded : null; internal static bool UsesDll(this ProjectInformation info, string dll) => info.References.Any(r => r.EndsWith(dll)); @@ -342,6 +330,8 @@ internal static Uri CreateTemporaryProject(Uri sourceFile, string sdkVersion) => // NB: We check whether the project uses either the 0.3–0.5 name (Primitives) or the 0.6– name (Intrinsic). internal static bool UsesIntrinsics(this ProjectInformation info) => info.UsesDll("Microsoft.Quantum.Intrinsic.dll") || info.UsesDll("Microsoft.Quantum.Primitives.dll"); + internal static bool UsesQSharpCore(this ProjectInformation info) => info.UsesDll("Microsoft.Quantum.QSharp.Core.dll"); + internal static bool UsesCanon(this ProjectInformation info) => info.UsesDll("Microsoft.Quantum.Canon.dll") || info.UsesDll("Microsoft.Quantum.Standard.dll"); diff --git a/src/QsCompiler/Tests.LanguageServer/Tests.LanguageServer.csproj b/src/QsCompiler/Tests.LanguageServer/Tests.LanguageServer.csproj index 9b233a9420..88d0727c6d 100644 --- a/src/QsCompiler/Tests.LanguageServer/Tests.LanguageServer.csproj +++ b/src/QsCompiler/Tests.LanguageServer/Tests.LanguageServer.csproj @@ -6,6 +6,7 @@ Tests.Microsoft.Quantum.QsLanguageServer Library $(NoWarn);NU1701 + $([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory)..\..\..\)) @@ -13,7 +14,7 @@ - + @@ -37,4 +38,18 @@ + + + + + + + + + + + + + + diff --git a/src/QsCompiler/Tests.LanguageServer/Tests.cs b/src/QsCompiler/Tests.LanguageServer/Tests.cs index 5618317220..21a6830693 100644 --- a/src/QsCompiler/Tests.LanguageServer/Tests.cs +++ b/src/QsCompiler/Tests.LanguageServer/Tests.cs @@ -2,9 +2,12 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; +using Microsoft.Quantum.QsCompiler.CompilationBuilder; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Linq; @@ -138,7 +141,7 @@ public async Task ServerCapabilitiesAsync() initReply.Capabilities.WorkspaceSymbolProvider.AssertCapability(shouldHave: false); initReply.Capabilities.RenameProvider.AssertCapability(); initReply.Capabilities.HoverProvider.AssertCapability(); - initReply.Capabilities.DocumentFormattingProvider.AssertCapability(shouldHave: false); + initReply.Capabilities.DocumentFormattingProvider.AssertCapability(shouldHave: true); initReply.Capabilities.DocumentRangeFormattingProvider.AssertCapability(shouldHave: false); initReply.Capabilities.CodeActionProvider.AssertCapability(); } @@ -274,9 +277,10 @@ async Task RunTest(bool emptyLastLine, bool useQsExtension) } } + await RunTest(emptyLastLine: true, useQsExtension: true); await RunTest(emptyLastLine: true, useQsExtension: false); + await RunTest(emptyLastLine: false, useQsExtension: true); await RunTest(emptyLastLine: false, useQsExtension: false); - await RunTest(emptyLastLine: true, useQsExtension: true); } [TestMethod] @@ -313,5 +317,52 @@ public async Task CodeContentTrackingAsync() Assert.AreEqual(expected, got); } } + + [TestMethod] + public async Task UpdateAndFormatAsync() + { + ManualResetEvent eventSignal = new ManualResetEvent(false); + async void CheckForLoadingCompleted(string msg, MessageType messageType) + { + await Console.Error.WriteLineAsync(msg); + if (msg.StartsWith("Done loading project")) + { + eventSignal.Set(); + } + } + + async Task RunFormattingTestAsync(string projectName) + { + var projectFile = ProjectLoaderTests.ProjectUri(projectName); + var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? ""; + var projectManager = new ProjectManager(ex => Assert.IsNull(ex), CheckForLoadingCompleted); + await projectManager.LoadProjectsAsync( + new[] { projectFile }, + CompilationContext.Editor.QsProjectLoader, + enableLazyLoading: false); + + // Note that the formatting command will return null until the project has finished loading, + // and similarly when a project is reloaded because it has been modified. + // All in all, that seem like reasonable behavior. + eventSignal.WaitOne(); + eventSignal.Reset(); + + var fileToFormat = new Uri(Path.Combine(projDir, "format", "Unformatted.qs")); + var expectedContent = File.ReadAllText(Path.Combine(projDir, "format", "Formatted.qs")); + var param = new DocumentFormattingParams + { + TextDocument = new TextDocumentIdentifier { Uri = fileToFormat }, + Options = new FormattingOptions { TabSize = 2, InsertSpaces = false, OtherOptions = new Dictionary() }, + }; + + var edits = projectManager.Formatting(param); + Assert.IsNotNull(edits); + Assert.AreEqual(1, edits!.Length); + Assert.AreEqual(expectedContent, edits[0].NewText); + } + + await RunFormattingTestAsync("test12"); + await RunFormattingTestAsync("test15"); + } } } diff --git a/src/QsCompiler/TextProcessor/QsExpressionParsing.fs b/src/QsCompiler/TextProcessor/QsExpressionParsing.fs index b9c0eace8e..b5f1157736 100644 --- a/src/QsCompiler/TextProcessor/QsExpressionParsing.fs +++ b/src/QsCompiler/TextProcessor/QsExpressionParsing.fs @@ -515,19 +515,28 @@ let private valueArray = <|> bracketDefinedCommaSepExpr (lArray, rArray) /// Parses a Q# array declaration as QsExpression. -/// Raises an InvalidContructorExpression if the array declaration keyword is not followed by a valid array constructor, +/// Adds an InvalidConstructorExpression if the array declaration keyword is not followed by a valid array constructor, /// and advances to the next whitespace character or QsFragmentHeader. let private newArray = let itemType = expectedQsType (lArray >>% ()) >>= fun itemType -> validateTypeSyntax true itemType >>% itemType let body = itemType .>>. (arrayBrackets (expectedExpr eof) |>> fst) |>> NewArray + let toExpr headRange (kind, bodyRange) = + QsExpression.New(kind, Range.Span headRange bodyRange) + let invalid = checkForInvalid (qsFragmentHeader >>% "" <|> (nextCharSatisfies Text.IsWhitespace >>. emptySpace)) ErrorCode.InvalidConstructorExpression >>% unknownExpr - arrayDecl.parse >>. (term body |>> QsExpression.New <|> (term invalid |>> fst)) + let withWarning (expr: QsExpression) = + let range = expr.Range |> QsNullable.defaultValue Range.Zero + QsCompilerDiagnostic.Warning(WarningCode.DeprecatedNewArray, []) range |> pushDiagnostic >>% expr + + arrayDecl.parse + >>= fun headRange -> term body |>> toExpr headRange <|> (term invalid |>> fst) + >>= withWarning /// used to temporarily store item accessors for both array item and named item access expressions type private ItemAccessor = diff --git a/src/QsFmt/App.Tests/App.Tests.fsproj b/src/QsFmt/App.Tests/App.Tests.fsproj index 820c140fb5..363bcd250c 100644 --- a/src/QsFmt/App.Tests/App.Tests.fsproj +++ b/src/QsFmt/App.Tests/App.Tests.fsproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 Microsoft.Quantum.QsFmt.App.Tests @@ -6,28 +6,162 @@ - + + Always + + + Always + - PreserveNewest + Always - PreserveNewest + Always - PreserveNewest + Always - PreserveNewest + Always - PreserveNewest + Always - PreserveNewest + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + diff --git a/src/QsFmt/App.Tests/Example1.qs b/src/QsFmt/App.Tests/Example1.qs deleted file mode 100644 index 6ee71df468..0000000000 --- a/src/QsFmt/App.Tests/Example1.qs +++ /dev/null @@ -1 +0,0 @@ -namespace Example1 { function Bar() : Int { return 0; } } diff --git a/src/QsFmt/App.Tests/Example2.qs b/src/QsFmt/App.Tests/Example2.qs deleted file mode 100644 index cec365892c..0000000000 --- a/src/QsFmt/App.Tests/Example2.qs +++ /dev/null @@ -1 +0,0 @@ -namespace Example2 { function Bar() : Int { return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/SyntaxError.qs b/src/QsFmt/App.Tests/Examples/SyntaxError.qs new file mode 100644 index 0000000000..d2d37ea651 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/SyntaxError.qs @@ -0,0 +1 @@ +namespace Foo { invalid syntax; } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/Driver.cs b/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/Driver.cs new file mode 100644 index 0000000000..dffbcc8788 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/Driver.cs @@ -0,0 +1,13 @@ +using Microsoft.Quantum.Simulation.Core; +using Microsoft.Quantum.Simulation.Simulators; + +namespace OldApplication +{ + class Driver + { + static void Main(string[] args) + { + + } + } +} diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/OldApplication.csproj b/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/OldApplication.csproj new file mode 100644 index 0000000000..c2c94b133c --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/OldApplication.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + x64 + + + + + + + + diff --git a/src/QsCompiler/TestProjects/test14/Operation14.qs b/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/Operation.qs similarity index 54% rename from src/QsCompiler/TestProjects/test14/Operation14.qs rename to src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/Operation.qs index 4b01284140..5f51e12592 100644 --- a/src/QsCompiler/TestProjects/test14/Operation14.qs +++ b/src/QsFmt/App.Tests/Examples/TestProjects/OldApplication/Operation.qs @@ -1,7 +1,4 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace test14 { +namespace OldApplication { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Intrinsic; diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/OldVersion/OldVersion.csproj b/src/QsFmt/App.Tests/Examples/TestProjects/OldVersion/OldVersion.csproj new file mode 100644 index 0000000000..ffac44e123 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/OldVersion/OldVersion.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.1 + + + diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/OldVersion/Program.qs b/src/QsFmt/App.Tests/Examples/TestProjects/OldVersion/Program.qs new file mode 100644 index 0000000000..c22d3f4148 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/OldVersion/Program.qs @@ -0,0 +1,11 @@ +namespace Quantum.QSharpApplication1 { + + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Intrinsic; + + + @EntryPoint() + operation HelloQ () : Unit { + Message("Hello quantum world!"); + } +} diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/ReferenceLibrary/Library.qs b/src/QsFmt/App.Tests/Examples/TestProjects/ReferenceLibrary/Library.qs new file mode 100644 index 0000000000..650943fa09 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/ReferenceLibrary/Library.qs @@ -0,0 +1,10 @@ +namespace Quantum.ReferenceLibrary { + + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Intrinsic; + + + operation LibraryOperation () : Unit { + Message("Hello from the Reference Library!"); + } +} diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/ReferenceLibrary/ReferenceLibrary.csproj b/src/QsFmt/App.Tests/Examples/TestProjects/ReferenceLibrary/ReferenceLibrary.csproj new file mode 100644 index 0000000000..39db37413f --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/ReferenceLibrary/ReferenceLibrary.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.1 + + + diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Excluded1.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Excluded1.qs new file mode 100644 index 0000000000..2239054759 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Excluded1.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded1() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Included1.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Included1.qs new file mode 100644 index 0000000000..9ea3b00a59 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Included1.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included1() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Program.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Program.qs new file mode 100644 index 0000000000..8e16620336 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/Program.qs @@ -0,0 +1,15 @@ +namespace Quantum.QSharpApplication1 { + + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Chemistry; + open Microsoft.Quantum.Intrinsic; + open Quantum.ReferenceLibrary; + + + @EntryPoint() + operation HelloQ () : Unit { + Message("Hello quantum world!"); + LibraryOperation(); + let x = HTerm([], []); + } +} diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/QSharpApplication1.csproj b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/QSharpApplication1.csproj new file mode 100644 index 0000000000..71a8f049d0 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/QSharpApplication1.csproj @@ -0,0 +1,24 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + Example1.qs + + + + + + + + + + diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/Excluded2.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/Excluded2.qs new file mode 100644 index 0000000000..6d39319e6f --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/Excluded2.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded2() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/Included2.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/Included2.qs new file mode 100644 index 0000000000..e43f0a6bb8 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/Included2.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included2() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/SubSubFolder/Excluded4.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/SubSubFolder/Excluded4.qs new file mode 100644 index 0000000000..25e12245a9 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/SubSubFolder/Excluded4.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded4() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/SubSubFolder/Included4.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/SubSubFolder/Included4.qs new file mode 100644 index 0000000000..f287e29711 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder1/SubSubFolder/Included4.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included4() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder2/Excluded3.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder2/Excluded3.qs new file mode 100644 index 0000000000..6c610f8de8 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder2/Excluded3.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded3() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder2/Included3.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder2/Included3.qs new file mode 100644 index 0000000000..0485b054ee --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleApplication/SubFolder2/Included3.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included3() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Excluded1.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Excluded1.qs new file mode 100644 index 0000000000..2239054759 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Excluded1.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded1() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Included1.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Included1.qs new file mode 100644 index 0000000000..9ea3b00a59 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Included1.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included1() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Library.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Library.qs new file mode 100644 index 0000000000..a1c9db7d4c --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/Library.qs @@ -0,0 +1,14 @@ +namespace Quantum.QSharpLibrary1 { + + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Chemistry; + open Microsoft.Quantum.Intrinsic; + open Quantum.ReferenceLibrary; + + + operation HelloQ () : Unit { + Message("Hello quantum world!"); + LibraryOperation(); + let x = HTerm([], []); + } +} diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/QSharpLibrary1.csproj b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/QSharpLibrary1.csproj new file mode 100644 index 0000000000..2d69cbcb3e --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/QSharpLibrary1.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.1 + + + + + + + + + Example1.qs + + + + + + + + + + diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/Excluded2.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/Excluded2.qs new file mode 100644 index 0000000000..6d39319e6f --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/Excluded2.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded2() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/Included2.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/Included2.qs new file mode 100644 index 0000000000..e43f0a6bb8 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/Included2.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included2() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/SubSubFolder/Excluded4.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/SubSubFolder/Excluded4.qs new file mode 100644 index 0000000000..25e12245a9 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/SubSubFolder/Excluded4.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded4() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/SubSubFolder/Included4.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/SubSubFolder/Included4.qs new file mode 100644 index 0000000000..f287e29711 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder1/SubSubFolder/Included4.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included4() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder2/Excluded3.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder2/Excluded3.qs new file mode 100644 index 0000000000..6c610f8de8 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder2/Excluded3.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded3() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder2/Included3.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder2/Included3.qs new file mode 100644 index 0000000000..0485b054ee --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleLibrary/SubFolder2/Included3.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included3() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Excluded1.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Excluded1.qs new file mode 100644 index 0000000000..2239054759 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Excluded1.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded1() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Included1.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Included1.qs new file mode 100644 index 0000000000..9ea3b00a59 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Included1.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included1() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/QSharpTestProject1.csproj b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/QSharpTestProject1.csproj new file mode 100644 index 0000000000..7a478df8c6 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/QSharpTestProject1.csproj @@ -0,0 +1,32 @@ + + + + netcoreapp3.1 + false + + + + + + + + + Example1.qs + + + + + + + + + + + + + + + + + + diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/Excluded2.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/Excluded2.qs new file mode 100644 index 0000000000..6d39319e6f --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/Excluded2.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded2() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/Included2.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/Included2.qs new file mode 100644 index 0000000000..e43f0a6bb8 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/Included2.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included2() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/SubSubFolder/Excluded4.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/SubSubFolder/Excluded4.qs new file mode 100644 index 0000000000..25e12245a9 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/SubSubFolder/Excluded4.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded4() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/SubSubFolder/Included4.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/SubSubFolder/Included4.qs new file mode 100644 index 0000000000..f287e29711 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder1/SubSubFolder/Included4.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included4() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder2/Excluded3.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder2/Excluded3.qs new file mode 100644 index 0000000000..6c610f8de8 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder2/Excluded3.qs @@ -0,0 +1 @@ +namespace TestTarget { function Excluded3() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder2/Included3.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder2/Included3.qs new file mode 100644 index 0000000000..0485b054ee --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/SubFolder2/Included3.qs @@ -0,0 +1 @@ +namespace TestTarget { function Included3() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Tests.qs b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Tests.qs new file mode 100644 index 0000000000..d9eba8a6db --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestProjects/SimpleTestProject/Tests.qs @@ -0,0 +1,20 @@ +namespace Quantum.QSharpTestProject1 { + + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Chemistry; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Intrinsic; + open Quantum.ReferenceLibrary; + + + @Test("QuantumSimulator") + operation AllocateQubit () : Unit { + + use q = Qubit(); + AssertMeasurement([PauliZ], [q], Zero, "Newly allocated qubit must be in |0> state."); + + Message("Test passed."); + LibraryOperation(); + let x = HTerm([], []); + } +} diff --git a/src/QsFmt/App.Tests/Examples/TestTarget/Excluded1.qs b/src/QsFmt/App.Tests/Examples/TestTarget/Excluded1.qs new file mode 100644 index 0000000000..70eff555a2 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestTarget/Excluded1.qs @@ -0,0 +1 @@ +namespace TestTarget { function Bar2() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestTarget/Excluded2.qs b/src/QsFmt/App.Tests/Examples/TestTarget/Excluded2.qs new file mode 100644 index 0000000000..1617c7ebf4 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestTarget/Excluded2.qs @@ -0,0 +1 @@ +namespace TestTarget { function Bar3() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestTarget/Included.qs b/src/QsFmt/App.Tests/Examples/TestTarget/Included.qs new file mode 100644 index 0000000000..52dc362af5 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestTarget/Included.qs @@ -0,0 +1 @@ +namespace TestTarget { function Bar1() : Int { for (i in 0..1) {} return 0; } } diff --git a/src/QsFmt/App.Tests/Examples/TestTarget/Program.qs b/src/QsFmt/App.Tests/Examples/TestTarget/Program.qs new file mode 100644 index 0000000000..c170a6c424 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestTarget/Program.qs @@ -0,0 +1 @@ +namespace TestTarget { @EntryPoint() operation Bar() : Unit { for (i in 0..1) {} } } diff --git a/src/QsFmt/App.Tests/Examples/TestTarget/TestTarget.csproj b/src/QsFmt/App.Tests/Examples/TestTarget/TestTarget.csproj new file mode 100644 index 0000000000..25a6851b49 --- /dev/null +++ b/src/QsFmt/App.Tests/Examples/TestTarget/TestTarget.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + diff --git a/src/QsFmt/App.Tests/ProjectTests.fs b/src/QsFmt/App.Tests/ProjectTests.fs new file mode 100644 index 0000000000..d42d3678c4 --- /dev/null +++ b/src/QsFmt/App.Tests/ProjectTests.fs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +module Microsoft.Quantum.QsFmt.App.ProjectTests + +open System.IO +open Microsoft.Quantum.QsFmt.App +open Xunit + +[] +let SimpleApplication () = + DesignTimeBuild.assemblyLoadContextSetup () + + let files, version = + DesignTimeBuild.getSourceFiles "Examples\TestProjects\SimpleApplication\QSharpApplication1.csproj" + + let files = files |> List.map Path.GetFullPath + + let expectedFiles = + [ + "Examples\TestProjects\SimpleApplication\Program.qs" + "Examples\TestProjects\SimpleApplication\Included1.qs" + "Examples\TestProjects\SimpleApplication\SubFolder1\Included2.qs" + "Examples\TestProjects\SimpleApplication\SubFolder2\Included3.qs" + "Examples\TestProjects\SimpleApplication\SubFolder1\SubSubFolder\Included4.qs" + "Examples\Example1.qs" + "Examples\Example2.qs" + ] + |> List.map Path.GetFullPath + + Assert.True(expectedFiles.Length = files.Length, "Didn't get the expected number of files.") + + for expected in expectedFiles do + Assert.True(List.contains expected files, sprintf "Expected but did not find file %s" expected) + +[] +let SimpleLibrary () = + DesignTimeBuild.assemblyLoadContextSetup () + + let files, version = DesignTimeBuild.getSourceFiles "Examples\TestProjects\SimpleLibrary\QSharpLibrary1.csproj" + let files = files |> List.map Path.GetFullPath + + let expectedFiles = + [ + "Examples\TestProjects\SimpleLibrary\Library.qs" + "Examples\TestProjects\SimpleLibrary\Included1.qs" + "Examples\TestProjects\SimpleLibrary\SubFolder1\Included2.qs" + "Examples\TestProjects\SimpleLibrary\SubFolder2\Included3.qs" + "Examples\TestProjects\SimpleLibrary\SubFolder1\SubSubFolder\Included4.qs" + "Examples\Example1.qs" + "Examples\Example2.qs" + ] + |> List.map Path.GetFullPath + + Assert.True(expectedFiles.Length = files.Length, "Didn't get the expected number of files.") + + for expected in expectedFiles do + Assert.True(List.contains expected files, sprintf "Expected but did not find file %s" expected) + +[] +let SimpleTestProject () = + DesignTimeBuild.assemblyLoadContextSetup () + + let files, version = + DesignTimeBuild.getSourceFiles "Examples\TestProjects\SimpleTestProject\QSharpTestProject1.csproj" + + let files = files |> List.map Path.GetFullPath + + let expectedFiles = + [ + "Examples\TestProjects\SimpleTestProject\Tests.qs" + "Examples\TestProjects\SimpleTestProject\Included1.qs" + "Examples\TestProjects\SimpleTestProject\SubFolder1\Included2.qs" + "Examples\TestProjects\SimpleTestProject\SubFolder2\Included3.qs" + "Examples\TestProjects\SimpleTestProject\SubFolder1\SubSubFolder\Included4.qs" + "Examples\Example1.qs" + "Examples\Example2.qs" + ] + |> List.map Path.GetFullPath + + Assert.True(expectedFiles.Length = files.Length, "Didn't get the expected number of files.") + + for expected in expectedFiles do + Assert.True(List.contains expected files, sprintf "Expected but did not find file %s" expected) diff --git a/src/QsFmt/App.Tests/SubExamples1/SubExample1.qs b/src/QsFmt/App.Tests/SubExamples1/SubExample1.qs deleted file mode 100644 index 97571b3efe..0000000000 --- a/src/QsFmt/App.Tests/SubExamples1/SubExample1.qs +++ /dev/null @@ -1 +0,0 @@ -namespace SubExample1 { function Bar() : Int { return 0; } } diff --git a/src/QsFmt/App.Tests/SubExamples1/SubExample2.qs b/src/QsFmt/App.Tests/SubExamples1/SubExample2.qs deleted file mode 100644 index bae61ebafb..0000000000 --- a/src/QsFmt/App.Tests/SubExamples1/SubExample2.qs +++ /dev/null @@ -1 +0,0 @@ -namespace SubExample2 { function Bar() : Int { return 0; } } diff --git a/src/QsFmt/App.Tests/SubExamples2/NestedExample2/NestedExample1.qs b/src/QsFmt/App.Tests/SubExamples2/NestedExample2/NestedExample1.qs deleted file mode 100644 index 319413d58b..0000000000 --- a/src/QsFmt/App.Tests/SubExamples2/NestedExample2/NestedExample1.qs +++ /dev/null @@ -1 +0,0 @@ -namespace NestedExample1 { function Bar() : Int { return 0; } } diff --git a/src/QsFmt/App.Tests/SubExamples2/NestedExample2/NestedExample2.qs b/src/QsFmt/App.Tests/SubExamples2/NestedExample2/NestedExample2.qs deleted file mode 100644 index b5cb88f176..0000000000 --- a/src/QsFmt/App.Tests/SubExamples2/NestedExample2/NestedExample2.qs +++ /dev/null @@ -1 +0,0 @@ -namespace NestedExample2 { function Bar() : Int { return 0; } } diff --git a/src/QsFmt/App.Tests/SubExamples2/SubExample3.qs b/src/QsFmt/App.Tests/SubExamples2/SubExample3.qs deleted file mode 100644 index 0d79aa7a2d..0000000000 --- a/src/QsFmt/App.Tests/SubExamples2/SubExample3.qs +++ /dev/null @@ -1 +0,0 @@ -namespace SubExample3 { function Bar() : Int { return 0; } } diff --git a/src/QsFmt/App.Tests/Tests.fs b/src/QsFmt/App.Tests/Tests.fs index afc7b51c99..1c8c5c3ebf 100644 --- a/src/QsFmt/App.Tests/Tests.fs +++ b/src/QsFmt/App.Tests/Tests.fs @@ -4,13 +4,14 @@ /// Tests for the command-line interface. module Microsoft.Quantum.QsFmt.App.Tests -open Microsoft.Quantum.QsFmt.App.Program open System open System.IO +open Microsoft.Quantum.QsFmt.App.Arguments +open Microsoft.Quantum.QsFmt.App.Program open Xunit /// The result of running the application. -type Result = +type private Result = { /// The exit status code. Code: int @@ -22,28 +23,29 @@ type Result = Error: string } -type TestFile = +type private TestFile = { Path: string Original: string Formatted: string Updated: string + UpdatedAndFormatted: String } /// /// Ensures that the new line characters will conform to the standard of the environment's new line character. /// -let standardizeNewLines (s: string) = +let private standardizeNewLines (s: string) = s.Replace("\r", "").Replace("\n", Environment.NewLine) -let CleanResult = +let private CleanResult = { Code = 0 Out = "" Error = "" } -let makeTestFile (path: string) = +let private makeTestFile (path: string) = let name = path.[(path.LastIndexOf "\\") + 1..(path.LastIndexOf ".qs") - 1] { @@ -64,19 +66,30 @@ let makeTestFile (path: string) = name |> sprintf "namespace %s { function Bar() : Int { for i in 0..1 {} return 0; } } +" + |> standardizeNewLines + UpdatedAndFormatted = + name + |> sprintf + "namespace %s { + function Bar() : Int { + for i in 0..1 {} + return 0; + } +} " |> standardizeNewLines } -let Example1 = makeTestFile "Examples\\Example1.qs" -let Example2 = makeTestFile "Examples\\Example2.qs" -let SubExample1 = makeTestFile "Examples\\SubExamples1\\SubExample1.qs" -let SubExample2 = makeTestFile "Examples\\SubExamples1\\SubExample2.qs" -let SubExample3 = makeTestFile "Examples\\SubExamples2\\SubExample3.qs" -let NestedExample1 = makeTestFile "Examples\\SubExamples2\\NestedExamples\\NestedExample1.qs" -let NestedExample2 = makeTestFile "Examples\\SubExamples2\\NestedExamples\\NestedExample2.qs" +let private Example1 = makeTestFile "Examples\\Example1.qs" +let private Example2 = makeTestFile "Examples\\Example2.qs" +let private SubExample1 = makeTestFile "Examples\\SubExamples1\\SubExample1.qs" +let private SubExample2 = makeTestFile "Examples\\SubExamples1\\SubExample2.qs" +let private SubExample3 = makeTestFile "Examples\\SubExamples2\\SubExample3.qs" +let private NestedExample1 = makeTestFile "Examples\\SubExamples2\\NestedExamples\\NestedExample1.qs" +let private NestedExample2 = makeTestFile "Examples\\SubExamples2\\NestedExamples\\NestedExample2.qs" -let StandardInputTest = +let private StandardInputTest = { Path = "-" Original = @@ -93,6 +106,15 @@ let StandardInputTest = |> standardizeNewLines Updated = "namespace StandardIn { function Bar() : Int { for i in 0..1 {} return 0; } } +" + |> standardizeNewLines + UpdatedAndFormatted = + "namespace StandardIn { + function Bar() : Int { + for i in 0..1 {} + return 0; + } +} " |> standardizeNewLines } @@ -125,23 +147,37 @@ let private run args input = Console.SetOut previousOutput Console.SetError previousError -let private runWithFiles isUpdate files standardInput expectedOutput args = +let private runWithFiles (commandKind: CommandKind) files standardInput expectedOutput args = try Assert.Equal(expectedOutput, run args standardInput) for file in files do let after = File.ReadAllText file.Path |> standardizeNewLines - let expected = (if isUpdate then file.Updated else file.Formatted) + + let expected = + match commandKind with + | Format -> file.Formatted + | Update -> file.Updated + | UpdateAndFormat -> file.UpdatedAndFormatted + Assert.Equal(expected, after) finally for file in files do File.WriteAllText(file.Path, file.Original) [] -let ``Updates file`` () = - runWithFiles true [ Example1 ] "" CleanResult [| "update"; Example1.Path |] +let ``Format file`` () = + runWithFiles Format [ Example1 ] "" CleanResult [| "format"; "-i"; Example1.Path |] + +[] +let ``Update file`` () = + runWithFiles Update [ Example1 ] "" CleanResult [| "update"; "-i"; Example1.Path |] [] +let ``Update and format file`` () = + runWithFiles UpdateAndFormat [ Example1 ] "" CleanResult [| "update-and-format"; "-i"; Example1.Path |] + +[] let ``Updates standard input`` () = Assert.Equal( { @@ -152,24 +188,23 @@ let ``Updates standard input`` () = run [| "update"; "-" |] StandardInputTest.Original ) -[] -[, Line 1, Character 16: mismatched input 'invalid' expecting {'function', 'internal', 'newtype', 'open', 'operation', '@', '}'} -")>] -let ``Shows syntax errors`` input errors = +[] +let ``Shows syntax errors`` () = Assert.Equal( { Code = 1 Out = "" - Error = errors |> standardizeNewLines + Error = + standardizeNewLines + "Examples\SyntaxError.qs, Line 1, Character 16: mismatched input 'invalid' expecting {'function', 'internal', 'newtype', 'open', 'operation', '@', '}'} +" }, - run [| "-" |] input + run [| "update"; "-i"; "Examples\\SyntaxError.qs" |] "" ) -[] -[] -let ``Shows file not found error`` path = - let result = run [| path |] "" +[] +let ``Shows file not found error`` () = + let result = run [| "update"; "-i"; "Examples\\NotFound.qs" |] "" Assert.Equal(3, result.Code) Assert.Empty result.Out Assert.NotEmpty result.Error @@ -178,27 +213,42 @@ let ``Shows file not found error`` path = let ``Input multiple files`` () = let files = [ Example1; Example2 ] - runWithFiles true files "" CleanResult [| "update"; Example1.Path; Example2.Path |] + runWithFiles Format files "" CleanResult [| "format"; "-i"; Example1.Path; Example2.Path |] + runWithFiles Update files "" CleanResult [| "update"; "-i"; Example1.Path; Example2.Path |] + runWithFiles UpdateAndFormat files "" CleanResult [| "update-and-format"; "-i"; Example1.Path; Example2.Path |] [] let ``Input directories`` () = let files = [ SubExample1; SubExample2; SubExample3 ] - runWithFiles true files "" CleanResult [| "update"; "Examples\\SubExamples1"; "Examples\\SubExamples2" |] + + runWithFiles Format files "" CleanResult [| "format"; "-i"; "Examples\\SubExamples1"; "Examples\\SubExamples2" |] + runWithFiles Update files "" CleanResult [| "update"; "-i"; "Examples\\SubExamples1"; "Examples\\SubExamples2" |] + + runWithFiles + UpdateAndFormat + files + "" + CleanResult + [| + "update-and-format" + "-i" + "Examples\\SubExamples1" + "Examples\\SubExamples2" + |] [] -let ``Input directories with files and stdin`` () = +let ``Input directories with files`` () = let files = [ Example1; SubExample1; SubExample2 ] - [| "update"; Example1.Path; "-"; "Examples\\SubExamples1" |] - |> runWithFiles - true + runWithFiles Format files "" CleanResult [| "format"; "-i"; Example1.Path; "Examples\\SubExamples1" |] + runWithFiles Update files "" CleanResult [| "update"; "-i"; Example1.Path; "Examples\\SubExamples1" |] + + runWithFiles + UpdateAndFormat files - StandardInputTest.Original - { - Code = 0 - Out = StandardInputTest.Updated - Error = "" - } + "" + CleanResult + [| "update-and-format"; "-i"; Example1.Path; "Examples\\SubExamples1" |] [] let ``Input directories with recursive flag`` () = @@ -212,34 +262,28 @@ let ``Input directories with recursive flag`` () = NestedExample2 ] - [| - "update" - "-r" - Example1.Path - "-" - "Examples\\SubExamples1" - "Examples\\SubExamples2" - |] - |> runWithFiles - true - files - StandardInputTest.Original - { - Code = 0 - Out = StandardInputTest.Updated - Error = "" - } + let args verb = + [| + verb + "-r" + "-i" + Example1.Path + "Examples\\SubExamples1" + "Examples\\SubExamples2" + |] + + args "format" |> runWithFiles Format files "" CleanResult + args "update" |> runWithFiles Update files "" CleanResult + args "update-and-format" |> runWithFiles UpdateAndFormat files "" CleanResult [] let ``Process correct files while erroring on incorrect`` () = let files = [ Example1; Example2 ] try - let result = - run [| "update"; Example1.Path; "-"; "Examples\\NotFound.qs"; Example2.Path |] StandardInputTest.Original + let result = run [| "update"; "-i"; Example1.Path; "Examples\\NotFound.qs"; Example2.Path |] "" Assert.Equal(3, result.Code) - Assert.Equal(StandardInputTest.Updated, result.Out) Assert.NotEmpty(result.Error) for file in files do @@ -254,16 +298,9 @@ let ``Backup flag`` () = let files = [ Example1; SubExample3 ] try - let result = run [| "update"; "-b"; "-"; Example1.Path; "Examples\\SubExamples2" |] StandardInputTest.Original + let result = run [| "update"; "-b"; "-i"; Example1.Path; "Examples\\SubExamples2" |] "" - Assert.Equal( - { - Code = 0 - Out = StandardInputTest.Updated - Error = "" - }, - result - ) + Assert.Equal(CleanResult, result) for file in files do let backup = file.Path + "~" @@ -292,11 +329,138 @@ This input has already been processed: Examples\Example1.qs |> standardizeNewLines } - [| - "update" - Example1.Path - "Examples\\SubExamples1" - SubExample1.Path - Example1.Path - |] - |> runWithFiles true files "" outputResult + let args verb = + [| + verb + "-i" + Example1.Path + "Examples\\SubExamples1" + SubExample1.Path + Example1.Path + |] + + args "format" |> runWithFiles Format files "" outputResult + args "update" |> runWithFiles Update files "" outputResult + args "update-and-format" |> runWithFiles UpdateAndFormat files "" outputResult + +[] +let ``Project file as input`` () = + + let makeTestFile (path: string) (index: int) = + { + Path = path + Original = File.ReadAllText path + Formatted = + index + |> sprintf + "namespace TestTarget { + function Bar%i() : Int { + for (i in 0..1) {} + return 0; + } +} +" + |> standardizeNewLines + Updated = + index + |> sprintf + "namespace TestTarget { function Bar%i() : Int { for i in 0..1 {} return 0; } } +" + |> standardizeNewLines + UpdatedAndFormatted = + index + |> sprintf + "namespace TestTarget { + function Bar%i() : Int { + for i in 0..1 {} + return 0; + } +} +" + |> standardizeNewLines + + } + + let TestTargetProgram = + let path = "Examples\\TestTarget\\Program.qs" + + { + Path = path + Original = File.ReadAllText path + Formatted = + "namespace TestTarget { + @EntryPoint() + operation Bar() : Unit { + for (i in 0..1) {} + } +} +" + |> standardizeNewLines + Updated = + "namespace TestTarget { @EntryPoint() operation Bar() : Unit { for i in 0..1 {} } } +" + |> standardizeNewLines + UpdatedAndFormatted = + "namespace TestTarget { + @EntryPoint() + operation Bar() : Unit { + for i in 0..1 {} + } +} +" + |> standardizeNewLines + } + + let TestTargetIncluded = makeTestFile "Examples\\TestTarget\\Included.qs" 1 + let TestTargetExcluded1 = makeTestFile "Examples\\TestTarget\\Excluded1.qs" 2 + let TestTargetExcluded2 = makeTestFile "Examples\\TestTarget\\Excluded2.qs" 3 + + + let files = [ TestTargetProgram; TestTargetIncluded ] + + let testCommand commandKind = + let verb = + match commandKind with + | Format -> "format" + | Update -> "update" + | UpdateAndFormat -> "update-and-format" + + [| verb; "-p"; "Examples\\TestTarget\\TestTarget.csproj" |] + |> runWithFiles commandKind files "" CleanResult + + let excluded1 = File.ReadAllText TestTargetExcluded1.Path + Assert.Equal(excluded1, TestTargetExcluded1.Original) + + let excluded2 = File.ReadAllText TestTargetExcluded2.Path + Assert.Equal(excluded2, TestTargetExcluded2.Original) + + testCommand Format + testCommand Update + testCommand UpdateAndFormat + +[] +let ``Outdated version project file as input`` () = + Assert.Equal( + { + Code = 6 + Out = "" + Error = + standardizeNewLines + "Error: Qdk Version is out of date. Only Qdk version 0.16.2104.138035 or later is supported. +" + }, + run [| "update"; "-p"; "Examples\\TestProjects\\OldVersion\\OldVersion.csproj" |] "" + ) + +[] +let ``Outdated system project file as input`` () = + let project = "Examples\\TestProjects\\OldApplication\\OldApplication.csproj" + let act = Action(fun () -> run [| "update"; "-p"; project |] "" |> ignore) + let ex = Assert.Throws(act) + + Assert.Equal( + ex.Message, + sprintf + "The given project file, %s is not a Q# project file. Please ensure your project file uses the Microsoft.Quantum.Sdk." + project + ) diff --git a/src/QsFmt/App/App.fsproj b/src/QsFmt/App/App.fsproj index cafe963286..4f5ab7054b 100644 --- a/src/QsFmt/App/App.fsproj +++ b/src/QsFmt/App/App.fsproj @@ -4,9 +4,23 @@ netcoreapp3.1 qsfmt Microsoft.Quantum.QsFmt.App + + MSB3277 + + + + + @@ -16,6 +30,10 @@ - + + + + + diff --git a/src/QsFmt/App/AssemblyInfo.fs b/src/QsFmt/App/AssemblyInfo.fs new file mode 100644 index 0000000000..8422068d78 --- /dev/null +++ b/src/QsFmt/App/AssemblyInfo.fs @@ -0,0 +1,6 @@ +module AssemblyInfo + +open System.Runtime.CompilerServices + +[] +do () diff --git a/src/QsFmt/App/CommandLineArguments.fs b/src/QsFmt/App/CommandLineArguments.fs new file mode 100644 index 0000000000..dcf42e015c --- /dev/null +++ b/src/QsFmt/App/CommandLineArguments.fs @@ -0,0 +1,259 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +module Microsoft.Quantum.QsFmt.App.Arguments + +open System +open System.IO +open System.Text.RegularExpressions +open CommandLine +open CommandLine.Text +open Microsoft.Quantum.QsFmt.App.DesignTimeBuild + +[