Skip to content

Commit 9e1cdc9

Browse files
committed
Typecheck cache update
1 parent bef8db3 commit 9e1cdc9

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

fcs/fcs-fable/service_shim.fs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,18 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcInitialState
305305

306306
member private x.ClearStaleCache (fileName: string, parsingOptions: FSharpParsingOptions) =
307307
let fileIndex = parsingOptions.SourceFiles |> Array.findIndex ((=) fileName)
308+
let filesAbove = parsingOptions.SourceFiles |> Array.take fileIndex
309+
// backup all cached typecheck entries above file
310+
let cachedAbove = filesAbove |> Array.choose (fun key ->
311+
match checkCache.TryGetValue(key) with
312+
| true, value -> Some (key, value)
313+
| false, _ -> None)
314+
// remove all parse cache entries with the same file name
308315
let staleParseKeys = parseCache.Keys |> Seq.filter (fun (n,_) -> n = fileName) |> Seq.toArray
309-
let staleCheckKeys = parsingOptions.SourceFiles |> Array.skip fileIndex
310316
staleParseKeys |> Array.iter (fun key -> parseCache.Remove(key) |> ignore)
311-
staleCheckKeys |> Array.iter (fun key -> checkCache.Remove(key) |> ignore)
317+
checkCache.Clear(); // clear all typecheck cache
318+
// restore all cached typecheck entries above file
319+
cachedAbove |> Array.iter (fun (key, value) -> checkCache.TryAdd(key, value) |> ignore)
312320

313321
member private x.ParseFile (fileName: string, source: string, parsingOptions: FSharpParsingOptions) =
314322
let parseCacheKey = fileName, hash source
@@ -373,6 +381,13 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcInitialState
373381
let tcState, declaredImpls = TypeCheckClosedInputSetFinish (implFiles, tcState)
374382
tcState, topAttrs, declaredImpls, tcEnvAtEndOfLastFile, moduleNamesDict
375383

384+
/// Errors grouped by file, sorted by line, column
385+
member private x.ErrorsByFile (fileNames: string[], errorList: FSharpErrorInfo[] list) =
386+
let errorMap = errorList |> Array.concat |> Array.groupBy (fun x -> x.FileName) |> Map.ofArray
387+
let errors = fileNames |> Array.choose errorMap.TryFind
388+
errors |> Array.iter (Array.sortInPlaceBy (fun x -> x.StartLineAlternate, x.StartColumn))
389+
errors |> Array.concat
390+
376391
/// Clears parse and typecheck caches.
377392
member x.ClearCache () =
378393
parseCache.Clear()
@@ -426,7 +441,7 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcInitialState
426441
// make project results
427442
let parseErrors = parseResults |> Array.collect (fun p -> p.Errors)
428443
let typedErrors = errorScope.Diagnostics |> List.toArray
429-
let errors = Array.append parseErrors typedErrors //TODO: order by file
444+
let errors = x.ErrorsByFile (fileNames, [ parseErrors; typedErrors ])
430445
let symbolUses = [] //TODO:
431446
let projectResults = x.MakeProjectResults (projectFileName, parseResults, tcState, errors, symbolUses, Some topAttrs, Some tcImplFiles)
432447

@@ -467,7 +482,7 @@ type InteractiveChecker internal (tcConfig, tcGlobals, tcImports, tcInitialState
467482
let parseErrorsBefore = parseResults |> Array.collect (fun p -> p.Errors)
468483
let typedErrorsBefore = errorScope.Diagnostics |> List.toArray
469484
let newErrors = match checkFileResults with | Some res -> res.Errors | None -> [||]
470-
let errors = [| yield! parseErrorsBefore; yield! typedErrorsBefore; yield! newErrors |] //TODO: order by file
485+
let errors = x.ErrorsByFile (fileNames, [ parseErrorsBefore; typedErrorsBefore; newErrors ])
471486

472487
// make partial project results
473488
let parseResults = Array.append parseResults [| parseFileResults |]

fcs/fcs-fable/test/bench.fs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,33 @@ let parseFiles projectPath outDir optimized =
115115
let showWarnings = false // supress warnings for clarity
116116
projectResults.Errors |> printErrors showWarnings
117117

118+
// // modify last file
119+
// sources.[sources.Length - 1] <- sources.[sources.Length - 1] + "\n"
120+
// let parseFSharpProject () = checker.ParseAndCheckProject(projectFileName, fileNames, sources)
121+
// let ms1, projectResults = measureTime parseFSharpProject ()
122+
// printfn "Project: %s, FCS time: %d ms (modified last file)" projectFileName ms1
123+
124+
// // modify middle file
125+
// sources.[sources.Length / 2] <- sources.[sources.Length / 2] + "\n"
126+
// let parseFSharpProject () = checker.ParseAndCheckProject(projectFileName, fileNames, sources)
127+
// let ms1, projectResults = measureTime parseFSharpProject ()
128+
// printfn "Project: %s, FCS time: %d ms (modified middle file)" projectFileName ms1
129+
130+
// // modify first file
131+
// sources.[0] <- sources.[0] + "\n"
132+
// let parseFSharpProject () = checker.ParseAndCheckProject(projectFileName, fileNames, sources)
133+
// let ms1, projectResults = measureTime parseFSharpProject ()
134+
// printfn "Project: %s, FCS time: %d ms (modified first file)" projectFileName ms1
135+
136+
// // clear cache
137+
// checker.ClearCache()
138+
139+
// // after clear cache
140+
// sources.[0] <- sources.[0] + "\n"
141+
// let parseFSharpProject () = checker.ParseAndCheckProject(projectFileName, fileNames, sources)
142+
// let ms1, projectResults = measureTime parseFSharpProject ()
143+
// printfn "Project: %s, FCS time: %d ms (after clear cache)" projectFileName ms1
144+
118145
// exclude signature files
119146
let fileNames = fileNames |> Array.filter (fun x -> not (x.EndsWith(".fsi")))
120147

0 commit comments

Comments
 (0)