Skip to content

Commit

Permalink
Stop incremental builder from accumulating TcSymbolUses/TcResolutions…
Browse files Browse the repository at this point in the history
…/etc. (#11666)

* Stop accumulating results in incremental build

* ParseAndCheckProjectImpl changes

* minor tweak
  • Loading branch information
TIHan authored Jun 16, 2021
1 parent f13b4ff commit 1e750b3
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 55 deletions.
57 changes: 47 additions & 10 deletions src/fsharp/service/FSharpCheckerResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2182,7 +2182,7 @@ type FSharpCheckProjectResults
tcConfigOption: TcConfig option,
keepAssemblyContents: bool,
diagnostics: FSharpDiagnostic[],
details:(TcGlobals * TcImports * CcuThunk * ModuleOrNamespaceType * TcSymbolUses list *
details:(TcGlobals * TcImports * CcuThunk * ModuleOrNamespaceType * Choice<IncrementalBuilder, TcSymbolUses> *
TopAttribs option * IRawFSharpAssemblyData option * ILAssemblyRef *
AccessorDomain * TypedImplFile list option * string[] * FSharpProjectOptions) option) =

Expand All @@ -2201,12 +2201,12 @@ type FSharpCheckProjectResults
member _.HasCriticalErrors = details.IsNone

member _.AssemblySignature =
let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let (tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
FSharpAssemblySignature(tcGlobals, thisCcu, ccuSig, tcImports, topAttribs, ccuSig)

member _.TypedImplementationFiles =
if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies"
let (tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let (tcGlobals, tcImports, thisCcu, _ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let mimpls =
match tcAssemblyExpr with
| None -> []
Expand All @@ -2215,7 +2215,7 @@ type FSharpCheckProjectResults

member info.AssemblyContents =
if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies"
let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let (tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let mimpls =
match tcAssemblyExpr with
| None -> []
Expand All @@ -2224,7 +2224,7 @@ type FSharpCheckProjectResults

member _.GetOptimizedAssemblyContents() =
if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies"
let (tcGlobals, tcImports, thisCcu, ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let (tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let mimpls =
match tcAssemblyExpr with
| None -> []
Expand All @@ -2243,10 +2243,28 @@ type FSharpCheckProjectResults

// Not, this does not have to be a SyncOp, it can be called from any thread
member _.GetUsesOfSymbol(symbol:FSharpSymbol, ?cancellationToken: CancellationToken) =
let (tcGlobals, _tcImports, _thisCcu, _ccuSig, tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let (tcGlobals, _tcImports, _thisCcu, _ccuSig, builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()

let results =
match builderOrSymbolUses with
| Choice1Of2 builder ->
builder.SourceFiles
|> Array.ofList
|> Array.collect (fun x ->
match builder.GetCheckResultsForFileInProjectEvenIfStale x with
| Some partialCheckResults ->
match partialCheckResults.TryPeekTcInfoWithExtras() with
| Some(_, tcInfoExtras) ->
tcInfoExtras.TcSymbolUses.GetUsesOfSymbol symbol.Item
| _ ->
[||]
| _ ->
[||]
)
| Choice2Of2 tcSymbolUses ->
tcSymbolUses.GetUsesOfSymbol symbol.Item

tcSymbolUses
|> Seq.collect (fun r -> r.GetUsesOfSymbol symbol.Item)
results
|> Seq.filter (fun symbolUse -> symbolUse.ItemOccurence <> ItemOccurence.RelatedText)
|> Seq.distinctBy (fun symbolUse -> symbolUse.ItemOccurence, symbolUse.Range)
|> Seq.map (fun symbolUse ->
Expand All @@ -2256,9 +2274,28 @@ type FSharpCheckProjectResults

// Not, this does not have to be a SyncOp, it can be called from any thread
member _.GetAllUsesOfAllSymbols(?cancellationToken: CancellationToken) =
let (tcGlobals, tcImports, thisCcu, ccuSig, tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let (tcGlobals, tcImports, thisCcu, ccuSig, builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions) = getDetails()
let cenv = SymbolEnv(tcGlobals, thisCcu, Some ccuSig, tcImports)

let tcSymbolUses =
match builderOrSymbolUses with
| Choice1Of2 builder ->
builder.SourceFiles
|> Array.ofList
|> Array.map (fun x ->
match builder.GetCheckResultsForFileInProjectEvenIfStale x with
| Some partialCheckResults ->
match partialCheckResults.TryPeekTcInfoWithExtras() with
| Some(_, tcInfoExtras) ->
tcInfoExtras.TcSymbolUses
| _ ->
TcSymbolUses.Empty
| _ ->
TcSymbolUses.Empty
)
| Choice2Of2 tcSymbolUses ->
[|tcSymbolUses|]

[| for r in tcSymbolUses do
for symbolUseChunk in r.AllUsesOfSymbols do
for symbolUse in symbolUseChunk do
Expand Down Expand Up @@ -2353,7 +2390,7 @@ type FsiInteractiveChecker(legacyReferenceResolver,
FSharpCheckProjectResults (filename, Some tcConfig,
keepAssemblyContents, errors,
Some(tcGlobals, tcImports, tcFileInfo.ThisCcu, tcFileInfo.CcuSigForFile,
[tcFileInfo.ScopeSymbolUses], None, None, mkSimpleAssemblyRef "stdin",
(Choice2Of2 tcFileInfo.ScopeSymbolUses), None, None, mkSimpleAssemblyRef "stdin",
tcState.TcEnvFromImpls.AccessRights, None, dependencyFiles,
projectOptions))

Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/service/FSharpCheckerResults.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ type public FSharpCheckProjectResults =
TcImports *
CcuThunk *
ModuleOrNamespaceType *
TcSymbolUses list *
Choice<IncrementalBuilder, TcSymbolUses> *
TopAttribs option *
IRawFSharpAssemblyData option *
ILAssemblyRef *
Expand Down
54 changes: 28 additions & 26 deletions src/fsharp/service/IncrementalBuild.fs
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,9 @@ type TcInfo =
[<NoEquality; NoComparison>]
type TcInfoExtras =
{
/// Accumulated resolutions, last file first
tcResolutionsRev: TcResolutions list

/// Accumulated symbol uses, last file first
tcSymbolUsesRev: TcSymbolUses list

/// Accumulated 'open' declarations, last file first
tcOpenDeclarationsRev: OpenDeclaration[] list
tcResolutions: TcResolutions
tcSymbolUses: TcSymbolUses
tcOpenDeclarations: OpenDeclaration[]

/// Result of checking most recent file, if any
latestImplFile: TypedImplFile option
Expand All @@ -202,16 +197,16 @@ type TcInfoExtras =
}

member x.TcSymbolUses =
List.rev x.tcSymbolUsesRev
x.tcSymbolUses

[<AutoOpen>]
module TcInfoHelpers =

let emptyTcInfoExtras =
{
tcResolutionsRev = []
tcSymbolUsesRev = []
tcOpenDeclarationsRev = []
tcResolutions = TcResolutions.Empty
tcSymbolUses = TcSymbolUses.Empty
tcOpenDeclarations = [||]
latestImplFile = None
itemKeyStore = None
semanticClassificationKeyStore = None
Expand Down Expand Up @@ -258,7 +253,6 @@ type BoundModel private (tcConfig: TcConfig,
beforeFileChecked: Event<string>,
fileChecked: Event<string>,
prevTcInfo: TcInfo,
prevTcInfoExtras: NodeCode<TcInfoExtras>,
syntaxTreeOpt: SyntaxTree option,
tcInfoStateOpt: TcInfoState option) as this =

Expand Down Expand Up @@ -295,8 +289,7 @@ type BoundModel private (tcConfig: TcConfig,

let defaultTypeCheck () =
node {
let! prevTcInfoExtras = prevTcInfoExtras
return FullState(prevTcInfo, prevTcInfoExtras)
return PartialState(prevTcInfo)
}

member _.TcConfig = tcConfig
Expand Down Expand Up @@ -347,7 +340,6 @@ type BoundModel private (tcConfig: TcConfig,
beforeFileChecked,
fileChecked,
prevTcInfo,
prevTcInfoExtras,
newSyntaxTreeOpt,
newTcInfoStateOpt)
else
Expand All @@ -366,7 +358,6 @@ type BoundModel private (tcConfig: TcConfig,
beforeFileChecked,
fileChecked,
tcInfo,
this.GetOrComputeTcInfoExtras(),
Some syntaxTree,
None)

Expand Down Expand Up @@ -402,7 +393,6 @@ type BoundModel private (tcConfig: TcConfig,
beforeFileChecked,
fileChecked,
prevTcInfo,
prevTcInfoExtras,
syntaxTreeOpt,
Some finishState)
}
Expand All @@ -417,6 +407,13 @@ type BoundModel private (tcConfig: TcConfig,
| ValueSome(tcInfo, _) -> Some tcInfo
| _ -> None

member _.TryPeekTcInfoWithExtras() =
match tcInfoNode with
| TcInfoNode(_, fullGraphNode) ->
match fullGraphNode.TryPeekValue() with
| ValueSome(tcInfo, tcInfoExtras) -> Some(tcInfo, tcInfoExtras)
| _ -> None

member _.GetOrComputeTcInfo() =
match tcInfoNode with
| TcInfoNode(partialGraphNode, _) ->
Expand Down Expand Up @@ -512,7 +509,6 @@ type BoundModel private (tcConfig: TcConfig,
if partialCheck then
return PartialState tcInfo
else
let! prevTcInfoOptional = prevTcInfoExtras
// Build symbol keys
let itemKeyStore, semanticClassification =
if enableBackgroundItemKeyStoreAndSemanticClassification then
Expand Down Expand Up @@ -543,9 +539,9 @@ type BoundModel private (tcConfig: TcConfig,
{
/// Only keep the typed interface files when doing a "full" build for fsc.exe, otherwise just throw them away
latestImplFile = if keepAssemblyContents then implFile else None
tcResolutionsRev = (if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty) :: prevTcInfoOptional.tcResolutionsRev
tcSymbolUsesRev = (if keepAllBackgroundSymbolUses then sink.GetSymbolUses() else TcSymbolUses.Empty) :: prevTcInfoOptional.tcSymbolUsesRev
tcOpenDeclarationsRev = sink.GetOpenDeclarations() :: prevTcInfoOptional.tcOpenDeclarationsRev
tcResolutions = (if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty)
tcSymbolUses = (if keepAllBackgroundSymbolUses then sink.GetSymbolUses() else TcSymbolUses.Empty)
tcOpenDeclarations = sink.GetOpenDeclarations()
itemKeyStore = itemKeyStore
semanticClassificationKeyStore = semanticClassification
}
Expand All @@ -563,7 +559,6 @@ type BoundModel private (tcConfig: TcConfig,
beforeFileChecked: Event<string>,
fileChecked: Event<string>,
prevTcInfo: TcInfo,
prevTcInfoExtras: NodeCode<TcInfoExtras>,
syntaxTreeOpt: SyntaxTree option) =
BoundModel(tcConfig, tcGlobals, tcImports,
keepAssemblyContents, keepAllBackgroundResolutions,
Expand All @@ -573,7 +568,6 @@ type BoundModel private (tcConfig: TcConfig,
beforeFileChecked,
fileChecked,
prevTcInfo,
prevTcInfoExtras,
syntaxTreeOpt,
None)

Expand Down Expand Up @@ -650,6 +644,8 @@ type PartialCheckResults (boundModel: BoundModel, timeStamp: DateTime) =

member _.TryPeekTcInfo() = boundModel.TryPeekTcInfo()

member _.TryPeekTcInfoWithExtras() = boundModel.TryPeekTcInfoWithExtras()

member _.GetOrComputeTcInfo() = boundModel.GetOrComputeTcInfo()

member _.GetOrComputeTcInfoWithExtras() = boundModel.GetOrComputeTcInfoWithExtras()
Expand Down Expand Up @@ -836,7 +832,6 @@ type IncrementalBuilder(
tcDependencyFiles = basicDependencies
sigNameOpt = None
}
let tcInfoExtras = emptyTcInfoExtras
return
BoundModel.Create(
tcConfig,
Expand All @@ -850,7 +845,6 @@ type IncrementalBuilder(
beforeFileChecked,
fileChecked,
tcInfo,
node { return tcInfoExtras },
None) }

/// Type check all files eagerly.
Expand Down Expand Up @@ -1191,6 +1185,14 @@ type IncrementalBuilder(
| Some (boundModel, timestamp) -> Some (PartialCheckResults (boundModel, timestamp))
| _ -> None

member builder.GetCheckResultsForFileInProjectEvenIfStale filename: PartialCheckResults option =
let slotOfFile = builder.GetSlotOfFileName filename
let result = tryGetSlot currentState slotOfFile

match result with
| Some (boundModel, timestamp) -> Some (PartialCheckResults (boundModel, timestamp))
| _ -> None

member builder.TryGetCheckResultsBeforeFileInProject (filename) =
let cache = TimeStampCache defaultTimeStamp
let tmpState = computeStampedFileNames currentState cache
Expand Down
22 changes: 13 additions & 9 deletions src/fsharp/service/IncrementalBuild.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,9 @@ type internal TcInfo =
[<NoEquality; NoComparison>]
type internal TcInfoExtras =
{
/// Accumulated resolutions, last file first
tcResolutionsRev: TcResolutions list

/// Accumulated symbol uses, last file first
tcSymbolUsesRev: TcSymbolUses list

/// Accumulated 'open' declarations, last file first
tcOpenDeclarationsRev: OpenDeclaration[] list
tcResolutions: TcResolutions
tcSymbolUses: TcSymbolUses
tcOpenDeclarations: OpenDeclaration[]

/// Result of checking most recent file, if any
latestImplFile: TypedImplFile option
Expand All @@ -92,7 +87,7 @@ type internal TcInfoExtras =
semanticClassificationKeyStore: SemanticClassificationKeyStore option
}

member TcSymbolUses: TcSymbolUses list
member TcSymbolUses: TcSymbolUses

/// Represents the state in the incremental graph associated with checking a file
[<Sealed>]
Expand All @@ -108,6 +103,8 @@ type internal PartialCheckResults =

member TryPeekTcInfo: unit -> TcInfo option

member TryPeekTcInfoWithExtras: unit -> (TcInfo * TcInfoExtras) option

/// Compute the "TcInfo" part of the results. If `enablePartialTypeChecking` is false then
/// extras will also be available.
member GetOrComputeTcInfo: unit -> NodeCode<TcInfo>
Expand Down Expand Up @@ -178,6 +175,13 @@ type internal IncrementalBuilder =
/// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread.
member GetCheckResultsBeforeFileInProjectEvenIfStale: filename:string -> PartialCheckResults option

/// Get the typecheck state of a slot, without checking if it is up-to-date w.r.t.
/// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available.
/// This is a very quick operation.
///
/// This is safe for use from non-compiler threads but the objects returned must in many cases be accessed only from the compiler thread.
member GetCheckResultsForFileInProjectEvenIfStale: filename:string -> PartialCheckResults option

/// Get the preceding typecheck state of a slot, but only if it is up-to-date w.r.t.
/// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available.
/// This is a relatively quick operation.
Expand Down
18 changes: 9 additions & 9 deletions src/fsharp/service/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -698,9 +698,9 @@ type BackgroundCompiler(

let! tcInfo, tcInfoExtras = tcProj.GetOrComputeTcInfoWithExtras()

let tcResolutionsRev = tcInfoExtras.tcResolutionsRev
let tcSymbolUsesRev = tcInfoExtras.tcSymbolUsesRev
let tcOpenDeclarationsRev = tcInfoExtras.tcOpenDeclarationsRev
let tcResolutions = tcInfoExtras.tcResolutions
let tcSymbolUses = tcInfoExtras.tcSymbolUses
let tcOpenDeclarations = tcInfoExtras.tcOpenDeclarations
let latestCcuSigForFile = tcInfo.latestCcuSigForFile
let tcState = tcInfo.tcState
let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile
Expand Down Expand Up @@ -730,12 +730,12 @@ type BackgroundCompiler(
tcState.Ccu,
tcProj.TcImports,
tcEnvAtEnd.AccessRights,
List.head tcResolutionsRev,
List.head tcSymbolUsesRev,
tcResolutions,
tcSymbolUses,
tcEnvAtEnd.NameEnv,
loadClosure,
latestImplementationFile,
List.head tcOpenDeclarationsRev)
tcOpenDeclarations)
return (parseResults, typedResults)
}

Expand Down Expand Up @@ -799,9 +799,9 @@ type BackgroundCompiler(
let errorOptions = tcProj.TcConfig.errorSeverityOptions
let fileName = TcGlobals.DummyFileNameForRangesWithoutASpecificLocation

let! tcInfo, tcInfoExtras = tcProj.GetOrComputeTcInfoWithExtras()
// Although we do not use 'tcInfoExtras', computing it will make sure we get an extra info.
let! tcInfo, _tcInfoExtras = tcProj.GetOrComputeTcInfoWithExtras()

let tcSymbolUses = tcInfoExtras.TcSymbolUses
let topAttribs = tcInfo.topAttribs
let tcState = tcInfo.tcState
let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile
Expand All @@ -817,7 +817,7 @@ type BackgroundCompiler(
keepAssemblyContents,
diagnostics,
Some(tcProj.TcGlobals, tcProj.TcImports, tcState.Ccu, tcState.CcuSig,
tcSymbolUses, topAttribs, tcAssemblyDataOpt, ilAssemRef,
(Choice1Of2 builder), topAttribs, tcAssemblyDataOpt, ilAssemRef,
tcEnvAtEnd.AccessRights, tcAssemblyExprOpt,
Array.ofList tcDependencyFiles,
options))
Expand Down

0 comments on commit 1e750b3

Please sign in to comment.