diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs index 2b704cf822af2..7e21d3405ecc9 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs @@ -72,7 +72,7 @@ private sealed class InProgressState : CompilationTrackerState /// correct snapshot in that the generators have not been rerun, but may be reusable if the generators /// are later found to give the same output. /// - public readonly Lazy LazyStaleCompilationWithGeneratedDocuments; + public readonly CancellableLazy LazyStaleCompilationWithGeneratedDocuments; /// /// The list of changes that have happened since we last computed a compilation. The oldState corresponds to @@ -86,7 +86,7 @@ public InProgressState( CreationPolicy creationPolicy, Lazy compilationWithoutGeneratedDocuments, CompilationTrackerGeneratorInfo generatorInfo, - Lazy staleCompilationWithGeneratedDocuments, + CancellableLazy staleCompilationWithGeneratedDocuments, ImmutableList pendingTranslationActions) : base(creationPolicy, generatorInfo) { @@ -123,8 +123,8 @@ public InProgressState( { } - private static Lazy CreateLazyCompilation(Compilation? staleCompilationWithGeneratedDocuments) - => new(() => staleCompilationWithGeneratedDocuments); + private static CancellableLazy CreateLazyCompilation(Compilation? staleCompilationWithGeneratedDocuments) + => new(staleCompilationWithGeneratedDocuments); } /// diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs index 21e53564084df..1b3ad30d20649 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs @@ -49,7 +49,7 @@ bool ContainsAssemblyOrModuleOrDynamic( /// /// Updates the creation policy for this tracker. Setting it to . /// - ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cancellationToken); + ICompilationTracker WithDoNotCreateCreationPolicy(); Task GetDependentVersionAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken); Task GetDependentSemanticVersionAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs index 5a79c9e6be6a9..98fb08ccbf46c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs @@ -32,7 +32,7 @@ private sealed partial class RegularCompilationTracker : ICompilationTracker private static readonly Func s_logBuildCompilationAsync = state => string.Join(",", state.AssemblyName, state.DocumentStates.Count); - private static readonly Lazy s_lazyNullCompilation = new Lazy(() => null); + private static readonly CancellableLazy s_lazyNullCompilation = new CancellableLazy((Compilation?)null); public ProjectState ProjectState { get; } @@ -145,7 +145,7 @@ public ICompilationTracker Fork( var (compilationWithoutGeneratedDocuments, staleCompilationWithGeneratedDocuments) = state switch { InProgressState inProgressState => (inProgressState.LazyCompilationWithoutGeneratedDocuments, inProgressState.LazyStaleCompilationWithGeneratedDocuments), - FinalCompilationTrackerState finalState => (new Lazy(() => finalState.CompilationWithoutGeneratedDocuments), new Lazy(() => finalState.FinalCompilationWithGeneratedDocuments)), + FinalCompilationTrackerState finalState => (new Lazy(() => finalState.CompilationWithoutGeneratedDocuments), new CancellableLazy(finalState.FinalCompilationWithGeneratedDocuments)), _ => throw ExceptionUtilities.UnexpectedValue(state.GetType()), }; @@ -404,7 +404,7 @@ async Task CollapseInProgressStateAsync(InProgressState initial var translationAction = inProgressState.PendingTranslationActions[0]; var compilationWithoutGeneratedDocuments = inProgressState.CompilationWithoutGeneratedDocuments; - var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value; + var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.GetValue(cancellationToken); // If staleCompilationWithGeneratedDocuments is the same as compilationWithoutGeneratedDocuments, // then it means a prior run of generators didn't produce any files. In that case, we'll just make @@ -476,7 +476,7 @@ async Task FinalizeCompilationWorkerAsync(InProgre var creationPolicy = inProgressState.CreationPolicy; var generatorInfo = inProgressState.GeneratorInfo; var compilationWithoutGeneratedDocuments = inProgressState.CompilationWithoutGeneratedDocuments; - var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value; + var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.GetValue(cancellationToken); // Project is complete only if the following are all true: // 1. HasAllInformation flag is set for the project @@ -735,7 +735,7 @@ public ICompilationTracker WithCreateCreationPolicy(bool forceRegeneration) skeletonReferenceCacheToClone: _skeletonReferenceCache); } - public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cancellationToken) + public ICompilationTracker WithDoNotCreateCreationPolicy() { var state = this.ReadState(); @@ -792,8 +792,7 @@ public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cance var alreadyParsedTrees = alreadyParsedTreesBuilder.ToImmutableAndClear(); var lazyCompilationWithoutGeneratedDocuments = new Lazy(() => this.CreateEmptyCompilation().AddSyntaxTrees(alreadyParsedTrees)); - // Safe cast to appease NRT system. - var lazyCompilationWithGeneratedDocuments = (Lazy)lazyCompilationWithoutGeneratedDocuments!; + var lazyCompilationWithGeneratedDocuments = new CancellableLazy(cancellationToken => lazyCompilationWithoutGeneratedDocuments.Value); return new RegularCompilationTracker( frozenProjectState, @@ -818,8 +817,12 @@ public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cance // us to a frozen state with that information. var generatorInfo = inProgressState.GeneratorInfo; var compilationWithoutGeneratedDocuments = inProgressState.LazyCompilationWithoutGeneratedDocuments; - var compilationWithGeneratedDocuments = new Lazy(() => compilationWithoutGeneratedDocuments.Value.AddSyntaxTrees( - generatorInfo.Documents.States.Values.Select(state => state.GetSyntaxTree(cancellationToken)))); + + var compilationWithGeneratedDocuments = new CancellableLazy(cancellationToken => + { + var syntaxTrees = generatorInfo.Documents.States.Values.Select(state => state.GetSyntaxTree(cancellationToken)); + return compilationWithoutGeneratedDocuments.Value.AddSyntaxTrees(syntaxTrees); + }); return new RegularCompilationTracker( frozenProjectState, @@ -931,9 +934,9 @@ private void ValidateState(CompilationTrackerState? state) ValidateCompilationTreesMatchesProjectState(inProgressState.CompilationWithoutGeneratedDocuments, projectState, generatorInfo: null); - if (inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value != null) + if (inProgressState.LazyStaleCompilationWithGeneratedDocuments.GetValue(CancellationToken.None) is Compilation staleCompilationWithGeneratedDocuments) { - ValidateCompilationTreesMatchesProjectState(inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value, projectState, inProgressState.GeneratorInfo); + ValidateCompilationTreesMatchesProjectState(staleCompilationWithGeneratedDocuments, projectState, inProgressState.GeneratorInfo); } } else diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs index d4c777ad64f9e..7db307dade635 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs @@ -89,9 +89,9 @@ public ICompilationTracker WithCreateCreationPolicy(bool forceRegeneration) : new WithFrozenSourceGeneratedDocumentsCompilationTracker(underlyingTracker, _replacementDocumentStates); } - public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cancellationToken) + public ICompilationTracker WithDoNotCreateCreationPolicy() { - var underlyingTracker = this.UnderlyingTracker.WithDoNotCreateCreationPolicy(cancellationToken); + var underlyingTracker = this.UnderlyingTracker.WithDoNotCreateCreationPolicy(); return underlyingTracker == this.UnderlyingTracker ? this : new WithFrozenSourceGeneratedDocumentsCompilationTracker(underlyingTracker, _replacementDocumentStates); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs index 465418c556a5f..2ec5b6f14a04c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs @@ -1481,7 +1481,7 @@ private SolutionCompilationState ComputeFrozenSnapshot(CancellationToken cancell // Since we're freezing, set both generators and skeletons to not be created. We don't want to take any // perf hit on either of those at all for our clients. - var newTracker = oldTracker.WithDoNotCreateCreationPolicy(cancellationToken); + var newTracker = oldTracker.WithDoNotCreateCreationPolicy(); if (oldTracker == newTracker) continue;