Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tooling] Prevent impl files with backing sig files from invalidating the build #10650

Merged
merged 2 commits into from
Dec 10, 2020
Merged
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
63 changes: 46 additions & 17 deletions src/fsharp/service/IncrementalBuild.fs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ module IncrementalBuildSyntaxTree =
| _ -> parse sigNameOpt
| _ -> parse sigNameOpt

member _.Invalidate() =
weakCache <- None

member _.FileName = filename

/// Accumulated results of type checking. The minimum amount of state in order to continue type-checking following files.
Expand Down Expand Up @@ -238,6 +241,32 @@ type SemanticModel private (tcConfig: TcConfig,

member _.TcImports = tcImports

member _.BackingSignature =
match syntaxTreeOpt with
| Some syntaxTree ->
let sigFileName = Path.ChangeExtension(syntaxTree.FileName, ".fsi")
match prevTcInfo.sigNameOpt with
| Some (expectedSigFileName, sigName) when String.Equals(expectedSigFileName, sigFileName, StringComparison.OrdinalIgnoreCase) ->
Some sigName
| _ ->
None
| _ ->
None

member this.Invalidate() =
let hasSig = this.BackingSignature.IsSome
match !lazyTcInfoState with
// If partial checking is enabled and we have a backing sig file, then do nothing. The partial state contains the sig state.
| Some(PartialState _) when enablePartialTypeChecking && hasSig -> ()
// If partial checking is enabled and we have a backing sig file, then use the partial state. The partial state contains the sig state.
| Some(FullState(tcInfo, _)) when enablePartialTypeChecking && hasSig -> lazyTcInfoState := Some(PartialState tcInfo)
| _ ->
lazyTcInfoState := None

// Always invalidate the syntax tree cache.
syntaxTreeOpt
|> Option.iter (fun x -> x.Invalidate())

member this.GetState(partialCheck: bool) =
let partialCheck =
// Only partial check if we have enabled it.
Expand Down Expand Up @@ -344,7 +373,7 @@ type SemanticModel private (tcConfig: TcConfig,
}
}

member private _.TypeCheck (partialCheck: bool) =
member private this.TypeCheck (partialCheck: bool) =
match partialCheck, !lazyTcInfoState with
| true, Some (PartialState _ as state)
| true, Some (FullState _ as state) -> state |> Eventually.Done
Expand All @@ -357,12 +386,7 @@ type SemanticModel private (tcConfig: TcConfig,
| Some syntaxTree ->
let sigNameOpt =
if partialCheck then
let sigFileName = Path.ChangeExtension(syntaxTree.FileName, ".fsi")
match prevTcInfo.sigNameOpt with
| Some (expectedSigFileName, sigName) when String.Equals(expectedSigFileName, sigFileName, StringComparison.OrdinalIgnoreCase) ->
Some sigName
| _ ->
None
this.BackingSignature
else
None
match syntaxTree.Parse sigNameOpt with
Expand Down Expand Up @@ -910,23 +934,28 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput
let stampedFileNames = Array.init fileNames.Length (fun _ -> DateTime.MinValue)
let stampedReferencedAssemblies = Array.init referencedAssemblies.Length (fun _ -> DateTime.MinValue)
let mutable initialSemanticModel = None
let semanticModels = Array.zeroCreate fileNames.Length
let semanticModels = Array.zeroCreate<SemanticModel option> fileNames.Length
let mutable finalizedSemanticModel = None

let computeStampedFileName (cache: TimeStampCache) (ctok: CompilationThreadToken) slot fileInfo cont =
let currentStamp = stampedFileNames.[slot]
let stamp = StampFileNameTask cache ctok fileInfo

if currentStamp <> stamp then
// Something changed, the finalized view of the project must be invalidated.
finalizedSemanticModel <- None

// Invalidate the file and all files below it.
stampedFileNames.[slot..]
|> Array.iteri (fun j _ ->
stampedFileNames.[slot + j] <- StampFileNameTask cache ctok fileNames.[slot + j]
semanticModels.[slot + j] <- None
)
match semanticModels.[slot] with
// This prevents an implementation file that has a backing signature file from invalidating the rest of the build.
| Some(semanticModel) when enablePartialTypeChecking && semanticModel.BackingSignature.IsSome ->
semanticModel.Invalidate()
| _ ->
// Something changed, the finalized view of the project must be invalidated.
finalizedSemanticModel <- None

// Invalidate the file and all files below it.
stampedFileNames.[slot..]
|> Array.iteri (fun j _ ->
stampedFileNames.[slot + j] <- StampFileNameTask cache ctok fileNames.[slot + j]
semanticModels.[slot + j] <- None
)

if semanticModels.[slot].IsNone then
cont slot fileInfo
Expand Down