Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/QsCompiler/CommandLineTool/LoadContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name)
return path == null ? null : LoadFromAssemblyPath(path);
}

private static ConcurrentBag<LoadContext> Loaded =
private static readonly ConcurrentBag<LoadContext> Loaded =
new ConcurrentBag<LoadContext>();

/// <summary>
Expand Down
63 changes: 54 additions & 9 deletions src/QsCompiler/CompilationManager/CompilationUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.Quantum.QsCompiler.DataTypes;
using Microsoft.Quantum.QsCompiler.Diagnostics;
using Microsoft.Quantum.QsCompiler.SymbolManagement;
using Microsoft.Quantum.QsCompiler.SyntaxProcessing;
using Microsoft.Quantum.QsCompiler.SyntaxTokens;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
using Microsoft.Quantum.QsCompiler.Transformations.SearchAndReplace;
using Microsoft.VisualStudio.LanguageServer.Protocol;


Expand All @@ -28,9 +31,9 @@ public class Headers
public readonly ImmutableArray<(SpecializationDeclarationHeader, SpecializationImplementation)> Specializations;
public readonly ImmutableArray<TypeDeclarationHeader> Types;

private Headers(string source,
IEnumerable<CallableDeclarationHeader> callables = null,
IEnumerable<(SpecializationDeclarationHeader, SpecializationImplementation)> specs = null,
internal Headers(string source,
IEnumerable<CallableDeclarationHeader> callables = null,
IEnumerable<(SpecializationDeclarationHeader, SpecializationImplementation)> specs = null,
IEnumerable<TypeDeclarationHeader> types = null)
{
NonNullable<string> SourceOr(NonNullable<string> origSource) => NonNullable<string>.New(source ?? origSource.Value);
Expand Down Expand Up @@ -74,6 +77,40 @@ private static IEnumerable<TypeDeclarationHeader> TypeHeaders(IEnumerable<(strin
attributes.Select(IsDeclaration("TypeDeclarationAttribute")).Where(v => v != null)
.Select(TypeDeclarationHeader.FromJson).Select(built => built.Item2);

/// <summary>
/// Renames all internal declarations in the headers to have names that are based on the ID of the referenced
/// assembly.
/// </summary>
/// <param name="id">A number uniquely identifying the referenced assembly that contains the headers.</param>
/// <param name="source">The path to the assembly that is the source of the given headers.</param>
/// <param name="headers">The declaration headers in the assembly.</param>
/// <returns></returns>
private static Headers RenameInternals(int id, string source, Headers headers)
{
var internalNames = headers.Callables
.Where(callable => callable.Modifiers.Access.IsInternal)
.Select(callable => callable.QualifiedName)
.Concat(headers.Types
.Where(type => type.Modifiers.Access.IsInternal)
.Select(type => type.QualifiedName))
.ToImmutableDictionary(name => name, name => GetNewNameForInternal(id, name));
var rename = new RenameReferences(internalNames);
var callables = headers.Callables.Select(rename.OnCallableDeclarationHeader);
var specializations = headers.Specializations.Select(
specialization => (rename.OnSpecializationDeclarationHeader(specialization.Item1),
rename.Namespaces.OnSpecializationImplementation(specialization.Item2)));
var types = headers.Types.Select(rename.OnTypeDeclarationHeader);
return new Headers(source, callables, specializations, types);
}

/// <summary>
/// Returns a new name for an internal declaration that is tagged with its reference ID.
/// </summary>
/// <param name="id">The ID of the reference in which this name was declared.</param>
/// <param name="name">The name of the internal declaration.</param>
/// <returns>A new name for an internal declaration that is tagged with its reference ID.</returns>
internal static QsQualifiedName GetNewNameForInternal(int id, QsQualifiedName name) =>
new QsQualifiedName(name.Namespace, NonNullable<string>.New($"__Reference{id}_{name.Name.Value}__"));

/// <summary>
/// Dictionary that maps the id of a referenced assembly (given by its location on disk) to the headers defined in that assembly.
Expand Down Expand Up @@ -109,14 +146,22 @@ internal References Remove(NonNullable<string> source, Action<ErrorCode, string[

/// <summary>
/// Given a dictionary that maps the ids of dll files to the corresponding headers,
/// initializes a new set of references based on the given headers and verifies that there are no conflicts.
/// Calls the given Action onError with suitable diagnostics if two or more references conflict,
/// i.e. if two or more references contain a declaration with the same fully qualified name.
/// Throws an ArgumentNullException if the given dictionary of references is null.
/// initializes a new set of references based on the given headers and verifies that there are no conflicts.
/// Calls the given Action onError with suitable diagnostics if two or more references conflict,
/// i.e. if two or more references contain a public declaration with the same fully qualified name.
/// Throws an ArgumentNullException if the given dictionary of references is null.
/// </summary>
public References(ImmutableDictionary<NonNullable<string>, Headers> refs, Action<ErrorCode, string[]> onError = null)
{
this.Declarations = refs ?? throw new ArgumentNullException(nameof(refs));
// TODO: We mangle the names of internal declarations in references to avoid name conflicts in the symbol
// table. However, it might be better to instead change the symbol table so it can support duplicate names
// as long as they are not in overlapping scopes, which is the case with internal declarations in separate
// assemblies.
this.Declarations =
(refs ?? throw new ArgumentNullException(nameof(refs)))
.Select((reference, index) => (reference.Key,
RenameInternals(index, reference.Key.Value, reference.Value)))
.ToImmutableDictionary(reference => reference.Key, reference => reference.Item2);
if (onError == null) return;

var conflictingCallables = refs.Values.SelectMany(r => r.Callables)
Expand Down Expand Up @@ -414,7 +459,7 @@ internal void UpdateCallables(IEnumerable<QsCallable> updates)
header.Location,
header.Signature,
header.ArgumentTuple,
ImmutableArray.Create<QsSpecialization>(defaultSpec),
ImmutableArray.Create(defaultSpec),
header.Documentation,
QsComments.Empty
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@ internal static bool TryGetReferences(this CompilationUnit compilation, QsQualif
referenceLocations = namespaces.SelectMany(ns =>
{
var locs = IdentifierReferences.Find(fullName, ns, defaultOffset, out var dLoc, limitToSourceFiles);
declLoc = declLoc ?? dLoc;
declLoc ??= dLoc;
return locs;
})
.Distinct().Select(AsLocation).ToArray(); // ToArray is needed here to force the execution before checking declLoc
.Select(AsLocation).ToArray(); // ToArray is needed here to force the execution before checking declLoc
declarationLocation = declLoc == null ? null : AsLocation(declLoc.Item1, declLoc.Item2.Offset, declLoc.Item2.Range);
return true;
}
Expand Down Expand Up @@ -218,16 +218,16 @@ internal static bool TryGetReferences(
.SelectMany(spec =>
spec.Implementation is SpecializationImplementation.Provided impl && spec.Location.IsValue
? IdentifierReferences.Find(definition.Item.Item1, impl.Item2, file.FileName, spec.Location.Item.Offset)
: ImmutableArray<IdentifierReferences.Location>.Empty)
.Distinct().Select(AsLocation);
: ImmutableHashSet<IdentifierReferences.Location>.Empty)
.Select(AsLocation);
}
else // the given position corresponds to a variable declared as part of a specialization declaration or implementation
{
var defStart = DiagnosticTools.GetAbsolutePosition(defOffset, defRange.Item1);
var statements = implementation.StatementsAfterDeclaration(defStart.Subtract(specPos));
var scope = new QsScope(statements.ToImmutableArray(), locals);
var rootOffset = DiagnosticTools.AsTuple(specPos);
referenceLocations = IdentifierReferences.Find(definition.Item.Item1, scope, file.FileName, rootOffset).Distinct().Select(AsLocation);
referenceLocations = IdentifierReferences.Find(definition.Item.Item1, scope, file.FileName, rootOffset).Select(AsLocation);
}
declarationLocation = AsLocation(file.FileName, definition.Item.Item2, defRange);
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/QsCompiler/Core/TypeTransformation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,4 @@ type TypeTransformationBase(options : TransformationOptions) =
| ExpressionType.Result -> this.OnResult ()
| ExpressionType.Pauli -> this.OnPauli ()
| ExpressionType.Range -> this.OnRange ()
ResolvedType.New |> Node.BuildOr t transformed
(fun t -> ResolvedType.New (true, t)) |> Node.BuildOr t transformed
2 changes: 2 additions & 0 deletions src/QsCompiler/DataStructures/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@ type QsSpecialization = {
with
member this.AddAttribute att = {this with Attributes = this.Attributes.Add att}
member this.WithImplementation impl = {this with Implementation = impl}
member this.WithParent (getName : Func<_,_>) = {this with Parent = getName.Invoke(this.Parent)}


/// describes a Q# function, operation, or type constructor
Expand Down Expand Up @@ -739,6 +740,7 @@ type QsCustomType = {
}
with
member this.AddAttribute att = {this with Attributes = this.Attributes.Add att}
member this.WithFullName (getName : Func<_,_>) = {this with FullName = getName.Invoke(this.FullName)}


/// Describes a valid Q# namespace element.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
/// This file contains redefinitions of types and callables declared in Tests.Compiler\TestCases\AccessModifiers.qs. It
/// is used as an assembly reference to test support for re-using names of inaccessible declarations in references.
namespace Microsoft.Quantum.Testing.AccessModifiers {
// TODO: Uncomment these definitions when re-using names of inaccessible declarations in references is supported.
internal newtype InternalType = Unit;

// internal newtype InternalType = Unit;

// internal function InternalFunction () : Unit {}
internal function InternalFunction () : Unit {}
}

/// This namespace contains additional definitions of types and callables meant to be used by the
Expand Down
9 changes: 6 additions & 3 deletions src/QsCompiler/Tests.Compiler/AccessModifierTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@ type AccessModifierTests (output) =
let name = name |> NonNullable<_>.New
this.Verify (QsQualifiedName.New (ns, name), diagnostics)

// Note: Since internal declarations in references are renamed, the error codes will be for unidentified callables
// and types instead of inaccessible ones.

[<Fact>]
member this.``Callables`` () =
this.Expect "CallableUseOK" []
this.Expect "CallableReferenceInternalInaccessible" [Error ErrorCode.InaccessibleCallable]
this.Expect "CallableReferenceInternalInaccessible" [Error ErrorCode.UnknownIdentifier]

[<Fact>]
member this.``Types`` () =
this.Expect "TypeUseOK" []
this.Expect "TypeReferenceInternalInaccessible" [Error ErrorCode.InaccessibleType]
this.Expect "TypeConstructorReferenceInternalInaccessible" [Error ErrorCode.InaccessibleCallable]
this.Expect "TypeReferenceInternalInaccessible" [Error ErrorCode.UnknownType]
this.Expect "TypeConstructorReferenceInternalInaccessible" [Error ErrorCode.UnknownIdentifier]

[<Fact>]
member this.``Callable signatures`` () =
Expand Down
Loading