Skip to content

Commit 630be62

Browse files
majochaT-Gro
andauthored
Refactoring of IncrementalBuilder (#14903)
* one pass mapFold, cache parse tasks * refactor a bit * ah, ok * works again? * some refactoring * fix test for now * lock it * better * cleanup * more correct? * not in use * restore test * wip * refactor away partialCheck flag where possible * fantomas * fix * ok * add this back * format * fmt * wip * restore enablePartialTypeChecking * restore enablePartialTypeChecking * fix conflict * naming stuff * fix test * task run * update docs * use SemaphoreSlim * add a comment * fix * revert to lock * make full type check more parallel * Revert "make full type check more parallel" This reverts commit 632b3ba. * refactor BoundModel, parallel typecheck when possible * use GraphNode to keep parsing result * fantomas * commited too much, fix * fix bug, fix tests * eager parsing * not useful and not deterministic * remove eager parsing * oh, well * cleanup * do not compute temp states * remove private * reclaim type check memory faster * dont check when state is given * less ugly --------- Co-authored-by: Tomas Grosup <[email protected]>
1 parent d373384 commit 630be62

File tree

6 files changed

+481
-691
lines changed

6 files changed

+481
-691
lines changed

src/Compiler/Driver/ParseAndCheckInputs.fs

Lines changed: 84 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,10 +1156,6 @@ let GetInitialTcState (m, ccuName, tcConfig: TcConfig, tcGlobals, tcImports: TcI
11561156
tcsImplicitOpenDeclarations = openDecls0
11571157
}
11581158

1159-
/// Dummy typed impl file that contains no definitions and is not used for emitting any kind of assembly.
1160-
let CreateEmptyDummyImplFile qualNameOfFile sigTy =
1161-
CheckedImplFile(qualNameOfFile, [], sigTy, ModuleOrNamespaceContents.TMDefs [], false, false, StampMap [], Map.empty)
1162-
11631159
let AddCheckResultsToTcState
11641160
(tcGlobals, amap, hadSig, prefixPathOpt, tcSink, tcImplEnv, qualNameOfFile, implFileSigType)
11651161
(tcState: TcState)
@@ -1208,28 +1204,68 @@ let AddCheckResultsToTcState
12081204

12091205
type PartialResult = TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType
12101206

1211-
/// Typecheck a single file (or interactive entry into F# Interactive)
1212-
let CheckOneInputAux
1207+
/// Returns partial type check result for skipped implementation files.
1208+
let SkippedImplFilePlaceholder (tcConfig: TcConfig, tcImports: TcImports, tcGlobals, tcState, input: ParsedInput) =
1209+
use _ =
1210+
Activity.start "ParseAndCheckInputs.SkippedImplFilePlaceholder" [| Activity.Tags.fileName, input.FileName |]
1211+
1212+
CheckSimulateException tcConfig
1213+
1214+
match input with
1215+
| ParsedInput.ImplFile file ->
1216+
let qualNameOfFile = file.QualifiedName
1217+
1218+
// Check if we've got an interface for this fragment
1219+
let rootSigOpt = tcState.tcsRootSigs.TryFind qualNameOfFile
1220+
1221+
// Check if we've already seen an implementation for this fragment
1222+
if Zset.contains qualNameOfFile tcState.tcsRootImpls then
1223+
errorR (Error(FSComp.SR.buildImplementationAlreadyGiven (qualNameOfFile.Text), input.Range))
1224+
1225+
let hadSig = rootSigOpt.IsSome
1226+
1227+
match rootSigOpt with
1228+
| Some rootSigTy ->
1229+
// Delay the typecheck the implementation file until the second phase of parallel processing.
1230+
// Adjust the TcState as if it has been checked, which makes the signature for the file available later
1231+
// in the compilation order.
1232+
let tcStateForImplFile = tcState
1233+
let amap = tcImports.GetImportMap()
1234+
1235+
let ccuSigForFile, tcState =
1236+
AddCheckResultsToTcState
1237+
(tcGlobals, amap, hadSig, None, TcResultsSink.NoSink, tcState.tcsTcImplEnv, qualNameOfFile, rootSigTy)
1238+
tcState
1239+
1240+
let emptyImplFile =
1241+
CheckedImplFile(qualNameOfFile, [], rootSigTy, ModuleOrNamespaceContents.TMDefs [], false, false, StampMap [], Map.empty)
1242+
1243+
let tcEnvAtEnd = tcStateForImplFile.TcEnvFromImpls
1244+
Some((tcEnvAtEnd, EmptyTopAttrs, Some emptyImplFile, ccuSigForFile), tcState)
1245+
1246+
| _ -> None
1247+
| _ -> None
1248+
1249+
/// Typecheck a single file (or interactive entry into F# Interactive).
1250+
let CheckOneInput
12131251
(
12141252
checkForErrors,
12151253
tcConfig: TcConfig,
12161254
tcImports: TcImports,
1217-
tcGlobals,
1218-
prefixPathOpt,
1219-
tcSink,
1255+
tcGlobals: TcGlobals,
1256+
prefixPathOpt: LongIdent option,
1257+
tcSink: TcResultsSink,
12201258
tcState: TcState,
1221-
inp: ParsedInput,
1222-
skipImplIfSigExists: bool
1223-
) =
1224-
1259+
input: ParsedInput
1260+
) : Cancellable<PartialResult * TcState> =
12251261
cancellable {
12261262
try
12271263
use _ =
1228-
Activity.start "ParseAndCheckInputs.CheckOneInput" [| Activity.Tags.fileName, inp.FileName |]
1264+
Activity.start "ParseAndCheckInputs.CheckOneInput" [| Activity.Tags.fileName, input.FileName |]
12291265

12301266
CheckSimulateException tcConfig
12311267

1232-
let m = inp.Range
1268+
let m = input.Range
12331269
let amap = tcImports.GetImportMap()
12341270

12351271
let conditionalDefines =
@@ -1238,7 +1274,7 @@ let CheckOneInputAux
12381274
else
12391275
Some tcConfig.conditionalDefines
12401276

1241-
match inp with
1277+
match input with
12421278
| ParsedInput.SigFile file ->
12431279
let qualNameOfFile = file.QualifiedName
12441280

@@ -1285,7 +1321,7 @@ let CheckOneInputAux
12851321
tcsCreatesGeneratedProvidedTypes = tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
12861322
}
12871323

1288-
return Choice1Of2(tcEnv, EmptyTopAttrs, None, ccuSigForFile), tcState
1324+
return (tcEnv, EmptyTopAttrs, None, ccuSigForFile), tcState
12891325

12901326
| ParsedInput.ImplFile file ->
12911327
let qualNameOfFile = file.QualifiedName
@@ -1299,92 +1335,47 @@ let CheckOneInputAux
12991335

13001336
let hadSig = rootSigOpt.IsSome
13011337

1302-
match rootSigOpt with
1303-
| Some rootSig when skipImplIfSigExists ->
1304-
// Delay the typecheck the implementation file until the second phase of parallel processing.
1305-
// Adjust the TcState as if it has been checked, which makes the signature for the file available later
1306-
// in the compilation order.
1307-
let tcStateForImplFile = tcState
1308-
let qualNameOfFile = file.QualifiedName
1309-
let priorErrors = checkForErrors ()
1310-
1311-
let ccuSigForFile, tcState =
1312-
AddCheckResultsToTcState
1313-
(tcGlobals, amap, hadSig, prefixPathOpt, tcSink, tcState.tcsTcImplEnv, qualNameOfFile, rootSig)
1314-
tcState
1338+
// Typecheck the implementation file
1339+
let! topAttrs, implFile, tcEnvAtEnd, createsGeneratedProvidedTypes =
1340+
CheckOneImplFile(
1341+
tcGlobals,
1342+
amap,
1343+
tcState.tcsCcu,
1344+
tcState.tcsImplicitOpenDeclarations,
1345+
checkForErrors,
1346+
conditionalDefines,
1347+
tcSink,
1348+
tcConfig.internalTestSpanStackReferring,
1349+
tcState.tcsTcImplEnv,
1350+
rootSigOpt,
1351+
file,
1352+
tcConfig.diagnosticsOptions
1353+
)
13151354

1316-
let partialResult =
1317-
(amap, conditionalDefines, rootSig, priorErrors, file, tcStateForImplFile, ccuSigForFile)
1355+
let tcState =
1356+
{ tcState with
1357+
tcsCreatesGeneratedProvidedTypes = tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
1358+
}
13181359

1319-
return Choice2Of2 partialResult, tcState
1360+
let ccuSigForFile, tcState =
1361+
AddCheckResultsToTcState
1362+
(tcGlobals, amap, hadSig, prefixPathOpt, tcSink, tcState.tcsTcImplEnv, qualNameOfFile, implFile.Signature)
1363+
tcState
13201364

1321-
| _ ->
1322-
// Typecheck the implementation file
1323-
let! topAttrs, implFile, tcEnvAtEnd, createsGeneratedProvidedTypes =
1324-
CheckOneImplFile(
1325-
tcGlobals,
1326-
amap,
1327-
tcState.tcsCcu,
1328-
tcState.tcsImplicitOpenDeclarations,
1329-
checkForErrors,
1330-
conditionalDefines,
1331-
tcSink,
1332-
tcConfig.internalTestSpanStackReferring,
1333-
tcState.tcsTcImplEnv,
1334-
rootSigOpt,
1335-
file,
1336-
tcConfig.diagnosticsOptions
1337-
)
1338-
1339-
let tcState =
1340-
{ tcState with
1341-
tcsCreatesGeneratedProvidedTypes = tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
1342-
}
1343-
1344-
let ccuSigForFile, tcState =
1345-
AddCheckResultsToTcState
1346-
(tcGlobals, amap, hadSig, prefixPathOpt, tcSink, tcState.tcsTcImplEnv, qualNameOfFile, implFile.Signature)
1347-
tcState
1348-
1349-
let result = (tcEnvAtEnd, topAttrs, Some implFile, ccuSigForFile)
1350-
return Choice1Of2 result, tcState
1365+
let result = (tcEnvAtEnd, topAttrs, Some implFile, ccuSigForFile)
1366+
return result, tcState
13511367

13521368
with e ->
13531369
errorRecovery e range0
1354-
return Choice1Of2(tcState.TcEnvFromSignatures, EmptyTopAttrs, None, tcState.tcsCcuSig), tcState
1355-
}
1356-
1357-
/// Typecheck a single file (or interactive entry into F# Interactive). If skipImplIfSigExists is set to true
1358-
/// then implementations with signature files give empty results.
1359-
let CheckOneInput
1360-
((checkForErrors,
1361-
tcConfig: TcConfig,
1362-
tcImports: TcImports,
1363-
tcGlobals,
1364-
prefixPathOpt,
1365-
tcSink,
1366-
tcState: TcState,
1367-
input: ParsedInput,
1368-
skipImplIfSigExists: bool): (unit -> bool) * TcConfig * TcImports * TcGlobals * LongIdent option * TcResultsSink * TcState * ParsedInput * bool)
1369-
: Cancellable<PartialResult * TcState> =
1370-
cancellable {
1371-
let! partialResult, tcState =
1372-
CheckOneInputAux(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input, skipImplIfSigExists)
1373-
1374-
match partialResult with
1375-
| Choice1Of2 result -> return result, tcState
1376-
| Choice2Of2 (_amap, _conditionalDefines, rootSig, _priorErrors, file, tcStateForImplFile, ccuSigForFile) ->
1377-
let emptyImplFile = CreateEmptyDummyImplFile file.QualifiedName rootSig
1378-
let tcEnvAtEnd = tcStateForImplFile.TcEnvFromImpls
1379-
return (tcEnvAtEnd, EmptyTopAttrs, Some emptyImplFile, ccuSigForFile), tcState
1370+
return (tcState.TcEnvFromSignatures, EmptyTopAttrs, None, tcState.tcsCcuSig), tcState
13801371
}
13811372

13821373
// Within a file, equip loggers to locally filter w.r.t. scope pragmas in each input
13831374
let DiagnosticsLoggerForInput (tcConfig: TcConfig, input: ParsedInput, oldLogger) =
13841375
GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, oldLogger)
13851376

13861377
/// Typecheck a single file (or interactive entry into F# Interactive)
1387-
let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, skipImplIfSigExists) tcState input =
1378+
let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt) tcState input =
13881379
// Equip loggers to locally filter w.r.t. scope pragmas in each input
13891380
use _ =
13901381
UseTransformedDiagnosticsLogger(fun oldLogger -> DiagnosticsLoggerForInput(tcConfig, input, oldLogger))
@@ -1393,7 +1384,7 @@ let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcG
13931384

13941385
RequireCompilationThread ctok
13951386

1396-
CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, input, skipImplIfSigExists)
1387+
CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, input)
13971388
|> Cancellable.runWithoutCancellation
13981389

13991390
/// Finish checking multiple files (or one interactive entry into F# Interactive)
@@ -1411,7 +1402,7 @@ let CheckMultipleInputsFinish (results, tcState: TcState) =
14111402

14121403
let CheckOneInputAndFinish (checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) =
14131404
cancellable {
1414-
let! result, tcState = CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input, false)
1405+
let! result, tcState = CheckOneInput(checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input)
14151406
let finishedResult = CheckMultipleInputsFinish([ result ], tcState)
14161407
return finishedResult
14171408
}
@@ -1431,7 +1422,7 @@ let CheckClosedInputSetFinish (declaredImpls: CheckedImplFile list, tcState) =
14311422

14321423
let CheckMultipleInputsSequential (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs) =
14331424
(tcState, inputs)
1434-
||> List.mapFold (CheckOneInputEntry(ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, false))
1425+
||> List.mapFold (CheckOneInputEntry(ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt))
14351426

14361427
open FSharp.Compiler.GraphChecking
14371428

src/Compiler/Driver/ParseAndCheckInputs.fsi

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ type TcState =
134134
/// Get the initial type checking state for a set of inputs
135135
val GetInitialTcState: range * string * TcConfig * TcGlobals * TcImports * TcEnv * OpenDeclaration list -> TcState
136136

137+
/// Returns partial type check result for skipped implementation files.
138+
val SkippedImplFilePlaceholder:
139+
tcConfig: TcConfig * tcImports: TcImports * tcGlobals: TcGlobals * tcState: TcState * input: ParsedInput ->
140+
((TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState) option
141+
137142
/// Check one input, returned as an Eventually computation
138143
val CheckOneInput:
139144
checkForErrors: (unit -> bool) *
@@ -143,8 +148,7 @@ val CheckOneInput:
143148
prefixPathOpt: LongIdent option *
144149
tcSink: NameResolution.TcResultsSink *
145150
tcState: TcState *
146-
input: ParsedInput *
147-
skipImplIfSigExists: bool ->
151+
input: ParsedInput ->
148152
Cancellable<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState>
149153

150154
/// Finish the checking of multiple inputs

0 commit comments

Comments
 (0)