Skip to content

Commit 39e8490

Browse files
dawedawe0101
authored andcommitted
Add a version of TryGetRecentCheckResultsForFile with project snapshot (dotnet#16720)
* First stab at adding a version of TryGetRecentCheckResultsForFile that takes a snapshot instead of project options * use version type without defaultof<_> = null * take sourcetext out of project snapshot, kind of forces us to an async return but let's see if this is acceptable * format * - reuse ParseAndCheckFileInProject cache for TryGetRecentCheckResultsForFile - extend version of ParseAndCheckFileInProject cache with the check sum of the source code - add test * format * cleanup * use a new LruCache member GetAll to get rid of the dummy version * cleanup * Update src/Compiler/Service/TransparentCompiler.fs Co-authored-by: Petr Pokorny <[email protected]> * unify key creation * just use ProjectSnapShot.FileKey * to have it on record, push a version with "f.Version |> Md5Hasher.toString" as the second part of lastFileKey.Version * use FileKeyWithExtraFileSnapshotVersion for the ParseAndCheckFileInProject cache * replace FileSnapShot after edit in Test * add CustomOperation tryGetRecentCheckResults for tests * - Make API non-async and don't return hash - let tests run for background compiler, too * better fix for commandLineOptions order * Update src/Compiler/Service/FSharpProjectSnapshot.fs Co-authored-by: Petr Pokorny <[email protected]> * Update tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs Co-authored-by: Petr Pokorny <[email protected]> * Update tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs Co-authored-by: Petr Pokorny <[email protected]> * fix version predicate * let LruCache.GetAll(key: 'TKey) return a seq instead of a list * compare signatures in CustomOperation tryGetRecentCheckResults to tighten the tests --------- Co-authored-by: Petr Pokorny <[email protected]>
1 parent 32e3b0a commit 39e8490

File tree

16 files changed

+274
-32
lines changed

16 files changed

+274
-32
lines changed

src/Compiler/Facilities/AsyncMemoize.fs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,15 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T
534534

535535
}
536536

537+
member _.TryGet(key: 'TKey, predicate: 'TVersion -> bool) : 'TValue option =
538+
let versionsAndJobs = cache.GetAll(key)
539+
540+
versionsAndJobs
541+
|> Seq.tryPick (fun (version, job) ->
542+
match predicate version, job with
543+
| true, Completed(completed, _) -> Some completed
544+
| _ -> None)
545+
537546
member _.Clear() = cache.Clear()
538547

539548
member _.Clear predicate = cache.Clear predicate

src/Compiler/Facilities/AsyncMemoize.fsi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T
6969

7070
member Get': key: 'TKey * computation: NodeCode<'TValue> -> NodeCode<'TValue>
7171

72+
member TryGet: key: 'TKey * predicate: ('TVersion -> bool) -> 'TValue option
73+
7274
member Event: IEvent<JobEvent * (string * 'TKey * 'TVersion)>
7375

7476
member OnEvent: ((JobEvent * (string * 'TKey * 'TVersion) -> unit) -> unit)

src/Compiler/Service/BackgroundCompiler.fs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ type internal IBackgroundCompiler =
181181

182182
abstract GetCachedScriptSnapshot: path: string -> FSharpProjectSnapshot option
183183

184+
abstract member TryGetRecentCheckResultsForFile:
185+
fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string ->
186+
(FSharpParseFileResults * FSharpCheckFileResults) option
187+
184188
abstract member BeforeBackgroundFileCheck: IEvent<string * FSharpProjectOptions>
185189

186190
abstract member FileChecked: IEvent<string * FSharpProjectOptions>
@@ -1176,6 +1180,16 @@ type internal BackgroundCompiler
11761180
| None -> None
11771181
| None -> None
11781182

1183+
member _.TryGetRecentCheckResultsForFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) =
1184+
projectSnapshot.ProjectSnapshot.SourceFiles
1185+
|> List.tryFind (fun f -> f.FileName = fileName)
1186+
|> Option.bind (fun (f: FSharpFileSnapshot) ->
1187+
let options = projectSnapshot.ToOptions()
1188+
let sourceText = f.GetSource() |> Async.AwaitTask |> Async.RunSynchronously
1189+
1190+
self.TryGetRecentCheckResultsForFile(fileName, options, Some sourceText, userOpName)
1191+
|> Option.map (fun (parseFileResults, checkFileResults, _hash) -> (parseFileResults, checkFileResults)))
1192+
11791193
/// Parse and typecheck the whole project (the implementation, called recursively as project graph is evaluated)
11801194
member private _.ParseAndCheckProjectImpl(options, userOpName) =
11811195
node {
@@ -1641,7 +1655,7 @@ type internal BackgroundCompiler
16411655
userOpName
16421656
)
16431657

1644-
let! snapshot = FSharpProjectSnapshot.FromOptions(options, DocumentSource.FileSystem)
1658+
let! snapshot = FSharpProjectSnapshot.FromOptions(options)
16451659
return snapshot, diagnostics
16461660
}
16471661

@@ -1742,3 +1756,11 @@ type internal BackgroundCompiler
17421756
// I'm not expecting anything actually async to happen here.
17431757
// As the snapshot will most likely not have any referenced projects
17441758
FSharpProjectSnapshot.FromOptions options |> Async.RunSynchronously)
1759+
1760+
member _.TryGetRecentCheckResultsForFile
1761+
(
1762+
fileName: string,
1763+
projectSnapshot: FSharpProjectSnapshot,
1764+
userOpName: string
1765+
) : (FSharpParseFileResults * FSharpCheckFileResults) option =
1766+
self.TryGetRecentCheckResultsForFile(fileName, projectSnapshot, userOpName)

src/Compiler/Service/BackgroundCompiler.fsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ type internal IBackgroundCompiler =
171171

172172
abstract GetCachedScriptSnapshot: path: string -> FSharpProjectSnapshot option
173173

174+
abstract TryGetRecentCheckResultsForFile:
175+
fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string ->
176+
(FSharpParseFileResults * FSharpCheckFileResults) option
177+
174178
abstract BeforeBackgroundFileCheck: IEvent<string * FSharpProjectOptions>
175179

176180
abstract FileChecked: IEvent<string * FSharpProjectOptions>

src/Compiler/Service/FSharpCheckerResults.fs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ open System.Threading.Tasks
5858
open System.Runtime.CompilerServices
5959
open Internal.Utilities.Hashing
6060

61+
[<Experimental "This type is experimental and likely to be removed in the future.">]
62+
[<RequireQualifiedAccess>]
63+
type DocumentSource =
64+
| FileSystem
65+
| Custom of (string -> Async<ISourceText option>)
66+
6167
type FSharpUnresolvedReferencesSet = FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list
6268

6369
[<Sealed>]

src/Compiler/Service/FSharpCheckerResults.fsi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ open FSharp.Compiler.Text
3030

3131
open Internal.Utilities.Collections
3232

33+
[<Experimental "This type is experimental and likely to be removed in the future.">]
34+
[<RequireQualifiedAccess>]
35+
type DocumentSource =
36+
| FileSystem
37+
| Custom of (string -> Async<ISourceText option>)
38+
3339
/// Delays the creation of an ILModuleReader
3440
[<Sealed>]
3541
type DelayedILModuleReader =

src/Compiler/Service/FSharpProjectSnapshot.fs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,12 @@ type internal ProjectSnapshotBase<'T when 'T :> IFileSnapshot>(projectCore: Proj
326326
member this.FileKey(fileName: string) = this.UpTo(fileName).LastFileKey
327327
member this.FileKey(index: FileIndex) = this.UpTo(index).LastFileKey
328328

329+
member this.FileKeyWithExtraFileSnapshotVersion(fileName: string) =
330+
let fileKey = this.FileKey fileName
331+
let fileSnapshot = this.SourceFiles |> Seq.find (fun f -> f.FileName = fileName)
332+
333+
fileKey.WithExtraVersion(fileSnapshot.Version |> Md5Hasher.toString)
334+
329335
/// Project snapshot with filenames and versions given as initial input
330336
and internal ProjectSnapshot = ProjectSnapshotBase<FSharpFileSnapshot>
331337

@@ -375,10 +381,10 @@ and internal ProjectCore
375381
let commandLineOptions =
376382
lazy
377383
(seq {
384+
yield! OtherOptions
385+
378386
for r in ReferencesOnDisk do
379387
$"-r:{r.Path}"
380-
381-
yield! OtherOptions
382388
}
383389
|> Seq.toList)
384390

src/Compiler/Service/TransparentCompiler.fs

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ type internal CompilerCaches(sizeFactor: int) =
307307
this.AssemblyData.Clear(shouldClear)
308308
this.SemanticClassification.Clear(snd >> shouldClear)
309309
this.ItemKeyStore.Clear(snd >> shouldClear)
310-
this.ScriptClosure.Clear(snd >> shouldClear) // Todo check if correct predicate
310+
this.ScriptClosure.Clear(snd >> shouldClear)
311311

312312
type internal TransparentCompiler
313313
(
@@ -1467,9 +1467,8 @@ type internal TransparentCompiler
14671467

14681468
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: ProjectSnapshot) =
14691469
caches.ParseAndCheckFileInProject.Get(
1470-
projectSnapshot.FileKey fileName,
1470+
projectSnapshot.FileKeyWithExtraFileSnapshotVersion fileName,
14711471
node {
1472-
14731472
use _ =
14741473
Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
14751474

@@ -1496,8 +1495,6 @@ type internal TransparentCompiler
14961495
let tcSymbolUses = sink.GetSymbolUses()
14971496
let tcOpenDeclarations = sink.GetOpenDeclarations()
14981497

1499-
let tcDependencyFiles = [] // TODO add as a set to TcIntermediate
1500-
15011498
// TODO: Apparently creating diagnostics can produce further diagnostics. So let's capture those too. Hopefully there is a more elegant solution...
15021499
// Probably diagnostics need to be evaluated during typecheck anyway for proper formatting, which might take care of this too.
15031500
let extraLogger = CapturingDiagnosticsLogger("DiagnosticsWhileCreatingDiagnostics")
@@ -1559,7 +1556,7 @@ type internal TransparentCompiler
15591556
projectSnapshot.IsIncompleteTypeCheckEnvironment,
15601557
None,
15611558
projectSnapshot.ToOptions(),
1562-
Array.ofList tcDependencyFiles,
1559+
Array.ofList tcInfo.tcDependencyFiles,
15631560
creationDiags,
15641561
parseResults.Diagnostics,
15651562
tcDiagnostics,
@@ -1602,6 +1599,29 @@ type internal TransparentCompiler
16021599
}
16031600
)
16041601

1602+
let TryGetRecentCheckResultsForFile
1603+
(
1604+
fileName: string,
1605+
projectSnapshot: FSharpProjectSnapshot,
1606+
userOpName: string
1607+
) : (FSharpParseFileResults * FSharpCheckFileResults) option =
1608+
ignore userOpName
1609+
1610+
let cacheKey =
1611+
projectSnapshot.ProjectSnapshot.FileKeyWithExtraFileSnapshotVersion fileName
1612+
1613+
let version = cacheKey.GetVersion()
1614+
1615+
let parseFileResultsAndcheckFileAnswer =
1616+
caches.ParseAndCheckFileInProject.TryGet(
1617+
cacheKey.GetKey(),
1618+
(fun (_fullVersion, fileContentVersion) -> fileContentVersion = (snd version))
1619+
)
1620+
1621+
match parseFileResultsAndcheckFileAnswer with
1622+
| Some(parseFileResults, FSharpCheckFileAnswer.Succeeded checkFileResults) -> Some(parseFileResults, checkFileResults)
1623+
| _ -> None
1624+
16051625
let ComputeProjectExtras (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshotWithSources) =
16061626
caches.ProjectExtras.Get(
16071627
projectSnapshot.SignatureKey,
@@ -2030,7 +2050,10 @@ type internal TransparentCompiler
20302050
) : NodeCode<seq<range>> =
20312051
node {
20322052
ignore canInvalidateProject
2033-
let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync
2053+
2054+
let! snapshot =
2055+
FSharpProjectSnapshot.FromOptions(options)
2056+
|> NodeCode.AwaitAsync
20342057

20352058
return! this.FindReferencesInFile(fileName, snapshot.ProjectSnapshot, symbol, userOpName)
20362059
}
@@ -2043,7 +2066,10 @@ type internal TransparentCompiler
20432066

20442067
member this.GetAssemblyData(options: FSharpProjectOptions, fileName, userOpName: string) : NodeCode<ProjectAssemblyDataResult> =
20452068
node {
2046-
let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync
2069+
let! snapshot =
2070+
FSharpProjectSnapshot.FromOptions(options)
2071+
|> NodeCode.AwaitAsync
2072+
20472073
return! this.GetAssemblyData(snapshot.ProjectSnapshot, fileName, userOpName)
20482074
}
20492075

@@ -2062,7 +2088,9 @@ type internal TransparentCompiler
20622088
userOpName: string
20632089
) : NodeCode<FSharpParseFileResults * FSharpCheckFileResults> =
20642090
node {
2065-
let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync
2091+
let! snapshot =
2092+
FSharpProjectSnapshot.FromOptions(options)
2093+
|> NodeCode.AwaitAsync
20662094

20672095
match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) with
20682096
| parseResult, FSharpCheckFileAnswer.Succeeded checkResult -> return parseResult, checkResult
@@ -2076,7 +2104,10 @@ type internal TransparentCompiler
20762104
userOpName: string
20772105
) : NodeCode<FSharpParseFileResults> =
20782106
node {
2079-
let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync
2107+
let! snapshot =
2108+
FSharpProjectSnapshot.FromOptions(options)
2109+
|> NodeCode.AwaitAsync
2110+
20802111
return! this.ParseFile(fileName, snapshot.ProjectSnapshot, userOpName)
20812112
}
20822113

@@ -2260,7 +2291,11 @@ type internal TransparentCompiler
22602291
) : NodeCode<EditorServices.SemanticClassificationView option> =
22612292
node {
22622293
ignore userOpName
2263-
let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync
2294+
2295+
let! snapshot =
2296+
FSharpProjectSnapshot.FromOptions(options)
2297+
|> NodeCode.AwaitAsync
2298+
22642299
return! ComputeSemanticClassification(fileName, snapshot.ProjectSnapshot)
22652300
}
22662301

@@ -2301,7 +2336,11 @@ type internal TransparentCompiler
23012336
member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode<FSharpCheckProjectResults> =
23022337
node {
23032338
ignore userOpName
2304-
let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync
2339+
2340+
let! snapshot =
2341+
FSharpProjectSnapshot.FromOptions(options)
2342+
|> NodeCode.AwaitAsync
2343+
23052344
return! ComputeParseAndCheckProject snapshot.ProjectSnapshot
23062345
}
23072346

@@ -2336,3 +2375,11 @@ type internal TransparentCompiler
23362375
backgroundCompiler.TryGetRecentCheckResultsForFile(fileName, options, sourceText, userOpName)
23372376

23382377
member this.GetCachedScriptSnapshot _ = None
2378+
2379+
member this.TryGetRecentCheckResultsForFile
2380+
(
2381+
fileName: string,
2382+
projectSnapshot: FSharpProjectSnapshot,
2383+
userOpName: string
2384+
) : (FSharpParseFileResults * FSharpCheckFileResults) option =
2385+
TryGetRecentCheckResultsForFile(fileName, projectSnapshot, userOpName)

src/Compiler/Service/TransparentCompiler.fsi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ type internal CompilerCaches =
118118
member ParseAndCheckAllFilesInProject: AsyncMemoizeDisabled<obj, obj, obj>
119119

120120
member ParseAndCheckFileInProject:
121-
AsyncMemoize<(string * (string * string)), string, (FSharpParseFileResults * FSharpCheckFileAnswer)>
121+
AsyncMemoize<(string * (string * string)), string * string, (FSharpParseFileResults * FSharpCheckFileAnswer)>
122122

123123
member ParseAndCheckProject: AsyncMemoize<(string * string), string, FSharpCheckProjectResults>
124124

src/Compiler/Service/service.fs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ open FSharp.Compiler.Text.Range
3737
open FSharp.Compiler.TcGlobals
3838
open FSharp.Compiler.BuildGraph
3939

40-
[<RequireQualifiedAccess>]
41-
type DocumentSource =
42-
| FileSystem
43-
| Custom of (string -> Async<ISourceText option>)
44-
4540
/// Callback that indicates whether a requested result has become obsolete.
4641
[<NoComparison; NoEquality>]
4742
type IsResultObsolete = IsResultObsolete of (unit -> bool)
@@ -346,6 +341,10 @@ type FSharpChecker
346341
let userOpName = defaultArg userOpName "Unknown"
347342
backgroundCompiler.TryGetRecentCheckResultsForFile(fileName, options, sourceText, userOpName)
348343

344+
member _.TryGetRecentCheckResultsForFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, ?userOpName: string) =
345+
let userOpName = defaultArg userOpName "Unknown"
346+
backgroundCompiler.TryGetRecentCheckResultsForFile(fileName, projectSnapshot, userOpName)
347+
349348
member _.Compile(argv: string[], ?userOpName: string) =
350349
let _userOpName = defaultArg userOpName "Unknown"
351350
use _ = Activity.start "FSharpChecker.Compile" [| Activity.Tags.userOpName, _userOpName |]

0 commit comments

Comments
 (0)