Skip to content

Commit

Permalink
Update code completion branch with new changes from master (microsoft#89
Browse files Browse the repository at this point in the history
)

* Updating QDK to latest version. (microsoft#53)

* Fixing doc gen call (microsoft#39)

* fixing doc gen call

* adding a test for docs generation

* need to generate docs for source files only such that we can build the docs for muliple dlls without interferences

* forgot to check if the dictionary exists before clearning it in test

* Updating qdk to latest version

* Fixing vs code extension build script on linux (microsoft#56)

* fixing a stackoverflow for large files (microsoft#55)

* Build VS Code dependencies from either pwsh or powershell. (microsoft#59)

* Add automatic indentation to Visual Studio extension (microsoft#60)

* Add automatic indentation to Visual Studio extension

* Find the indentation of the last non-empty line

The previous line can be empty, which would reset the indentation to 0 if e.g. you pressed enter twice in a row. Loop backwards to find the last non-empty line and use that line's indentation instead.

* Remove assumption from GetLastNonEmptyLine

* Move QsSmartIndentProvider to the top of the file

* Flip order of ternary operator in GetIndentation

* Add doc comment to GetDesiredIndentation

* Add note about nullable return type of GetDesiredIndentation

* Show signature help for the first argument (microsoft#63)

We also trigger signature help on "("

* Always log exceptions from file queries in debug mode (microsoft#70)

* Handling specialization redeclarations (microsoft#85)

* Add install template and new project commands to VS Code extension. (microsoft#79)

* Compile time errors for overflowing int and double literals (microsoft#87)
  • Loading branch information
bamarsha committed Jul 28, 2019
1 parent d917055 commit b4babbd
Show file tree
Hide file tree
Showing 26 changed files with 1,027 additions and 236 deletions.
7 changes: 5 additions & 2 deletions src/QsCompiler/CompilationManager/CompilationUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,11 @@ internal void UpdateCallables(IEnumerable<QsCallable> updates)
var specializations = this.GlobalSymbols.DefinedSpecializations(header.QualifiedName).Select(defined =>
{
var specHeader = defined.Item2;
var compiledSpecs = compiled.Specializations.Where(spec => spec.Kind == specHeader.Kind);
QsCompilerError.Verify(compiledSpecs.Count() <= 1, "more than one specialization of the same kind exists"); // currently not supported
var compiledSpecs = compiled.Specializations.Where(spec =>
spec.Kind == specHeader.Kind &&
spec.TypeArguments.Equals(specHeader.TypeArguments)
);
QsCompilerError.Verify(compiledSpecs.Count() <= 1, "more than one specialization of the same kind exists");
if (!compiledSpecs.Any()) return null; // may happen if a file has been modified during global type checking
var compiledSpec = compiledSpecs.Single();
Expand Down
9 changes: 9 additions & 0 deletions src/QsCompiler/CompilationManager/CompilationUnitManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,11 @@ public WorkspaceEdit Rename(RenameParams param)
// -> 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

/// <param name="suppressExceptionLogging">
/// Whether to suppress logging of exceptions from the query.
/// <para/>
/// NOTE: In debug mode, exceptions are always logged even if this parameter is true.
/// </param>
internal T FileQuery<T>(TextDocumentIdentifier textDocument,
Func<FileContentManager, CompilationUnit, T> Query, bool suppressExceptionLogging = false)
where T : class
Expand All @@ -589,7 +594,11 @@ T TryQueryFile(FileContentManager f)
try { return Query(f, this.CompilationUnit); }
catch (Exception ex)
{
#if DEBUG
this.LogException(ex);
#else
if (!suppressExceptionLogging) this.LogException(ex);
#endif
return null;
}
}
Expand Down
51 changes: 30 additions & 21 deletions src/QsCompiler/CompilationManager/FileContentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -495,20 +495,20 @@ private void VerifyTokenUpdate(IReadOnlyList<CodeFragment> fragments)
}

/// <summary>
/// Replaces Transformation with an Action that first executes the given Transformation (unless it is null, in which case it is ignored),
/// and then replaces the tokens at lineNr with the ones returned by UpdateTokens when called on the current tokens
/// Returns an Action as out parameter that replaces the tokens at lineNr
/// with the ones returned by UpdateTokens when called on the current tokens
/// (i.e. the ones after having applied Transformation) on that line.
/// Applies ModifiedTokens to the tokens at the given lineNr to obtain the list of tokens for which to mark all connections as edited.
/// Then replaces MarkEdited with an Action that first exectutes the given MarkEdited (unless it is null, in which case it is ignored),
/// and then adds lineNr as well as all lines containing connections to mark to EditedTokens.
/// Then constructs and returns an Action as out parameter
/// that adds lineNr as well as all lines containing connections to mark to EditedTokens.
/// Throws an ArgumentNullException if UpdatedTokens or ModifiedTokens is null.
/// Throws an ArgumentException if any of the values returned by UpdatedTokens or ModifiedTokens is null.
/// Throws an ArgumentOutOfRangeException if linrNr is not a valid index for the current Tokens.
/// </summary>
private void TransformAndMarkEdited(int lineNr,
Func<ImmutableArray<CodeFragment>, ImmutableArray<CodeFragment>> UpdatedTokens,
Func<ImmutableArray<CodeFragment>, ImmutableArray<CodeFragment>> ModifiedTokens,
ref Action Transformation, ref Action MarkEdited)
out Action Transformation, out Action MarkEdited)
{
this.Tokens.SyncRoot.EnterWriteLock();
try
Expand All @@ -517,21 +517,17 @@ private void VerifyTokenUpdate(IReadOnlyList<CodeFragment> fragments)
if (ModifiedTokens == null) throw new ArgumentNullException(nameof(ModifiedTokens));
if (lineNr < 0 || lineNr >= this.Tokens.Count()) throw new ArgumentOutOfRangeException(nameof(lineNr));

var PriorTransformation = Transformation ?? (() => { return; });
Transformation = () =>
{
PriorTransformation();
var updated = UpdatedTokens(this.GetTokenizedLine(lineNr));
if (updated == null) throw new ArgumentException($"{nameof(UpdatedTokens)} must not return null");
this.Tokens.Transform(lineNr, _ => updated);
};

var modified = ModifiedTokens(this.GetTokenizedLine(lineNr));
if (modified == null) throw new ArgumentException($"{nameof(ModifiedTokens)} must not return null");
var PriorMarkEdited = MarkEdited ?? (() => { return; });
MarkEdited = () =>
{
PriorMarkEdited();
this.EditedTokens.Add(lineNr);
foreach (var token in modified)
{
Expand Down Expand Up @@ -565,13 +561,17 @@ private void RemoveTokensInRange(Range range)
if (!Utils.IsValidRange(range)) throw new ArgumentException("invalid range"); // *don't* verify against the current file content
if (range.End.Line >= this.Tokens.Count()) throw new ArgumentOutOfRangeException(nameof(range));

Action ApplyTransformations = null;
Action MarkEdited = null;
void FilterAndMarkEdited(int index, Func<CodeFragment, bool> predicate) =>
var ApplyTransformations = new List<Action>();
var MarkEdited = new List<Action>();
void FilterAndMarkEdited(int index, Func<CodeFragment, bool> predicate)
{
TransformAndMarkEdited(index,
tokens => tokens.Where(predicate).ToImmutableArray(),
tokens => tokens.Where(x => !predicate(x)).ToImmutableArray(),
ref ApplyTransformations, ref MarkEdited);
out var transformation, out var edited);
ApplyTransformations.Add(transformation);
MarkEdited.Add(edited);
}

var (start, end) = (range.Start.Line, range.End.Line);
FilterAndMarkEdited(start, ContextBuilder.NotOverlappingWith(range.WithUpdatedLineNumber(-start)));
Expand All @@ -587,9 +587,12 @@ private void RemoveTokensInRange(Range range)

// which lines get marked as edited depends on the tokens prior to transformation,
// hence we accumulate all transformations and apply them only at the end
QsCompilerError.Verify(ApplyTransformations != null && MarkEdited != null, $"{nameof(ApplyTransformations)} and {nameof(MarkEdited)} in {nameof(RemoveTokensInRange)} should not be null");
QsCompilerError.RaiseOnFailure(() => MarkEdited(), $"marking edited in {nameof(RemoveTokensInRange)} failed");
QsCompilerError.RaiseOnFailure(() => ApplyTransformations(), $"applying transformations in {nameof(RemoveTokensInRange)} failed");
QsCompilerError.RaiseOnFailure(() =>
{ foreach (var edited in MarkEdited) edited(); }
, $"marking edited in {nameof(RemoveTokensInRange)} failed");
QsCompilerError.RaiseOnFailure(() =>
{ foreach (var transformation in ApplyTransformations) transformation(); }
, $"applying transformations in {nameof(RemoveTokensInRange)} failed");
}
finally { this.Tokens.SyncRoot.ExitWriteLock(); }
}
Expand Down Expand Up @@ -623,8 +626,8 @@ internal void TokensUpdate(IReadOnlyList<CodeFragment> fragments)
this.Header.AddCallableDeclarations(newCallableDecl);

// update the Tokens
Action ApplyTransformations = null;
Action MarkEdited = null;
var ApplyTransformations = new List<Action>();
var MarkEdited = new List<Action>();
while (fragments.Any())
{
var startLine = fragments.First().GetRange().Start.Line;
Expand Down Expand Up @@ -656,14 +659,20 @@ ImmutableArray<CodeFragment> MergeAndAttachComments(ImmutableArray<CodeFragment>
return merged.ToImmutableArray();
}

this.TransformAndMarkEdited(startLine, MergeAndAttachComments, _ => tokens, ref ApplyTransformations, ref MarkEdited);
this.TransformAndMarkEdited(startLine, MergeAndAttachComments, _ => tokens, out var transformation, out var edited);
ApplyTransformations.Add(transformation);
MarkEdited.Add(edited);
fragments = fragments.SkipWhile(fragment => fragment.GetRange().Start.Line == startLine).ToList();
}

// which lines get marked as edited depends on the tokens after the transformations,
// hence we accumulate all mark-ups and apply them only after applying all transformations
QsCompilerError.RaiseOnFailure(() => ApplyTransformations(), $"applying transformations in {nameof(TokensUpdate)} failed");
QsCompilerError.RaiseOnFailure(() => MarkEdited(), $"marking edited in {nameof(TokensUpdate)} failed");
QsCompilerError.RaiseOnFailure(() =>
{ foreach (var transformation in ApplyTransformations) transformation(); }
, $"applying transformations in {nameof(TokensUpdate)} failed");
QsCompilerError.RaiseOnFailure(() =>
{ foreach (var edited in MarkEdited) edited(); }
, $"marking edited in {nameof(TokensUpdate)} failed");
}
finally { this.SyncRoot.ExitWriteLock(); }
}
Expand Down
71 changes: 35 additions & 36 deletions src/QsCompiler/CompilationManager/TypeChecking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,40 +1088,41 @@ internal static void ImportGlobalSymbols(this FileContentManager file, Compilati
}

/// <summary>
/// Given a lookup of all specializations and their build directives for the parent callable,
/// Given a function that returns the generator directive for a given specialization kind, or null if none has been defined for that kind,
/// determines the necessary functor support required for each operation call within a user defined implementation of the specified specialization.
/// Throws an ArgumentNullException if the given specialization for which to determine the required functor support is null,
/// or if the given dictionary of all relevant build directives or any of its values is.
/// or if the given function to query the directives is.
/// </summary>
private static IEnumerable<QsFunctor> RequiredFunctorSupport(QsSpecializationKind spec,
ImmutableDictionary<QsSpecializationKind, QsNullable<QsGeneratorDirective>> directives)
Func<QsSpecializationKind, QsGeneratorDirective> directives)
{
if (spec == null) throw new ArgumentNullException(nameof(spec));
if (directives == null) throw new ArgumentNullException(nameof(directives));

if (directives.TryGetValue(QsSpecializationKind.QsAdjoint, out var adjDir) &&
spec.IsQsBody && adjDir.IsValue && !(adjDir.Item.IsSelfInverse || adjDir.Item.IsInvalidGenerator))
var adjDir = directives(QsSpecializationKind.QsAdjoint);
var ctlDir = directives(QsSpecializationKind.QsControlled);
var ctlAdjDir = directives(QsSpecializationKind.QsControlledAdjoint);

if (spec.IsQsBody && adjDir != null && !(adjDir.IsSelfInverse || adjDir.IsInvalidGenerator))
{
if (adjDir.Item.IsInvert) yield return QsFunctor.Adjoint;
if (adjDir.IsInvert) yield return QsFunctor.Adjoint;
else QsCompilerError.Raise("expecting adjoint functor generator directive to be 'invert'");
}

if (directives.TryGetValue(QsSpecializationKind.QsControlled, out var ctlDir) &&
spec.IsQsBody && ctlDir.IsValue && !ctlDir.Item.IsInvalidGenerator)
if (spec.IsQsBody && ctlDir != null && !ctlDir.IsInvalidGenerator)
{
if (ctlDir.Item.IsDistribute) yield return QsFunctor.Controlled;
if (ctlDir.IsDistribute) yield return QsFunctor.Controlled;
else QsCompilerError.Raise("expecting controlled functor generator directive to be 'distribute'");
}

// since a directive for a controlled adjoint specialization requires an auto-generation based on either the adjoint or the controlled version
// when the latter may or may not be auto-generated, we also need to check the controlled adjoint specialization
if (directives.TryGetValue(QsSpecializationKind.QsControlledAdjoint, out var ctlAdjDir) &&
ctlAdjDir.IsValue && !(ctlAdjDir.Item.IsSelfInverse || ctlAdjDir.Item.IsInvalidGenerator))
if (ctlAdjDir != null && !(ctlAdjDir.IsSelfInverse || ctlAdjDir.IsInvalidGenerator))
{
if (ctlAdjDir.Item.IsDistribute)
{ if (spec.IsQsAdjoint || (spec.IsQsBody && adjDir.IsValue)) yield return QsFunctor.Controlled; }
else if (ctlAdjDir.Item.IsInvert)
{ if (spec.IsQsControlled || (spec.IsQsBody && ctlDir.IsValue)) yield return QsFunctor.Adjoint; }
if (ctlAdjDir.IsDistribute)
{ if (spec.IsQsAdjoint || (spec.IsQsBody && adjDir != null)) yield return QsFunctor.Controlled; }
else if (ctlAdjDir.IsInvert)
{ if (spec.IsQsControlled || (spec.IsQsBody && ctlDir != null)) yield return QsFunctor.Adjoint; }
else QsCompilerError.Raise("expecting controlled adjoint functor generator directive to be either 'invert' or 'distribute'");
}
}
Expand All @@ -1147,10 +1148,10 @@ private static ImmutableArray<QsSpecialization> BuildSpecializations
if (diagnostics == null) throw new ArgumentNullException(nameof(diagnostics));

if (cancellationToken.IsCancellationRequested) return ImmutableArray<QsSpecialization>.Empty;
var definedSpecs = symbols.DefinedSpecializations(new QsQualifiedName(specsRoot.Namespace, specsRoot.Callable)).ToLookup(s => s.Item2.Kind);
var directives = definedSpecs.ToImmutableDictionary(
specs => specs.Key,
specs => QsCompilerError.RaiseOnFailure(specs.Single, "more than one specialization of the same kind exists").Item1); // currently not supported
var definedSpecs = symbols.DefinedSpecializations(new QsQualifiedName(specsRoot.Namespace, specsRoot.Callable))
.ToLookup(s => s.Item2.Kind).ToImmutableDictionary(
specs => specs.Key,
specs => QsCompilerError.RaiseOnFailure(specs.Single, "more than one specialization of the same kind exists")); // currently not supported

QsSpecialization GetSpecialization(SpecializationDeclarationHeader spec, ResolvedSignature signature,
SpecializationImplementation implementation, QsComments comments = null) =>
Expand All @@ -1160,11 +1161,11 @@ private static ImmutableArray<QsSpecialization> BuildSpecializations
QsSpecialization BuildSpecialization(QsSpecializationKind kind, ResolvedSignature signature, QsSpecializationGeneratorKind<QsSymbol> gen, FragmentTree.TreeNode root,
Func<QsSymbol, Tuple<QsTuple<LocalVariableDeclaration<QsLocalSymbol>>, QsCompilerDiagnostic[]>> buildArg, QsComments comments = null)
{
if (!directives.TryGetValue(kind, out var directive))
if (!definedSpecs.TryGetValue(kind, out var defined))
throw new ArgumentException($"missing entry for {kind} specialization of {specsRoot.Namespace}.{specsRoot.Callable}");
var spec = definedSpecs[kind].Single().Item2;
var (directive, spec) = defined;

var required = RequiredFunctorSupport(kind, directives);
var required = RequiredFunctorSupport(kind, k => definedSpecs.TryGetValue(k, out defined) && defined.Item1.IsValue ? defined.Item1.Item : null);
var symbolTracker = new SymbolTracker<Position>(symbols, spec.SourceFile, spec.Parent, required);
var implementation = directive.IsValue ? SpecializationImplementation.NewGenerated(directive.Item) : null;

Expand Down Expand Up @@ -1192,6 +1193,7 @@ QsSpecialization BuildSpec (FragmentTree.TreeNode root)
if (cancellationToken.IsCancellationRequested) return null;
bool InvalidCharacteristicsOrSupportedFunctors(params QsFunctor[] functors) =>
parentCharacteristics.AreInvalid || !functors.Any(f => !supportedFunctors.Contains(f));
if (!definedSpecs.Values.Any(d => DiagnosticTools.AsPosition(d.Item2.Position) == root.Fragment.GetRange().Start)) return null; // only process specializations that are valid

if (FileHeader.IsCallableDeclaration(root.Fragment)) // no specializations have been defined -> one default body
{
Expand Down Expand Up @@ -1227,25 +1229,22 @@ QsSpecialization BuildSpec (FragmentTree.TreeNode root)

// build the specializations defined in the source code
var existing = ImmutableArray.CreateBuilder<QsSpecialization>();
existing.AddRange(specsRoot.Specializations.Select(BuildSpec));
existing.AddRange(specsRoot.Specializations.Select(BuildSpec).Where(s => s != null));
if (cancellationToken.IsCancellationRequested) return existing.ToImmutableArray();

// additionally we need to build the specializations that are missing in the source code
var existingKinds = existing.Select(t => t.Kind).ToImmutableHashSet();
foreach (var defined in definedSpecs)
foreach (var (directive, spec) in definedSpecs.Values)
{
var (directive, spec) = defined.Single();
if (!existingKinds.Contains(spec.Kind))
{
var implementation = directive.IsValue
? SpecializationImplementation.NewGenerated(directive.Item)
: SpecializationImplementation.Intrinsic;
if (spec.Kind.IsQsBody || spec.Kind.IsQsAdjoint)
{ existing.Add(GetSpecialization(spec, parentSignature, implementation)); }
else if (spec.Kind.IsQsControlled || spec.Kind.IsQsControlledAdjoint)
{ existing.Add(GetSpecialization(spec, controlledSignature, implementation)); }
else QsCompilerError.Raise("unknown functor kind");
}
if (existingKinds.Contains(spec.Kind)) continue;
var implementation = directive.IsValue
? SpecializationImplementation.NewGenerated(directive.Item)
: SpecializationImplementation.Intrinsic;
if (spec.Kind.IsQsBody || spec.Kind.IsQsAdjoint)
{ existing.Add(GetSpecialization(spec, parentSignature, implementation)); }
else if (spec.Kind.IsQsControlled || spec.Kind.IsQsControlledAdjoint)
{ existing.Add(GetSpecialization(spec, controlledSignature, implementation)); }
else QsCompilerError.Raise("unknown functor kind");
}
return existing.ToImmutableArray();
}
Expand Down

0 comments on commit b4babbd

Please sign in to comment.