diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 64e1526dc39..297837968bc 100755 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -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. @@ -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. @@ -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 @@ -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 @@ -910,7 +934,7 @@ 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 fileNames.Length let mutable finalizedSemanticModel = None let computeStampedFileName (cache: TimeStampCache) (ctok: CompilationThreadToken) slot fileInfo cont = @@ -918,15 +942,20 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput 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