diff --git a/src/QsCompiler/CommandLineTool/Commands/Build.cs b/src/QsCompiler/CommandLineTool/Commands/Build.cs index 6ccd4b8b0d..ef31dbef64 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Build.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Build.cs @@ -206,7 +206,7 @@ public static int Run(BuildOptions options, ConsoleLogger logger) { ProjectName = options.ProjectName, AssemblyConstants = assemblyConstants, - TargetPackageAssemblies = options.TargetSpecificDecompositions, + TargetPackageAssemblies = options.TargetSpecificDecompositions ?? Enumerable.Empty(), RuntimeCapabilities = options.RuntimeCapabilites, SkipMonomorphization = options.RuntimeCapabilites == RuntimeCapabilities.Unknown, GenerateFunctorSupport = true, @@ -226,7 +226,11 @@ public static int Run(BuildOptions options, ConsoleLogger logger) CompilationLoader.CompilationTaskEvent += CompilationTracker.OnCompilationTaskEvent; } - var loaded = new CompilationLoader(options.LoadSourcesOrSnippet(logger), options.References, loadOptions, logger); + var loaded = new CompilationLoader( + options.LoadSourcesOrSnippet(logger), + options.References ?? Enumerable.Empty(), + loadOptions, + logger); if (options.PerfFolder != null) { try diff --git a/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs b/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs index 51094dc6ce..14fc8486bc 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs @@ -274,7 +274,7 @@ public static int Run(DiagnoseOptions options, ConsoleLogger logger) var loadOptions = new CompilationLoader.Configuration { AssemblyConstants = assemblyConstants, - TargetPackageAssemblies = options.TargetSpecificDecompositions, + TargetPackageAssemblies = options.TargetSpecificDecompositions ?? Enumerable.Empty(), RuntimeCapabilities = options.RuntimeCapabilites, SkipMonomorphization = options.RuntimeCapabilites == RuntimeCapabilities.Unknown, GenerateFunctorSupport = true, @@ -285,7 +285,11 @@ public static int Run(DiagnoseOptions options, ConsoleLogger logger) EnableAdditionalChecks = true, ExposeReferencesViaTestNames = options.ExposeReferencesViaTestNames }; - var loaded = new CompilationLoader(options.LoadSourcesOrSnippet(logger), options.References, loadOptions, logger); + var loaded = new CompilationLoader( + options.LoadSourcesOrSnippet(logger), + options.References ?? Enumerable.Empty(), + loadOptions, + logger); if (loaded.VerifiedCompilation == null) { return ReturnCode.Status(loaded); diff --git a/src/QsCompiler/CommandLineTool/Commands/Format.cs b/src/QsCompiler/CommandLineTool/Commands/Format.cs index 684bdda5be..7a77aa2bf4 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Format.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Format.cs @@ -175,11 +175,18 @@ ImmutableDictionary LoadSources(SourceFileLoader loadFromDisk) => options.LoadSourcesOrSnippet(logger)(loadFromDisk) .ToImmutableDictionary(entry => entry.Key, entry => UpdateArrayLiterals(entry.Value)); // manually replace array literals - var loaded = new CompilationLoader(LoadSources, options.References, logger: logger); // no rewrite steps, no generation + // no rewrite steps, no generation + var loaded = + new CompilationLoader(LoadSources, options.References ?? Enumerable.Empty(), logger: logger); if (ReturnCode.Status(loaded) == ReturnCode.UNRESOLVED_FILES) { return ReturnCode.UNRESOLVED_FILES; // ignore compilation errors } + else if (loaded.VerifiedCompilation is null) + { + logger.Log(ErrorCode.QsGenerationFailed, Enumerable.Empty()); + return ReturnCode.CODE_GENERATION_ERRORS; + } // TODO: a lot of the formatting logic defined here and also in the routines above // is supposed to move into the compilation manager in order to be available for the language server to provide formatting diff --git a/src/QsCompiler/CommandLineTool/CompilationTracker.cs b/src/QsCompiler/CommandLineTool/CompilationTracker.cs index c13ec95433..d46c54291d 100644 --- a/src/QsCompiler/CommandLineTool/CompilationTracker.cs +++ b/src/QsCompiler/CommandLineTool/CompilationTracker.cs @@ -26,7 +26,7 @@ private class CompilationTask /// /// Represents the name of the parent compilation task. /// - public readonly string ParentName; + public readonly string? ParentName; /// /// Represents the name of the compilation task. @@ -56,7 +56,7 @@ private class CompilationTask /// /// Generates a key that uniquely identifies a task in the compilation process based on the task's name and its parent's name. /// - internal static string GenerateKey(string parentName, string name) + internal static string GenerateKey(string? parentName, string name) { return string.Format("{0}.{1}", parentName ?? "ROOT", name); } @@ -64,7 +64,7 @@ internal static string GenerateKey(string parentName, string name) /// /// Creates a compilation task object and starts its stopwatch. /// - public CompilationTask(string parentName, string name) + public CompilationTask(string? parentName, string name) { this.ParentName = parentName; this.Name = name; diff --git a/src/QsCompiler/CommandLineTool/Options.cs b/src/QsCompiler/CommandLineTool/Options.cs index f637f3249e..7653d59ca8 100644 --- a/src/QsCompiler/CommandLineTool/Options.cs +++ b/src/QsCompiler/CommandLineTool/Options.cs @@ -298,17 +298,17 @@ public static bool IsCodeSnippet(NonNullable fileId) => /// internal CompilationLoader.SourceLoader LoadSourcesOrSnippet(ILogger logger) => loadFromDisk => { - bool inputIsEmptyOrNull = this.Input == null || !this.Input.Any(); - if (this.CodeSnippet == null && !inputIsEmptyOrNull) + var input = this.Input ?? Enumerable.Empty(); + if (this.CodeSnippet == null && input.Any()) { - return loadFromDisk(this.Input); + return loadFromDisk(input); } - else if (this.CodeSnippet != null && inputIsEmptyOrNull) + else if (this.CodeSnippet != null && !input.Any()) { return new Dictionary { { SNIPPET_FILE_URI, AsSnippet(this.CodeSnippet, this.WithinFunction) } }.ToImmutableDictionary(); } - if (inputIsEmptyOrNull) + if (!input.Any()) { logger?.Log(ErrorCode.MissingInputFileOrSnippet, Enumerable.Empty()); } diff --git a/src/QsCompiler/CompilationManager/Diagnostics.cs b/src/QsCompiler/CompilationManager/Diagnostics.cs index d0c8beb27a..f512056eb7 100644 --- a/src/QsCompiler/CompilationManager/Diagnostics.cs +++ b/src/QsCompiler/CompilationManager/Diagnostics.cs @@ -129,7 +129,7 @@ internal static string Warning(int code) => // warnings 70** - public static Diagnostic LoadWarning(WarningCode code, IEnumerable args, string source) => + public static Diagnostic LoadWarning(WarningCode code, IEnumerable args, string? source) => new Diagnostic { Severity = DiagnosticSeverity.Warning, @@ -164,7 +164,7 @@ internal static string Error(int code) => // errors 70** - public static Diagnostic LoadError(ErrorCode code, IEnumerable args, string source) => + public static Diagnostic LoadError(ErrorCode code, IEnumerable args, string? source) => new Diagnostic { Severity = DiagnosticSeverity.Error, diff --git a/src/QsCompiler/Compiler/CompilationLoader.cs b/src/QsCompiler/Compiler/CompilationLoader.cs index 71a7b8bc4f..de98c2002d 100644 --- a/src/QsCompiler/Compiler/CompilationLoader.cs +++ b/src/QsCompiler/Compiler/CompilationLoader.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -17,6 +18,7 @@ using Microsoft.Quantum.QsCompiler.ReservedKeywords; using Microsoft.Quantum.QsCompiler.Serialization; using Microsoft.Quantum.QsCompiler.SyntaxTree; +using Microsoft.Quantum.QsCompiler.Transformations; using Microsoft.Quantum.QsCompiler.Transformations.BasicTransformations; using Microsoft.VisualStudio.LanguageServer.Protocol; using Newtonsoft.Json.Bson; @@ -44,10 +46,10 @@ public enum CompilationTaskEventType public class CompilationTaskEventArgs : EventArgs { public CompilationTaskEventType Type; - public string ParentTaskName; + public string? ParentTaskName; public string TaskName; - public CompilationTaskEventArgs(CompilationTaskEventType type, string parentTaskName, string taskName) + public CompilationTaskEventArgs(CompilationTaskEventType type, string? parentTaskName, string taskName) { this.ParentTaskName = parentTaskName; this.TaskName = taskName; @@ -75,12 +77,12 @@ public CompilationTaskEventArgs(CompilationTaskEventType type, string parentTask /// /// Used to raise a compilation task event. /// - public static event CompilationTaskEventHandler CompilationTaskEvent; + public static event CompilationTaskEventHandler? CompilationTaskEvent; /// /// If LoadAssembly is not null, it will be used to load the dlls that are search for classes defining rewrite steps. /// - public static Func LoadAssembly { get; set; } + public static Func? LoadAssembly { get; set; } /// /// Sorts the given list of step according to their relative priority give by getPriority. @@ -98,7 +100,7 @@ public struct Configuration /// The name of the project. Used as assembly name in the generated dll. /// The name of the project with a suitable extension will also be used as the name of the generated binary file. /// - public string ProjectName; + public string? ProjectName; /// /// If set to true, the syntax tree rewrite step that replaces all generation directives @@ -148,13 +150,13 @@ public struct Configuration /// Directory where the compiled binaries will be generated. /// No binaries will be written to disk unless this path is specified and valid. /// - public string BuildOutputFolder; + public string? BuildOutputFolder; /// /// Output path for the dll containing the compiled binaries. /// No dll will be generated unless this path is specified and valid. /// - public string DllOutputPath; + public string? DllOutputPath; /// /// If set to true, then referenced dlls will be loaded purely based on attributes in the contained C# code. @@ -173,7 +175,7 @@ public struct Configuration /// (i.e. classes implementing IRewriteStep) and the corresponding output folder. /// The contained rewrite steps will be executed in the defined order and priority at the end of the compilation. /// - public IEnumerable<(string, string)> RewriteSteps; + public IEnumerable<(string, string?)> RewriteSteps; /// /// If set to true, the post-condition for loaded rewrite steps is checked if the corresponding verification is implemented. @@ -219,7 +221,7 @@ public struct Configuration /// If the ProjectName does not have an ending "proj", appends a .qsproj ending to the project name. /// Returns null if the project name is null. /// - internal string ProjectNameWithExtension => + internal string? ProjectNameWithExtension => this.ProjectName == null ? null : this.ProjectName.EndsWith("proj") ? this.ProjectName : $"{this.ProjectName}.qsproj"; @@ -228,7 +230,7 @@ public struct Configuration /// If the ProjectName does have an extension ending with "proj", returns the project name without that extension. /// Returns null if the project name is null. /// - internal string ProjectNameWithoutExtension => + internal string? ProjectNameWithoutExtension => this.ProjectName == null ? null : Path.GetExtension(this.ProjectName).EndsWith("proj") ? Path.GetFileNameWithoutExtension(this.ProjectName) : this.ProjectName; @@ -366,7 +368,7 @@ internal bool Success(Configuration options) => /// Returns a status NotRun if no such step was found or executed. /// Execution is considered successful if the precondition and transformation (if any) returned true. /// - public Status LoadedRewriteStep(string name, string source = null) + public Status LoadedRewriteStep(string name, string? source = null) { var uri = string.IsNullOrWhiteSpace(source) ? null : new Uri(Path.GetFullPath(source)); bool MatchesQuery(int index) => this.externalRewriteSteps[index].Name == name && (source == null || this.externalRewriteSteps[index].Origin == uri); @@ -389,7 +391,7 @@ public Status LoadedRewriteStep(string name, string source = null) /// /// Logger used to log all diagnostic events during compilation. /// - private readonly ILogger logger; + private readonly ILogger? logger; /// /// Configuration specifying the compilation steps to execute. @@ -416,27 +418,27 @@ public Status LoadedRewriteStep(string name, string source = null) /// /// Contains the initial compilation built by the compilation unit manager after verification. /// - public readonly CompilationUnitManager.Compilation VerifiedCompilation; + public readonly CompilationUnitManager.Compilation? VerifiedCompilation; /// /// Contains the built compilation including the syntax tree after executing all configured rewrite steps. /// - public readonly QsCompilation CompilationOutput; + public readonly QsCompilation? CompilationOutput; /// /// Contains the absolute path where the binary representation of the generated syntax tree has been written to disk. /// - public readonly string PathToCompiledBinary; + public readonly string? PathToCompiledBinary; /// /// Contains the absolute path where the generated dll containing the compiled binary has been written to disk. /// - public readonly string DllOutputPath; + public readonly string? DllOutputPath; /// /// Contains the full Q# syntax tree after executing all configured rewrite steps, including the content of loaded references. /// - public IEnumerable GeneratedSyntaxTree => + public IEnumerable? GeneratedSyntaxTree => this.CompilationOutput?.Namespaces; /// @@ -452,7 +454,7 @@ public Status LoadedRewriteStep(string name, string source = null) /// Uses the specified logger to log all diagnostic events. /// Throws an ArgumentNullException if either one of the given loaders is null or returns null. /// - public CompilationLoader(SourceLoader loadSources, ReferenceLoader loadReferences, Configuration? options = null, ILogger logger = null) + public CompilationLoader(SourceLoader loadSources, ReferenceLoader loadReferences, Configuration? options = null, ILogger? logger = null) { this.RaiseCompilationTaskStart(null, "OverallCompilation"); @@ -536,7 +538,7 @@ public CompilationLoader(SourceLoader loadSources, ReferenceLoader loadReference // executing the specified rewrite steps - var steps = new List<(int, Func)>(); + var steps = new List<(int, Func)>(); if (this.config.ConvertClassicalControl) { @@ -571,7 +573,7 @@ public CompilationLoader(SourceLoader loadSources, ReferenceLoader loadReference for (int j = 0; j < this.externalRewriteSteps.Length; j++) { var priority = this.externalRewriteSteps[j].Priority; - Func Execute(int index) => () => + Func Execute(int index) => () => this.ExecuteAsAtomicTransformation(this.externalRewriteSteps[index], ref this.compilationStatus.LoadedRewriteSteps[index]); steps.Add((priority, Execute(j))); } @@ -630,7 +632,7 @@ Func Execute(int index) => () => /// executing the compilation steps specified by the given options. /// Uses the specified logger to log all diagnostic events. /// - public CompilationLoader(IEnumerable sources, IEnumerable references, Configuration? options = null, ILogger logger = null) + public CompilationLoader(IEnumerable sources, IEnumerable references, Configuration? options = null, ILogger? logger = null) : this(load => load(sources), load => load(references), options, logger) { } @@ -641,7 +643,7 @@ public CompilationLoader(IEnumerable sources, IEnumerable refere /// Uses the specified logger to log all diagnostic events. /// Throws an ArgumentNullException if the given loader is null or returns null. /// - public CompilationLoader(IEnumerable sources, ReferenceLoader loadReferences, Configuration? options = null, ILogger logger = null) + public CompilationLoader(IEnumerable sources, ReferenceLoader loadReferences, Configuration? options = null, ILogger? logger = null) : this(load => load(sources), loadReferences, options, logger) { } @@ -652,7 +654,7 @@ public CompilationLoader(IEnumerable sources, ReferenceLoader loadRefere /// Uses the specified logger to log all diagnostic events. /// Throws an ArgumentNullException if the given loader is null or returns null. /// - public CompilationLoader(SourceLoader loadSources, IEnumerable references, Configuration? options = null, ILogger logger = null) + public CompilationLoader(SourceLoader loadSources, IEnumerable references, Configuration? options = null, ILogger? logger = null) : this(loadSources, load => load(references), options, logger) { } @@ -721,7 +723,7 @@ private void PrintResolvedFiles(IEnumerable sourceFiles) return; } var args = sourceFiles.Any() - ? sourceFiles.Select(f => f?.LocalPath).ToArray() + ? sourceFiles.Select(f => f.LocalPath).ToArray() : new string[] { "(none)" }; this.logger?.Log(InformationCode.CompilingWithSourceFiles, Enumerable.Empty(), messageParam: Formatting.Indent(args).ToArray()); } @@ -763,22 +765,22 @@ private void PrintLoadedRewriteSteps(IEnumerable rewrit /// /// Raises a compilation task start event. /// - private void RaiseCompilationTaskStart(string parentTaskName, string taskName) => + private void RaiseCompilationTaskStart(string? parentTaskName, string taskName) => CompilationTaskEvent?.Invoke(this, new CompilationTaskEventArgs(CompilationTaskEventType.Start, parentTaskName, taskName)); /// /// Raises a compilation task end event. /// - private void RaiseCompilationTaskEnd(string parentTaskName, string taskName) => + private void RaiseCompilationTaskEnd(string? parentTaskName, string taskName) => CompilationTaskEvent?.Invoke(this, new CompilationTaskEventArgs(CompilationTaskEventType.End, parentTaskName, taskName)); /// /// Executes the given rewrite step on the current CompilationOutput, and updates the given status accordingly. /// Sets the CompilationOutput to the transformed compilation if the status indicates success. /// - private QsCompilation ExecuteAsAtomicTransformation(RewriteSteps.LoadedStep rewriteStep, ref Status status) + private QsCompilation? ExecuteAsAtomicTransformation(RewriteSteps.LoadedStep rewriteStep, ref Status status) { - QsCompilation transformed = null; + QsCompilation? transformed = null; if (this.compilationStatus.Validation != Status.Succeeded) { status = Status.NotRun; @@ -799,7 +801,7 @@ private QsCompilation ExecuteAsAtomicTransformation(RewriteSteps.LoadedStep rewr /// Returns the unmodified CompilationOutput otherwise. /// Throws an ArgumentNullException if the given sequence of paths is null. /// - private QsCompilation ReplaceTargetSpecificImplementations(IEnumerable paths, Uri rewriteStepOrigin, int nrReferences) + private QsCompilation? ReplaceTargetSpecificImplementations(IEnumerable paths, Uri rewriteStepOrigin, int nrReferences) { if (paths == null) { @@ -814,8 +816,7 @@ private QsCompilation ReplaceTargetSpecificImplementations(IEnumerable p try { var targetDll = Path.GetFullPath(path); - var loadSucceeded = AssemblyLoader.LoadReferencedAssembly(targetDll, out var loaded, LogException); - if (loadSucceeded) + if (AssemblyLoader.LoadReferencedAssembly(targetDll, out var loaded, LogException)) { return (NonNullable.New(path), loaded.Namespaces); } @@ -830,7 +831,7 @@ private QsCompilation ReplaceTargetSpecificImplementations(IEnumerable p } } - var natives = paths.Select(LoadReferences).Where(loaded => loaded.HasValue).Select(loaded => loaded.Value).ToArray(); + var natives = paths.SelectNotNull(LoadReferences).ToArray(); var combinedSuccessfully = References.CombineSyntaxTrees(out var replacements, additionalAssemblies: nrReferences, onError: LogError, natives); if (!combinedSuccessfully) { @@ -847,7 +848,7 @@ private QsCompilation ReplaceTargetSpecificImplementations(IEnumerable p /// Catches and logs any thrown exception. Returns the status of the rewrite step. /// Throws an ArgumentNullException if the rewrite step to execute or the given compilation is null. /// - private Status ExecuteRewriteStep(RewriteSteps.LoadedStep rewriteStep, QsCompilation compilation, out QsCompilation transformed) + private Status ExecuteRewriteStep(RewriteSteps.LoadedStep rewriteStep, QsCompilation? compilation, out QsCompilation? transformed) { if (rewriteStep == null) { @@ -858,7 +859,7 @@ private Status ExecuteRewriteStep(RewriteSteps.LoadedStep rewriteStep, QsCompila throw new ArgumentNullException(nameof(compilation)); } - string GetDiagnosticsCode(DiagnosticSeverity severity) => + string? GetDiagnosticsCode(DiagnosticSeverity severity) => rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Error ? Errors.Code(ErrorCode.CsharpGenerationGeneratedError) : rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Warning ? Warnings.Code(WarningCode.CsharpGenerationGeneratedWarning) : rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Information ? Informations.Code(InformationCode.CsharpGenerationGeneratedInfo) : @@ -1019,7 +1020,7 @@ void LogError() => this.LogAndUpdate( /// Does *not* close the given memory stream. /// Throws an ArgumentNullException if the given memory stream is null. /// - private string GenerateBinary(MemoryStream serialization) + private string? GenerateBinary(MemoryStream serialization) { if (serialization == null) { @@ -1058,7 +1059,7 @@ private string GenerateBinary(MemoryStream serialization) /// Does *not* close the given memory stream. /// Throws an ArgumentNullException if the given memory stream is null. /// - private string GenerateDll(MemoryStream serialization) + private string? GenerateDll(MemoryStream serialization) { if (serialization == null) { @@ -1097,7 +1098,8 @@ bool CanBeIncluded(NonNullable dll) try { - var referencePaths = GetSourceFiles.Apply(this.CompilationOutput.Namespaces) // we choose to keep only Q# references that have been used + var referencePaths = this.CompilationOutput?.Namespaces + .Apply(ns => GetSourceFiles.Apply(ns)) // we choose to keep only Q# references that have been used .Where(file => file.Value.EndsWith(".dll")); var references = referencePaths.Select((dll, id) => (dll, CreateReference(dll.Value, id), CanBeIncluded(dll))).ToImmutableArray(); var csharpTree = MetadataGeneration.GenerateAssemblyMetadata(references.Where(r => r.Item3).Select(r => r.Item2)); @@ -1140,14 +1142,14 @@ bool CanBeIncluded(NonNullable dll) /// Given the path to a Q# binary file, reads the content of that file and returns the corresponding compilation as out parameter. /// Throws the corresponding exception if the given path does not correspond to a suitable binary file. /// - public static bool ReadBinary(string file, out QsCompilation syntaxTree) => + public static bool ReadBinary(string file, [NotNullWhen(true)] out QsCompilation? syntaxTree) => ReadBinary(new MemoryStream(File.ReadAllBytes(Path.GetFullPath(file))), out syntaxTree); /// /// Given a stream with the content of a Q# binary file, returns the corresponding compilation as out parameter. /// Throws an ArgumentNullException if the given stream is null. /// - public static bool ReadBinary(Stream stream, out QsCompilation syntaxTree) => + public static bool ReadBinary(Stream stream, [NotNullWhen(true)] out QsCompilation? syntaxTree) => AssemblyLoader.LoadSyntaxTree(stream, out syntaxTree); /// @@ -1157,7 +1159,7 @@ public static bool ReadBinary(Stream stream, out QsCompilation syntaxTree) => /// Throws an ArgumentException if the given file id is incompatible with and id assigned by the Q# compiler. /// Throws the corresponding exception any of the path operations fails or if the writing fails. /// - public static string GeneratedFile(NonNullable fileId, string outputFolder, string fileEnding, string content = null) + public static string GeneratedFile(NonNullable fileId, string outputFolder, string fileEnding, string? content = null) { if (!CompilationUnitManager.TryGetUri(fileId, out var file)) { diff --git a/src/QsCompiler/Compiler/Compiler.csproj b/src/QsCompiler/Compiler/Compiler.csproj index 2a5f429a9d..0aa3b0593f 100644 --- a/src/QsCompiler/Compiler/Compiler.csproj +++ b/src/QsCompiler/Compiler/Compiler.csproj @@ -6,6 +6,8 @@ Microsoft.Quantum.Compiler Microsoft.Quantum.QsCompiler Microsoft Q# compiler library. + enable + nullable diff --git a/src/QsCompiler/Compiler/ExternalRewriteSteps.cs b/src/QsCompiler/Compiler/ExternalRewriteSteps.cs index 934cfe74df..7dcfff6941 100644 --- a/src/QsCompiler/Compiler/ExternalRewriteSteps.cs +++ b/src/QsCompiler/Compiler/ExternalRewriteSteps.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -12,8 +13,8 @@ using Microsoft.Quantum.QsCompiler.Diagnostics; using Microsoft.Quantum.QsCompiler.ReservedKeywords; using Microsoft.Quantum.QsCompiler.SyntaxTree; +using Microsoft.Quantum.QsCompiler.Transformations; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Lsp = Microsoft.VisualStudio.LanguageServer.Protocol; using Range = Microsoft.Quantum.QsCompiler.DataTypes.Range; namespace Microsoft.Quantum.QsCompiler @@ -26,28 +27,30 @@ internal static class RewriteSteps internal class LoadedStep : IRewriteStep { internal readonly Uri Origin; - private readonly IRewriteStep selfAsStep; + private readonly IRewriteStep? selfAsStep; private readonly object selfAsObject; - private readonly MethodInfo[] interfaceMethods; + private readonly MethodInfo[]? interfaceMethods; - private MethodInfo InterfaceMethod(string name) => + private MethodInfo? InterfaceMethod(string name) => // This choice of filtering the interface methods may seem a bit particular. // However, unless you know what you are doing, please don't change it. // If you are sure you know what you are doing, please make sure the loading via reflection works for rewrite steps // implemented in both F# or C#, and whether they are compiled against the current compiler version or an older one. this.interfaceMethods?.FirstOrDefault(method => method.Name.Split("-").Last() == name); - private object GetViaReflection(string name) => + private object? GetViaReflection(string name) => this.InterfaceMethod($"get_{name}")?.Invoke(this.selfAsObject, null); + [return: MaybeNull] private T GetViaReflection(string name) => (T)this.InterfaceMethod($"get_{name}")?.Invoke(this.selfAsObject, null); private void SetViaReflection(string name, T arg) => - this.InterfaceMethod($"set_{name}")?.Invoke(this.selfAsObject, new object[] { arg }); + this.InterfaceMethod($"set_{name}")?.Invoke(this.selfAsObject, new object?[] { arg }); - private T InvokeViaReflection(string name, params object[] args) => + [return: MaybeNull] + private T InvokeViaReflection(string name, params object?[] args) => (T)this.InterfaceMethod(name)?.Invoke(this.selfAsObject, args); /// @@ -75,7 +78,9 @@ internal LoadedStep(object implementation, Type interfaceType, Uri origin) // The Name and Priority need to be fixed throughout the loading, // so whatever their value is when loaded that's what these values well be as far at the compiler is concerned. - this.Name = this.selfAsStep?.Name ?? this.GetViaReflection(nameof(IRewriteStep.Name)); + this.Name = this.selfAsStep?.Name + ?? this.GetViaReflection(nameof(IRewriteStep.Name)) + ?? "(no name)"; this.Priority = this.selfAsStep?.Priority ?? this.GetViaReflection(nameof(IRewriteStep.Priority)); } @@ -83,7 +88,7 @@ internal LoadedStep(object implementation, Type interfaceType, Uri origin) public int Priority { get; } - internal static Diagnostic ConvertDiagnostic(IRewriteStep.Diagnostic diagnostic, Func getCode = null) + internal static Diagnostic ConvertDiagnostic(IRewriteStep.Diagnostic diagnostic, Func? getCode = null) { var severity = diagnostic.Severity == CodeAnalysis.DiagnosticSeverity.Error ? DiagnosticSeverity.Error : @@ -108,10 +113,11 @@ internal static Diagnostic ConvertDiagnostic(IRewriteStep.Diagnostic diagnostic, }; } - public IDictionary AssemblyConstants + public IDictionary AssemblyConstants { get => this.selfAsStep?.AssemblyConstants - ?? this.GetViaReflection>(nameof(IRewriteStep.AssemblyConstants)); + ?? this.GetViaReflection>(nameof(IRewriteStep.AssemblyConstants)) + ?? ImmutableDictionary.Empty; } public IEnumerable GeneratedDiagnostics @@ -125,9 +131,9 @@ public IEnumerable GeneratedDiagnostics static bool IEnumerableInterface(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>); var enumerable = this.GetViaReflection(nameof(IRewriteStep.GeneratedDiagnostics)) as IEnumerable; var itemType = enumerable?.GetType().GetInterfaces().FirstOrDefault(IEnumerableInterface)?.GetGenericArguments().FirstOrDefault(); - if (itemType == null) + if (enumerable is null || itemType is null) { - return null; + return Enumerable.Empty(); } var diagnostics = ImmutableArray.CreateBuilder(); @@ -167,15 +173,15 @@ public bool ImplementsPostconditionVerification ?? this.GetViaReflection(nameof(IRewriteStep.ImplementsPostconditionVerification)); } - public bool Transformation(QsCompilation compilation, out QsCompilation transformed) + public bool Transformation(QsCompilation compilation, [NotNullWhen(true)] out QsCompilation? transformed) { if (this.selfAsStep != null) { return this.selfAsStep.Transformation(compilation, out transformed); } - var args = new object[] { compilation, null }; + var args = new object?[] { compilation, null }; var success = this.InvokeViaReflection(nameof(IRewriteStep.Transformation), args); - transformed = success ? (QsCompilation)args[1] : compilation; + transformed = success ? args[1] as QsCompilation ?? compilation : compilation; return success; } @@ -183,9 +189,10 @@ public bool PreconditionVerification(QsCompilation compilation) => this.selfAsStep?.PreconditionVerification(compilation) ?? this.InvokeViaReflection(nameof(IRewriteStep.PreconditionVerification), compilation); - public bool PostconditionVerification(QsCompilation compilation) => - this.selfAsStep?.PostconditionVerification(compilation) - ?? this.InvokeViaReflection(nameof(IRewriteStep.PostconditionVerification), compilation); + public bool PostconditionVerification(QsCompilation? compilation) => + !(compilation is null) + && (this.selfAsStep?.PostconditionVerification(compilation) + ?? this.InvokeViaReflection(nameof(IRewriteStep.PostconditionVerification), compilation)); } /// @@ -199,15 +206,15 @@ public bool PostconditionVerification(QsCompilation compilation) => /// internal static ImmutableArray Load( CompilationLoader.Configuration config, - Action onDiagnostic = null, - Action onException = null) + Action? onDiagnostic = null, + Action? onException = null) { if (config.RewriteSteps == null) { return ImmutableArray.Empty; } static Assembly LoadAssembly(string path) => CompilationLoader.LoadAssembly?.Invoke(path) ?? Assembly.LoadFrom(path); - Uri WithFullPath(string file) + Uri? WithFullPath(string file) { try { @@ -221,7 +228,7 @@ Uri WithFullPath(string file) } } - var specifiedPluginDlls = config.RewriteSteps.Select(step => (WithFullPath(step.Item1), step.Item2)).Where(step => step.Item1 != null).ToList(); + var specifiedPluginDlls = config.RewriteSteps.SelectNotNull(step => WithFullPath(step.Item1)?.Apply(path => (path, step.Item2))); var (foundDlls, notFoundDlls) = specifiedPluginDlls.Partition(step => File.Exists(step.Item1.LocalPath)); foreach (var file in notFoundDlls.Select(step => step.Item1).Distinct()) { diff --git a/src/QsCompiler/Compiler/FunctorGeneration.cs b/src/QsCompiler/Compiler/FunctorGeneration.cs index dec2d358b8..a7ca06fc62 100644 --- a/src/QsCompiler/Compiler/FunctorGeneration.cs +++ b/src/QsCompiler/Compiler/FunctorGeneration.cs @@ -19,7 +19,7 @@ public static class CodeGeneration /// Given the argument tuple of a specialization, returns the argument tuple for its controlled version. /// Returns null if the given argument tuple is null. /// - private static QsTuple> ControlledArg(QsTuple> arg) => + private static QsTuple>? ControlledArg(QsTuple> arg) => arg != null ? SyntaxGenerator.WithControlQubits( arg, @@ -33,7 +33,7 @@ private static QsTuple> ControlledArg(Qs /// Throws an ArgumentException if more than one specialization of that kind exist. /// Throws an ArgumentNullException if the sequence of specializations is null, or contains any entries that are null. /// - private static QsSpecialization GetSpecialization(this IEnumerable specs, QsSpecializationKind kind) + private static QsSpecialization? GetSpecialization(this IEnumerable specs, QsSpecializationKind kind) { if (specs == null || specs.Any(s => s == null)) { @@ -51,7 +51,7 @@ private static QsSpecialization GetSpecialization(this IEnumerable - private static (QsTuple>, QsScope)? GetContent(this SpecializationImplementation impl) => + private static (QsTuple>, QsScope)? GetContent(this SpecializationImplementation? impl) => impl is SpecializationImplementation.Provided content ? (content.Item1, content.Item2) : ((QsTuple>, QsScope)?)null; @@ -202,7 +202,7 @@ private static QsCallable BuildControlledAdjoint(this QsCallable callable) /// Returns a boolean indicating if the evaluation of all directives was successful. /// Throws an ArgumentNullException (that is not logged or ignored) if the given compilation is null. /// - public static bool GenerateFunctorSpecializations(QsCompilation compilation, out QsCompilation built, Action onException = null) + public static bool GenerateFunctorSpecializations(QsCompilation compilation, out QsCompilation built, Action? onException = null) { if (compilation == null) { diff --git a/src/QsCompiler/Compiler/Logging.cs b/src/QsCompiler/Compiler/Logging.cs index 72252a2f3d..5b5cf77a40 100644 --- a/src/QsCompiler/Compiler/Logging.cs +++ b/src/QsCompiler/Compiler/Logging.cs @@ -13,11 +13,11 @@ namespace Microsoft.Quantum.QsCompiler.Diagnostics { public interface ILogger { - void Log(ErrorCode item, IEnumerable args, string source = null, LSP.Range range = null); + void Log(ErrorCode item, IEnumerable args, string? source = null, LSP.Range? range = null); - void Log(WarningCode item, IEnumerable args, string source = null, LSP.Range range = null); + void Log(WarningCode item, IEnumerable args, string? source = null, LSP.Range? range = null); - void Log(InformationCode item, IEnumerable args, string source = null, LSP.Range range = null, params string[] messageParam); + void Log(InformationCode item, IEnumerable args, string? source = null, LSP.Range? range = null, params string[] messageParam); void Log(params Diagnostic[] messages); @@ -39,7 +39,7 @@ public abstract class LogTracker : ILogger public LogTracker( DiagnosticSeverity verbosity = DiagnosticSeverity.Warning, - IEnumerable noWarn = null, + IEnumerable? noWarn = null, int lineNrOffset = 0) { this.Verbosity = verbosity; @@ -75,7 +75,7 @@ protected internal virtual void OnException(Exception ex) => /// Logs a diagnostic message based on the given error code, /// with the given source as the file for which the error occurred. /// - public void Log(ErrorCode code, IEnumerable args, string source = null, LSP.Range range = null) => + public void Log(ErrorCode code, IEnumerable args, string? source = null, LSP.Range? range = null) => this.Log(new Diagnostic { Severity = DiagnosticSeverity.Error, @@ -89,7 +89,7 @@ public void Log(ErrorCode code, IEnumerable args, string source = null, /// Logs a a diagnostic message based on the given warning code, /// with the given source as the file for which the error occurred. /// - public void Log(WarningCode code, IEnumerable args, string source = null, LSP.Range range = null) => + public void Log(WarningCode code, IEnumerable args, string? source = null, LSP.Range? range = null) => this.Log(new Diagnostic { Severity = DiagnosticSeverity.Warning, @@ -104,7 +104,7 @@ public void Log(WarningCode code, IEnumerable args, string source = null /// with any message parameters appended on a new line to the message defined by the information code. /// The given source is listed as the file for which the error occurred. /// - public void Log(InformationCode code, IEnumerable args, string source = null, LSP.Range range = null, params string[] messageParam) => + public void Log(InformationCode code, IEnumerable args, string? source = null, LSP.Range? range = null, params string[] messageParam) => this.Log(new Diagnostic { Severity = DiagnosticSeverity.Information, @@ -140,7 +140,7 @@ public void Log(params Diagnostic[] messages) /// Calls Print on the given diagnostic if the verbosity is sufficiently high. /// Does nothing if the given diagnostic is null. /// - private void Output(Diagnostic msg) + private void Output(Diagnostic? msg) { if (msg?.Severity <= this.Verbosity) { @@ -198,7 +198,7 @@ public void Log(Exception ex) public static class Formatting { - public static IEnumerable Indent(params string[] items) => + public static IEnumerable? Indent(params string[] items) => items?.Select(msg => $" {msg}"); /// diff --git a/src/QsCompiler/Compiler/PluginInterface.cs b/src/QsCompiler/Compiler/PluginInterface.cs index 46ecb3f6fa..83d007a10f 100644 --- a/src/QsCompiler/Compiler/PluginInterface.cs +++ b/src/QsCompiler/Compiler/PluginInterface.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.Quantum.QsCompiler.CompilationBuilder; using Microsoft.Quantum.QsCompiler.DataTypes; @@ -67,13 +68,13 @@ public struct Diagnostic /// /// Diagnostic message to be displayed to the user. /// - public string Message { get; set; } + public string? Message { get; set; } /// /// Absolute path of the file where the code that caused the generation of the diagnostic is located. /// The source is null if the diagnostic is not caused by a piece of source code. /// - public string Source { get; set; } + public string? Source { get; set; } /// /// The stage during which the diagnostic was generated. @@ -85,13 +86,13 @@ public struct Diagnostic /// Zero-based range in the source file of the code that caused the generation of the diagnostic. /// The range is null if the diagnostic is not caused by a piece of source code. /// - public Range Range { get; set; } + public Range? Range { get; set; } /// /// Initializes a new diagnostic. /// If a diagnostic generated by the Q# compiler is given as argument, the values are initialized accordingly. /// - public static Diagnostic Create(VS.Diagnostic d = null, Stage stage = Stage.Unknown) => + public static Diagnostic Create(VS.Diagnostic? d = null, Stage stage = Stage.Unknown) => d == null ? default : new Diagnostic { Severity = d.Severity switch @@ -123,7 +124,7 @@ public static Diagnostic Create(VS.Diagnostic d = null, Stage stage = Stage.Unkn /// Dictionary that will be populated by the Q# compiler when the rewrite step is loaded. /// It contains the assembly constants for the Q# compilation unit on which the rewrite step is acting. /// - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } /// /// Contains diagnostics generated by the rewrite step and intended for display to the user. @@ -173,7 +174,7 @@ public static Diagnostic Create(VS.Diagnostic d = null, Stage stage = Stage.Unkn /// Q# compilation that satisfies the implemented precondition, if any. /// Q# compilation after transformation. This value should not be null if the transformation succeeded. /// Whether or not the transformation succeeded. - public bool Transformation(QsCompilation compilation, out QsCompilation transformed); + public bool Transformation(QsCompilation compilation, [NotNullWhen(true)] out QsCompilation? transformed); /// /// Verifies whether a given compilation satisfies the postcondition after executing the implemented transformation (if any). diff --git a/src/QsCompiler/Compiler/Process.cs b/src/QsCompiler/Compiler/Process.cs index 0bce9973a8..149f3f28c2 100644 --- a/src/QsCompiler/Compiler/Process.cs +++ b/src/QsCompiler/Compiler/Process.cs @@ -16,7 +16,7 @@ public static class ProcessRunner /// Returns true if the process completed within the specified time without throwing an exception, and false otherwise. /// Any thrown exception is returned as out parameter. /// - public static bool Run(Process process, StringBuilder output, StringBuilder error, out Exception ex, int timeout) + 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)) @@ -86,8 +86,8 @@ public static bool Run( out StringBuilder outstream, out StringBuilder errstream, out int exitCode, - out Exception ex, - IDictionary envVariables = null, + out Exception? ex, + IDictionary? envVariables = null, int timeout = 10000) { var process = new Process(); diff --git a/src/QsCompiler/Compiler/RewriteSteps/ClassicallyControlled.cs b/src/QsCompiler/Compiler/RewriteSteps/ClassicallyControlled.cs index 01e2b236cf..77462e531a 100644 --- a/src/QsCompiler/Compiler/RewriteSteps/ClassicallyControlled.cs +++ b/src/QsCompiler/Compiler/RewriteSteps/ClassicallyControlled.cs @@ -19,9 +19,9 @@ internal class ClassicallyControlled : IRewriteStep public int Priority => RewriteStepPriorities.ControlFlowSubstitutions; - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } - public IEnumerable GeneratedDiagnostics => null; + public IEnumerable GeneratedDiagnostics => Enumerable.Empty(); public bool ImplementsPreconditionVerification => true; @@ -31,7 +31,7 @@ internal class ClassicallyControlled : IRewriteStep public ClassicallyControlled() { - this.AssemblyConstants = new Dictionary(); + this.AssemblyConstants = new Dictionary(); } public bool PreconditionVerification(QsCompilation compilation) diff --git a/src/QsCompiler/Compiler/RewriteSteps/ConjugationInlining.cs b/src/QsCompiler/Compiler/RewriteSteps/ConjugationInlining.cs index 6de6fd5167..c4af9007b5 100644 --- a/src/QsCompiler/Compiler/RewriteSteps/ConjugationInlining.cs +++ b/src/QsCompiler/Compiler/RewriteSteps/ConjugationInlining.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Linq; using Microsoft.Quantum.QsCompiler.SyntaxTree; namespace Microsoft.Quantum.QsCompiler.BuiltInRewriteSteps @@ -15,9 +16,9 @@ internal class ConjugationInlining : IRewriteStep public int Priority => RewriteStepPriorities.InliningOfConjugations; - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } - public IEnumerable GeneratedDiagnostics => null; + public IEnumerable GeneratedDiagnostics => Enumerable.Empty(); public bool ImplementsPreconditionVerification => false; @@ -27,7 +28,7 @@ internal class ConjugationInlining : IRewriteStep public ConjugationInlining() { - this.AssemblyConstants = new Dictionary(); + this.AssemblyConstants = new Dictionary(); } public bool PreconditionVerification(QsCompilation compilation) diff --git a/src/QsCompiler/Compiler/RewriteSteps/FullPreEvaluation.cs b/src/QsCompiler/Compiler/RewriteSteps/FullPreEvaluation.cs index 4c08854840..0dc7e5c83b 100644 --- a/src/QsCompiler/Compiler/RewriteSteps/FullPreEvaluation.cs +++ b/src/QsCompiler/Compiler/RewriteSteps/FullPreEvaluation.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Linq; using Microsoft.Quantum.QsCompiler.SyntaxTree; namespace Microsoft.Quantum.QsCompiler.BuiltInRewriteSteps @@ -15,9 +16,9 @@ internal class FullPreEvaluation : IRewriteStep public int Priority => RewriteStepPriorities.EvaluationOfClassicalComputations; - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } - public IEnumerable GeneratedDiagnostics => null; + public IEnumerable GeneratedDiagnostics => Enumerable.Empty(); public bool ImplementsPreconditionVerification => false; @@ -27,7 +28,7 @@ internal class FullPreEvaluation : IRewriteStep public FullPreEvaluation() { - this.AssemblyConstants = new Dictionary(); + this.AssemblyConstants = new Dictionary(); } public bool PreconditionVerification(QsCompilation compilation) diff --git a/src/QsCompiler/Compiler/RewriteSteps/FunctorGeneration.cs b/src/QsCompiler/Compiler/RewriteSteps/FunctorGeneration.cs index 1903dded15..9d3b958ac4 100644 --- a/src/QsCompiler/Compiler/RewriteSteps/FunctorGeneration.cs +++ b/src/QsCompiler/Compiler/RewriteSteps/FunctorGeneration.cs @@ -16,9 +16,9 @@ internal class FunctorGeneration : IRewriteStep public int Priority => RewriteStepPriorities.GenerationOfFunctorSupport; - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } - public IEnumerable GeneratedDiagnostics => null; + public IEnumerable GeneratedDiagnostics => Enumerable.Empty(); public bool ImplementsPreconditionVerification => true; @@ -28,7 +28,7 @@ internal class FunctorGeneration : IRewriteStep public FunctorGeneration() { - this.AssemblyConstants = new Dictionary(); + this.AssemblyConstants = new Dictionary(); } public bool PreconditionVerification(QsCompilation compilation) diff --git a/src/QsCompiler/Compiler/RewriteSteps/IntrinsicResolution.cs b/src/QsCompiler/Compiler/RewriteSteps/IntrinsicResolution.cs index 292a86b01f..6e9f4de3d7 100644 --- a/src/QsCompiler/Compiler/RewriteSteps/IntrinsicResolution.cs +++ b/src/QsCompiler/Compiler/RewriteSteps/IntrinsicResolution.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Linq; using Microsoft.Quantum.QsCompiler.SyntaxTree; using Microsoft.Quantum.QsCompiler.Transformations.IntrinsicResolution; @@ -16,9 +17,9 @@ internal class IntrinsicResolution : IRewriteStep public int Priority => 10; // Not used for built-in transformations like this - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } - public IEnumerable GeneratedDiagnostics => null; + public IEnumerable GeneratedDiagnostics => Enumerable.Empty(); public bool ImplementsPreconditionVerification => false; @@ -30,7 +31,7 @@ internal class IntrinsicResolution : IRewriteStep public IntrinsicResolution(QsCompilation environment) { - this.AssemblyConstants = new Dictionary(); + this.AssemblyConstants = new Dictionary(); this.Environment = environment; } diff --git a/src/QsCompiler/Compiler/RewriteSteps/Monomorphization.cs b/src/QsCompiler/Compiler/RewriteSteps/Monomorphization.cs index 62be6f0a9f..1c4b387e16 100644 --- a/src/QsCompiler/Compiler/RewriteSteps/Monomorphization.cs +++ b/src/QsCompiler/Compiler/RewriteSteps/Monomorphization.cs @@ -18,9 +18,9 @@ internal class Monomorphization : IRewriteStep public int Priority => RewriteStepPriorities.TypeParameterElimination; - public IDictionary AssemblyConstants { get; } + public IDictionary AssemblyConstants { get; } - public IEnumerable GeneratedDiagnostics => null; + public IEnumerable GeneratedDiagnostics => Enumerable.Empty(); public bool ImplementsPreconditionVerification => true; @@ -30,7 +30,7 @@ internal class Monomorphization : IRewriteStep public Monomorphization() { - this.AssemblyConstants = new Dictionary(); + this.AssemblyConstants = new Dictionary(); } public bool PreconditionVerification(QsCompilation compilation) => compilation.EntryPoints.Any(); diff --git a/src/QsCompiler/Transformations/Properties/AssemblyInfo.cs b/src/QsCompiler/Transformations/Properties/AssemblyInfo.cs index c1001398a0..73d743a24a 100644 --- a/src/QsCompiler/Transformations/Properties/AssemblyInfo.cs +++ b/src/QsCompiler/Transformations/Properties/AssemblyInfo.cs @@ -4,5 +4,6 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.Quantum.QsCompilationManager" + SigningConstants.PublicKey)] +[assembly: InternalsVisibleTo("Microsoft.Quantum.QsCompiler" + SigningConstants.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.Quantum.QsLanguageServer" + SigningConstants.PublicKey)] [assembly: InternalsVisibleTo("Tests.Microsoft.Quantum.QsCompiler" + SigningConstants.PublicKey)]