From 6339b2ee946f4241a4b63796c606a94e61a54d98 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Wed, 5 Apr 2023 13:47:51 +0200
Subject: [PATCH 001/222] AsyncMemoize v1
---
src/Compiler/FSharp.Compiler.Service.fsproj | 1 +
src/Compiler/Facilities/AsyncMemoize.fs | 130 ++++++++++++++++++
src/Compiler/Facilities/BuildGraph.fsi | 2 +
.../CompilerService/AsyncMemoize.fs | 115 ++++++++++++++++
.../FSharp.Compiler.ComponentTests.fsproj | 12 +-
5 files changed, 254 insertions(+), 6 deletions(-)
create mode 100644 src/Compiler/Facilities/AsyncMemoize.fs
create mode 100644 tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj
index 537636de072..56c023a3a46 100644
--- a/src/Compiler/FSharp.Compiler.Service.fsproj
+++ b/src/Compiler/FSharp.Compiler.Service.fsproj
@@ -153,6 +153,7 @@
+
--unicode --lexlib Internal.Utilities.Text.Lexing
AbstractIL\illex.fsl
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
new file mode 100644
index 00000000000..d7f17f2352c
--- /dev/null
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -0,0 +1,130 @@
+namespace Internal.Utilities.Collections
+
+open FSharp.Compiler.BuildGraph
+open System.Threading
+open System.Collections.Generic
+
+type internal Action<'TKey, 'TValue> =
+ | GetOrCompute of ('TKey -> NodeCode<'TValue>) * CancellationToken
+ | CancelRequest
+ | JobCompleted
+
+type MemoizeRequest<'TKey, 'TValue> = 'TKey * Action<'TKey, 'TValue> * AsyncReplyChannel>
+
+type internal Job<'TValue> =
+ | Running of NodeCode<'TValue> * CancellationTokenSource
+ | Completed of NodeCode<'TValue>
+
+type internal JobEvent<'TKey> =
+ | Started of 'TKey
+ | Finished of 'TKey
+ | Canceled of 'TKey
+
+ member this.Key =
+ match this with
+ | Started key -> key
+ | Finished key -> key
+ | Canceled key -> key
+
+type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?eventLog: ResizeArray>) =
+
+ let tok = obj ()
+
+ let cache =
+ MruCache<_, 'TKey, Job<'TValue>>(keepStrongly = 10, areSame = (fun (x, y) -> x = y))
+
+ let requestCounts = Dictionary<'TKey, int>()
+
+ let incrRequestCount key =
+ requestCounts.[key] <-
+ if requestCounts.ContainsKey key then
+ requestCounts.[key] + 1
+ else
+ 1
+
+ let sendAsync (inbox: MailboxProcessor<_>) key msg =
+ inbox.PostAndAsyncReply(fun rc -> key, msg, rc) |> Async.Ignore |> Async.Start
+
+ let log event =
+ eventLog |> Option.iter (fun log -> log.Add event)
+
+ let agent =
+ MailboxProcessor.Start(fun (inbox: MailboxProcessor>) ->
+
+ let post = sendAsync inbox
+
+ async {
+ while true do
+
+ let! key, action, replyChannel = inbox.Receive()
+
+ match action, cache.TryGet(tok, key) with
+ | GetOrCompute _, Some (Completed job) -> replyChannel.Reply job
+ | GetOrCompute (_, ct), Some (Running (job, _)) ->
+
+ incrRequestCount key
+ replyChannel.Reply job
+ ct.Register(fun _ -> post key CancelRequest) |> ignore
+
+ | GetOrCompute (computation, ct), None ->
+
+ let cts = new CancellationTokenSource()
+
+ let startedComputation =
+ Async.StartAsTask(
+ Async.AwaitNodeCode(
+ node {
+ let! result = computation key
+ post key JobCompleted
+ return result
+ }
+ ),
+ cancellationToken = cts.Token
+ )
+
+ log (Started key)
+
+ let job = NodeCode.AwaitTask startedComputation
+
+ cache.Set(tok, key, (Running(job, cts)))
+
+ incrRequestCount key
+
+ ct.Register(fun _ -> post key CancelRequest) |> ignore
+
+ replyChannel.Reply job
+
+ | CancelRequest, Some (Running (_, cts)) ->
+ let requestCount = requestCounts.TryGetValue key |> snd
+
+ if requestCount > 1 then
+ requestCounts.[key] <- requestCount - 1
+
+ else
+ cts.Cancel()
+ cache.RemoveAnySimilar(tok, key)
+ requestCounts.Remove key |> ignore
+ log (Canceled key)
+
+ | CancelRequest, None
+ | CancelRequest, Some (Completed _) -> ()
+
+ | JobCompleted, Some (Running (job, _)) ->
+ cache.Set(tok, key, (Completed job))
+ requestCounts.Remove key |> ignore
+ log (Finished key)
+
+ | JobCompleted, _ -> failwith "If this happens there's a bug"
+
+ })
+
+ member _.Get(key, computation) =
+ node {
+ let! ct = NodeCode.CancellationToken
+
+ let! job =
+ agent.PostAndAsyncReply(fun rc -> key, (GetOrCompute(computation, ct)), rc)
+ |> NodeCode.AwaitAsync
+
+ return! job
+ }
diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi
index 1bfa2f30cac..afbf9d2898b 100644
--- a/src/Compiler/Facilities/BuildGraph.fsi
+++ b/src/Compiler/Facilities/BuildGraph.fsi
@@ -70,6 +70,8 @@ type NodeCode =
static member Parallel: computations: (NodeCode<'T> seq) -> NodeCode<'T[]>
+ static member AwaitAsync: computation: Async<'T> -> NodeCode<'T>
+
static member AwaitTask: task: Task<'T> -> NodeCode<'T>
static member AwaitTask: task: Task -> NodeCode
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
new file mode 100644
index 00000000000..78123ef4efd
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -0,0 +1,115 @@
+module FSharp.Compiler.ComponentTests.CompilerService.AsyncMemoize
+
+open System
+open System.Threading
+open Xunit
+open FSharp.Test
+open FSharp.Compiler.BuildGraph
+open Internal.Utilities.Collections
+open System.Threading.Tasks
+
+[]
+let ``Basics``() =
+
+ let computation key = node {
+ do! Async.Sleep 1 |> NodeCode.AwaitAsync
+ return key * 2
+ }
+
+ let eventLog = ResizeArray()
+
+ let memoize = AsyncMemoize(eventLog)
+
+ let task =
+ NodeCode.Parallel(seq {
+ memoize.Get(5, computation)
+ memoize.Get(5, computation)
+ memoize.Get(2, computation)
+ memoize.Get(5, computation)
+ memoize.Get(3, computation)
+ memoize.Get(2, computation)
+ }) |> NodeCode.StartAsTask_ForTesting
+
+ let result = task.Result
+ let expected = [| 10; 10; 4; 10; 6; 4|]
+
+ Assert.Equal(expected, result)
+
+ let groups = eventLog |> Seq.groupBy (fun e -> e.Key) |> Seq.toList
+ Assert.Equal(3, groups.Length)
+ for key, events in groups do
+ Assert.Equal array>([| Started key; Finished key |], events |> Seq.toArray)
+
+[]
+let ``We can cancel a job`` () =
+
+ let computation key = node {
+ do! Async.Sleep 1000 |> NodeCode.AwaitAsync
+ failwith "Should be canceled before it gets here"
+ return key * 2
+ }
+
+ let eventLog = ResizeArray()
+ let memoize = AsyncMemoize(eventLog)
+
+ use cts1 = new CancellationTokenSource()
+ use cts2 = new CancellationTokenSource()
+ use cts3 = new CancellationTokenSource()
+
+ let key = 1
+
+ let _task1 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts1.Token)
+ let _task2 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts2.Token)
+ let _task3 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts3.Token)
+
+ Thread.Sleep 10
+
+ Assert.Equal array>([| Started key |], eventLog |> Seq.toArray )
+
+ cts1.Cancel()
+ cts2.Cancel()
+
+ Assert.Equal array>([| Started key |], eventLog |> Seq.toArray )
+
+ cts3.Cancel()
+
+ Thread.Sleep 10
+
+ Assert.Equal array>([| Started key; Canceled key |], eventLog |> Seq.toArray )
+
+ try
+ Task.WaitAll(_task1, _task2, _task3)
+ with :? AggregateException as ex ->
+ Assert.Equal(3, ex.InnerExceptions.Count)
+ Assert.True(ex.InnerExceptions |> Seq.forall (fun e -> e :? TaskCanceledException))
+
+[]
+let ``Job keeps running even if first requestor cancels`` () =
+ let computation key = node {
+ do! Async.Sleep 100 |> NodeCode.AwaitAsync
+ return key * 2
+ }
+
+ let eventLog = ResizeArray()
+ let memoize = AsyncMemoize(eventLog)
+
+ use cts1 = new CancellationTokenSource()
+ use cts2 = new CancellationTokenSource()
+ use cts3 = new CancellationTokenSource()
+
+ let key = 1
+
+ let _task1 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts1.Token)
+ let _task2 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts2.Token)
+ let _task3 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts3.Token)
+
+ Thread.Sleep 10
+
+ cts1.Cancel()
+ cts3.Cancel()
+
+ let result = _task2.Result
+ Assert.Equal(2, result)
+
+ Assert.Equal array>([| Started key; Finished key |], eventLog |> Seq.toArray )
+
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
index f3f67a4020a..2447e2a0906 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
+++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
@@ -221,7 +221,11 @@
-
+
+
+
+ %(RelativeDir)TestSource\%(Filename)%(Extension)
+
@@ -247,11 +251,7 @@
-
-
- %(RelativeDir)TestSource\%(Filename)%(Extension)
-
-
+
From 1059824f747c89f92c140e786a232b6ee926a959 Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Wed, 5 Apr 2023 16:31:03 +0200
Subject: [PATCH 002/222] IBackgroundCompiler
---
src/Compiler/FSharp.Compiler.Service.fsproj | 4 +-
src/Compiler/Service/BackgroundCompiler.fs | 1523 +++++++++++++++++++
src/Compiler/Service/TransparentCompiler.fs | 54 +
src/Compiler/Service/service.fs | 1136 +-------------
4 files changed, 1581 insertions(+), 1136 deletions(-)
create mode 100644 src/Compiler/Service/BackgroundCompiler.fs
create mode 100644 src/Compiler/Service/TransparentCompiler.fs
diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj
index 56c023a3a46..d6e391936db 100644
--- a/src/Compiler/FSharp.Compiler.Service.fsproj
+++ b/src/Compiler/FSharp.Compiler.Service.fsproj
@@ -464,7 +464,9 @@
-
+
+
+
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
new file mode 100644
index 00000000000..3882e06bc8d
--- /dev/null
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -0,0 +1,1523 @@
+namespace FSharp.Compiler.CodeAnalysis
+
+open FSharp.Compiler.Text
+open FSharp.Compiler.BuildGraph
+
+open System
+open System.Diagnostics
+open System.IO
+open System.Reflection
+open System.Reflection.Emit
+open System.Threading
+open Internal.Utilities.Collections
+open Internal.Utilities.Library
+open Internal.Utilities.Library.Extras
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.AbstractIL.ILBinaryReader
+open FSharp.Compiler.AbstractIL.ILDynamicAssemblyWriter
+open FSharp.Compiler.CodeAnalysis
+open FSharp.Compiler.CompilerConfig
+open FSharp.Compiler.CompilerDiagnostics
+open FSharp.Compiler.CompilerImports
+open FSharp.Compiler.CompilerOptions
+open FSharp.Compiler.DependencyManager
+open FSharp.Compiler.Diagnostics
+open FSharp.Compiler.Driver
+open FSharp.Compiler.DiagnosticsLogger
+open FSharp.Compiler.IO
+open FSharp.Compiler.ParseAndCheckInputs
+open FSharp.Compiler.ScriptClosure
+open FSharp.Compiler.Symbols
+open FSharp.Compiler.Syntax
+open FSharp.Compiler.Tokenization
+open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.BuildGraph
+
+type SourceTextHash = int64
+type CacheStamp = int64
+type FileName = string
+type FilePath = string
+type ProjectPath = string
+type FileVersion = int
+
+type internal IBackgroundCompiler =
+
+ /// Type-check the result obtained by parsing. Force the evaluation of the antecedent type checking context if needed.
+ abstract member CheckFileInProject:
+ parseResults: FSharpParseFileResults *
+ fileName: string *
+ fileVersion: int *
+ sourceText: ISourceText *
+ options: FSharpProjectOptions *
+ userOpName: string ->
+ NodeCode
+
+ /// Type-check the result obtained by parsing, but only if the antecedent type checking context is available.
+ abstract member CheckFileInProjectAllowingStaleCachedResults:
+ parseResults: FSharpParseFileResults *
+ fileName: string *
+ fileVersion: int *
+ sourceText: ISourceText *
+ options: FSharpProjectOptions *
+ userOpName: string ->
+ NodeCode
+
+ abstract member ClearCache: options: seq * userOpName: string -> unit
+
+ abstract member ClearCaches: unit -> unit
+
+ abstract member DownsizeCaches: unit -> unit
+
+ abstract member FindReferencesInFile:
+ fileName: string *
+ options: FSharpProjectOptions *
+ symbol: FSharp.Compiler.Symbols.FSharpSymbol *
+ canInvalidateProject: bool *
+ userOpName: string ->
+ NodeCode>
+
+ abstract member GetAssemblyData:
+ options: FSharpProjectOptions * userOpName: string -> NodeCode
+
+ /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API)
+ abstract member GetBackgroundCheckResultsForFileInProject:
+ fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode
+
+ /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API)
+ abstract member GetBackgroundParseResultsForFileInProject:
+ fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode
+
+ abstract member GetCachedCheckFileResult:
+ builder: IncrementalBuilder * fileName: string * sourceText: ISourceText * options: FSharpProjectOptions ->
+ NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option>
+
+ abstract member GetProjectOptionsFromScript:
+ fileName: string *
+ sourceText: ISourceText *
+ previewEnabled: bool option *
+ loadedTimeStamp: System.DateTime option *
+ otherFlags: string array option *
+ useFsiAuxLib: bool option *
+ useSdkRefs: bool option *
+ sdkDirOverride: string option *
+ assumeDotNetFramework: bool option *
+ optionsStamp: int64 option *
+ userOpName: string ->
+ Async
+
+ abstract member GetSemanticClassificationForFile:
+ fileName: string * options: FSharpProjectOptions * userOpName: string ->
+ NodeCode
+
+ abstract member InvalidateConfiguration: options: FSharpProjectOptions * userOpName: string -> unit
+
+ abstract member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode
+
+ abstract member NotifyProjectCleaned: options: FSharpProjectOptions * userOpName: string -> Async
+
+ /// Parses and checks the source file and returns untyped AST and check results.
+ abstract member ParseAndCheckFileInProject:
+ fileName: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string ->
+ NodeCode
+
+ /// Parse and typecheck the whole project.
+ abstract member ParseAndCheckProject: options: FSharpProjectOptions * userOpName: string -> NodeCode
+
+ abstract member ParseFile:
+ fileName: string * sourceText: ISourceText * options: FSharpParsingOptions * cache: bool * userOpName: string ->
+ Async
+
+ /// Try to get recent approximate type check results for a file.
+ abstract member TryGetRecentCheckResultsForFile:
+ fileName: string * options: FSharpProjectOptions * sourceText: ISourceText option * userOpName: string ->
+ (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option
+
+ abstract member BeforeBackgroundFileCheck: IEvent
+
+ abstract member FileChecked: IEvent
+
+ abstract member FileParsed: IEvent
+
+ abstract member FrameworkImportsCache: FrameworkImportsCache
+
+ abstract member ProjectChecked: IEvent
+
+type ParseCacheLockToken() =
+ interface LockToken
+
+type ScriptClosureCacheToken() =
+ interface LockToken
+
+type CheckFileCacheKey = FileName * SourceTextHash * FSharpProjectOptions
+type CheckFileCacheValue = FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash * DateTime
+
+[]
+module EnvMisc =
+ let braceMatchCacheSize = GetEnvInteger "FCS_BraceMatchCacheSize" 5
+ let parseFileCacheSize = GetEnvInteger "FCS_ParseFileCacheSize" 2
+ let checkFileInProjectCacheSize = GetEnvInteger "FCS_CheckFileInProjectCacheSize" 10
+
+ let projectCacheSizeDefault = GetEnvInteger "FCS_ProjectCacheSizeDefault" 3
+
+ let frameworkTcImportsCacheStrongSize =
+ GetEnvInteger "FCS_frameworkTcImportsCacheStrongSizeDefault" 8
+
+[]
+module Helpers =
+
+ /// Determine whether two (fileName,options) keys are identical w.r.t. affect on checking
+ let AreSameForChecking2 ((fileName1: string, options1: FSharpProjectOptions), (fileName2, options2)) =
+ (fileName1 = fileName2)
+ && FSharpProjectOptions.AreSameForChecking(options1, options2)
+
+ /// Determine whether two (fileName,options) keys should be identical w.r.t. resource usage
+ let AreSubsumable2 ((fileName1: string, o1: FSharpProjectOptions), (fileName2: string, o2: FSharpProjectOptions)) =
+ (fileName1 = fileName2) && FSharpProjectOptions.UseSameProject(o1, o2)
+
+ /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. parsing
+ let AreSameForParsing ((fileName1: string, source1Hash: int64, options1), (fileName2, source2Hash, options2)) =
+ fileName1 = fileName2 && options1 = options2 && source1Hash = source2Hash
+
+ let AreSimilarForParsing ((fileName1, _, _), (fileName2, _, _)) = fileName1 = fileName2
+
+ /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. checking
+ let AreSameForChecking3 ((fileName1: string, source1Hash: int64, options1: FSharpProjectOptions), (fileName2, source2Hash, options2)) =
+ (fileName1 = fileName2)
+ && FSharpProjectOptions.AreSameForChecking(options1, options2)
+ && source1Hash = source2Hash
+
+ /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. resource usage
+ let AreSubsumable3 ((fileName1: string, _, o1: FSharpProjectOptions), (fileName2: string, _, o2: FSharpProjectOptions)) =
+ (fileName1 = fileName2) && FSharpProjectOptions.UseSameProject(o1, o2)
+
+ /// If a symbol is an attribute check if given set of names contains its name without the Attribute suffix
+ let rec NamesContainAttribute (symbol: FSharpSymbol) names =
+ match symbol with
+ | :? FSharpMemberOrFunctionOrValue as mofov ->
+ mofov.DeclaringEntity
+ |> Option.map (fun entity -> NamesContainAttribute entity names)
+ |> Option.defaultValue false
+ | :? FSharpEntity as entity when entity.IsAttributeType && symbol.DisplayNameCore.EndsWithOrdinal "Attribute" ->
+ let nameWithoutAttribute = String.dropSuffix symbol.DisplayNameCore "Attribute"
+ names |> Set.contains nameWithoutAttribute
+ | _ -> false
+
+// There is only one instance of this type, held in FSharpChecker
+type internal BackgroundCompiler
+ (
+ legacyReferenceResolver,
+ projectCacheSize,
+ keepAssemblyContents,
+ keepAllBackgroundResolutions,
+ tryGetMetadataSnapshot,
+ suggestNamesForErrors,
+ keepAllBackgroundSymbolUses,
+ enableBackgroundItemKeyStoreAndSemanticClassification,
+ enablePartialTypeChecking,
+ parallelReferenceResolution,
+ captureIdentifiersWhenParsing,
+ getSource: (string -> ISourceText option) option,
+ useChangeNotifications,
+ useSyntaxTreeCache
+ ) as self =
+
+ let beforeFileChecked = Event()
+ let fileParsed = Event()
+ let fileChecked = Event()
+ let projectChecked = Event()
+
+ // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.scriptClosureCache
+ /// Information about the derived script closure.
+ let scriptClosureCache =
+ MruCache(
+ projectCacheSize,
+ areSame = FSharpProjectOptions.AreSameForChecking,
+ areSimilar = FSharpProjectOptions.UseSameProject
+ )
+
+ let frameworkTcImportsCache =
+ FrameworkImportsCache(frameworkTcImportsCacheStrongSize)
+
+ // We currently share one global dependency provider for all scripts for the FSharpChecker.
+ // For projects, one is used per project.
+ //
+ // Sharing one for all scripts is necessary for good performance from GetProjectOptionsFromScript,
+ // which requires a dependency provider to process through the project options prior to working out
+ // if the cached incremental builder can be used for the project.
+ let dependencyProviderForScripts = new DependencyProvider()
+
+ let getProjectReferences (options: FSharpProjectOptions) userOpName =
+ [
+ for r in options.ReferencedProjects do
+
+ match r with
+ | FSharpReferencedProject.FSharpReference (nm, opts) ->
+ // Don't use cross-project references for FSharp.Core, since various bits of code
+ // require a concrete FSharp.Core to exist on-disk. The only solutions that have
+ // these cross-project references to FSharp.Core are VisualFSharp.sln and FSharp.sln. The ramification
+ // of this is that you need to build FSharp.Core to get intellisense in those projects.
+
+ if
+ (try
+ Path.GetFileNameWithoutExtension(nm)
+ with _ ->
+ "")
+ <> GetFSharpCoreLibraryName()
+ then
+ { new IProjectReference with
+ member x.EvaluateRawContents() =
+ node {
+ Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm)
+ return! self.GetAssemblyData(opts, userOpName + ".CheckReferencedProject(" + nm + ")")
+ }
+
+ member x.TryGetLogicalTimeStamp(cache) =
+ self.TryGetLogicalTimeStampForProject(cache, opts)
+
+ member x.FileName = nm
+ }
+
+ | FSharpReferencedProject.PEReference (nm, getStamp, delayedReader) ->
+ { new IProjectReference with
+ member x.EvaluateRawContents() =
+ node {
+ let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> NodeCode.FromCancellable
+
+ match ilReaderOpt with
+ | Some ilReader ->
+ let ilModuleDef, ilAsmRefs = ilReader.ILModuleDef, ilReader.ILAssemblyRefs
+ let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData
+ return ProjectAssemblyDataResult.Available data
+ | _ ->
+ // Note 'false' - if a PEReference doesn't find an ILModuleReader then we don't
+ // continue to try to use an on-disk DLL
+ return ProjectAssemblyDataResult.Unavailable false
+ }
+
+ member x.TryGetLogicalTimeStamp _ = getStamp () |> Some
+ member x.FileName = nm
+ }
+
+ | FSharpReferencedProject.ILModuleReference (nm, getStamp, getReader) ->
+ { new IProjectReference with
+ member x.EvaluateRawContents() =
+ node {
+ let ilReader = getReader ()
+ let ilModuleDef, ilAsmRefs = ilReader.ILModuleDef, ilReader.ILAssemblyRefs
+ let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData
+ return ProjectAssemblyDataResult.Available data
+ }
+
+ member x.TryGetLogicalTimeStamp _ = getStamp () |> Some
+ member x.FileName = nm
+ }
+ ]
+
+ /// CreateOneIncrementalBuilder (for background type checking). Note that fsc.fs also
+ /// creates an incremental builder used by the command line compiler.
+ let CreateOneIncrementalBuilder (options: FSharpProjectOptions, userOpName) =
+ node {
+ use _ =
+ Activity.start "BackgroundCompiler.CreateOneIncrementalBuilder" [| Activity.Tags.project, options.ProjectFileName |]
+
+ Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "CreateOneIncrementalBuilder", options.ProjectFileName)
+ let projectReferences = getProjectReferences options userOpName
+
+ let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options)
+
+ let dependencyProvider =
+ if options.UseScriptResolutionRules then
+ Some dependencyProviderForScripts
+ else
+ None
+
+ let! builderOpt, diagnostics =
+ IncrementalBuilder.TryCreateIncrementalBuilderForProjectOptions(
+ legacyReferenceResolver,
+ FSharpCheckerResultsSettings.defaultFSharpBinariesDir,
+ frameworkTcImportsCache,
+ loadClosure,
+ Array.toList options.SourceFiles,
+ Array.toList options.OtherOptions,
+ projectReferences,
+ options.ProjectDirectory,
+ options.UseScriptResolutionRules,
+ keepAssemblyContents,
+ keepAllBackgroundResolutions,
+ tryGetMetadataSnapshot,
+ suggestNamesForErrors,
+ keepAllBackgroundSymbolUses,
+ enableBackgroundItemKeyStoreAndSemanticClassification,
+ enablePartialTypeChecking,
+ dependencyProvider,
+ parallelReferenceResolution,
+ captureIdentifiersWhenParsing,
+ getSource,
+ useChangeNotifications,
+ useSyntaxTreeCache
+ )
+
+ match builderOpt with
+ | None -> ()
+ | Some builder ->
+
+#if !NO_TYPEPROVIDERS
+ // Register the behaviour that responds to CCUs being invalidated because of type
+ // provider Invalidate events. This invalidates the configuration in the build.
+ builder.ImportsInvalidatedByTypeProvider.Add(fun () -> self.InvalidateConfiguration(options, userOpName))
+#endif
+
+ // Register the callback called just before a file is typechecked by the background builder (without recording
+ // errors or intellisense information).
+ //
+ // This indicates to the UI that the file type check state is dirty. If the file is open and visible then
+ // the UI will sooner or later request a typecheck of the file, recording errors and intellisense information.
+ builder.BeforeFileChecked.Add(fun file -> beforeFileChecked.Trigger(file, options))
+ builder.FileParsed.Add(fun file -> fileParsed.Trigger(file, options))
+ builder.FileChecked.Add(fun file -> fileChecked.Trigger(file, options))
+ builder.ProjectChecked.Add(fun () -> projectChecked.Trigger options)
+
+ return (builderOpt, diagnostics)
+ }
+
+ let parseCacheLock = Lock()
+
+ // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.parseFileInProjectCache. Most recently used cache for parsing files.
+ let parseFileCache =
+ MruCache(
+ parseFileCacheSize,
+ areSimilar = AreSimilarForParsing,
+ areSame = AreSameForParsing
+ )
+
+ // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.checkFileInProjectCache
+ //
+ /// Cache which holds recently seen type-checks.
+ /// This cache may hold out-of-date entries, in two senses
+ /// - there may be a more recent antecedent state available because the background build has made it available
+ /// - the source for the file may have changed
+
+ // Also keyed on source. This can only be out of date if the antecedent is out of date
+ let checkFileInProjectCache =
+ MruCache>(
+ keepStrongly = checkFileInProjectCacheSize,
+ areSame = AreSameForChecking3,
+ areSimilar = AreSubsumable3
+ )
+
+ // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.incrementalBuildersCache. This root typically holds more
+ // live information than anything else in the F# Language Service, since it holds up to 3 (projectCacheStrongSize) background project builds
+ // strongly.
+ //
+ /// Cache of builds keyed by options.
+ let gate = obj ()
+
+ let incrementalBuildersCache =
+ MruCache>(
+ keepStrongly = projectCacheSize,
+ keepMax = projectCacheSize,
+ areSame = FSharpProjectOptions.AreSameForChecking,
+ areSimilar = FSharpProjectOptions.UseSameProject
+ )
+
+ let tryGetBuilderNode options =
+ incrementalBuildersCache.TryGet(AnyCallerThread, options)
+
+ let tryGetBuilder options : NodeCode option =
+ tryGetBuilderNode options |> Option.map (fun x -> x.GetOrComputeValue())
+
+ let tryGetSimilarBuilder options : NodeCode option =
+ incrementalBuildersCache.TryGetSimilar(AnyCallerThread, options)
+ |> Option.map (fun x -> x.GetOrComputeValue())
+
+ let tryGetAnyBuilder options : NodeCode option =
+ incrementalBuildersCache.TryGetAny(AnyCallerThread, options)
+ |> Option.map (fun x -> x.GetOrComputeValue())
+
+ let createBuilderNode (options, userOpName, ct: CancellationToken) =
+ lock gate (fun () ->
+ if ct.IsCancellationRequested then
+ GraphNode.FromResult(None, [||])
+ else
+ let getBuilderNode = GraphNode(CreateOneIncrementalBuilder(options, userOpName))
+ incrementalBuildersCache.Set(AnyCallerThread, options, getBuilderNode)
+ getBuilderNode)
+
+ let createAndGetBuilder (options, userOpName) =
+ node {
+ let! ct = NodeCode.CancellationToken
+ let getBuilderNode = createBuilderNode (options, userOpName, ct)
+ return! getBuilderNode.GetOrComputeValue()
+ }
+
+ let getOrCreateBuilder (options, userOpName) : NodeCode =
+ match tryGetBuilder options with
+ | Some getBuilder ->
+ node {
+ match! getBuilder with
+ | builderOpt, creationDiags when builderOpt.IsNone || not builderOpt.Value.IsReferencesInvalidated ->
+ return builderOpt, creationDiags
+ | _ ->
+ // The builder could be re-created,
+ // clear the check file caches that are associated with it.
+ // We must do this in order to not return stale results when references
+ // in the project get changed/added/removed.
+ parseCacheLock.AcquireLock(fun ltok ->
+ options.SourceFiles
+ |> Array.iter (fun sourceFile ->
+ let key = (sourceFile, 0L, options)
+ checkFileInProjectCache.RemoveAnySimilar(ltok, key)))
+
+ return! createAndGetBuilder (options, userOpName)
+ }
+ | _ -> createAndGetBuilder (options, userOpName)
+
+ let getSimilarOrCreateBuilder (options, userOpName) =
+ match tryGetSimilarBuilder options with
+ | Some res -> res
+ // The builder does not exist at all. Create it.
+ | None -> getOrCreateBuilder (options, userOpName)
+
+ let getOrCreateBuilderWithInvalidationFlag (options, canInvalidateProject, userOpName) =
+ if canInvalidateProject then
+ getOrCreateBuilder (options, userOpName)
+ else
+ getSimilarOrCreateBuilder (options, userOpName)
+
+ let getAnyBuilder (options, userOpName) =
+ match tryGetAnyBuilder options with
+ | Some getBuilder -> getBuilder
+ | _ -> getOrCreateBuilder (options, userOpName)
+
+ static let mutable actualParseFileCount = 0
+
+ static let mutable actualCheckFileCount = 0
+
+ /// Should be a fast operation. Ensures that we have only one async lazy object per file and its hash.
+ let getCheckFileNode (parseResults, sourceText, fileName, options, _fileVersion, builder, tcPrior, tcInfo, creationDiags) =
+
+ // Here we lock for the creation of the node, not its execution
+ parseCacheLock.AcquireLock(fun ltok ->
+ let key = (fileName, sourceText.GetHashCode() |> int64, options)
+
+ match checkFileInProjectCache.TryGet(ltok, key) with
+ | Some res -> res
+ | _ ->
+ let res =
+ GraphNode(
+ node {
+ let! res =
+ self.CheckOneFileImplAux(
+ parseResults,
+ sourceText,
+ fileName,
+ options,
+ builder,
+ tcPrior,
+ tcInfo,
+ creationDiags
+ )
+
+ Interlocked.Increment(&actualCheckFileCount) |> ignore
+ return res
+ }
+ )
+
+ checkFileInProjectCache.Set(ltok, key, res)
+ res)
+
+ member _.ParseFile(fileName: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, userOpName: string) =
+ async {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.ParseFile"
+ [|
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ Activity.Tags.cache, cache.ToString()
+ |]
+
+ if cache then
+ let hash = sourceText.GetHashCode() |> int64
+
+ match parseCacheLock.AcquireLock(fun ltok -> parseFileCache.TryGet(ltok, (fileName, hash, options))) with
+ | Some res -> return res
+ | None ->
+ Interlocked.Increment(&actualParseFileCount) |> ignore
+
+ let parseDiagnostics, parseTree, anyErrors =
+ ParseAndCheckFile.parseFile (
+ sourceText,
+ fileName,
+ options,
+ userOpName,
+ suggestNamesForErrors,
+ captureIdentifiersWhenParsing
+ )
+
+ let res =
+ FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, options.SourceFiles)
+
+ parseCacheLock.AcquireLock(fun ltok -> parseFileCache.Set(ltok, (fileName, hash, options), res))
+ return res
+ else
+ let parseDiagnostics, parseTree, anyErrors =
+ ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, false, captureIdentifiersWhenParsing)
+
+ return FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, options.SourceFiles)
+ }
+
+ /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API)
+ member _.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.GetBackgroundParseResultsForFileInProject"
+ [| Activity.Tags.fileName, fileName; Activity.Tags.userOpName, userOpName |]
+
+ let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None ->
+ let parseTree = EmptyParsedInput(fileName, (false, false))
+ return FSharpParseFileResults(creationDiags, parseTree, true, [||])
+ | Some builder ->
+ let parseTree, _, _, parseDiagnostics = builder.GetParseResultsForFile fileName
+
+ let parseDiagnostics =
+ DiagnosticHelpers.CreateDiagnostics(
+ builder.TcConfig.diagnosticsOptions,
+ false,
+ fileName,
+ parseDiagnostics,
+ suggestNamesForErrors
+ )
+
+ let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
+
+ let parseResults =
+ FSharpParseFileResults(
+ diagnostics = diagnostics,
+ input = parseTree,
+ parseHadErrors = false,
+ dependencyFiles = builder.AllDependenciesDeprecated
+ )
+
+ return parseResults
+ }
+
+ member _.GetCachedCheckFileResult(builder: IncrementalBuilder, fileName, sourceText: ISourceText, options) =
+ node {
+ use _ =
+ Activity.start "BackgroundCompiler.GetCachedCheckFileResult" [| Activity.Tags.fileName, fileName |]
+
+ let hash = sourceText.GetHashCode() |> int64
+ let key = (fileName, hash, options)
+
+ let cachedResultsOpt =
+ parseCacheLock.AcquireLock(fun ltok -> checkFileInProjectCache.TryGet(ltok, key))
+
+ match cachedResultsOpt with
+ | Some cachedResults ->
+ match! cachedResults.GetOrComputeValue() with
+ | parseResults, checkResults, _, priorTimeStamp when
+ (match builder.GetCheckResultsBeforeFileInProjectEvenIfStale fileName with
+ | None -> false
+ | Some (tcPrior) ->
+ tcPrior.ProjectTimeStamp = priorTimeStamp
+ && builder.AreCheckResultsBeforeFileInProjectReady(fileName))
+ ->
+ return Some(parseResults, checkResults)
+ | _ ->
+ parseCacheLock.AcquireLock(fun ltok -> checkFileInProjectCache.RemoveAnySimilar(ltok, key))
+ return None
+ | _ -> return None
+ }
+
+ member private _.CheckOneFileImplAux
+ (
+ parseResults: FSharpParseFileResults,
+ sourceText: ISourceText,
+ fileName: string,
+ options: FSharpProjectOptions,
+ builder: IncrementalBuilder,
+ tcPrior: PartialCheckResults,
+ tcInfo: TcInfo,
+ creationDiags: FSharpDiagnostic[]
+ ) : NodeCode =
+
+ node {
+ // Get additional script #load closure information if applicable.
+ // For scripts, this will have been recorded by GetProjectOptionsFromScript.
+ let tcConfig = tcPrior.TcConfig
+ let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options)
+
+ let! checkAnswer =
+ FSharpCheckFileResults.CheckOneFile(
+ parseResults,
+ sourceText,
+ fileName,
+ options.ProjectFileName,
+ tcConfig,
+ tcPrior.TcGlobals,
+ tcPrior.TcImports,
+ tcInfo.tcState,
+ tcInfo.moduleNamesDict,
+ loadClosure,
+ tcInfo.TcDiagnostics,
+ options.IsIncompleteTypeCheckEnvironment,
+ options,
+ builder,
+ Array.ofList tcInfo.tcDependencyFiles,
+ creationDiags,
+ parseResults.Diagnostics,
+ keepAssemblyContents,
+ suggestNamesForErrors
+ )
+ |> NodeCode.FromCancellable
+
+ GraphNode.SetPreferredUILang tcConfig.preferredUiLang
+ return (parseResults, checkAnswer, sourceText.GetHashCode() |> int64, tcPrior.ProjectTimeStamp)
+ }
+
+ member private bc.CheckOneFileImpl
+ (
+ parseResults: FSharpParseFileResults,
+ sourceText: ISourceText,
+ fileName: string,
+ options: FSharpProjectOptions,
+ fileVersion: int,
+ builder: IncrementalBuilder,
+ tcPrior: PartialCheckResults,
+ tcInfo: TcInfo,
+ creationDiags: FSharpDiagnostic[]
+ ) =
+
+ node {
+ match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with
+ | Some (_, results) -> return FSharpCheckFileAnswer.Succeeded results
+ | _ ->
+ let lazyCheckFile =
+ getCheckFileNode (parseResults, sourceText, fileName, options, fileVersion, builder, tcPrior, tcInfo, creationDiags)
+
+ let! _, results, _, _ = lazyCheckFile.GetOrComputeValue()
+ return FSharpCheckFileAnswer.Succeeded results
+ }
+
+ /// Type-check the result obtained by parsing, but only if the antecedent type checking context is available.
+ member bc.CheckFileInProjectAllowingStaleCachedResults
+ (
+ parseResults: FSharpParseFileResults,
+ fileName,
+ fileVersion,
+ sourceText: ISourceText,
+ options,
+ userOpName
+ ) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.CheckFileInProjectAllowingStaleCachedResults"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ let! cachedResults =
+ node {
+ let! builderOpt, creationDiags = getAnyBuilder (options, userOpName)
+
+ match builderOpt with
+ | Some builder ->
+ match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with
+ | Some (_, checkResults) -> return Some(builder, creationDiags, Some(FSharpCheckFileAnswer.Succeeded checkResults))
+ | _ -> return Some(builder, creationDiags, None)
+ | _ -> return None // the builder wasn't ready
+ }
+
+ match cachedResults with
+ | None -> return None
+ | Some (_, _, Some x) -> return Some x
+ | Some (builder, creationDiags, None) ->
+ Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "CheckFileInProjectAllowingStaleCachedResults.CacheMiss", fileName)
+
+ match builder.GetCheckResultsBeforeFileInProjectEvenIfStale fileName with
+ | Some tcPrior ->
+ match tcPrior.TryPeekTcInfo() with
+ | Some tcInfo ->
+ let! checkResults =
+ bc.CheckOneFileImpl(
+ parseResults,
+ sourceText,
+ fileName,
+ options,
+ fileVersion,
+ builder,
+ tcPrior,
+ tcInfo,
+ creationDiags
+ )
+
+ return Some checkResults
+ | None -> return None
+ | None -> return None // the incremental builder was not up to date
+ }
+
+ /// Type-check the result obtained by parsing. Force the evaluation of the antecedent type checking context if needed.
+ member bc.CheckFileInProject
+ (
+ parseResults: FSharpParseFileResults,
+ fileName,
+ fileVersion,
+ sourceText: ISourceText,
+ options,
+ userOpName
+ ) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.CheckFileInProject"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None ->
+ return FSharpCheckFileAnswer.Succeeded(FSharpCheckFileResults.MakeEmpty(fileName, creationDiags, keepAssemblyContents))
+ | Some builder ->
+ // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date
+ let! cachedResults = bc.GetCachedCheckFileResult(builder, fileName, sourceText, options)
+
+ match cachedResults with
+ | Some (_, checkResults) -> return FSharpCheckFileAnswer.Succeeded checkResults
+ | _ ->
+ let! tcPrior = builder.GetCheckResultsBeforeFileInProject fileName
+ let! tcInfo = tcPrior.GetOrComputeTcInfo()
+
+ return!
+ bc.CheckOneFileImpl(
+ parseResults,
+ sourceText,
+ fileName,
+ options,
+ fileVersion,
+ builder,
+ tcPrior,
+ tcInfo,
+ creationDiags
+ )
+ }
+
+ /// Parses and checks the source file and returns untyped AST and check results.
+ member bc.ParseAndCheckFileInProject
+ (
+ fileName: string,
+ fileVersion,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions,
+ userOpName
+ ) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.ParseAndCheckFileInProject"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None ->
+ let parseTree = EmptyParsedInput(fileName, (false, false))
+ let parseResults = FSharpParseFileResults(creationDiags, parseTree, true, [||])
+ return (parseResults, FSharpCheckFileAnswer.Aborted)
+
+ | Some builder ->
+ let! cachedResults = bc.GetCachedCheckFileResult(builder, fileName, sourceText, options)
+
+ match cachedResults with
+ | Some (parseResults, checkResults) -> return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
+ | _ ->
+ let! tcPrior = builder.GetCheckResultsBeforeFileInProject fileName
+ let! tcInfo = tcPrior.GetOrComputeTcInfo()
+ // Do the parsing.
+ let parsingOptions =
+ FSharpParsingOptions.FromTcConfig(
+ builder.TcConfig,
+ Array.ofList builder.SourceFiles,
+ options.UseScriptResolutionRules
+ )
+
+ GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
+
+ let parseDiagnostics, parseTree, anyErrors =
+ ParseAndCheckFile.parseFile (
+ sourceText,
+ fileName,
+ parsingOptions,
+ userOpName,
+ suggestNamesForErrors,
+ captureIdentifiersWhenParsing
+ )
+
+ let parseResults =
+ FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, builder.AllDependenciesDeprecated)
+
+ let! checkResults =
+ bc.CheckOneFileImpl(
+ parseResults,
+ sourceText,
+ fileName,
+ options,
+ fileVersion,
+ builder,
+ tcPrior,
+ tcInfo,
+ creationDiags
+ )
+
+ return (parseResults, checkResults)
+ }
+
+ member _.NotifyFileChanged(fileName, options, userOpName) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.NotifyFileChanged"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ let! builderOpt, _ = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None -> return ()
+ | Some builder -> do! builder.NotifyFileChanged(fileName, DateTime.UtcNow)
+ }
+
+ /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API)
+ member _.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.ParseAndCheckFileInProject"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None ->
+ let parseTree = EmptyParsedInput(fileName, (false, false))
+ let parseResults = FSharpParseFileResults(creationDiags, parseTree, true, [||])
+ let typedResults = FSharpCheckFileResults.MakeEmpty(fileName, creationDiags, true)
+ return (parseResults, typedResults)
+ | Some builder ->
+ let parseTree, _, _, parseDiagnostics = builder.GetParseResultsForFile fileName
+ let! tcProj = builder.GetFullCheckResultsAfterFileInProject fileName
+
+ let! tcInfo, tcInfoExtras = tcProj.GetOrComputeTcInfoWithExtras()
+
+ let tcResolutions = tcInfoExtras.tcResolutions
+ let tcSymbolUses = tcInfoExtras.tcSymbolUses
+ let tcOpenDeclarations = tcInfoExtras.tcOpenDeclarations
+ let latestCcuSigForFile = tcInfo.latestCcuSigForFile
+ let tcState = tcInfo.tcState
+ let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile
+ let latestImplementationFile = tcInfoExtras.latestImplFile
+ let tcDependencyFiles = tcInfo.tcDependencyFiles
+ let tcDiagnostics = tcInfo.TcDiagnostics
+ let diagnosticsOptions = builder.TcConfig.diagnosticsOptions
+
+ let parseDiagnostics =
+ DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, parseDiagnostics, suggestNamesForErrors)
+
+ let parseDiagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
+
+ let tcDiagnostics =
+ DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, tcDiagnostics, suggestNamesForErrors)
+
+ let tcDiagnostics = [| yield! creationDiags; yield! tcDiagnostics |]
+
+ let parseResults =
+ FSharpParseFileResults(
+ diagnostics = parseDiagnostics,
+ input = parseTree,
+ parseHadErrors = false,
+ dependencyFiles = builder.AllDependenciesDeprecated
+ )
+
+ let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options)
+
+ let typedResults =
+ FSharpCheckFileResults.Make(
+ fileName,
+ options.ProjectFileName,
+ tcProj.TcConfig,
+ tcProj.TcGlobals,
+ options.IsIncompleteTypeCheckEnvironment,
+ builder,
+ options,
+ Array.ofList tcDependencyFiles,
+ creationDiags,
+ parseResults.Diagnostics,
+ tcDiagnostics,
+ keepAssemblyContents,
+ Option.get latestCcuSigForFile,
+ tcState.Ccu,
+ tcProj.TcImports,
+ tcEnvAtEnd.AccessRights,
+ tcResolutions,
+ tcSymbolUses,
+ tcEnvAtEnd.NameEnv,
+ loadClosure,
+ latestImplementationFile,
+ tcOpenDeclarations
+ )
+
+ return (parseResults, typedResults)
+ }
+
+ member _.FindReferencesInFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ symbol: FSharpSymbol,
+ canInvalidateProject: bool,
+ userOpName: string
+ ) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.FindReferencesInFile"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ "symbol", symbol.FullName
+ |]
+
+ let! builderOpt, _ = getOrCreateBuilderWithInvalidationFlag (options, canInvalidateProject, userOpName)
+
+ match builderOpt with
+ | None -> return Seq.empty
+ | Some builder ->
+ if builder.ContainsFile fileName then
+ let! checkResults = builder.GetFullCheckResultsAfterFileInProject fileName
+ let! keyStoreOpt = checkResults.GetOrComputeItemKeyStoreIfEnabled()
+
+ match keyStoreOpt with
+ | None -> return Seq.empty
+ | Some reader -> return reader.FindAll symbol.Item
+ else
+ return Seq.empty
+ }
+
+ member _.GetSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, userOpName: string) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.GetSemanticClassificationForFile"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ let! builderOpt, _ = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None -> return None
+ | Some builder ->
+ let! checkResults = builder.GetFullCheckResultsAfterFileInProject fileName
+ let! scopt = checkResults.GetOrComputeSemanticClassificationIfEnabled()
+
+ match scopt with
+ | None -> return None
+ | Some sc -> return Some(sc.GetView())
+ }
+
+ /// Try to get recent approximate type check results for a file.
+ member _.TryGetRecentCheckResultsForFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ sourceText: ISourceText option,
+ _userOpName: string
+ ) =
+ use _ =
+ Activity.start
+ "BackgroundCompiler.GetSemanticClassificationForFile"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.fileName, fileName
+ Activity.Tags.userOpName, _userOpName
+ |]
+
+ match sourceText with
+ | Some sourceText ->
+ let hash = sourceText.GetHashCode() |> int64
+
+ let resOpt =
+ parseCacheLock.AcquireLock(fun ltok -> checkFileInProjectCache.TryGet(ltok, (fileName, hash, options)))
+
+ match resOpt with
+ | Some res ->
+ match res.TryPeekValue() with
+ | ValueSome (a, b, c, _) -> Some(a, b, c)
+ | ValueNone -> None
+ | None -> None
+ | None -> None
+
+ /// Parse and typecheck the whole project (the implementation, called recursively as project graph is evaluated)
+ member private _.ParseAndCheckProjectImpl(options, userOpName) =
+ node {
+ let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None ->
+ let emptyResults =
+ FSharpCheckProjectResults(options.ProjectFileName, None, keepAssemblyContents, creationDiags, None)
+
+ return emptyResults
+ | Some builder ->
+ let! tcProj, ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt = builder.GetFullCheckResultsAndImplementationsForProject()
+ let diagnosticsOptions = tcProj.TcConfig.diagnosticsOptions
+ let fileName = DummyFileNameForRangesWithoutASpecificLocation
+
+ // Although we do not use 'tcInfoExtras', computing it will make sure we get an extra info.
+ let! tcInfo, _tcInfoExtras = tcProj.GetOrComputeTcInfoWithExtras()
+
+ let topAttribs = tcInfo.topAttribs
+ let tcState = tcInfo.tcState
+ let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile
+ let tcDiagnostics = tcInfo.TcDiagnostics
+ let tcDependencyFiles = tcInfo.tcDependencyFiles
+
+ let tcDiagnostics =
+ DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, true, fileName, tcDiagnostics, suggestNamesForErrors)
+
+ let diagnostics = [| yield! creationDiags; yield! tcDiagnostics |]
+
+ let getAssemblyData () =
+ match tcAssemblyDataOpt with
+ | ProjectAssemblyDataResult.Available data -> Some data
+ | _ -> None
+
+ let details =
+ (tcProj.TcGlobals,
+ tcProj.TcImports,
+ tcState.Ccu,
+ tcState.CcuSig,
+ Choice1Of2 builder,
+ topAttribs,
+ getAssemblyData,
+ ilAssemRef,
+ tcEnvAtEnd.AccessRights,
+ tcAssemblyExprOpt,
+ Array.ofList tcDependencyFiles,
+ options)
+
+ let results =
+ FSharpCheckProjectResults(
+ options.ProjectFileName,
+ Some tcProj.TcConfig,
+ keepAssemblyContents,
+ diagnostics,
+ Some details
+ )
+
+ return results
+ }
+
+ member _.GetAssemblyData(options, userOpName) =
+ node {
+ use _ =
+ Activity.start
+ "BackgroundCompiler.GetAssemblyData"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ let! builderOpt, _ = getOrCreateBuilder (options, userOpName)
+
+ match builderOpt with
+ | None -> return ProjectAssemblyDataResult.Unavailable true
+ | Some builder ->
+ let! _, _, tcAssemblyDataOpt, _ = builder.GetCheckResultsAndImplementationsForProject()
+ return tcAssemblyDataOpt
+ }
+
+ /// Get the timestamp that would be on the output if fully built immediately
+ member private _.TryGetLogicalTimeStampForProject(cache, options) =
+ match tryGetBuilderNode options with
+ | Some lazyWork ->
+ match lazyWork.TryPeekValue() with
+ | ValueSome (Some builder, _) -> Some(builder.GetLogicalTimeStampForProject(cache))
+ | _ -> None
+ | _ -> None
+
+ /// Parse and typecheck the whole project.
+ member bc.ParseAndCheckProject(options, userOpName) =
+ use _ =
+ Activity.start
+ "BackgroundCompiler.ParseAndCheckProject"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ bc.ParseAndCheckProjectImpl(options, userOpName)
+
+ member _.GetProjectOptionsFromScript
+ (
+ fileName,
+ sourceText,
+ previewEnabled,
+ loadedTimeStamp,
+ otherFlags,
+ useFsiAuxLib: bool option,
+ useSdkRefs: bool option,
+ sdkDirOverride: string option,
+ assumeDotNetFramework: bool option,
+ optionsStamp: int64 option,
+ _userOpName
+ ) =
+ use _ =
+ Activity.start
+ "BackgroundCompiler.GetProjectOptionsFromScript"
+ [| Activity.Tags.fileName, fileName; Activity.Tags.userOpName, _userOpName |]
+
+ cancellable {
+ use diagnostics = new DiagnosticsScope()
+
+ // Do we add a reference to FSharp.Compiler.Interactive.Settings by default?
+ let useFsiAuxLib = defaultArg useFsiAuxLib true
+ let useSdkRefs = defaultArg useSdkRefs true
+ let reduceMemoryUsage = ReduceMemoryFlag.Yes
+ let previewEnabled = defaultArg previewEnabled false
+
+ // Do we assume .NET Framework references for scripts?
+ let assumeDotNetFramework = defaultArg assumeDotNetFramework true
+
+ let extraFlags =
+ if previewEnabled then
+ [| "--langversion:preview" |]
+ else
+ [||]
+
+ let otherFlags = defaultArg otherFlags extraFlags
+
+ let useSimpleResolution =
+ otherFlags |> Array.exists (fun x -> x = "--simpleresolution")
+
+ let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading
+
+ let applyCompilerOptions tcConfigB =
+ let fsiCompilerOptions = GetCoreFsiCompilerOptions tcConfigB
+ ParseCompilerOptions(ignore, fsiCompilerOptions, Array.toList otherFlags)
+
+ let loadClosure =
+ LoadClosure.ComputeClosureOfScriptText(
+ legacyReferenceResolver,
+ FSharpCheckerResultsSettings.defaultFSharpBinariesDir,
+ fileName,
+ sourceText,
+ CodeContext.Editing,
+ useSimpleResolution,
+ useFsiAuxLib,
+ useSdkRefs,
+ sdkDirOverride,
+ Lexhelp.LexResourceManager(),
+ applyCompilerOptions,
+ assumeDotNetFramework,
+ tryGetMetadataSnapshot,
+ reduceMemoryUsage,
+ dependencyProviderForScripts
+ )
+
+ let otherFlags =
+ [|
+ yield "--noframework"
+ yield "--warn:3"
+ yield! otherFlags
+ for r in loadClosure.References do
+ yield "-r:" + fst r
+ for code, _ in loadClosure.NoWarns do
+ yield "--nowarn:" + code
+ |]
+
+ let options =
+ {
+ ProjectFileName = fileName + ".fsproj" // Make a name that is unique in this directory.
+ ProjectId = None
+ SourceFiles = loadClosure.SourceFiles |> List.map fst |> List.toArray
+ OtherOptions = otherFlags
+ ReferencedProjects = [||]
+ IsIncompleteTypeCheckEnvironment = false
+ UseScriptResolutionRules = true
+ LoadTime = loadedTimeStamp
+ UnresolvedReferences = Some(FSharpUnresolvedReferencesSet(loadClosure.UnresolvedReferences))
+ OriginalLoadReferences = loadClosure.OriginalLoadReferences
+ Stamp = optionsStamp
+ }
+
+ scriptClosureCache.Set(AnyCallerThread, options, loadClosure) // Save the full load closure for later correlation.
+
+ let diags =
+ loadClosure.LoadClosureRootFileDiagnostics
+ |> List.map (fun (exn, isError) -> FSharpDiagnostic.CreateFromException(exn, isError, range.Zero, false))
+
+ return options, (diags @ diagnostics.Diagnostics)
+ }
+ |> Cancellable.toAsync
+
+ member bc.InvalidateConfiguration(options: FSharpProjectOptions, userOpName) =
+ use _ =
+ Activity.start
+ "BackgroundCompiler.InvalidateConfiguration"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ if incrementalBuildersCache.ContainsSimilarKey(AnyCallerThread, options) then
+ parseCacheLock.AcquireLock(fun ltok ->
+ for sourceFile in options.SourceFiles do
+ checkFileInProjectCache.RemoveAnySimilar(ltok, (sourceFile, 0L, options)))
+
+ let _ = createBuilderNode (options, userOpName, CancellationToken.None)
+ ()
+
+ member bc.ClearCache(options: seq, _userOpName) =
+ use _ =
+ Activity.start "BackgroundCompiler.ClearCache" [| Activity.Tags.userOpName, _userOpName |]
+
+ lock gate (fun () ->
+ options
+ |> Seq.iter (fun options -> incrementalBuildersCache.RemoveAnySimilar(AnyCallerThread, options)))
+
+ member _.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName) =
+ use _ =
+ Activity.start
+ "BackgroundCompiler.NotifyProjectCleaned"
+ [|
+ Activity.Tags.project, options.ProjectFileName
+ Activity.Tags.userOpName, userOpName
+ |]
+
+ async {
+ let! ct = Async.CancellationToken
+ // If there was a similar entry (as there normally will have been) then re-establish an empty builder . This
+ // is a somewhat arbitrary choice - it will have the effect of releasing memory associated with the previous
+ // builder, but costs some time.
+ if incrementalBuildersCache.ContainsSimilarKey(AnyCallerThread, options) then
+ let _ = createBuilderNode (options, userOpName, ct)
+ ()
+ }
+
+ member _.BeforeBackgroundFileCheck = beforeFileChecked.Publish
+
+ member _.FileParsed = fileParsed.Publish
+
+ member _.FileChecked = fileChecked.Publish
+
+ member _.ProjectChecked = projectChecked.Publish
+
+ member _.ClearCaches() =
+ use _ = Activity.startNoTags "BackgroundCompiler.ClearCaches"
+
+ lock gate (fun () ->
+ parseCacheLock.AcquireLock(fun ltok ->
+ checkFileInProjectCache.Clear(ltok)
+ parseFileCache.Clear(ltok))
+
+ incrementalBuildersCache.Clear(AnyCallerThread)
+ frameworkTcImportsCache.Clear()
+ scriptClosureCache.Clear AnyCallerThread)
+
+ member _.DownsizeCaches() =
+ use _ = Activity.startNoTags "BackgroundCompiler.DownsizeCaches"
+
+ lock gate (fun () ->
+ parseCacheLock.AcquireLock(fun ltok ->
+ checkFileInProjectCache.Resize(ltok, newKeepStrongly = 1)
+ parseFileCache.Resize(ltok, newKeepStrongly = 1))
+
+ incrementalBuildersCache.Resize(AnyCallerThread, newKeepStrongly = 1, newKeepMax = 1)
+ frameworkTcImportsCache.Downsize()
+ scriptClosureCache.Resize(AnyCallerThread, newKeepStrongly = 1, newKeepMax = 1))
+
+ member _.FrameworkImportsCache = frameworkTcImportsCache
+
+ static member ActualParseFileCount = actualParseFileCount
+
+ static member ActualCheckFileCount = actualCheckFileCount
+
+ interface IBackgroundCompiler with
+ member _.BeforeBackgroundFileCheck = self.BeforeBackgroundFileCheck
+
+ member _.CheckFileInProject
+ (
+ parseResults: FSharpParseFileResults,
+ fileName: string,
+ fileVersion: int,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ self.CheckFileInProject(parseResults, fileName, fileVersion, sourceText, options, userOpName)
+
+ member _.CheckFileInProjectAllowingStaleCachedResults
+ (
+ parseResults: FSharpParseFileResults,
+ fileName: string,
+ fileVersion: int,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ self.CheckFileInProjectAllowingStaleCachedResults(parseResults, fileName, fileVersion, sourceText, options, userOpName)
+
+ member _.ClearCache(options: seq, userOpName: string) : unit = self.ClearCache(options, userOpName)
+ member _.ClearCaches() : unit = self.ClearCaches()
+ member _.DownsizeCaches() : unit = self.DownsizeCaches()
+ member _.FileChecked: IEvent = self.FileChecked
+ member _.FileParsed: IEvent = self.FileParsed
+
+ member _.FindReferencesInFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ symbol: FSharpSymbol,
+ canInvalidateProject: bool,
+ userOpName: string
+ ) : NodeCode> =
+ self.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
+
+ member _.FrameworkImportsCache: FrameworkImportsCache = self.FrameworkImportsCache
+
+ member _.GetAssemblyData(options: FSharpProjectOptions, userOpName: string) : NodeCode =
+ self.GetAssemblyData(options, userOpName)
+
+ member _.GetBackgroundCheckResultsForFileInProject
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ self.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName)
+
+ member _.GetBackgroundParseResultsForFileInProject
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ self.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName)
+
+ member _.GetCachedCheckFileResult
+ (
+ builder: IncrementalBuilder,
+ fileName: string,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions
+ ) : NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> =
+ self.GetCachedCheckFileResult(builder, fileName, sourceText, options)
+
+ member _.GetProjectOptionsFromScript
+ (
+ fileName: string,
+ sourceText: ISourceText,
+ previewEnabled: bool option,
+ loadedTimeStamp: DateTime option,
+ otherFlags: string array option,
+ useFsiAuxLib: bool option,
+ useSdkRefs: bool option,
+ sdkDirOverride: string option,
+ assumeDotNetFramework: bool option,
+ optionsStamp: int64 option,
+ userOpName: string
+ ) : Async =
+ self.GetProjectOptionsFromScript(
+ fileName,
+ sourceText,
+ previewEnabled,
+ loadedTimeStamp,
+ otherFlags,
+ useFsiAuxLib,
+ useSdkRefs,
+ sdkDirOverride,
+ assumeDotNetFramework,
+ optionsStamp,
+ userOpName
+ )
+
+ member _.GetSemanticClassificationForFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ self.GetSemanticClassificationForFile(fileName, options, userOpName)
+
+ member _.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string) : unit =
+ self.InvalidateConfiguration(options, userOpName)
+
+ member _.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : NodeCode =
+ self.NotifyFileChanged(fileName, options, userOpName)
+
+ member _.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async =
+ self.NotifyProjectCleaned(options, userOpName)
+
+ member _.ParseAndCheckFileInProject
+ (
+ fileName: string,
+ fileVersion: int,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ self.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName)
+
+ member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode =
+ self.ParseAndCheckProject(options, userOpName)
+
+ member _.ParseFile
+ (
+ fileName: string,
+ sourceText: ISourceText,
+ options: FSharpParsingOptions,
+ cache: bool,
+ userOpName: string
+ ) : Async =
+ self.ParseFile(fileName, sourceText, options, cache, userOpName)
+
+ member _.ProjectChecked: IEvent = self.ProjectChecked
+
+ member _.TryGetRecentCheckResultsForFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ sourceText: ISourceText option,
+ userOpName: string
+ ) : (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option =
+ self.TryGetRecentCheckResultsForFile(fileName, options, sourceText, userOpName)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
new file mode 100644
index 00000000000..28d5996b5b0
--- /dev/null
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -0,0 +1,54 @@
+namespace FSharp.Compiler.CodeAnalysis
+
+
+type internal TransparentCompiler() =
+
+ interface IBackgroundCompiler with
+ member this.BeforeBackgroundFileCheck: IEvent =
+ raise (System.NotImplementedException())
+ member this.CheckFileInProject(parseResults: FSharpParseFileResults, fileName: string, fileVersion: int, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.CheckFileInProjectAllowingStaleCachedResults(parseResults: FSharpParseFileResults, fileName: string, fileVersion: int, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.ClearCache(options: seq, userOpName: string): unit =
+ raise (System.NotImplementedException())
+ member this.ClearCaches(): unit =
+ raise (System.NotImplementedException())
+ member this.DownsizeCaches(): unit =
+ raise (System.NotImplementedException())
+ member this.FileChecked: IEvent =
+ raise (System.NotImplementedException())
+ member this.FileParsed: IEvent =
+ raise (System.NotImplementedException())
+ member this.FindReferencesInFile(fileName: string, options: FSharpProjectOptions, symbol: FSharp.Compiler.Symbols.FSharpSymbol, canInvalidateProject: bool, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode> =
+ raise (System.NotImplementedException())
+ member this.FrameworkImportsCache: FrameworkImportsCache =
+ raise (System.NotImplementedException())
+ member this.GetAssemblyData(options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.GetBackgroundCheckResultsForFileInProject(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.GetBackgroundParseResultsForFileInProject(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.GetCachedCheckFileResult(builder: IncrementalBuilder, fileName: string, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions): FSharp.Compiler.BuildGraph.NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> =
+ raise (System.NotImplementedException())
+ member this.GetProjectOptionsFromScript(fileName: string, sourceText: FSharp.Compiler.Text.ISourceText, previewEnabled: bool option, loadedTimeStamp: System.DateTime option, otherFlags: string array option, useFsiAuxLib: bool option, useSdkRefs: bool option, sdkDirOverride: string option, assumeDotNetFramework: bool option, optionsStamp: int64 option, userOpName: string): Async =
+ raise (System.NotImplementedException())
+ member this.GetSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string): unit =
+ raise (System.NotImplementedException())
+ member this.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string): Async =
+ raise (System.NotImplementedException())
+ member this.ParseAndCheckFileInProject(fileName: string, fileVersion: int, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
+ raise (System.NotImplementedException())
+ member this.ParseFile(fileName: string, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpParsingOptions, cache: bool, userOpName: string): Async =
+ raise (System.NotImplementedException())
+ member this.ProjectChecked: IEvent =
+ raise (System.NotImplementedException())
+ member this.TryGetRecentCheckResultsForFile(fileName: string, options: FSharpProjectOptions, sourceText: FSharp.Compiler.Text.ISourceText option, userOpName: string): (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option =
+ raise (System.NotImplementedException())
\ No newline at end of file
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index cf5487e25df..8b6a9c1766a 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -36,19 +36,6 @@ open FSharp.Compiler.Text.Range
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.BuildGraph
-[]
-module EnvMisc =
- let braceMatchCacheSize = GetEnvInteger "FCS_BraceMatchCacheSize" 5
- let parseFileCacheSize = GetEnvInteger "FCS_ParseFileCacheSize" 2
- let checkFileInProjectCacheSize = GetEnvInteger "FCS_CheckFileInProjectCacheSize" 10
-
- let projectCacheSizeDefault = GetEnvInteger "FCS_ProjectCacheSizeDefault" 3
- let frameworkTcImportsCacheStrongSize = GetEnvInteger "FCS_frameworkTcImportsCacheStrongSizeDefault" 8
-
-//----------------------------------------------------------------------------
-// BackgroundCompiler
-//
-
[]
type DocumentSource =
| FileSystem
@@ -58,46 +45,6 @@ type DocumentSource =
[]
type IsResultObsolete = IsResultObsolete of (unit -> bool)
-[]
-module Helpers =
-
- /// Determine whether two (fileName,options) keys are identical w.r.t. affect on checking
- let AreSameForChecking2 ((fileName1: string, options1: FSharpProjectOptions), (fileName2, options2)) =
- (fileName1 = fileName2)
- && FSharpProjectOptions.AreSameForChecking(options1, options2)
-
- /// Determine whether two (fileName,options) keys should be identical w.r.t. resource usage
- let AreSubsumable2 ((fileName1: string, o1: FSharpProjectOptions), (fileName2: string, o2: FSharpProjectOptions)) =
- (fileName1 = fileName2) && FSharpProjectOptions.UseSameProject(o1, o2)
-
- /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. parsing
- let AreSameForParsing ((fileName1: string, source1Hash: int64, options1), (fileName2, source2Hash, options2)) =
- fileName1 = fileName2 && options1 = options2 && source1Hash = source2Hash
-
- let AreSimilarForParsing ((fileName1, _, _), (fileName2, _, _)) = fileName1 = fileName2
-
- /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. checking
- let AreSameForChecking3 ((fileName1: string, source1Hash: int64, options1: FSharpProjectOptions), (fileName2, source2Hash, options2)) =
- (fileName1 = fileName2)
- && FSharpProjectOptions.AreSameForChecking(options1, options2)
- && source1Hash = source2Hash
-
- /// Determine whether two (fileName,sourceText,options) keys should be identical w.r.t. resource usage
- let AreSubsumable3 ((fileName1: string, _, o1: FSharpProjectOptions), (fileName2: string, _, o2: FSharpProjectOptions)) =
- (fileName1 = fileName2) && FSharpProjectOptions.UseSameProject(o1, o2)
-
- /// If a symbol is an attribute check if given set of names contains its name without the Attribute suffix
- let rec NamesContainAttribute (symbol: FSharpSymbol) names =
- match symbol with
- | :? FSharpMemberOrFunctionOrValue as mofov ->
- mofov.DeclaringEntity
- |> Option.map (fun entity -> NamesContainAttribute entity names)
- |> Option.defaultValue false
- | :? FSharpEntity as entity when entity.IsAttributeType && symbol.DisplayNameCore.EndsWithOrdinal "Attribute" ->
- let nameWithoutAttribute = String.dropSuffix symbol.DisplayNameCore "Attribute"
- names |> Set.contains nameWithoutAttribute
- | _ -> false
-
module CompileHelpers =
let mkCompilationDiagnosticsHandlers () =
let diagnostics = ResizeArray<_>()
@@ -164,1088 +111,6 @@ module CompileHelpers =
Console.SetError error
| None -> ()
-type SourceTextHash = int64
-type CacheStamp = int64
-type FileName = string
-type FilePath = string
-type ProjectPath = string
-type FileVersion = int
-
-type ParseCacheLockToken() =
- interface LockToken
-
-type ScriptClosureCacheToken() =
- interface LockToken
-
-type CheckFileCacheKey = FileName * SourceTextHash * FSharpProjectOptions
-type CheckFileCacheValue = FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash * DateTime
-
-// There is only one instance of this type, held in FSharpChecker
-type BackgroundCompiler
- (
- legacyReferenceResolver,
- projectCacheSize,
- keepAssemblyContents,
- keepAllBackgroundResolutions,
- tryGetMetadataSnapshot,
- suggestNamesForErrors,
- keepAllBackgroundSymbolUses,
- enableBackgroundItemKeyStoreAndSemanticClassification,
- enablePartialTypeChecking,
- parallelReferenceResolution,
- captureIdentifiersWhenParsing,
- getSource: (string -> ISourceText option) option,
- useChangeNotifications,
- useSyntaxTreeCache
- ) as self =
-
- let beforeFileChecked = Event()
- let fileParsed = Event()
- let fileChecked = Event()
- let projectChecked = Event()
-
- // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.scriptClosureCache
- /// Information about the derived script closure.
- let scriptClosureCache =
- MruCache(
- projectCacheSize,
- areSame = FSharpProjectOptions.AreSameForChecking,
- areSimilar = FSharpProjectOptions.UseSameProject
- )
-
- let frameworkTcImportsCache = FrameworkImportsCache(frameworkTcImportsCacheStrongSize)
-
- // We currently share one global dependency provider for all scripts for the FSharpChecker.
- // For projects, one is used per project.
- //
- // Sharing one for all scripts is necessary for good performance from GetProjectOptionsFromScript,
- // which requires a dependency provider to process through the project options prior to working out
- // if the cached incremental builder can be used for the project.
- let dependencyProviderForScripts = new DependencyProvider()
-
- let getProjectReferences (options: FSharpProjectOptions) userOpName =
- [
- for r in options.ReferencedProjects do
-
- match r with
- | FSharpReferencedProject.FSharpReference (nm, opts) ->
- // Don't use cross-project references for FSharp.Core, since various bits of code
- // require a concrete FSharp.Core to exist on-disk. The only solutions that have
- // these cross-project references to FSharp.Core are VisualFSharp.sln and FSharp.sln. The ramification
- // of this is that you need to build FSharp.Core to get intellisense in those projects.
-
- if
- (try
- Path.GetFileNameWithoutExtension(nm)
- with _ ->
- "")
- <> GetFSharpCoreLibraryName()
- then
- { new IProjectReference with
- member x.EvaluateRawContents() =
- node {
- Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm)
- return! self.GetAssemblyData(opts, userOpName + ".CheckReferencedProject(" + nm + ")")
- }
-
- member x.TryGetLogicalTimeStamp(cache) =
- self.TryGetLogicalTimeStampForProject(cache, opts)
-
- member x.FileName = nm
- }
-
- | FSharpReferencedProject.PEReference (nm, getStamp, delayedReader) ->
- { new IProjectReference with
- member x.EvaluateRawContents() =
- node {
- let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> NodeCode.FromCancellable
-
- match ilReaderOpt with
- | Some ilReader ->
- let ilModuleDef, ilAsmRefs = ilReader.ILModuleDef, ilReader.ILAssemblyRefs
- let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData
- return ProjectAssemblyDataResult.Available data
- | _ ->
- // Note 'false' - if a PEReference doesn't find an ILModuleReader then we don't
- // continue to try to use an on-disk DLL
- return ProjectAssemblyDataResult.Unavailable false
- }
-
- member x.TryGetLogicalTimeStamp _ = getStamp () |> Some
- member x.FileName = nm
- }
-
- | FSharpReferencedProject.ILModuleReference (nm, getStamp, getReader) ->
- { new IProjectReference with
- member x.EvaluateRawContents() =
- node {
- let ilReader = getReader ()
- let ilModuleDef, ilAsmRefs = ilReader.ILModuleDef, ilReader.ILAssemblyRefs
- let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData
- return ProjectAssemblyDataResult.Available data
- }
-
- member x.TryGetLogicalTimeStamp _ = getStamp () |> Some
- member x.FileName = nm
- }
- ]
-
- /// CreateOneIncrementalBuilder (for background type checking). Note that fsc.fs also
- /// creates an incremental builder used by the command line compiler.
- let CreateOneIncrementalBuilder (options: FSharpProjectOptions, userOpName) =
- node {
- use _ =
- Activity.start "BackgroundCompiler.CreateOneIncrementalBuilder" [| Activity.Tags.project, options.ProjectFileName |]
-
- Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "CreateOneIncrementalBuilder", options.ProjectFileName)
- let projectReferences = getProjectReferences options userOpName
-
- let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options)
-
- let dependencyProvider =
- if options.UseScriptResolutionRules then
- Some dependencyProviderForScripts
- else
- None
-
- let! builderOpt, diagnostics =
- IncrementalBuilder.TryCreateIncrementalBuilderForProjectOptions(
- legacyReferenceResolver,
- FSharpCheckerResultsSettings.defaultFSharpBinariesDir,
- frameworkTcImportsCache,
- loadClosure,
- Array.toList options.SourceFiles,
- Array.toList options.OtherOptions,
- projectReferences,
- options.ProjectDirectory,
- options.UseScriptResolutionRules,
- keepAssemblyContents,
- keepAllBackgroundResolutions,
- tryGetMetadataSnapshot,
- suggestNamesForErrors,
- keepAllBackgroundSymbolUses,
- enableBackgroundItemKeyStoreAndSemanticClassification,
- enablePartialTypeChecking,
- dependencyProvider,
- parallelReferenceResolution,
- captureIdentifiersWhenParsing,
- getSource,
- useChangeNotifications,
- useSyntaxTreeCache
- )
-
- match builderOpt with
- | None -> ()
- | Some builder ->
-
-#if !NO_TYPEPROVIDERS
- // Register the behaviour that responds to CCUs being invalidated because of type
- // provider Invalidate events. This invalidates the configuration in the build.
- builder.ImportsInvalidatedByTypeProvider.Add(fun () -> self.InvalidateConfiguration(options, userOpName))
-#endif
-
- // Register the callback called just before a file is typechecked by the background builder (without recording
- // errors or intellisense information).
- //
- // This indicates to the UI that the file type check state is dirty. If the file is open and visible then
- // the UI will sooner or later request a typecheck of the file, recording errors and intellisense information.
- builder.BeforeFileChecked.Add(fun file -> beforeFileChecked.Trigger(file, options))
- builder.FileParsed.Add(fun file -> fileParsed.Trigger(file, options))
- builder.FileChecked.Add(fun file -> fileChecked.Trigger(file, options))
- builder.ProjectChecked.Add(fun () -> projectChecked.Trigger options)
-
- return (builderOpt, diagnostics)
- }
-
- let parseCacheLock = Lock()
-
- // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.parseFileInProjectCache. Most recently used cache for parsing files.
- let parseFileCache =
- MruCache(parseFileCacheSize, areSimilar = AreSimilarForParsing, areSame = AreSameForParsing)
-
- // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.checkFileInProjectCache
- //
- /// Cache which holds recently seen type-checks.
- /// This cache may hold out-of-date entries, in two senses
- /// - there may be a more recent antecedent state available because the background build has made it available
- /// - the source for the file may have changed
-
- // Also keyed on source. This can only be out of date if the antecedent is out of date
- let checkFileInProjectCache =
- MruCache>(
- keepStrongly = checkFileInProjectCacheSize,
- areSame = AreSameForChecking3,
- areSimilar = AreSubsumable3
- )
-
- // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.incrementalBuildersCache. This root typically holds more
- // live information than anything else in the F# Language Service, since it holds up to 3 (projectCacheStrongSize) background project builds
- // strongly.
- //
- /// Cache of builds keyed by options.
- let gate = obj ()
-
- let incrementalBuildersCache =
- MruCache>(
- keepStrongly = projectCacheSize,
- keepMax = projectCacheSize,
- areSame = FSharpProjectOptions.AreSameForChecking,
- areSimilar = FSharpProjectOptions.UseSameProject
- )
-
- let tryGetBuilderNode options =
- incrementalBuildersCache.TryGet(AnyCallerThread, options)
-
- let tryGetBuilder options : NodeCode option =
- tryGetBuilderNode options |> Option.map (fun x -> x.GetOrComputeValue())
-
- let tryGetSimilarBuilder options : NodeCode option =
- incrementalBuildersCache.TryGetSimilar(AnyCallerThread, options)
- |> Option.map (fun x -> x.GetOrComputeValue())
-
- let tryGetAnyBuilder options : NodeCode option =
- incrementalBuildersCache.TryGetAny(AnyCallerThread, options)
- |> Option.map (fun x -> x.GetOrComputeValue())
-
- let createBuilderNode (options, userOpName, ct: CancellationToken) =
- lock gate (fun () ->
- if ct.IsCancellationRequested then
- GraphNode.FromResult(None, [||])
- else
- let getBuilderNode = GraphNode(CreateOneIncrementalBuilder(options, userOpName))
- incrementalBuildersCache.Set(AnyCallerThread, options, getBuilderNode)
- getBuilderNode)
-
- let createAndGetBuilder (options, userOpName) =
- node {
- let! ct = NodeCode.CancellationToken
- let getBuilderNode = createBuilderNode (options, userOpName, ct)
- return! getBuilderNode.GetOrComputeValue()
- }
-
- let getOrCreateBuilder (options, userOpName) : NodeCode =
- match tryGetBuilder options with
- | Some getBuilder ->
- node {
- match! getBuilder with
- | builderOpt, creationDiags when builderOpt.IsNone || not builderOpt.Value.IsReferencesInvalidated -> return builderOpt, creationDiags
- | _ ->
- // The builder could be re-created,
- // clear the check file caches that are associated with it.
- // We must do this in order to not return stale results when references
- // in the project get changed/added/removed.
- parseCacheLock.AcquireLock(fun ltok ->
- options.SourceFiles
- |> Array.iter (fun sourceFile ->
- let key = (sourceFile, 0L, options)
- checkFileInProjectCache.RemoveAnySimilar(ltok, key)))
-
- return! createAndGetBuilder (options, userOpName)
- }
- | _ -> createAndGetBuilder (options, userOpName)
-
- let getSimilarOrCreateBuilder (options, userOpName) =
- match tryGetSimilarBuilder options with
- | Some res -> res
- // The builder does not exist at all. Create it.
- | None -> getOrCreateBuilder (options, userOpName)
-
- let getOrCreateBuilderWithInvalidationFlag (options, canInvalidateProject, userOpName) =
- if canInvalidateProject then
- getOrCreateBuilder (options, userOpName)
- else
- getSimilarOrCreateBuilder (options, userOpName)
-
- let getAnyBuilder (options, userOpName) =
- match tryGetAnyBuilder options with
- | Some getBuilder -> getBuilder
- | _ -> getOrCreateBuilder (options, userOpName)
-
- static let mutable actualParseFileCount = 0
-
- static let mutable actualCheckFileCount = 0
-
- /// Should be a fast operation. Ensures that we have only one async lazy object per file and its hash.
- let getCheckFileNode (parseResults, sourceText, fileName, options, _fileVersion, builder, tcPrior, tcInfo, creationDiags) =
-
- // Here we lock for the creation of the node, not its execution
- parseCacheLock.AcquireLock(fun ltok ->
- let key = (fileName, sourceText.GetHashCode() |> int64, options)
-
- match checkFileInProjectCache.TryGet(ltok, key) with
- | Some res -> res
- | _ ->
- let res =
- GraphNode(
- node {
- let! res = self.CheckOneFileImplAux(parseResults, sourceText, fileName, options, builder, tcPrior, tcInfo, creationDiags)
- Interlocked.Increment(&actualCheckFileCount) |> ignore
- return res
- }
- )
-
- checkFileInProjectCache.Set(ltok, key, res)
- res)
-
- member _.ParseFile(fileName: string, sourceText: ISourceText, options: FSharpParsingOptions, cache: bool, userOpName: string) =
- async {
- use _ =
- Activity.start
- "BackgroundCompiler.ParseFile"
- [|
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- Activity.Tags.cache, cache.ToString()
- |]
-
- if cache then
- let hash = sourceText.GetHashCode() |> int64
-
- match parseCacheLock.AcquireLock(fun ltok -> parseFileCache.TryGet(ltok, (fileName, hash, options))) with
- | Some res -> return res
- | None ->
- Interlocked.Increment(&actualParseFileCount) |> ignore
-
- let parseDiagnostics, parseTree, anyErrors =
- ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, suggestNamesForErrors, captureIdentifiersWhenParsing)
-
- let res = FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, options.SourceFiles)
- parseCacheLock.AcquireLock(fun ltok -> parseFileCache.Set(ltok, (fileName, hash, options), res))
- return res
- else
- let parseDiagnostics, parseTree, anyErrors =
- ParseAndCheckFile.parseFile (sourceText, fileName, options, userOpName, false, captureIdentifiersWhenParsing)
-
- return FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, options.SourceFiles)
- }
-
- /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API)
- member _.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.GetBackgroundParseResultsForFileInProject"
- [| Activity.Tags.fileName, fileName; Activity.Tags.userOpName, userOpName |]
-
- let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None ->
- let parseTree = EmptyParsedInput(fileName, (false, false))
- return FSharpParseFileResults(creationDiags, parseTree, true, [||])
- | Some builder ->
- let parseTree, _, _, parseDiagnostics = builder.GetParseResultsForFile fileName
-
- let parseDiagnostics =
- DiagnosticHelpers.CreateDiagnostics(builder.TcConfig.diagnosticsOptions, false, fileName, parseDiagnostics, suggestNamesForErrors)
-
- let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
-
- let parseResults =
- FSharpParseFileResults(
- diagnostics = diagnostics,
- input = parseTree,
- parseHadErrors = false,
- dependencyFiles = builder.AllDependenciesDeprecated
- )
-
- return parseResults
- }
-
- member _.GetCachedCheckFileResult(builder: IncrementalBuilder, fileName, sourceText: ISourceText, options) =
- node {
- use _ =
- Activity.start "BackgroundCompiler.GetCachedCheckFileResult" [| Activity.Tags.fileName, fileName |]
-
- let hash = sourceText.GetHashCode() |> int64
- let key = (fileName, hash, options)
- let cachedResultsOpt = parseCacheLock.AcquireLock(fun ltok -> checkFileInProjectCache.TryGet(ltok, key))
-
- match cachedResultsOpt with
- | Some cachedResults ->
- match! cachedResults.GetOrComputeValue() with
- | parseResults, checkResults, _, priorTimeStamp when
- (match builder.GetCheckResultsBeforeFileInProjectEvenIfStale fileName with
- | None -> false
- | Some (tcPrior) ->
- tcPrior.ProjectTimeStamp = priorTimeStamp
- && builder.AreCheckResultsBeforeFileInProjectReady(fileName))
- ->
- return Some(parseResults, checkResults)
- | _ ->
- parseCacheLock.AcquireLock(fun ltok -> checkFileInProjectCache.RemoveAnySimilar(ltok, key))
- return None
- | _ -> return None
- }
-
- member private _.CheckOneFileImplAux
- (
- parseResults: FSharpParseFileResults,
- sourceText: ISourceText,
- fileName: string,
- options: FSharpProjectOptions,
- builder: IncrementalBuilder,
- tcPrior: PartialCheckResults,
- tcInfo: TcInfo,
- creationDiags: FSharpDiagnostic[]
- ) : NodeCode =
-
- node {
- // Get additional script #load closure information if applicable.
- // For scripts, this will have been recorded by GetProjectOptionsFromScript.
- let tcConfig = tcPrior.TcConfig
- let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options)
-
- let! checkAnswer =
- FSharpCheckFileResults.CheckOneFile(
- parseResults,
- sourceText,
- fileName,
- options.ProjectFileName,
- tcConfig,
- tcPrior.TcGlobals,
- tcPrior.TcImports,
- tcInfo.tcState,
- tcInfo.moduleNamesDict,
- loadClosure,
- tcInfo.TcDiagnostics,
- options.IsIncompleteTypeCheckEnvironment,
- options,
- builder,
- Array.ofList tcInfo.tcDependencyFiles,
- creationDiags,
- parseResults.Diagnostics,
- keepAssemblyContents,
- suggestNamesForErrors
- )
- |> NodeCode.FromCancellable
-
- GraphNode.SetPreferredUILang tcConfig.preferredUiLang
- return (parseResults, checkAnswer, sourceText.GetHashCode() |> int64, tcPrior.ProjectTimeStamp)
- }
-
- member private bc.CheckOneFileImpl
- (
- parseResults: FSharpParseFileResults,
- sourceText: ISourceText,
- fileName: string,
- options: FSharpProjectOptions,
- fileVersion: int,
- builder: IncrementalBuilder,
- tcPrior: PartialCheckResults,
- tcInfo: TcInfo,
- creationDiags: FSharpDiagnostic[]
- ) =
-
- node {
- match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with
- | Some (_, results) -> return FSharpCheckFileAnswer.Succeeded results
- | _ ->
- let lazyCheckFile =
- getCheckFileNode (parseResults, sourceText, fileName, options, fileVersion, builder, tcPrior, tcInfo, creationDiags)
-
- let! _, results, _, _ = lazyCheckFile.GetOrComputeValue()
- return FSharpCheckFileAnswer.Succeeded results
- }
-
- /// Type-check the result obtained by parsing, but only if the antecedent type checking context is available.
- member bc.CheckFileInProjectAllowingStaleCachedResults
- (
- parseResults: FSharpParseFileResults,
- fileName,
- fileVersion,
- sourceText: ISourceText,
- options,
- userOpName
- ) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.CheckFileInProjectAllowingStaleCachedResults"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- |]
-
- let! cachedResults =
- node {
- let! builderOpt, creationDiags = getAnyBuilder (options, userOpName)
-
- match builderOpt with
- | Some builder ->
- match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with
- | Some (_, checkResults) -> return Some(builder, creationDiags, Some(FSharpCheckFileAnswer.Succeeded checkResults))
- | _ -> return Some(builder, creationDiags, None)
- | _ -> return None // the builder wasn't ready
- }
-
- match cachedResults with
- | None -> return None
- | Some (_, _, Some x) -> return Some x
- | Some (builder, creationDiags, None) ->
- Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "CheckFileInProjectAllowingStaleCachedResults.CacheMiss", fileName)
-
- match builder.GetCheckResultsBeforeFileInProjectEvenIfStale fileName with
- | Some tcPrior ->
- match tcPrior.TryPeekTcInfo() with
- | Some tcInfo ->
- let! checkResults =
- bc.CheckOneFileImpl(parseResults, sourceText, fileName, options, fileVersion, builder, tcPrior, tcInfo, creationDiags)
-
- return Some checkResults
- | None -> return None
- | None -> return None // the incremental builder was not up to date
- }
-
- /// Type-check the result obtained by parsing. Force the evaluation of the antecedent type checking context if needed.
- member bc.CheckFileInProject(parseResults: FSharpParseFileResults, fileName, fileVersion, sourceText: ISourceText, options, userOpName) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.CheckFileInProject"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- |]
-
- let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None -> return FSharpCheckFileAnswer.Succeeded(FSharpCheckFileResults.MakeEmpty(fileName, creationDiags, keepAssemblyContents))
- | Some builder ->
- // Check the cache. We can only use cached results when there is no work to do to bring the background builder up-to-date
- let! cachedResults = bc.GetCachedCheckFileResult(builder, fileName, sourceText, options)
-
- match cachedResults with
- | Some (_, checkResults) -> return FSharpCheckFileAnswer.Succeeded checkResults
- | _ ->
- let! tcPrior = builder.GetCheckResultsBeforeFileInProject fileName
- let! tcInfo = tcPrior.GetOrComputeTcInfo()
- return! bc.CheckOneFileImpl(parseResults, sourceText, fileName, options, fileVersion, builder, tcPrior, tcInfo, creationDiags)
- }
-
- /// Parses and checks the source file and returns untyped AST and check results.
- member bc.ParseAndCheckFileInProject(fileName: string, fileVersion, sourceText: ISourceText, options: FSharpProjectOptions, userOpName) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.ParseAndCheckFileInProject"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- |]
-
- let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None ->
- let parseTree = EmptyParsedInput(fileName, (false, false))
- let parseResults = FSharpParseFileResults(creationDiags, parseTree, true, [||])
- return (parseResults, FSharpCheckFileAnswer.Aborted)
-
- | Some builder ->
- let! cachedResults = bc.GetCachedCheckFileResult(builder, fileName, sourceText, options)
-
- match cachedResults with
- | Some (parseResults, checkResults) -> return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
- | _ ->
- let! tcPrior = builder.GetCheckResultsBeforeFileInProject fileName
- let! tcInfo = tcPrior.GetOrComputeTcInfo()
- // Do the parsing.
- let parsingOptions =
- FSharpParsingOptions.FromTcConfig(builder.TcConfig, Array.ofList builder.SourceFiles, options.UseScriptResolutionRules)
-
- GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
-
- let parseDiagnostics, parseTree, anyErrors =
- ParseAndCheckFile.parseFile (
- sourceText,
- fileName,
- parsingOptions,
- userOpName,
- suggestNamesForErrors,
- captureIdentifiersWhenParsing
- )
-
- let parseResults =
- FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, builder.AllDependenciesDeprecated)
-
- let! checkResults =
- bc.CheckOneFileImpl(parseResults, sourceText, fileName, options, fileVersion, builder, tcPrior, tcInfo, creationDiags)
-
- return (parseResults, checkResults)
- }
-
- member _.NotifyFileChanged(fileName, options, userOpName) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.NotifyFileChanged"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- |]
-
- let! builderOpt, _ = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None -> return ()
- | Some builder -> do! builder.NotifyFileChanged(fileName, DateTime.UtcNow)
- }
-
- /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API)
- member _.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.ParseAndCheckFileInProject"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- |]
-
- let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None ->
- let parseTree = EmptyParsedInput(fileName, (false, false))
- let parseResults = FSharpParseFileResults(creationDiags, parseTree, true, [||])
- let typedResults = FSharpCheckFileResults.MakeEmpty(fileName, creationDiags, true)
- return (parseResults, typedResults)
- | Some builder ->
- let parseTree, _, _, parseDiagnostics = builder.GetParseResultsForFile fileName
- let! tcProj = builder.GetFullCheckResultsAfterFileInProject fileName
-
- let! tcInfo, tcInfoExtras = tcProj.GetOrComputeTcInfoWithExtras()
-
- let tcResolutions = tcInfoExtras.tcResolutions
- let tcSymbolUses = tcInfoExtras.tcSymbolUses
- let tcOpenDeclarations = tcInfoExtras.tcOpenDeclarations
- let latestCcuSigForFile = tcInfo.latestCcuSigForFile
- let tcState = tcInfo.tcState
- let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile
- let latestImplementationFile = tcInfoExtras.latestImplFile
- let tcDependencyFiles = tcInfo.tcDependencyFiles
- let tcDiagnostics = tcInfo.TcDiagnostics
- let diagnosticsOptions = builder.TcConfig.diagnosticsOptions
-
- let parseDiagnostics =
- DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, parseDiagnostics, suggestNamesForErrors)
-
- let parseDiagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
-
- let tcDiagnostics =
- DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, false, fileName, tcDiagnostics, suggestNamesForErrors)
-
- let tcDiagnostics = [| yield! creationDiags; yield! tcDiagnostics |]
-
- let parseResults =
- FSharpParseFileResults(
- diagnostics = parseDiagnostics,
- input = parseTree,
- parseHadErrors = false,
- dependencyFiles = builder.AllDependenciesDeprecated
- )
-
- let loadClosure = scriptClosureCache.TryGet(AnyCallerThread, options)
-
- let typedResults =
- FSharpCheckFileResults.Make(
- fileName,
- options.ProjectFileName,
- tcProj.TcConfig,
- tcProj.TcGlobals,
- options.IsIncompleteTypeCheckEnvironment,
- builder,
- options,
- Array.ofList tcDependencyFiles,
- creationDiags,
- parseResults.Diagnostics,
- tcDiagnostics,
- keepAssemblyContents,
- Option.get latestCcuSigForFile,
- tcState.Ccu,
- tcProj.TcImports,
- tcEnvAtEnd.AccessRights,
- tcResolutions,
- tcSymbolUses,
- tcEnvAtEnd.NameEnv,
- loadClosure,
- latestImplementationFile,
- tcOpenDeclarations
- )
-
- return (parseResults, typedResults)
- }
-
- member _.FindReferencesInFile
- (
- fileName: string,
- options: FSharpProjectOptions,
- symbol: FSharpSymbol,
- canInvalidateProject: bool,
- userOpName: string
- ) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.FindReferencesInFile"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- "symbol", symbol.FullName
- |]
-
- let! builderOpt, _ = getOrCreateBuilderWithInvalidationFlag (options, canInvalidateProject, userOpName)
-
- match builderOpt with
- | None -> return Seq.empty
- | Some builder ->
- if builder.ContainsFile fileName then
- let! checkResults = builder.GetFullCheckResultsAfterFileInProject fileName
- let! keyStoreOpt = checkResults.GetOrComputeItemKeyStoreIfEnabled()
-
- match keyStoreOpt with
- | None -> return Seq.empty
- | Some reader -> return reader.FindAll symbol.Item
- else
- return Seq.empty
- }
-
- member _.GetSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, userOpName: string) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.GetSemanticClassificationForFile"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, userOpName
- |]
-
- let! builderOpt, _ = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None -> return None
- | Some builder ->
- let! checkResults = builder.GetFullCheckResultsAfterFileInProject fileName
- let! scopt = checkResults.GetOrComputeSemanticClassificationIfEnabled()
-
- match scopt with
- | None -> return None
- | Some sc -> return Some(sc.GetView())
- }
-
- /// Try to get recent approximate type check results for a file.
- member _.TryGetRecentCheckResultsForFile(fileName: string, options: FSharpProjectOptions, sourceText: ISourceText option, _userOpName: string) =
- use _ =
- Activity.start
- "BackgroundCompiler.GetSemanticClassificationForFile"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.fileName, fileName
- Activity.Tags.userOpName, _userOpName
- |]
-
- match sourceText with
- | Some sourceText ->
- let hash = sourceText.GetHashCode() |> int64
-
- let resOpt =
- parseCacheLock.AcquireLock(fun ltok -> checkFileInProjectCache.TryGet(ltok, (fileName, hash, options)))
-
- match resOpt with
- | Some res ->
- match res.TryPeekValue() with
- | ValueSome (a, b, c, _) -> Some(a, b, c)
- | ValueNone -> None
- | None -> None
- | None -> None
-
- /// Parse and typecheck the whole project (the implementation, called recursively as project graph is evaluated)
- member private _.ParseAndCheckProjectImpl(options, userOpName) =
- node {
- let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None ->
- let emptyResults =
- FSharpCheckProjectResults(options.ProjectFileName, None, keepAssemblyContents, creationDiags, None)
-
- return emptyResults
- | Some builder ->
- let! tcProj, ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt = builder.GetFullCheckResultsAndImplementationsForProject()
- let diagnosticsOptions = tcProj.TcConfig.diagnosticsOptions
- let fileName = DummyFileNameForRangesWithoutASpecificLocation
-
- // Although we do not use 'tcInfoExtras', computing it will make sure we get an extra info.
- let! tcInfo, _tcInfoExtras = tcProj.GetOrComputeTcInfoWithExtras()
-
- let topAttribs = tcInfo.topAttribs
- let tcState = tcInfo.tcState
- let tcEnvAtEnd = tcInfo.tcEnvAtEndOfFile
- let tcDiagnostics = tcInfo.TcDiagnostics
- let tcDependencyFiles = tcInfo.tcDependencyFiles
-
- let tcDiagnostics =
- DiagnosticHelpers.CreateDiagnostics(diagnosticsOptions, true, fileName, tcDiagnostics, suggestNamesForErrors)
-
- let diagnostics = [| yield! creationDiags; yield! tcDiagnostics |]
-
- let getAssemblyData () =
- match tcAssemblyDataOpt with
- | ProjectAssemblyDataResult.Available data -> Some data
- | _ -> None
-
- let details =
- (tcProj.TcGlobals,
- tcProj.TcImports,
- tcState.Ccu,
- tcState.CcuSig,
- Choice1Of2 builder,
- topAttribs,
- getAssemblyData,
- ilAssemRef,
- tcEnvAtEnd.AccessRights,
- tcAssemblyExprOpt,
- Array.ofList tcDependencyFiles,
- options)
-
- let results =
- FSharpCheckProjectResults(options.ProjectFileName, Some tcProj.TcConfig, keepAssemblyContents, diagnostics, Some details)
-
- return results
- }
-
- member _.GetAssemblyData(options, userOpName) =
- node {
- use _ =
- Activity.start
- "BackgroundCompiler.GetAssemblyData"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.userOpName, userOpName
- |]
-
- let! builderOpt, _ = getOrCreateBuilder (options, userOpName)
-
- match builderOpt with
- | None -> return ProjectAssemblyDataResult.Unavailable true
- | Some builder ->
- let! _, _, tcAssemblyDataOpt, _ = builder.GetCheckResultsAndImplementationsForProject()
- return tcAssemblyDataOpt
- }
-
- /// Get the timestamp that would be on the output if fully built immediately
- member private _.TryGetLogicalTimeStampForProject(cache, options) =
- match tryGetBuilderNode options with
- | Some lazyWork ->
- match lazyWork.TryPeekValue() with
- | ValueSome (Some builder, _) -> Some(builder.GetLogicalTimeStampForProject(cache))
- | _ -> None
- | _ -> None
-
- /// Parse and typecheck the whole project.
- member bc.ParseAndCheckProject(options, userOpName) =
- use _ =
- Activity.start
- "BackgroundCompiler.ParseAndCheckProject"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.userOpName, userOpName
- |]
-
- bc.ParseAndCheckProjectImpl(options, userOpName)
-
- member _.GetProjectOptionsFromScript
- (
- fileName,
- sourceText,
- previewEnabled,
- loadedTimeStamp,
- otherFlags,
- useFsiAuxLib: bool option,
- useSdkRefs: bool option,
- sdkDirOverride: string option,
- assumeDotNetFramework: bool option,
- optionsStamp: int64 option,
- _userOpName
- ) =
- use _ =
- Activity.start
- "BackgroundCompiler.GetProjectOptionsFromScript"
- [| Activity.Tags.fileName, fileName; Activity.Tags.userOpName, _userOpName |]
-
- cancellable {
- use diagnostics = new DiagnosticsScope()
-
- // Do we add a reference to FSharp.Compiler.Interactive.Settings by default?
- let useFsiAuxLib = defaultArg useFsiAuxLib true
- let useSdkRefs = defaultArg useSdkRefs true
- let reduceMemoryUsage = ReduceMemoryFlag.Yes
- let previewEnabled = defaultArg previewEnabled false
-
- // Do we assume .NET Framework references for scripts?
- let assumeDotNetFramework = defaultArg assumeDotNetFramework true
-
- let extraFlags =
- if previewEnabled then
- [| "--langversion:preview" |]
- else
- [||]
-
- let otherFlags = defaultArg otherFlags extraFlags
-
- let useSimpleResolution = otherFlags |> Array.exists (fun x -> x = "--simpleresolution")
-
- let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading
-
- let applyCompilerOptions tcConfigB =
- let fsiCompilerOptions = GetCoreFsiCompilerOptions tcConfigB
- ParseCompilerOptions(ignore, fsiCompilerOptions, Array.toList otherFlags)
-
- let loadClosure =
- LoadClosure.ComputeClosureOfScriptText(
- legacyReferenceResolver,
- FSharpCheckerResultsSettings.defaultFSharpBinariesDir,
- fileName,
- sourceText,
- CodeContext.Editing,
- useSimpleResolution,
- useFsiAuxLib,
- useSdkRefs,
- sdkDirOverride,
- Lexhelp.LexResourceManager(),
- applyCompilerOptions,
- assumeDotNetFramework,
- tryGetMetadataSnapshot,
- reduceMemoryUsage,
- dependencyProviderForScripts
- )
-
- let otherFlags =
- [|
- yield "--noframework"
- yield "--warn:3"
- yield! otherFlags
- for r in loadClosure.References do
- yield "-r:" + fst r
- for code, _ in loadClosure.NoWarns do
- yield "--nowarn:" + code
- |]
-
- let options =
- {
- ProjectFileName = fileName + ".fsproj" // Make a name that is unique in this directory.
- ProjectId = None
- SourceFiles = loadClosure.SourceFiles |> List.map fst |> List.toArray
- OtherOptions = otherFlags
- ReferencedProjects = [||]
- IsIncompleteTypeCheckEnvironment = false
- UseScriptResolutionRules = true
- LoadTime = loadedTimeStamp
- UnresolvedReferences = Some(FSharpUnresolvedReferencesSet(loadClosure.UnresolvedReferences))
- OriginalLoadReferences = loadClosure.OriginalLoadReferences
- Stamp = optionsStamp
- }
-
- scriptClosureCache.Set(AnyCallerThread, options, loadClosure) // Save the full load closure for later correlation.
-
- let diags =
- loadClosure.LoadClosureRootFileDiagnostics
- |> List.map (fun (exn, isError) -> FSharpDiagnostic.CreateFromException(exn, isError, range.Zero, false))
-
- return options, (diags @ diagnostics.Diagnostics)
- }
- |> Cancellable.toAsync
-
- member bc.InvalidateConfiguration(options: FSharpProjectOptions, userOpName) =
- use _ =
- Activity.start
- "BackgroundCompiler.InvalidateConfiguration"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.userOpName, userOpName
- |]
-
- if incrementalBuildersCache.ContainsSimilarKey(AnyCallerThread, options) then
- parseCacheLock.AcquireLock(fun ltok ->
- for sourceFile in options.SourceFiles do
- checkFileInProjectCache.RemoveAnySimilar(ltok, (sourceFile, 0L, options)))
-
- let _ = createBuilderNode (options, userOpName, CancellationToken.None)
- ()
-
- member bc.ClearCache(options: seq, _userOpName) =
- use _ = Activity.start "BackgroundCompiler.ClearCache" [| Activity.Tags.userOpName, _userOpName |]
-
- lock gate (fun () ->
- options
- |> Seq.iter (fun options -> incrementalBuildersCache.RemoveAnySimilar(AnyCallerThread, options)))
-
- member _.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName) =
- use _ =
- Activity.start
- "BackgroundCompiler.NotifyProjectCleaned"
- [|
- Activity.Tags.project, options.ProjectFileName
- Activity.Tags.userOpName, userOpName
- |]
-
- async {
- let! ct = Async.CancellationToken
- // If there was a similar entry (as there normally will have been) then re-establish an empty builder . This
- // is a somewhat arbitrary choice - it will have the effect of releasing memory associated with the previous
- // builder, but costs some time.
- if incrementalBuildersCache.ContainsSimilarKey(AnyCallerThread, options) then
- let _ = createBuilderNode (options, userOpName, ct)
- ()
- }
-
- member _.BeforeBackgroundFileCheck = beforeFileChecked.Publish
-
- member _.FileParsed = fileParsed.Publish
-
- member _.FileChecked = fileChecked.Publish
-
- member _.ProjectChecked = projectChecked.Publish
-
- member _.ClearCaches() =
- use _ = Activity.startNoTags "BackgroundCompiler.ClearCaches"
-
- lock gate (fun () ->
- parseCacheLock.AcquireLock(fun ltok ->
- checkFileInProjectCache.Clear(ltok)
- parseFileCache.Clear(ltok))
-
- incrementalBuildersCache.Clear(AnyCallerThread)
- frameworkTcImportsCache.Clear()
- scriptClosureCache.Clear AnyCallerThread)
-
- member _.DownsizeCaches() =
- use _ = Activity.startNoTags "BackgroundCompiler.DownsizeCaches"
-
- lock gate (fun () ->
- parseCacheLock.AcquireLock(fun ltok ->
- checkFileInProjectCache.Resize(ltok, newKeepStrongly = 1)
- parseFileCache.Resize(ltok, newKeepStrongly = 1))
-
- incrementalBuildersCache.Resize(AnyCallerThread, newKeepStrongly = 1, newKeepMax = 1)
- frameworkTcImportsCache.Downsize()
- scriptClosureCache.Resize(AnyCallerThread, newKeepStrongly = 1, newKeepMax = 1))
-
- member _.FrameworkImportsCache = frameworkTcImportsCache
-
- static member ActualParseFileCount = actualParseFileCount
-
- static member ActualCheckFileCount = actualCheckFileCount
-
[]
// There is typically only one instance of this type in an IDE process.
type FSharpChecker
@@ -1283,6 +148,7 @@ type FSharpChecker
useChangeNotifications,
useSyntaxTreeCache
)
+ :> IBackgroundCompiler
static let globalInstance = lazy FSharpChecker.Create()
From 55f784abedb0b273eeff66e4c91f1cbb77b0c86a Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Wed, 12 Apr 2023 12:07:11 +0200
Subject: [PATCH 003/222] wip
---
src/Compiler/Facilities/AsyncMemoize.fs | 1 +
src/Compiler/Service/BackgroundCompiler.fs | 2 +-
src/Compiler/Service/FSharpCheckerResults.fs | 129 ++++++-
src/Compiler/Service/FSharpCheckerResults.fsi | 105 +++++-
src/Compiler/Service/TransparentCompiler.fs | 345 +++++++++++++++---
src/Compiler/Service/service.fs | 58 ++-
src/Compiler/Service/service.fsi | 4 +-
.../ProjectGeneration.fs | 6 +-
8 files changed, 575 insertions(+), 75 deletions(-)
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
index d7f17f2352c..960d2d0eeda 100644
--- a/src/Compiler/Facilities/AsyncMemoize.fs
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -110,6 +110,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?eventLog: Resiz
| CancelRequest, Some (Completed _) -> ()
| JobCompleted, Some (Running (job, _)) ->
+ // TODO: should we re-wrap the result?
cache.Set(tok, key, (Completed job))
requestCounts.Remove key |> ignore
log (Finished key)
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index 3882e06bc8d..227a0b670c5 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -671,7 +671,7 @@ type internal BackgroundCompiler
tcInfo.TcDiagnostics,
options.IsIncompleteTypeCheckEnvironment,
options,
- builder,
+ Some builder,
Array.ofList tcInfo.tcDependencyFiles,
creationDiags,
parseResults.Diagnostics,
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 7582e109849..a70274d731e 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -58,6 +58,7 @@ open FSharp.Compiler.BuildGraph
open Internal.Utilities
open Internal.Utilities.Collections
open FSharp.Compiler.AbstractIL.ILBinaryReader
+open System.Threading.Tasks
type FSharpUnresolvedReferencesSet = FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list
@@ -114,6 +115,130 @@ type internal DelayedILModuleReader =
}
| _ -> cancellable.Return(Some this.result)
+
+
+type FSharpFileKey = string * string
+
+type FSharpProjectSnapshotKey =
+ {
+ ProjectFileName: string
+ SourceFiles: FSharpFileKey list
+ OtherOptions: string list
+ ReferencedProjects: FSharpProjectSnapshotKey list
+
+ // Do we need these?
+ IsIncompleteTypeCheckEnvironment: bool
+ UseScriptResolutionRules: bool
+ }
+
+[]
+type FSharpFileSnapshot = {
+ FileName: string
+ Version: string
+ GetSource: unit -> Task
+} with
+ member this.Key = this.FileName, this.Version
+ override this.Equals(o) =
+ match o with
+ | :? FSharpFileSnapshot as o -> o.FileName = this.FileName && o.Version = this.Version
+ | _ -> false
+
+ override this.GetHashCode() = this.Key.GetHashCode()
+
+
+
+[]
+type FSharpProjectSnapshot =
+ {
+ ProjectFileName: string
+ ProjectId: string option
+ SourceFiles: FSharpFileSnapshot list
+ OtherOptions: string list
+ ReferencedProjects: FSharpReferencedProjectSnapshot list
+ IsIncompleteTypeCheckEnvironment: bool
+ UseScriptResolutionRules: bool
+ LoadTime: DateTime
+ UnresolvedReferences: FSharpUnresolvedReferencesSet option
+ OriginalLoadReferences: (range * string * string) list
+ Stamp: int64 option
+ }
+ static member UseSameProject(options1, options2) =
+ match options1.ProjectId, options2.ProjectId with
+ | Some (projectId1), Some (projectId2) when
+ not (String.IsNullOrWhiteSpace(projectId1))
+ && not (String.IsNullOrWhiteSpace(projectId2))
+ ->
+ projectId1 = projectId2
+ | Some _, Some _
+ | None, None -> options1.ProjectFileName = options2.ProjectFileName
+ | _ -> false
+
+ static member AreSameForChecking(options1, options2) =
+ match options1.Stamp, options2.Stamp with
+ | Some x, Some y -> (x = y)
+ | _ ->
+ FSharpProjectSnapshot.UseSameProject(options1, options2)
+ && options1.SourceFiles = options2.SourceFiles
+ && options1.OtherOptions = options2.OtherOptions
+ && options1.UnresolvedReferences = options2.UnresolvedReferences
+ && options1.OriginalLoadReferences = options2.OriginalLoadReferences
+ && options1.ReferencedProjects.Length = options2.ReferencedProjects.Length
+ && (options1.ReferencedProjects, options2.ReferencedProjects)
+ ||> List.forall2 (fun r1 r2 ->
+ match r1, r2 with
+ | FSharpReferencedProjectSnapshot.FSharpReference (n1, a), FSharpReferencedProjectSnapshot.FSharpReference (n2, b) ->
+ n1 = n2 && FSharpProjectSnapshot.AreSameForChecking(a, b))
+
+ && options1.LoadTime = options2.LoadTime
+
+ member po.ProjectDirectory = Path.GetDirectoryName(po.ProjectFileName)
+
+ member this.Key = {
+ ProjectFileName = this.ProjectFileName
+ SourceFiles = this.SourceFiles |> List.map (fun x -> x.Key)
+ OtherOptions = this.OtherOptions
+ ReferencedProjects = this.ReferencedProjects |> List.map (function FSharpReference (_, x) -> x.Key)
+ IsIncompleteTypeCheckEnvironment = this.IsIncompleteTypeCheckEnvironment
+ UseScriptResolutionRules = this.UseScriptResolutionRules
+ }
+
+ override this.ToString() =
+ "FSharpProjectSnapshot(" + this.ProjectFileName + ")"
+
+and [] public FSharpReferencedProjectSnapshot =
+ internal
+ | FSharpReference of projectOutputFile: string * options: FSharpProjectSnapshot
+ //| PEReference of projectOutputFile: string * getStamp: (unit -> DateTime) * delayedReader: DelayedILModuleReader
+ //| ILModuleReference of
+ // projectOutputFile: string *
+ // getStamp: (unit -> DateTime) *
+ // getReader: (unit -> ILModuleReader)
+
+ ///
+ /// The fully qualified path to the output of the referenced project. This should be the same value as the -r
+ /// reference in the project options for this referenced project.
+ ///
+ member this.OutputFile = match this with FSharpReference (projectOutputFile, _) -> projectOutputFile
+
+ ///
+ /// Creates a reference for an F# project. The physical data for it is stored/cached inside of the compiler service.
+ ///
+ /// The fully qualified path to the output of the referenced project. This should be the same value as the -r reference in the project options for this referenced project.
+ /// The Project Options for this F# project
+ static member CreateFSharp(projectOutputFile, options: FSharpProjectSnapshot) = FSharpReference (projectOutputFile, options)
+
+ override this.Equals(o) =
+ match o with
+ | :? FSharpReferencedProjectSnapshot as o ->
+ match this, o with
+ | FSharpReference (projectOutputFile1, options1), FSharpReference (projectOutputFile2, options2) ->
+ projectOutputFile1 = projectOutputFile2 && options1 = options2
+
+ | _ -> false
+
+ override this.GetHashCode() = this.OutputFile.GetHashCode()
+
+
[]
type FSharpReferencedProject =
| FSharpReference of projectOutputFile: string * options: FSharpProjectOptions
@@ -2996,7 +3121,7 @@ type FSharpCheckFileResults
backgroundDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity)[],
isIncompleteTypeCheckEnvironment: bool,
projectOptions: FSharpProjectOptions,
- builder: IncrementalBuilder,
+ builder: IncrementalBuilder option,
dependencyFiles: string[],
creationErrors: FSharpDiagnostic[],
parseErrors: FSharpDiagnostic[],
@@ -3025,7 +3150,7 @@ type FSharpCheckFileResults
FSharpCheckFileResults.JoinErrors(isIncompleteTypeCheckEnvironment, creationErrors, parseErrors, tcErrors)
let results =
- FSharpCheckFileResults(mainInputFileName, errors, Some tcFileInfo, dependencyFiles, Some builder, keepAssemblyContents)
+ FSharpCheckFileResults(mainInputFileName, errors, Some tcFileInfo, dependencyFiles, builder, keepAssemblyContents)
return results
}
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 5b14cdf9bc7..0294123474c 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -39,6 +39,108 @@ type internal DelayedILModuleReader =
/// Unused in this API
type public FSharpUnresolvedReferencesSet = internal FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list
+
+type FSharpFileKey = string * string
+
+type FSharpProjectSnapshotKey =
+ {
+ ProjectFileName: string
+ SourceFiles: FSharpFileKey list
+ OtherOptions: string list
+ ReferencedProjects: FSharpProjectSnapshotKey list
+
+ // Do we need these?
+ IsIncompleteTypeCheckEnvironment: bool
+ UseScriptResolutionRules: bool
+ }
+
+[]
+type FSharpFileSnapshot = {
+ FileName: string
+ Version: string
+ GetSource: unit -> System.Threading.Tasks.Task
+} with member Key: FSharpFileKey
+
+[]
+type FSharpProjectSnapshot =
+ {
+ // Note that this may not reduce to just the project directory, because there may be two projects in the same directory.
+ ProjectFileName: string
+
+ /// This is the unique identifier for the project, it is case sensitive. If it's None, will key off of ProjectFileName in our caching.
+ ProjectId: string option
+
+ /// The files in the project
+ SourceFiles: FSharpFileSnapshot list
+
+ /// Additional command line argument options for the project. These can include additional files and references.
+ OtherOptions: string list
+
+ /// The command line arguments for the other projects referenced by this project, indexed by the
+ /// exact text used in the "-r:" reference in FSharpProjectOptions.
+ ReferencedProjects: FSharpReferencedProjectSnapshot list
+
+ /// When true, the typechecking environment is known a priori to be incomplete, for
+ /// example when a .fs file is opened outside of a project. In this case, the number of error
+ /// messages reported is reduced.
+ IsIncompleteTypeCheckEnvironment: bool
+
+ /// When true, use the reference resolution rules for scripts rather than the rules for compiler.
+ UseScriptResolutionRules: bool
+
+ /// Timestamp of project/script load, used to differentiate between different instances of a project load.
+ /// This ensures that a complete reload of the project or script type checking
+ /// context occurs on project or script unload/reload.
+ LoadTime: DateTime
+
+ /// Unused in this API and should be 'None' when used as user-specified input
+ UnresolvedReferences: FSharpUnresolvedReferencesSet option
+
+ /// Unused in this API and should be '[]' when used as user-specified input
+ OriginalLoadReferences: (range * string * string) list
+
+ /// An optional stamp to uniquely identify this set of options
+ /// If two sets of options both have stamps, then they are considered equal
+ /// if and only if the stamps are equal
+ Stamp: int64 option
+ }
+
+ /// Whether the two parse options refer to the same project.
+ static member internal UseSameProject: options1: FSharpProjectSnapshot * options2: FSharpProjectSnapshot -> bool
+
+ /// Compare two options sets with respect to the parts of the options that are important to building.
+ static member internal AreSameForChecking: options1: FSharpProjectSnapshot * options2: FSharpProjectSnapshot -> bool
+
+ /// Compute the project directory.
+ member internal ProjectDirectory: string
+
+ member Key: FSharpProjectSnapshotKey
+
+
+and [] public FSharpReferencedProjectSnapshot =
+ internal
+ | FSharpReference of projectOutputFile: string * options: FSharpProjectSnapshot
+ //| PEReference of projectOutputFile: string * version: string * delayedReader: DelayedILModuleReader
+ //| ILModuleReference of
+ // projectOutputFile: string *
+ // getStamp: (unit -> DateTime) *
+ // getReader: (unit -> ILModuleReader)
+
+ ///
+ /// The fully qualified path to the output of the referenced project. This should be the same value as the -r
+ /// reference in the project options for this referenced project.
+ ///
+ member OutputFile: string
+
+ ///
+ /// Creates a reference for an F# project. The physical data for it is stored/cached inside of the compiler service.
+ ///
+ /// The fully qualified path to the output of the referenced project. This should be the same value as the -r reference in the project options for this referenced project.
+ /// The Project Options for this F# project
+ static member CreateFSharp: projectOutputFile: string * options: FSharpProjectSnapshot -> FSharpReferencedProjectSnapshot
+
+
+
/// A set of information describing a project or script build configuration.
type public FSharpProjectOptions =
{
@@ -137,6 +239,7 @@ and [] public FSharpReferencedProject =
projectOutputFile: string * getStamp: (unit -> DateTime) * getReader: (unit -> ILModuleReader) ->
FSharpReferencedProject
+
/// Represents the use of an F# symbol from F# source code
[]
type public FSharpSymbolUse =
@@ -467,7 +570,7 @@ type public FSharpCheckFileResults =
backgroundDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity)[] *
isIncompleteTypeCheckEnvironment: bool *
projectOptions: FSharpProjectOptions *
- builder: IncrementalBuilder *
+ builder: IncrementalBuilder option *
dependencyFiles: string[] *
creationErrors: FSharpDiagnostic[] *
parseErrors: FSharpDiagnostic[] *
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 28d5996b5b0..98c1fd5b8f5 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -1,54 +1,303 @@
namespace FSharp.Compiler.CodeAnalysis
+open FSharp.Compiler.Text
+open FSharp.Compiler.BuildGraph
+open FSharp.Compiler.Symbols
+open FSharp.Compiler.CompilerConfig
+open FSharp.Compiler.Diagnostics
+open System
+open FSharp.Compiler
+open Internal.Utilities.Collections
+open FSharp.Compiler.ParseAndCheckInputs
+
+
+
+type internal FSharpFile = {
+ Range: range
+ Source: FSharpFileSnapshot
+ IsLastCompiland: bool
+ IsExe: bool
+}
+
+/// Things we need to start parsing and checking files for a given project snapshot
+type BootstrapInfo = {
+ TcConfig: TcConfig
+ SourceFiles: FSharpFile list
+}
+
+
+type internal TransparentCompiler
+ (
+ legacyReferenceResolver,
+ projectCacheSize,
+ keepAssemblyContents,
+ keepAllBackgroundResolutions,
+ tryGetMetadataSnapshot,
+ suggestNamesForErrors,
+ keepAllBackgroundSymbolUses,
+ enableBackgroundItemKeyStoreAndSemanticClassification,
+ enablePartialTypeChecking,
+ parallelReferenceResolution,
+ captureIdentifiersWhenParsing,
+ getSource: (string -> ISourceText option) option,
+ useChangeNotifications,
+ useSyntaxTreeCache
+ ) =
+
+ // Is having just one of these ok?
+ let lexResourceManager = Lexhelp.LexResourceManager()
+
+ let ParseFileCache = AsyncMemoize()
+ let ParseAndCheckFileInProjectCache = AsyncMemoize()
+
+
+ // use this to process not-yet-implemented tasks
+ let backgroundCompiler =
+ BackgroundCompiler(
+ legacyReferenceResolver,
+ projectCacheSize,
+ keepAssemblyContents,
+ keepAllBackgroundResolutions,
+ tryGetMetadataSnapshot,
+ suggestNamesForErrors,
+ keepAllBackgroundSymbolUses,
+ enableBackgroundItemKeyStoreAndSemanticClassification,
+ enablePartialTypeChecking,
+ parallelReferenceResolution,
+ captureIdentifiersWhenParsing,
+ getSource,
+ useChangeNotifications,
+ useSyntaxTreeCache
+ )
+ :> IBackgroundCompiler
+
+
+ let ComputeParseFile (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) userOpName _key = node {
+
+ return ()
+
+ }
+
+
+ let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) _key =
+ node {
+
+ let! bootstrapInfoOpt, creationDiags = getBootstrapInfo projectSnapshot // probably cache
+
+ match bootstrapInfoOpt with
+ | None ->
+ let parseTree = EmptyParsedInput(fileName, (false, false))
+ let parseResults = FSharpParseFileResults(creationDiags, parseTree, true, [||])
+ return (parseResults, FSharpCheckFileAnswer.Aborted)
+
+ | Some bootstrapInfo ->
+
+
+
+
+ // Do the parsing.
+ let parsingOptions =
+ FSharpParsingOptions.FromTcConfig(
+ bootstrapInfo.TcConfig,
+ projectSnapshot.SourceFiles |> Seq.map (fun f -> f.FileName) |> Array.ofSeq,
+ projectSnapshot.UseScriptResolutionRules
+ )
+
+ // TODO: what is this?
+ // GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
+
+ let parseDiagnostics, parseTree, anyErrors =
+ ParseAndCheckFile.parseFile (
+ sourceText,
+ fileName,
+ parsingOptions,
+ userOpName,
+ suggestNamesForErrors,
+ captureIdentifiersWhenParsing
+ )
+
+ // TODO: check if we need this in parse results
+ let dependencyFiles = [||]
+
+ let parseResults =
+ FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, dependencyFiles)
+
+ let! checkResults =
+ bc.CheckOneFileImpl(
+ parseResults,
+ sourceText,
+ fileName,
+ options,
+ fileVersion,
+ builder,
+ tcPrior,
+ tcInfo,
+ creationDiags
+ )
+
+ return (parseResults, checkResults)
+ }
+
+ member _.ParseAndCheckFileInProject
+ (
+ fileName: string,
+ projectSnapshot: FSharpProjectSnapshot,
+ userOpName: string
+ ) : NodeCode = node {
+ ignore userOpName // TODO
+ let key = fileName, projectSnapshot.Key
+ return! ParseAndCheckFileInProjectCache.Get(key, ComputeParseAndCheckFileInProject fileName projectSnapshot)
+ }
-type internal TransparentCompiler() =
interface IBackgroundCompiler with
member this.BeforeBackgroundFileCheck: IEvent =
- raise (System.NotImplementedException())
- member this.CheckFileInProject(parseResults: FSharpParseFileResults, fileName: string, fileVersion: int, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.CheckFileInProjectAllowingStaleCachedResults(parseResults: FSharpParseFileResults, fileName: string, fileVersion: int, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.ClearCache(options: seq, userOpName: string): unit =
- raise (System.NotImplementedException())
- member this.ClearCaches(): unit =
- raise (System.NotImplementedException())
- member this.DownsizeCaches(): unit =
- raise (System.NotImplementedException())
- member this.FileChecked: IEvent =
- raise (System.NotImplementedException())
- member this.FileParsed: IEvent =
- raise (System.NotImplementedException())
- member this.FindReferencesInFile(fileName: string, options: FSharpProjectOptions, symbol: FSharp.Compiler.Symbols.FSharpSymbol, canInvalidateProject: bool, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode> =
- raise (System.NotImplementedException())
- member this.FrameworkImportsCache: FrameworkImportsCache =
- raise (System.NotImplementedException())
- member this.GetAssemblyData(options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.GetBackgroundCheckResultsForFileInProject(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.GetBackgroundParseResultsForFileInProject(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.GetCachedCheckFileResult(builder: IncrementalBuilder, fileName: string, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions): FSharp.Compiler.BuildGraph.NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> =
- raise (System.NotImplementedException())
- member this.GetProjectOptionsFromScript(fileName: string, sourceText: FSharp.Compiler.Text.ISourceText, previewEnabled: bool option, loadedTimeStamp: System.DateTime option, otherFlags: string array option, useFsiAuxLib: bool option, useSdkRefs: bool option, sdkDirOverride: string option, assumeDotNetFramework: bool option, optionsStamp: int64 option, userOpName: string): Async =
- raise (System.NotImplementedException())
- member this.GetSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string): unit =
- raise (System.NotImplementedException())
- member this.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string): Async =
- raise (System.NotImplementedException())
- member this.ParseAndCheckFileInProject(fileName: string, fileVersion: int, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string): FSharp.Compiler.BuildGraph.NodeCode =
- raise (System.NotImplementedException())
- member this.ParseFile(fileName: string, sourceText: FSharp.Compiler.Text.ISourceText, options: FSharpParsingOptions, cache: bool, userOpName: string): Async =
- raise (System.NotImplementedException())
- member this.ProjectChecked: IEvent =
- raise (System.NotImplementedException())
- member this.TryGetRecentCheckResultsForFile(fileName: string, options: FSharpProjectOptions, sourceText: FSharp.Compiler.Text.ISourceText option, userOpName: string): (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option =
- raise (System.NotImplementedException())
\ No newline at end of file
+ backgroundCompiler.BeforeBackgroundFileCheck
+
+ member _.CheckFileInProject
+ (
+ parseResults: FSharpParseFileResults,
+ fileName: string,
+ fileVersion: int,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ backgroundCompiler.CheckFileInProject(parseResults, fileName, fileVersion, sourceText, options, userOpName)
+
+ member _.CheckFileInProjectAllowingStaleCachedResults
+ (
+ parseResults: FSharpParseFileResults,
+ fileName: string,
+ fileVersion: int,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ backgroundCompiler.CheckFileInProjectAllowingStaleCachedResults(parseResults, fileName, fileVersion, sourceText, options, userOpName)
+
+ member _.ClearCache(options: seq, userOpName: string) : unit = backgroundCompiler.ClearCache(options, userOpName)
+ member _.ClearCaches() : unit = backgroundCompiler.ClearCaches()
+ member _.DownsizeCaches() : unit = backgroundCompiler.DownsizeCaches()
+ member _.FileChecked: IEvent = backgroundCompiler.FileChecked
+ member _.FileParsed: IEvent = backgroundCompiler.FileParsed
+
+ member _.FindReferencesInFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ symbol: FSharpSymbol,
+ canInvalidateProject: bool,
+ userOpName: string
+ ) : NodeCode> =
+ backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
+
+ member _.FrameworkImportsCache: FrameworkImportsCache = backgroundCompiler.FrameworkImportsCache
+
+ member _.GetAssemblyData(options: FSharpProjectOptions, userOpName: string) : NodeCode =
+ backgroundCompiler.GetAssemblyData(options, userOpName)
+
+ member _.GetBackgroundCheckResultsForFileInProject
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ backgroundCompiler.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName)
+
+ member _.GetBackgroundParseResultsForFileInProject
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ backgroundCompiler.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName)
+
+ member _.GetCachedCheckFileResult
+ (
+ builder: IncrementalBuilder,
+ fileName: string,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions
+ ) : NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> =
+ backgroundCompiler.GetCachedCheckFileResult(builder, fileName, sourceText, options)
+
+ member _.GetProjectOptionsFromScript
+ (
+ fileName: string,
+ sourceText: ISourceText,
+ previewEnabled: bool option,
+ loadedTimeStamp: DateTime option,
+ otherFlags: string array option,
+ useFsiAuxLib: bool option,
+ useSdkRefs: bool option,
+ sdkDirOverride: string option,
+ assumeDotNetFramework: bool option,
+ optionsStamp: int64 option,
+ userOpName: string
+ ) : Async =
+ backgroundCompiler.GetProjectOptionsFromScript(
+ fileName,
+ sourceText,
+ previewEnabled,
+ loadedTimeStamp,
+ otherFlags,
+ useFsiAuxLib,
+ useSdkRefs,
+ sdkDirOverride,
+ assumeDotNetFramework,
+ optionsStamp,
+ userOpName
+ )
+
+ member _.GetSemanticClassificationForFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+ backgroundCompiler.GetSemanticClassificationForFile(fileName, options, userOpName)
+
+ member _.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string) : unit =
+ backgroundCompiler.InvalidateConfiguration(options, userOpName)
+
+ member _.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : NodeCode =
+ backgroundCompiler.NotifyFileChanged(fileName, options, userOpName)
+
+ member _.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async =
+ backgroundCompiler.NotifyProjectCleaned(options, userOpName)
+
+ member _.ParseAndCheckFileInProject
+ (
+ fileName: string,
+ fileVersion: int,
+ sourceText: ISourceText,
+ options: FSharpProjectOptions,
+ userOpName: string
+ ) : NodeCode =
+
+ backgroundCompiler.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName)
+
+ member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode =
+ backgroundCompiler.ParseAndCheckProject(options, userOpName)
+
+ member _.ParseFile
+ (
+ fileName: string,
+ sourceText: ISourceText,
+ options: FSharpParsingOptions,
+ cache: bool,
+ userOpName: string
+ ) : Async =
+ backgroundCompiler.ParseFile(fileName, sourceText, options, cache, userOpName)
+
+ member _.ProjectChecked: IEvent = backgroundCompiler.ProjectChecked
+
+ member _.TryGetRecentCheckResultsForFile
+ (
+ fileName: string,
+ options: FSharpProjectOptions,
+ sourceText: ISourceText option,
+ userOpName: string
+ ) : (FSharpParseFileResults * FSharpCheckFileResults * SourceTextHash) option =
+ backgroundCompiler.TryGetRecentCheckResultsForFile(fileName, options, sourceText, userOpName)
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index 8b6a9c1766a..bd7501463d1 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -128,27 +128,43 @@ type FSharpChecker
captureIdentifiersWhenParsing,
getSource,
useChangeNotifications,
- useSyntaxTreeCache
+ useSyntaxTreeCache,
+ useTransparentCompiler
) =
let backgroundCompiler =
- BackgroundCompiler(
- legacyReferenceResolver,
- projectCacheSize,
- keepAssemblyContents,
- keepAllBackgroundResolutions,
- tryGetMetadataSnapshot,
- suggestNamesForErrors,
- keepAllBackgroundSymbolUses,
- enableBackgroundItemKeyStoreAndSemanticClassification,
- enablePartialTypeChecking,
- parallelReferenceResolution,
- captureIdentifiersWhenParsing,
- getSource,
- useChangeNotifications,
- useSyntaxTreeCache
- )
- :> IBackgroundCompiler
+ if useTransparentCompiler = Some true then
+ TransparentCompiler(
+ legacyReferenceResolver,
+ projectCacheSize,
+ keepAssemblyContents,
+ keepAllBackgroundResolutions,
+ tryGetMetadataSnapshot,
+ suggestNamesForErrors,
+ keepAllBackgroundSymbolUses,
+ enableBackgroundItemKeyStoreAndSemanticClassification,
+ enablePartialTypeChecking,
+ parallelReferenceResolution,
+ captureIdentifiersWhenParsing,
+ getSource,
+ useChangeNotifications,
+ useSyntaxTreeCache) :> IBackgroundCompiler
+ else
+ BackgroundCompiler(
+ legacyReferenceResolver,
+ projectCacheSize,
+ keepAssemblyContents,
+ keepAllBackgroundResolutions,
+ tryGetMetadataSnapshot,
+ suggestNamesForErrors,
+ keepAllBackgroundSymbolUses,
+ enableBackgroundItemKeyStoreAndSemanticClassification,
+ enablePartialTypeChecking,
+ parallelReferenceResolution,
+ captureIdentifiersWhenParsing,
+ getSource,
+ useChangeNotifications,
+ useSyntaxTreeCache) :> IBackgroundCompiler
static let globalInstance = lazy FSharpChecker.Create()
@@ -192,7 +208,8 @@ type FSharpChecker
?parallelReferenceResolution: bool,
?captureIdentifiersWhenParsing: bool,
?documentSource: DocumentSource,
- ?useSyntaxTreeCache: bool
+ ?useSyntaxTreeCache: bool,
+ ?useTransparentCompiler: bool
) =
use _ = Activity.startNoTags "FSharpChecker.Create"
@@ -243,7 +260,8 @@ type FSharpChecker
| Some (DocumentSource.Custom f) -> Some f
| _ -> None),
useChangeNotifications,
- useSyntaxTreeCache
+ useSyntaxTreeCache,
+ useTransparentCompiler
)
member _.ReferenceResolver = legacyReferenceResolver
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index 5d482b3cbed..497baf4d347 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -42,6 +42,7 @@ type public FSharpChecker =
/// When set to true we create a set of all identifiers for each parsed file which can be used to speed up finding references.
/// Default: FileSystem. You can use Custom source to provide a function that will return the source for a given file path instead of reading it from the file system. Note that with this option the FSharpChecker will also not monitor the file system for file changes. It will expect to be notified of changes via the NotifyFileChanged method.
/// Default: true. Indicates whether to keep parsing results in a cache.
+ /// Default: false. Indicates whether we use a new experimental background compiler.
static member Create:
?projectCacheSize: int *
?keepAssemblyContents: bool *
@@ -55,7 +56,8 @@ type public FSharpChecker =
?parallelReferenceResolution: bool *
?captureIdentifiersWhenParsing: bool *
[] ?documentSource: DocumentSource *
- [] ?useSyntaxTreeCache: bool ->
+ [] ?useSyntaxTreeCache: bool *
+ [] ?useTransparentCompiler: bool ->
FSharpChecker
///
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 578a39aa17d..3f14fa601a1 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -468,7 +468,8 @@ module Helpers =
enableBackgroundItemKeyStoreAndSemanticClassification = true,
enablePartialTypeChecking = true,
captureIdentifiersWhenParsing = true,
- documentSource = DocumentSource.Custom getSource)
+ documentSource = DocumentSource.Custom getSource,
+ useTransparentCompiler = true)
let options =
let baseOptions, _ =
@@ -564,7 +565,8 @@ type ProjectWorkflowBuilder
enablePartialTypeChecking = true,
captureIdentifiersWhenParsing = true,
documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem),
- useSyntaxTreeCache = defaultArg useSyntaxTreeCache false
+ useSyntaxTreeCache = defaultArg useSyntaxTreeCache false,
+ useTransparentCompiler = true
))
let mapProjectAsync f workflow =
From 9fe9e221f7a860e028ed57fa5dc43ae1f2887dbd Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Fri, 14 Apr 2023 12:30:38 +0200
Subject: [PATCH 004/222] wip
---
src/Compiler/Service/FSharpCheckerResults.fs | 17 +
src/Compiler/Service/FSharpCheckerResults.fsi | 5 +
src/Compiler/Service/TransparentCompiler.fs | 325 ++++++++++++++++--
3 files changed, 318 insertions(+), 29 deletions(-)
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index a70274d731e..63b9e1893d0 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -202,6 +202,8 @@ type FSharpProjectSnapshot =
UseScriptResolutionRules = this.UseScriptResolutionRules
}
+ member this.SourceFileNames = this.SourceFiles |> List.map (fun x -> x.FileName)
+
override this.ToString() =
"FSharpProjectSnapshot(" + this.ProjectFileName + ")"
@@ -327,6 +329,21 @@ and FSharpProjectOptions =
override this.ToString() =
"FSharpProjectOptions(" + this.ProjectFileName + ")"
+type FSharpProjectSnapshot with
+ member this.ToOptions (): FSharpProjectOptions = {
+ ProjectFileName = this.ProjectFileName
+ ProjectId = this.ProjectId
+ SourceFiles = this.SourceFiles |> Seq.map (fun x -> x.FileName) |> Seq.toArray
+ OtherOptions = this.OtherOptions |> List.toArray
+ ReferencedProjects = this.ReferencedProjects |> Seq.map (function FSharpReference (name, opts) -> FSharpReferencedProject.FSharpReference (name, opts.ToOptions())) |> Seq.toArray
+ IsIncompleteTypeCheckEnvironment = this.IsIncompleteTypeCheckEnvironment
+ UseScriptResolutionRules = this.UseScriptResolutionRules
+ LoadTime = this.LoadTime
+ UnresolvedReferences = this.UnresolvedReferences
+ OriginalLoadReferences = this.OriginalLoadReferences
+ Stamp = this.Stamp
+ }
+
[]
module internal FSharpCheckerResultsSettings =
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 0294123474c..6dfe65ca2b5 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -114,6 +114,8 @@ type FSharpProjectSnapshot =
/// Compute the project directory.
member internal ProjectDirectory: string
+ member SourceFileNames: string list
+
member Key: FSharpProjectSnapshotKey
@@ -239,6 +241,9 @@ and [] public FSharpReferencedProject =
projectOutputFile: string * getStamp: (unit -> DateTime) * getReader: (unit -> ILModuleReader) ->
FSharpReferencedProject
+type FSharpProjectSnapshot with
+ member ToOptions: unit -> FSharpProjectOptions
+
/// Represents the use of an F# symbol from F# source code
[]
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 98c1fd5b8f5..01cc8bfaccb 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -9,6 +9,16 @@ open System
open FSharp.Compiler
open Internal.Utilities.Collections
open FSharp.Compiler.ParseAndCheckInputs
+open FSharp.Compiler.ScriptClosure
+open FSharp.Compiler.AbstractIL.ILBinaryReader
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.ConstraintSolver
+open System.Diagnostics
+open System.IO
+open FSharp.Compiler.CompilerOptions
+open FSharp.Compiler.Xml
+open FSharp.Compiler.CompilerImports
@@ -49,7 +59,7 @@ type internal TransparentCompiler
let ParseFileCache = AsyncMemoize()
let ParseAndCheckFileInProjectCache = AsyncMemoize()
-
+ let FrameworkImportsCache = AsyncMemoize()
// use this to process not-yet-implemented tasks
let backgroundCompiler =
@@ -71,18 +81,296 @@ type internal TransparentCompiler
)
:> IBackgroundCompiler
+ let getProjectReferences (project: FSharpProjectSnapshot) userOpName =
+ [
+ for r in project.ReferencedProjects do
+
+ match r with
+ | FSharpReferencedProjectSnapshot.FSharpReference (nm, opts) ->
+ // Don't use cross-project references for FSharp.Core, since various bits of code
+ // require a concrete FSharp.Core to exist on-disk. The only solutions that have
+ // these cross-project references to FSharp.Core are VisualFSharp.sln and FSharp.sln. The ramification
+ // of this is that you need to build FSharp.Core to get intellisense in those projects.
+
+ if
+ (try
+ Path.GetFileNameWithoutExtension(nm)
+ with _ ->
+ "")
+ <> GetFSharpCoreLibraryName()
+ then
+ { new IProjectReference with
+ member x.EvaluateRawContents() =
+ node {
+ Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm)
+ return! backgroundCompiler.GetAssemblyData(opts.ToOptions(), userOpName + ".CheckReferencedProject(" + nm + ")")
+ }
+
+ member x.TryGetLogicalTimeStamp(cache) =
+ // TODO:
+ None
+
+ member x.FileName = nm
+ }
+ ]
+
+
+ let ComputeFrameworkImports (tcConfig: TcConfig) _key = node {
+ let tcConfigP = TcConfigProvider.Constant tcConfig
+ return! TcImports.BuildFrameworkTcImports (tcConfigP, frameworkDLLs, nonFrameworkResolutions)
+ }
+
+
+ let ComputeBootstapInfo (projectSnapshot: FSharpProjectSnapshot) =
+ node {
+
+ let useSimpleResolutionSwitch = "--simpleresolution"
+ let commandLineArgs = projectSnapshot.OtherOptions
+ let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir
+ let useScriptResolutionRules = projectSnapshot.UseScriptResolutionRules
+
+ let projectReferences = getProjectReferences projectSnapshot "ComputeBootstapInfo"
+ let sourceFiles = projectSnapshot.SourceFileNames
+
+ // TODO: script support
+ let loadClosureOpt: LoadClosure option = None
+
+ let tcConfigB, sourceFiles =
+
+ let getSwitchValue switchString =
+ match commandLineArgs |> List.tryFindIndex(fun s -> s.StartsWithOrdinal switchString) with
+ | Some idx -> Some(commandLineArgs[idx].Substring(switchString.Length))
+ | _ -> None
+
+ let sdkDirOverride =
+ match loadClosureOpt with
+ | None -> None
+ | Some loadClosure -> loadClosure.SdkDirOverride
+
+ // see also fsc.fs: runFromCommandLineToImportingAssemblies(), as there are many similarities to where the PS creates a tcConfigB
+ let tcConfigB =
+ TcConfigBuilder.CreateNew(legacyReferenceResolver,
+ defaultFSharpBinariesDir,
+ implicitIncludeDir=projectSnapshot.ProjectDirectory,
+ reduceMemoryUsage=ReduceMemoryFlag.Yes,
+ isInteractive=useScriptResolutionRules,
+ isInvalidationSupported=true,
+ defaultCopyFSharpCore=CopyFSharpCoreFlag.No,
+ tryGetMetadataSnapshot=tryGetMetadataSnapshot,
+ sdkDirOverride=sdkDirOverride,
+ rangeForErrors=range0)
+
+ tcConfigB.primaryAssembly <-
+ match loadClosureOpt with
+ | None -> PrimaryAssembly.Mscorlib
+ | Some loadClosure ->
+ if loadClosure.UseDesktopFramework then
+ PrimaryAssembly.Mscorlib
+ else
+ PrimaryAssembly.System_Runtime
+
+ tcConfigB.resolutionEnvironment <- (LegacyResolutionEnvironment.EditingOrCompilation true)
+
+ tcConfigB.conditionalDefines <-
+ let define = if useScriptResolutionRules then "INTERACTIVE" else "COMPILED"
+ define :: tcConfigB.conditionalDefines
+
+ tcConfigB.projectReferences <- projectReferences
+
+ tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome
+
+ // Apply command-line arguments and collect more source files if they are in the arguments
+ let sourceFilesNew = ApplyCommandLineArgs(tcConfigB, sourceFiles, commandLineArgs)
+
+ // Never open PDB files for the language service, even if --standalone is specified
+ tcConfigB.openDebugInformationForLaterStaticLinking <- false
+
+ tcConfigB.xmlDocInfoLoader <-
+ { new IXmlDocumentationInfoLoader with
+ /// Try to load xml documentation associated with an assembly by the same file path with the extension ".xml".
+ member _.TryLoad(assemblyFileName) =
+ let xmlFileName = Path.ChangeExtension(assemblyFileName, ".xml")
+
+ // REVIEW: File IO - Will eventually need to change this to use a file system interface of some sort.
+ XmlDocumentationInfo.TryCreateFromFile(xmlFileName)
+ }
+ |> Some
+
+ tcConfigB.parallelReferenceResolution <- parallelReferenceResolution
+ tcConfigB.captureIdentifiersWhenParsing <- captureIdentifiersWhenParsing
+
+ tcConfigB, sourceFilesNew
+
+ // If this is a builder for a script, re-apply the settings inferred from the
+ // script and its load closure to the configuration.
+ //
+ // NOTE: it would probably be cleaner and more accurate to re-run the load closure at this point.
+ let setupConfigFromLoadClosure () =
+ match loadClosureOpt with
+ | Some loadClosure ->
+ let dllReferences =
+ [for reference in tcConfigB.referencedDLLs do
+ // If there's (one or more) resolutions of closure references then yield them all
+ match loadClosure.References |> List.tryFind (fun (resolved, _)->resolved=reference.Text) with
+ | Some (resolved, closureReferences) ->
+ for closureReference in closureReferences do
+ yield AssemblyReference(closureReference.originalReference.Range, resolved, None)
+ | None -> yield reference]
+ tcConfigB.referencedDLLs <- []
+ tcConfigB.primaryAssembly <- (if loadClosure.UseDesktopFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime)
+ // Add one by one to remove duplicates
+ dllReferences |> List.iter (fun dllReference ->
+ tcConfigB.AddReferencedAssemblyByPath(dllReference.Range, dllReference.Text))
+ tcConfigB.knownUnresolvedReferences <- loadClosure.UnresolvedReferences
+ | None -> ()
+
+ setupConfigFromLoadClosure()
+
+ let tcConfig = TcConfig.Create(tcConfigB, validate=true)
+ let outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
+
+ // Resolve assemblies and create the framework TcImports. This is done when constructing the
+ // builder itself, rather than as an incremental task. This caches a level of "system" references. No type providers are
+ // included in these references.
+ let! tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences = frameworkTcImportsCache.Get(tcConfig)
+
+ // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
+ // This is ok because not much can actually go wrong here.
+ let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
+ use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+
+ // Get the names and time stamps of all the non-framework referenced assemblies, which will act
+ // as inputs to one of the nodes in the build.
+ //
+ // This operation is done when constructing the builder itself, rather than as an incremental task.
+ let nonFrameworkAssemblyInputs =
+ // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
+ // This is ok because not much can actually go wrong here.
+ let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
+ // Return the disposable object that cleans up
+ use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+
+ [ for r in nonFrameworkResolutions do
+ let fileName = r.resolvedPath
+ yield (Choice1Of2 fileName, (fun (cache: TimeStampCache) -> cache.GetFileTimeStamp fileName))
+
+ for pr in projectReferences do
+ yield Choice2Of2 pr, (fun (cache: TimeStampCache) -> cache.GetProjectReferenceTimeStamp pr) ]
+
+ // Start importing
+
+ let tcConfigP = TcConfigProvider.Constant tcConfig
+ let beforeFileChecked = Event()
+ let fileChecked = Event()
+
+#if !NO_TYPEPROVIDERS
+ let importsInvalidatedByTypeProvider = Event()
+#endif
+
+ // Check for the existence of loaded sources and prepend them to the sources list if present.
+ let sourceFiles = tcConfig.GetAvailableLoadedSources() @ (sourceFiles |>List.map (fun s -> rangeStartup, s))
+
+ // Mark up the source files with an indicator flag indicating if they are the last source file in the project
+ let sourceFiles =
+ let flags, isExe = tcConfig.ComputeCanContainEntryPoint(sourceFiles |> List.map snd)
+ ((sourceFiles, flags) ||> List.map2 (fun (m, nm) flag -> (m, nm, (flag, isExe))))
+
+ let basicDependencies =
+ [ for UnresolvedAssemblyReference(referenceText, _) in unresolvedReferences do
+ // Exclude things that are definitely not a file name
+ if not(FileSystem.IsInvalidPathShim referenceText) then
+ let file = if FileSystem.IsPathRootedShim referenceText then referenceText else Path.Combine(projectDirectory, referenceText)
+ yield file
+
+ for r in nonFrameworkResolutions do
+ yield r.resolvedPath ]
+
+ let allDependencies =
+ [| yield! basicDependencies
+ for _, f, _ in sourceFiles do
+ yield f |]
+
+ // For scripts, the dependency provider is already available.
+ // For projects create a fresh one for the project.
+ let dependencyProvider =
+ match dependencyProvider with
+ | None -> new DependencyProvider()
+ | Some dependencyProvider -> dependencyProvider
+
+ let defaultTimeStamp = DateTime.UtcNow
+
+ let! initialBoundModel =
+ CombineImportedAssembliesTask(
+ assemblyName,
+ tcConfig,
+ tcConfigP,
+ tcGlobals,
+ frameworkTcImports,
+ nonFrameworkResolutions,
+ unresolvedReferences,
+ dependencyProvider,
+ loadClosureOpt,
+ basicDependencies,
+ keepAssemblyContents,
+ keepAllBackgroundResolutions,
+ keepAllBackgroundSymbolUses,
+ enableBackgroundItemKeyStoreAndSemanticClassification,
+ enablePartialTypeChecking,
+ beforeFileChecked,
+ fileChecked
+#if !NO_TYPEPROVIDERS
+ ,importsInvalidatedByTypeProvider
+#endif
+ )
+
+ let getFSharpSource fileName =
+ getSource
+ |> Option.map(fun getSource ->
+ let timeStamp = DateTime.UtcNow
+ let getTimeStamp = fun () -> timeStamp
+ let getSourceText() = getSource fileName
+ FSharpSource.Create(fileName, getTimeStamp, getSourceText))
+ |> Option.defaultWith(fun () -> FSharpSource.CreateFromFile(fileName))
+
+ let sourceFiles =
+ sourceFiles
+ |> List.map (fun (m, fileName, isLastCompiland) ->
+ { Range = m; Source = getFSharpSource fileName; Flags = isLastCompiland } )
+
+ return (), ()
+ }
+
+
+ let ComputeParseFile (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) bootstrapInfo userOpName _key = node {
+
+ let parsingOptions =
+ FSharpParsingOptions.FromTcConfig(
+ bootstrapInfo.TcConfig,
+ projectSnapshot.SourceFiles |> Seq.map (fun f -> f.FileName) |> Array.ofSeq,
+ projectSnapshot.UseScriptResolutionRules
+ )
+
+ // TODO: what is this?
+ // GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
- let ComputeParseFile (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) userOpName _key = node {
+ let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
- return ()
+ return ParseAndCheckFile.parseFile (
+ sourceText,
+ file.Source.FileName,
+ parsingOptions,
+ userOpName,
+ suggestNamesForErrors,
+ captureIdentifiersWhenParsing
+ )
}
- let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) _key =
+ let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
node {
- let! bootstrapInfoOpt, creationDiags = getBootstrapInfo projectSnapshot // probably cache
+ let! bootstrapInfoOpt, creationDiags = ComputeBootstapInfo projectSnapshot // probably cache
match bootstrapInfoOpt with
| None ->
@@ -92,31 +380,10 @@ type internal TransparentCompiler
| Some bootstrapInfo ->
+ let file = bootstrapInfo.SourceFiles |> List.find (fun f -> f.Source.FileName = fileName)
+ let! parseDiagnostics, parseTree, anyErrors = ParseFileCache.Get(file.Source.Key, ComputeParseFile file projectSnapshot bootstrapInfo userOpName)
-
-
- // Do the parsing.
- let parsingOptions =
- FSharpParsingOptions.FromTcConfig(
- bootstrapInfo.TcConfig,
- projectSnapshot.SourceFiles |> Seq.map (fun f -> f.FileName) |> Array.ofSeq,
- projectSnapshot.UseScriptResolutionRules
- )
-
- // TODO: what is this?
- // GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
-
- let parseDiagnostics, parseTree, anyErrors =
- ParseAndCheckFile.parseFile (
- sourceText,
- fileName,
- parsingOptions,
- userOpName,
- suggestNamesForErrors,
- captureIdentifiersWhenParsing
- )
-
- // TODO: check if we need this in parse results
+ // TODO: check if we really need this in parse results
let dependencyFiles = [||]
let parseResults =
From beae07e39fdce0f581f057ab72e68133316587d9 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Tue, 18 Apr 2023 11:54:54 +0200
Subject: [PATCH 005/222] wip
---
src/Compiler/Service/IncrementalBuild.fsi | 3 +
src/Compiler/Service/TransparentCompiler.fs | 85 ++++++++++++++-------
2 files changed, 60 insertions(+), 28 deletions(-)
diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi
index 9ffc66a2fdb..fc095cda82a 100644
--- a/src/Compiler/Service/IncrementalBuild.fsi
+++ b/src/Compiler/Service/IncrementalBuild.fsi
@@ -23,6 +23,9 @@ open FSharp.Compiler.Text
open FSharp.Compiler.TypedTree
open FSharp.Compiler.BuildGraph
+
+type FrameworkImportsCacheKey = FrameworkImportsCacheKey of resolvedpath: string list * assemblyName: string * targetFrameworkDirectories: string list * fsharpBinaries: string * langVersion: decimal
+
/// Lookup the global static cache for building the FrameworkTcImports
type internal FrameworkImportsCache =
new: size: int -> FrameworkImportsCache
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 01cc8bfaccb..d82b2b79acb 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -1,25 +1,29 @@
namespace FSharp.Compiler.CodeAnalysis
-open FSharp.Compiler.Text
+open System
+open System.Diagnostics
+open System.IO
+
+open Internal.Utilities.Collections
+open Internal.Utilities.Library
+
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.AbstractIL.ILBinaryReader
open FSharp.Compiler.BuildGraph
-open FSharp.Compiler.Symbols
+open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.CompilerConfig
+open FSharp.Compiler.CompilerImports
+open FSharp.Compiler.CompilerOptions
+open FSharp.Compiler.DependencyManager
open FSharp.Compiler.Diagnostics
-open System
-open FSharp.Compiler
-open Internal.Utilities.Collections
-open FSharp.Compiler.ParseAndCheckInputs
+open FSharp.Compiler.DiagnosticsLogger
+open FSharp.Compiler.IO
open FSharp.Compiler.ScriptClosure
-open FSharp.Compiler.AbstractIL.ILBinaryReader
+open FSharp.Compiler.Symbols
+open FSharp.Compiler.Text
open FSharp.Compiler.Text.Range
-open FSharp.Compiler.AbstractIL.IL
-open FSharp.Compiler.ConstraintSolver
-open System.Diagnostics
-open System.IO
-open FSharp.Compiler.CompilerOptions
open FSharp.Compiler.Xml
-open FSharp.Compiler.CompilerImports
-
type internal FSharpFile = {
@@ -61,6 +65,14 @@ type internal TransparentCompiler
let ParseAndCheckFileInProjectCache = AsyncMemoize()
let FrameworkImportsCache = AsyncMemoize()
+ // We currently share one global dependency provider for all scripts for the FSharpChecker.
+ // For projects, one is used per project.
+ //
+ // Sharing one for all scripts is necessary for good performance from GetProjectOptionsFromScript,
+ // which requires a dependency provider to process through the project options prior to working out
+ // if the cached incremental builder can be used for the project.
+ let dependencyProviderForScripts = new DependencyProvider()
+
// use this to process not-yet-implemented tasks
let backgroundCompiler =
BackgroundCompiler(
@@ -115,13 +127,13 @@ type internal TransparentCompiler
]
- let ComputeFrameworkImports (tcConfig: TcConfig) _key = node {
+ let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions _key = node {
let tcConfigP = TcConfigProvider.Constant tcConfig
return! TcImports.BuildFrameworkTcImports (tcConfigP, frameworkDLLs, nonFrameworkResolutions)
}
- let ComputeBootstapInfo (projectSnapshot: FSharpProjectSnapshot) =
+ let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) =
node {
let useSimpleResolutionSwitch = "--simpleresolution"
@@ -129,7 +141,7 @@ type internal TransparentCompiler
let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir
let useScriptResolutionRules = projectSnapshot.UseScriptResolutionRules
- let projectReferences = getProjectReferences projectSnapshot "ComputeBootstapInfo"
+ let projectReferences = getProjectReferences projectSnapshot "ComputeBootstrapInfo"
let sourceFiles = projectSnapshot.SourceFileNames
// TODO: script support
@@ -137,7 +149,7 @@ type internal TransparentCompiler
let tcConfigB, sourceFiles =
- let getSwitchValue switchString =
+ let getSwitchValue (switchString: string) =
match commandLineArgs |> List.tryFindIndex(fun s -> s.StartsWithOrdinal switchString) with
| Some idx -> Some(commandLineArgs[idx].Substring(switchString.Length))
| _ -> None
@@ -229,10 +241,29 @@ type internal TransparentCompiler
let tcConfig = TcConfig.Create(tcConfigB, validate=true)
let outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
- // Resolve assemblies and create the framework TcImports. This is done when constructing the
- // builder itself, rather than as an incremental task. This caches a level of "system" references. No type providers are
+ // Resolve assemblies and create the framework TcImports. This caches a level of "system" references. No type providers are
// included in these references.
- let! tcGlobals, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences = frameworkTcImportsCache.Get(tcConfig)
+
+ let frameworkDLLs, nonFrameworkResolutions, unresolvedReferences = TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig)
+
+ let frameworkDLLsKey =
+ frameworkDLLs
+ |> List.map (fun ar->ar.resolvedPath) // The cache key. Just the minimal data.
+ |> List.sort // Sort to promote cache hits.
+
+ // Prepare the frameworkTcImportsCache
+ //
+ // The data elements in this key are very important. There should be nothing else in the TcConfig that logically affects
+ // the import of a set of framework DLLs into F# CCUs. That is, the F# CCUs that result from a set of DLLs (including
+ // FSharp.Core.dll and mscorlib.dll) must be logically invariant of all the other compiler configuration parameters.
+ let key =
+ FrameworkImportsCacheKey(frameworkDLLsKey,
+ tcConfig.primaryAssembly.Name,
+ tcConfig.GetTargetFrameworkDirectories(),
+ tcConfig.fsharpBinariesDir,
+ tcConfig.langVersion.SpecifiedVersion)
+
+ let! tcGlobals, frameworkTcImports = FrameworkImportsCache.Get(key, ComputeFrameworkImports tcConfig frameworkDLLs nonFrameworkResolutions)
// Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
// This is ok because not much can actually go wrong here.
@@ -279,7 +310,7 @@ type internal TransparentCompiler
[ for UnresolvedAssemblyReference(referenceText, _) in unresolvedReferences do
// Exclude things that are definitely not a file name
if not(FileSystem.IsInvalidPathShim referenceText) then
- let file = if FileSystem.IsPathRootedShim referenceText then referenceText else Path.Combine(projectDirectory, referenceText)
+ let file = if FileSystem.IsPathRootedShim referenceText then referenceText else Path.Combine(projectSnapshot.ProjectDirectory, referenceText)
yield file
for r in nonFrameworkResolutions do
@@ -293,11 +324,9 @@ type internal TransparentCompiler
// For scripts, the dependency provider is already available.
// For projects create a fresh one for the project.
let dependencyProvider =
- match dependencyProvider with
- | None -> new DependencyProvider()
- | Some dependencyProvider -> dependencyProvider
-
- let defaultTimeStamp = DateTime.UtcNow
+ if projectSnapshot.UseScriptResolutionRules
+ then dependencyProviderForScripts
+ else new DependencyProvider()
let! initialBoundModel =
CombineImportedAssembliesTask(
@@ -370,7 +399,7 @@ type internal TransparentCompiler
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
node {
- let! bootstrapInfoOpt, creationDiags = ComputeBootstapInfo projectSnapshot // probably cache
+ let! bootstrapInfoOpt, creationDiags = ComputeBootstrapInfo projectSnapshot // probably cache
match bootstrapInfoOpt with
| None ->
From 0af5d0ef775ac74740d1389327df8b754e2df3fc Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Fri, 21 Apr 2023 12:32:42 +0200
Subject: [PATCH 006/222] wip
---
src/Compiler/Driver/GraphChecking/Graph.fs | 46 ++-
src/Compiler/Driver/GraphChecking/Graph.fsi | 2 +
src/Compiler/Service/FSharpCheckerResults.fs | 5 +-
src/Compiler/Service/FSharpCheckerResults.fsi | 3 +
src/Compiler/Service/TransparentCompiler.fs | 328 +++++++++++++-----
src/Compiler/Service/service.fs | 1 +
.../FSharp.Compiler.ComponentTests.fsproj | 1 +
.../TypeChecks/Graph/GraphOperations.fs | 30 ++
8 files changed, 324 insertions(+), 92 deletions(-)
create mode 100644 tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fs b/src/Compiler/Driver/GraphChecking/Graph.fs
index 0e776181a63..4a2cbb29661 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fs
+++ b/src/Compiler/Driver/GraphChecking/Graph.fs
@@ -27,26 +27,36 @@ module internal Graph =
|> Array.map (fun (KeyValue (k, v)) -> k, v)
|> readOnlyDict
- let transitive<'Node when 'Node: equality> (graph: Graph<'Node>) : Graph<'Node> =
- /// Find transitive dependencies of a single node.
- let transitiveDeps (node: 'Node) =
- let visited = HashSet<'Node>()
+ /// Find transitive dependencies of a single node.
+ let transitiveDeps (node: 'Node) (graph: Graph<'Node>) =
+ let visited = HashSet<'Node>()
- let rec dfs (node: 'Node) =
- graph[node]
- // Add direct dependencies.
- // Use HashSet.Add return value semantics to filter out those that were added previously.
- |> Array.filter visited.Add
- |> Array.iter dfs
+ let rec dfs (node: 'Node) =
+ graph[node]
+ // Add direct dependencies.
+ // Use HashSet.Add return value semantics to filter out those that were added previously.
+ |> Array.filter visited.Add
+ |> Array.iter dfs
- dfs node
- visited |> Seq.toArray
+ dfs node
+ visited |> Seq.toArray
+ let transitive<'Node when 'Node: equality> (graph: Graph<'Node>) : Graph<'Node> =
graph.Keys
|> Seq.toArray
- |> Array.Parallel.map (fun node -> node, transitiveDeps node)
+ |> Array.Parallel.map (fun node -> node, graph |> transitiveDeps node)
|> readOnlyDict
+ /// Get subgraph of the given graph that contains only nodes that are reachable from the given node.
+ let subGraphFor node graph =
+ let allDeps = graph |> transitiveDeps node
+ let relevant n = n = node || allDeps |> Array.contains n
+ graph
+ |> Seq.choose (fun (KeyValue (src, deps)) ->
+ if relevant src then Some (src, deps |> Array.filter relevant) else None)
+ |> make
+
+
/// Create a reverse of the graph
let reverse (originalGraph: Graph<'Node>) : Graph<'Node> =
originalGraph
@@ -59,6 +69,16 @@ module internal Graph =
|> readOnlyDict
|> addIfMissing originalGraph.Keys
+ let cutLeaves (graph: Graph<'Node>) =
+ let notLeaves = set [ for (KeyValue (node, deps)) in graph do if deps.Length > 0 then node ]
+ let leaves =
+ set [ for (KeyValue (node, deps)) in graph do
+ if deps.Length = 0 then node
+ yield! deps |> Array.filter (notLeaves.Contains >> not) ]
+ leaves, seq { for (KeyValue (node, deps)) in graph do
+ if deps.Length > 0 then
+ node, deps |> Array.filter (leaves.Contains >> not) } |> make
+
let printCustom (graph: Graph<'Node>) (nodePrinter: 'Node -> string) : unit =
printfn "Graph:"
let join (xs: string[]) = System.String.Join(", ", xs)
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fsi b/src/Compiler/Driver/GraphChecking/Graph.fsi
index 95542470d8a..c6afc3ee768 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fsi
+++ b/src/Compiler/Driver/GraphChecking/Graph.fsi
@@ -13,6 +13,8 @@ module internal Graph =
/// Create a transitive closure of the graph in O(n^2) time (but parallelize it).
/// The resulting graph contains edge A -> C iff the input graph contains a (directed) non-zero length path from A to C.
val transitive<'Node when 'Node: equality> : graph: Graph<'Node> -> Graph<'Node>
+ /// Get a sub-graph of the graph containing only the nodes reachable from the given node.
+ val subGraphFor: node: 'Node -> graph: Graph<'Node> -> Graph<'Node> when 'Node: equality
/// Create a reverse of the graph.
val reverse<'Node when 'Node: equality> : originalGraph: Graph<'Node> -> Graph<'Node>
/// Print the contents of the graph to the standard output.
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index ae8778b9135..4a07c23c66e 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -146,7 +146,6 @@ type FSharpFileSnapshot = {
override this.GetHashCode() = this.Key.GetHashCode()
-
[]
type FSharpProjectSnapshot =
{
@@ -193,6 +192,10 @@ type FSharpProjectSnapshot =
member po.ProjectDirectory = Path.GetDirectoryName(po.ProjectFileName)
+ member this.UpTo fileName =
+ let fileIndex = this.SourceFiles |> List.findIndex (fun x -> x.FileName = fileName)
+ { this with SourceFiles = this.SourceFiles[..fileIndex] }
+
member this.Key = {
ProjectFileName = this.ProjectFileName
SourceFiles = this.SourceFiles |> List.map (fun x -> x.Key)
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 361665a68da..3fe91074124 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -116,6 +116,9 @@ type FSharpProjectSnapshot =
member SourceFileNames: string list
+ /// A snapshot of the same project but only up to the given file (including).
+ member UpTo: fileName: string -> FSharpProjectSnapshot
+
member Key: FSharpProjectSnapshotKey
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index d82b2b79acb..9ee1aa8b5d6 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -1,4 +1,4 @@
-namespace FSharp.Compiler.CodeAnalysis
+namespace FSharp.Compiler.CodeAnalysis.TransparentCompiler
open System
open System.Diagnostics
@@ -21,9 +21,14 @@ open FSharp.Compiler.DiagnosticsLogger
open FSharp.Compiler.IO
open FSharp.Compiler.ScriptClosure
open FSharp.Compiler.Symbols
+open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Range
open FSharp.Compiler.Xml
+open System.Threading.Tasks
+open FSharp.Compiler.ParseAndCheckInputs
+open FSharp.Compiler.GraphChecking
+open FSharp.Compiler.Syntax
type internal FSharpFile = {
@@ -34,12 +39,15 @@ type internal FSharpFile = {
}
/// Things we need to start parsing and checking files for a given project snapshot
-type BootstrapInfo = {
+type internal BootstrapInfo = {
TcConfig: TcConfig
+ TcImports: TcImports
+ TcGlobals: TcGlobals
+ InitialTcInfo: TcInfo
SourceFiles: FSharpFile list
+ LoadClosure: LoadClosure option
}
-
type internal TransparentCompiler
(
legacyReferenceResolver,
@@ -59,11 +67,14 @@ type internal TransparentCompiler
) =
// Is having just one of these ok?
- let lexResourceManager = Lexhelp.LexResourceManager()
+ let _lexResourceManager = Lexhelp.LexResourceManager()
let ParseFileCache = AsyncMemoize()
let ParseAndCheckFileInProjectCache = AsyncMemoize()
let FrameworkImportsCache = AsyncMemoize()
+ let BootstrapInfoCache = AsyncMemoize()
+ let TcPriorCache = AsyncMemoize()
+ let DependencyGraphForLastFileCache = AsyncMemoize()
// We currently share one global dependency provider for all scripts for the FSharpChecker.
// For projects, one is used per project.
@@ -132,17 +143,92 @@ type internal TransparentCompiler
return! TcImports.BuildFrameworkTcImports (tcConfigP, frameworkDLLs, nonFrameworkResolutions)
}
+ // Link all the assemblies together and produce the input typecheck accumulator
+ let CombineImportedAssembliesTask (
+ assemblyName,
+ tcConfig: TcConfig,
+ tcConfigP,
+ tcGlobals,
+ frameworkTcImports,
+ nonFrameworkResolutions,
+ unresolvedReferences,
+ dependencyProvider,
+ loadClosureOpt: LoadClosure option,
+ basicDependencies
+#if !NO_TYPEPROVIDERS
+ ,importsInvalidatedByTypeProvider: Event
+#endif
+ ) =
- let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) =
- node {
+ node {
+ let diagnosticsLogger = CompilationDiagnosticLogger("CombineImportedAssembliesTask", tcConfig.diagnosticsOptions)
+ use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+ let! tcImports =
+ node {
+ try
+ let! tcImports = TcImports.BuildNonFrameworkTcImports(tcConfigP, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, dependencyProvider)
+#if !NO_TYPEPROVIDERS
+ tcImports.GetCcusExcludingBase() |> Seq.iter (fun ccu ->
+ // When a CCU reports an invalidation, merge them together and just report a
+ // general "imports invalidated". This triggers a rebuild.
+ //
+ // We are explicit about what the handler closure captures to help reason about the
+ // lifetime of captured objects, especially in case the type provider instance gets leaked
+ // or keeps itself alive mistakenly, e.g. via some global state in the type provider instance.
+ //
+ // The handler only captures
+ // 1. a weak reference to the importsInvalidated event.
+ //
+ // The IncrementalBuilder holds the strong reference the importsInvalidated event.
+ //
+ // In the invalidation handler we use a weak reference to allow the IncrementalBuilder to
+ // be collected if, for some reason, a TP instance is not disposed or not GC'd.
+ let capturedImportsInvalidated = WeakReference<_>(importsInvalidatedByTypeProvider)
+ ccu.Deref.InvalidateEvent.Add(fun _ ->
+ match capturedImportsInvalidated.TryGetTarget() with
+ | true, tg -> tg.Trigger()
+ | _ -> ()))
+#endif
+ return tcImports
+ with exn ->
+ Debug.Assert(false, sprintf "Could not BuildAllReferencedDllTcImports %A" exn)
+ diagnosticsLogger.Warning exn
+ return frameworkTcImports
+ }
+
+ let tcInitial, openDecls0 = GetInitialTcEnv (assemblyName, rangeStartup, tcConfig, tcImports, tcGlobals)
+ let tcState = GetInitialTcState (rangeStartup, assemblyName, tcConfig, tcGlobals, tcImports, tcInitial, openDecls0)
+ let loadClosureErrors =
+ [ match loadClosureOpt with
+ | None -> ()
+ | Some loadClosure ->
+ for inp in loadClosure.Inputs do
+ yield! inp.MetaCommandDiagnostics ]
+
+ let initialErrors = Array.append (Array.ofList loadClosureErrors) (diagnosticsLogger.GetDiagnostics())
+ let tcInfo =
+ {
+ tcState=tcState
+ tcEnvAtEndOfFile=tcInitial
+ topAttribs=None
+ latestCcuSigForFile=None
+ tcDiagnosticsRev = [ initialErrors ]
+ moduleNamesDict = Map.empty
+ tcDependencyFiles = basicDependencies
+ sigNameOpt = None
+ }
+ return tcImports, tcInfo
+ }
+
+ let ComputeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
+ node {
let useSimpleResolutionSwitch = "--simpleresolution"
let commandLineArgs = projectSnapshot.OtherOptions
let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir
let useScriptResolutionRules = projectSnapshot.UseScriptResolutionRules
let projectReferences = getProjectReferences projectSnapshot "ComputeBootstrapInfo"
- let sourceFiles = projectSnapshot.SourceFileNames
// TODO: script support
let loadClosureOpt: LoadClosure option = None
@@ -192,7 +278,7 @@ type internal TransparentCompiler
tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome
// Apply command-line arguments and collect more source files if they are in the arguments
- let sourceFilesNew = ApplyCommandLineArgs(tcConfigB, sourceFiles, commandLineArgs)
+ let sourceFilesNew = ApplyCommandLineArgs(tcConfigB, projectSnapshot.SourceFileNames, commandLineArgs)
// Never open PDB files for the language service, even if --standalone is specified
tcConfigB.openDebugInformationForLaterStaticLinking <- false
@@ -239,7 +325,7 @@ type internal TransparentCompiler
setupConfigFromLoadClosure()
let tcConfig = TcConfig.Create(tcConfigB, validate=true)
- let outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
+ let _outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
// Resolve assemblies and create the framework TcImports. This caches a level of "system" references. No type providers are
// included in these references.
@@ -270,36 +356,33 @@ type internal TransparentCompiler
let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
- // Get the names and time stamps of all the non-framework referenced assemblies, which will act
- // as inputs to one of the nodes in the build.
- //
- // This operation is done when constructing the builder itself, rather than as an incremental task.
- let nonFrameworkAssemblyInputs =
- // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
- // This is ok because not much can actually go wrong here.
- let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
- // Return the disposable object that cleans up
- use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
-
- [ for r in nonFrameworkResolutions do
- let fileName = r.resolvedPath
- yield (Choice1Of2 fileName, (fun (cache: TimeStampCache) -> cache.GetFileTimeStamp fileName))
-
- for pr in projectReferences do
- yield Choice2Of2 pr, (fun (cache: TimeStampCache) -> cache.GetProjectReferenceTimeStamp pr) ]
-
- // Start importing
+ // TODO: might need to put something like this somewhere
+ //// Get the names and time stamps of all the non-framework referenced assemblies, which will act
+ //// as inputs to one of the nodes in the build.
+ ////
+ //// This operation is done when constructing the builder itself, rather than as an incremental task.
+ //let nonFrameworkAssemblyInputs =
+ // // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
+ // // This is ok because not much can actually go wrong here.
+ // let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
+ // // Return the disposable object that cleans up
+ // use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+
+ // [ for r in nonFrameworkResolutions do
+ // let fileName = r.resolvedPath
+ // yield (Choice1Of2 fileName, (fun (cache: TimeStampCache) -> cache.GetFileTimeStamp fileName))
+
+ // for pr in projectReferences do
+ // yield Choice2Of2 pr, (fun (cache: TimeStampCache) -> cache.GetProjectReferenceTimeStamp pr) ]
let tcConfigP = TcConfigProvider.Constant tcConfig
- let beforeFileChecked = Event()
- let fileChecked = Event()
-#if !NO_TYPEPROVIDERS
+ #if !NO_TYPEPROVIDERS
let importsInvalidatedByTypeProvider = Event()
-#endif
+ #endif
// Check for the existence of loaded sources and prepend them to the sources list if present.
- let sourceFiles = tcConfig.GetAvailableLoadedSources() @ (sourceFiles |>List.map (fun s -> rangeStartup, s))
+ let sourceFiles = tcConfig.GetAvailableLoadedSources() @ (sourceFiles |> List.map (fun s -> rangeStartup, s))
// Mark up the source files with an indicator flag indicating if they are the last source file in the project
let sourceFiles =
@@ -314,12 +397,7 @@ type internal TransparentCompiler
yield file
for r in nonFrameworkResolutions do
- yield r.resolvedPath ]
-
- let allDependencies =
- [| yield! basicDependencies
- for _, f, _ in sourceFiles do
- yield f |]
+ yield r.resolvedPath ]
// For scripts, the dependency provider is already available.
// For projects create a fresh one for the project.
@@ -328,7 +406,7 @@ type internal TransparentCompiler
then dependencyProviderForScripts
else new DependencyProvider()
- let! initialBoundModel =
+ let! tcImports, initialTcInfo =
CombineImportedAssembliesTask(
assemblyName,
tcConfig,
@@ -339,36 +417,67 @@ type internal TransparentCompiler
unresolvedReferences,
dependencyProvider,
loadClosureOpt,
- basicDependencies,
- keepAssemblyContents,
- keepAllBackgroundResolutions,
- keepAllBackgroundSymbolUses,
- enableBackgroundItemKeyStoreAndSemanticClassification,
- enablePartialTypeChecking,
- beforeFileChecked,
- fileChecked
-#if !NO_TYPEPROVIDERS
+ basicDependencies
+ #if !NO_TYPEPROVIDERS
,importsInvalidatedByTypeProvider
-#endif
+ #endif
)
- let getFSharpSource fileName =
- getSource
- |> Option.map(fun getSource ->
- let timeStamp = DateTime.UtcNow
- let getTimeStamp = fun () -> timeStamp
- let getSourceText() = getSource fileName
- FSharpSource.Create(fileName, getTimeStamp, getSourceText))
- |> Option.defaultWith(fun () -> FSharpSource.CreateFromFile(fileName))
+ let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
let sourceFiles =
sourceFiles
- |> List.map (fun (m, fileName, isLastCompiland) ->
- { Range = m; Source = getFSharpSource fileName; Flags = isLastCompiland } )
-
- return (), ()
+ |> List.map (fun (m, fileName, (isLastCompiland, isExe)) ->
+ let source =
+ fileSnapshots.TryFind fileName
+ |> Option.defaultWith (fun () ->
+ // TODO: does this commonly happen?
+ {
+ FileName = fileName
+ Version = (FileSystem.GetLastWriteTimeShim fileName).Ticks.ToString()
+ GetSource = (fun () -> fileName |> File.ReadAllText |> SourceText.ofString |> Task.FromResult)
+ })
+ { Range = m; Source = source; IsLastCompiland = isLastCompiland; IsExe = isExe })
+
+ return Some {
+ TcConfig = tcConfig
+ TcImports = tcImports
+ TcGlobals = tcGlobals
+ InitialTcInfo = initialTcInfo
+ SourceFiles = sourceFiles
+ LoadClosure = loadClosureOpt
+ }
}
+ let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) _key =
+ node {
+
+ // Trap and report diagnostics from creation.
+ let delayedLogger = CapturingDiagnosticsLogger("IncrementalBuilderCreation")
+ use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter)
+
+ let! bootstrapInfoOpt =
+ node {
+ try
+ return! ComputeBootstrapInfoInner projectSnapshot
+ with exn ->
+ errorRecoveryNoRange exn
+ return None
+ }
+
+ let diagnostics =
+ match bootstrapInfoOpt with
+ | Some bootstrapInfo ->
+ let diagnosticsOptions = bootstrapInfo.TcConfig.diagnosticsOptions
+ let diagnosticsLogger = CompilationDiagnosticLogger("IncrementalBuilderCreation", diagnosticsOptions)
+ delayedLogger.CommitDelayedDiagnostics diagnosticsLogger
+ diagnosticsLogger.GetDiagnostics()
+ | _ ->
+ Array.ofList delayedLogger.Diagnostics
+ |> Array.map (fun (diagnostic, severity) ->
+ FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, suggestNamesForErrors))
+ return bootstrapInfoOpt, diagnostics
+ }
let ComputeParseFile (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) bootstrapInfo userOpName _key = node {
@@ -383,8 +492,7 @@ type internal TransparentCompiler
// GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
-
- return ParseAndCheckFile.parseFile (
+ let diagnostics, parsedInput, anyErrors = ParseAndCheckFile.parseFile(
sourceText,
file.Source.FileName,
parsingOptions,
@@ -392,14 +500,64 @@ type internal TransparentCompiler
suggestNamesForErrors,
captureIdentifiersWhenParsing
)
-
+ return diagnostics, parsedInput, anyErrors, sourceText
}
+ let ComputeDependencyGraphForLastFile parsedInputs (tcConfig: TcConfig) _key =
+ node {
+ let sourceFiles: FileInProject array =
+ parsedInputs
+ |> Seq.toArray
+ |> Array.mapi (fun idx (input: ParsedInput) ->
+ {
+ Idx = idx
+ FileName = input.FileName
+ ParsedInput = input
+ })
+
+ let filePairs = FilePairMap(sourceFiles)
+
+ // TODO: we will probably want to cache and re-use larger graphs if available
+ let graph =
+ DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
+ |> Graph.subGraphFor (sourceFiles |> Array.last).Idx
+
+ return graph, filePairs
+ }
+
+ // Type check everything that is needed to check given file
+ let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) userOpName _key: NodeCode =
+ node {
+
+ // parse required files
+ let files = seq {
+ yield! bootstrapInfo.SourceFiles |> Seq.takeWhile ((<>) file)
+ file
+ }
+
+ let! parsedInputs =
+ files
+ |> Seq.map (fun f ->
+ node {
+ let! _diagnostics, parsedInput, _anyErrors, _sourceText = ParseFileCache.Get((f.Source.Key, f.IsLastCompiland, f.IsExe), ComputeParseFile f projectSnapshot bootstrapInfo userOpName)
+ // TODO: Do we need to do something here when we get parse errors?
+ return parsedInput
+ })
+ |> NodeCode.Parallel
+
+ // compute dependency graph
+ let graphKey = projectSnapshot.UpTo(file.Source.FileName).SourceFileNames
+ let! _graph, _filePairs = DependencyGraphForLastFileCache.Get(graphKey, ComputeDependencyGraphForLastFile parsedInputs bootstrapInfo.TcConfig)
+
+
+
+ return bootstrapInfo.InitialTcInfo
+ }
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
node {
- let! bootstrapInfoOpt, creationDiags = ComputeBootstrapInfo projectSnapshot // probably cache
+ let! bootstrapInfoOpt, creationDiags = BootstrapInfoCache.Get(projectSnapshot.Key, ComputeBootstrapInfo projectSnapshot) // probably cache
match bootstrapInfoOpt with
| None ->
@@ -410,7 +568,11 @@ type internal TransparentCompiler
| Some bootstrapInfo ->
let file = bootstrapInfo.SourceFiles |> List.find (fun f -> f.Source.FileName = fileName)
- let! parseDiagnostics, parseTree, anyErrors = ParseFileCache.Get(file.Source.Key, ComputeParseFile file projectSnapshot bootstrapInfo userOpName)
+
+ let priorSnapshot = projectSnapshot.UpTo fileName
+ let! tcInfo = TcPriorCache.Get(priorSnapshot.Key, ComputeTcPrior file bootstrapInfo priorSnapshot userOpName)
+
+ let! parseDiagnostics, parseTree, anyErrors, sourceText = ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file projectSnapshot bootstrapInfo userOpName)
// TODO: check if we really need this in parse results
let dependencyFiles = [||]
@@ -419,19 +581,30 @@ type internal TransparentCompiler
FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, dependencyFiles)
let! checkResults =
- bc.CheckOneFileImpl(
+ FSharpCheckFileResults.CheckOneFile(
parseResults,
sourceText,
fileName,
- options,
- fileVersion,
- builder,
- tcPrior,
- tcInfo,
- creationDiags
+ projectSnapshot.ProjectFileName,
+ bootstrapInfo.TcConfig,
+ bootstrapInfo.TcGlobals,
+ bootstrapInfo.TcImports,
+ tcInfo.tcState,
+ tcInfo.moduleNamesDict,
+ bootstrapInfo.LoadClosure,
+ tcInfo.TcDiagnostics,
+ projectSnapshot.IsIncompleteTypeCheckEnvironment,
+ projectSnapshot.ToOptions(),
+ None,
+ Array.ofList tcInfo.tcDependencyFiles,
+ creationDiags,
+ parseResults.Diagnostics,
+ keepAssemblyContents,
+ suggestNamesForErrors
)
+ |> NodeCode.FromCancellable
- return (parseResults, checkResults)
+ return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
}
member _.ParseAndCheckFileInProject
@@ -439,10 +612,9 @@ type internal TransparentCompiler
fileName: string,
projectSnapshot: FSharpProjectSnapshot,
userOpName: string
- ) : NodeCode = node {
- ignore userOpName // TODO
+ ) = node {
let key = fileName, projectSnapshot.Key
- return! ParseAndCheckFileInProjectCache.Get(key, ComputeParseAndCheckFileInProject fileName projectSnapshot)
+ return! ParseAndCheckFileInProjectCache.Get(key, ComputeParseAndCheckFileInProject fileName projectSnapshot userOpName)
}
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index bd7501463d1..22d9e69da7d 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -17,6 +17,7 @@ open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.AbstractIL.ILBinaryReader
open FSharp.Compiler.AbstractIL.ILDynamicAssemblyWriter
open FSharp.Compiler.CodeAnalysis
+open FSharp.Compiler.CodeAnalysis.TransparentCompiler
open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.CompilerDiagnostics
open FSharp.Compiler.CompilerImports
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
index 9470772e261..bc4a072aee6 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
+++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
@@ -197,6 +197,7 @@
+
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
new file mode 100644
index 00000000000..0c18032e33b
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
@@ -0,0 +1,30 @@
+module FSharp.Compiler.ComponentTests.TypeChecks.Graph.GraphOperations
+
+open Xunit
+open FSharp.Compiler.GraphChecking
+
+
+[]
+let ``Transform graph to layers of leaves`` () =
+
+ let g = Graph.make [
+ 'B', [|'A'|]
+ 'C', [|'A'|]
+ 'E', [|'A'; 'B'; 'C'|]
+ 'F', [|'C'; 'D'|]
+ ]
+
+ //let layers = g |> Graph.leaves |> Seq.toList
+
+ let _expected = [
+ [|'A'; 'D'|]
+ [|'B'; 'C'|]
+ [|'E'; 'F'|]
+ ]
+
+ let _x = Graph.reverse g
+
+ ()
+
+ //Assert.Equal(expected, layers)
+
From a0d4e854642da9d6e64a289abe26a65675ecb8a8 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Wed, 26 Apr 2023 12:33:24 +0200
Subject: [PATCH 007/222] wip
---
src/Compiler/Driver/GraphChecking/Graph.fs | 9 ++
src/Compiler/Driver/GraphChecking/Graph.fsi | 2 +
src/Compiler/Driver/ParseAndCheckInputs.fs | 6 +-
src/Compiler/Service/FSharpCheckerResults.fs | 5 +-
src/Compiler/Service/FSharpCheckerResults.fsi | 3 +
src/Compiler/Service/IncrementalBuild.fs | 8 +-
src/Compiler/Service/TransparentCompiler.fs | 110 ++++++++++++++++--
.../TypeChecks/Graph/GraphOperations.fs | 70 +++++++++--
.../ProjectGeneration.fs | 13 +++
.../LanguageService/LanguageService.fs | 3 +-
10 files changed, 201 insertions(+), 28 deletions(-)
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fs b/src/Compiler/Driver/GraphChecking/Graph.fs
index 4a2cbb29661..c3e6de9731c 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fs
+++ b/src/Compiler/Driver/GraphChecking/Graph.fs
@@ -69,6 +69,7 @@ module internal Graph =
|> readOnlyDict
|> addIfMissing originalGraph.Keys
+ /// Returns leaves of the graph and the remaining graph without the leaves.
let cutLeaves (graph: Graph<'Node>) =
let notLeaves = set [ for (KeyValue (node, deps)) in graph do if deps.Length > 0 then node ]
let leaves =
@@ -79,6 +80,14 @@ module internal Graph =
if deps.Length > 0 then
node, deps |> Array.filter (leaves.Contains >> not) } |> make
+ /// Returns layers of leaves repeatedly removed from the graph until there's nothing left
+ let leafSequence (graph: Graph<'Node>) =
+ let rec loop (graph: Graph<'Node>) acc =
+ match graph |> cutLeaves with
+ | leaves, _ when leaves.IsEmpty -> acc
+ | leaves, graph -> seq { yield! acc; leaves } |> loop graph
+ loop graph Seq.empty
+
let printCustom (graph: Graph<'Node>) (nodePrinter: 'Node -> string) : unit =
printfn "Graph:"
let join (xs: string[]) = System.String.Join(", ", xs)
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fsi b/src/Compiler/Driver/GraphChecking/Graph.fsi
index c6afc3ee768..8c6b9c29079 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fsi
+++ b/src/Compiler/Driver/GraphChecking/Graph.fsi
@@ -17,6 +17,8 @@ module internal Graph =
val subGraphFor: node: 'Node -> graph: Graph<'Node> -> Graph<'Node> when 'Node: equality
/// Create a reverse of the graph.
val reverse<'Node when 'Node: equality> : originalGraph: Graph<'Node> -> Graph<'Node>
+ /// Returns layers of leaves repeatedly removed from the graph until there's nothing left
+ val leafSequence: graph: Graph<'Node> -> Set<'Node> seq
/// Print the contents of the graph to the standard output.
val print: graph: Graph<'Node> -> unit
/// Create a simple Mermaid graph and save it under the path specified.
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs
index 66327892688..55c200bf6fc 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fs
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fs
@@ -1467,14 +1467,14 @@ let CheckOneInputWithCallback
prefixPathOpt,
tcSink,
tcState: TcState,
- inp: ParsedInput,
+ input: ParsedInput,
_skipImplIfSigExists: bool): (unit -> bool) * TcConfig * TcImports * TcGlobals * LongIdent option * TcResultsSink * TcState * ParsedInput * bool)
: Cancellable> =
cancellable {
try
CheckSimulateException tcConfig
- let m = inp.Range
+ let m = input.Range
let amap = tcImports.GetImportMap()
let conditionalDefines =
@@ -1483,7 +1483,7 @@ let CheckOneInputWithCallback
else
Some tcConfig.conditionalDefines
- match inp with
+ match input with
| ParsedInput.SigFile file ->
let qualNameOfFile = file.QualifiedName
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 4a07c23c66e..9c3855789e0 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -192,9 +192,12 @@ type FSharpProjectSnapshot =
member po.ProjectDirectory = Path.GetDirectoryName(po.ProjectFileName)
+ member this.UpTo fileIndex =
+ { this with SourceFiles = this.SourceFiles[..fileIndex] }
+
member this.UpTo fileName =
let fileIndex = this.SourceFiles |> List.findIndex (fun x -> x.FileName = fileName)
- { this with SourceFiles = this.SourceFiles[..fileIndex] }
+ this.UpTo fileIndex
member this.Key = {
ProjectFileName = this.ProjectFileName
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 3fe91074124..cf7f6f45714 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -116,6 +116,9 @@ type FSharpProjectSnapshot =
member SourceFileNames: string list
+ /// A snapshot of the same project but only up to the given file index (including).
+ member UpTo: fileIndex: int -> FSharpProjectSnapshot
+
/// A snapshot of the same project but only up to the given file (including).
member UpTo: fileName: string -> FSharpProjectSnapshot
diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs
index 4d88e39c428..03b540bc256 100644
--- a/src/Compiler/Service/IncrementalBuild.fs
+++ b/src/Compiler/Service/IncrementalBuild.fs
@@ -325,7 +325,7 @@ type BoundModel private (
let getTcInfoExtras (typeCheck: GraphNode) =
node {
- let! _ , sink, implFile, fileName = typeCheck.GetOrComputeValue()
+ let! _x , sink, implFile, fileName = typeCheck.GetOrComputeValue()
// Build symbol keys
let itemKeyStore, semanticClassification =
if enableBackgroundItemKeyStoreAndSemanticClassification then
@@ -914,7 +914,7 @@ module IncrementalBuilderStateHelpers =
return! prevBoundModel.Next(syntaxTree)
})
- let rec createFinalizeBoundModelGraphNode (initialState: IncrementalBuilderInitialState) (boundModels: GraphNode seq) =
+ let createFinalizeBoundModelGraphNode (initialState: IncrementalBuilderInitialState) (boundModels: GraphNode seq) =
GraphNode(node {
use _ = Activity.start "GetCheckResultsAndImplementationsForProject" [|Activity.Tags.project, initialState.outfile|]
let! result =
@@ -928,7 +928,7 @@ module IncrementalBuilderStateHelpers =
return result, DateTime.UtcNow
})
- and computeStampedFileNames (initialState: IncrementalBuilderInitialState) (state: IncrementalBuilderState) (cache: TimeStampCache) =
+ let computeStampedFileNames (initialState: IncrementalBuilderInitialState) (state: IncrementalBuilderState) (cache: TimeStampCache) =
let slots =
if initialState.useChangeNotifications then
state.slots
@@ -967,7 +967,7 @@ module IncrementalBuilderStateHelpers =
else
state
- and computeStampedReferencedAssemblies (initialState: IncrementalBuilderInitialState) state canTriggerInvalidation (cache: TimeStampCache) =
+ let computeStampedReferencedAssemblies (initialState: IncrementalBuilderInitialState) state canTriggerInvalidation (cache: TimeStampCache) =
let stampedReferencedAssemblies = state.stampedReferencedAssemblies.ToBuilder()
let mutable referencesUpdated = false
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 9ee1aa8b5d6..8d2825ee6c7 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -29,6 +29,8 @@ open System.Threading.Tasks
open FSharp.Compiler.ParseAndCheckInputs
open FSharp.Compiler.GraphChecking
open FSharp.Compiler.Syntax
+open FSharp.Compiler.CompilerDiagnostics
+open FSharp.Compiler.NameResolution
type internal FSharpFile = {
@@ -48,6 +50,8 @@ type internal BootstrapInfo = {
LoadClosure: LoadClosure option
}
+//type ParseResults
+
type internal TransparentCompiler
(
legacyReferenceResolver,
@@ -67,13 +71,14 @@ type internal TransparentCompiler
) =
// Is having just one of these ok?
- let _lexResourceManager = Lexhelp.LexResourceManager()
+ let lexResourceManager = Lexhelp.LexResourceManager()
let ParseFileCache = AsyncMemoize()
let ParseAndCheckFileInProjectCache = AsyncMemoize()
let FrameworkImportsCache = AsyncMemoize()
let BootstrapInfoCache = AsyncMemoize()
let TcPriorCache = AsyncMemoize()
+ let TcIntermediateCache = AsyncMemoize()
let DependencyGraphForLastFileCache = AsyncMemoize()
// We currently share one global dependency provider for all scripts for the FSharpChecker.
@@ -221,7 +226,7 @@ type internal TransparentCompiler
return tcImports, tcInfo
}
- let ComputeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
+ let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
node {
let useSimpleResolutionSwitch = "--simpleresolution"
let commandLineArgs = projectSnapshot.OtherOptions
@@ -459,7 +464,7 @@ type internal TransparentCompiler
let! bootstrapInfoOpt =
node {
try
- return! ComputeBootstrapInfoInner projectSnapshot
+ return! computeBootstrapInfoInner projectSnapshot
with exn ->
errorRecoveryNoRange exn
return None
@@ -479,7 +484,7 @@ type internal TransparentCompiler
return bootstrapInfoOpt, diagnostics
}
- let ComputeParseFile (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) bootstrapInfo userOpName _key = node {
+ let ComputeParseFile' (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) bootstrapInfo userOpName _key = node {
let parsingOptions =
FSharpParsingOptions.FromTcConfig(
@@ -503,6 +508,22 @@ type internal TransparentCompiler
return diagnostics, parsedInput, anyErrors, sourceText
}
+ let ComputeParseFile (file: FSharpFile) bootstrapInfo _key =
+ node {
+ let tcConfig = bootstrapInfo.TcConfig
+ let diagnosticsLogger = CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions)
+ // Return the disposable object that cleans up
+ use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse)
+
+ let flags = file.IsLastCompiland, file.IsExe
+ let fileName = file.Source.FileName
+ let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
+
+ let input = ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, flags, diagnosticsLogger, sourceText)
+
+ return input, diagnosticsLogger.GetDiagnostics()
+ }
+
let ComputeDependencyGraphForLastFile parsedInputs (tcConfig: TcConfig) _key =
node {
let sourceFiles: FileInProject array =
@@ -525,6 +546,63 @@ type internal TransparentCompiler
return graph, filePairs
}
+ let ComputeTcIntermediate (parsedInput: ParsedInput) bootstrapInfo prevTcInfo _key =
+ node {
+ let input = parsedInput
+ let fileName = input.FileName
+ let tcConfig = bootstrapInfo.TcConfig
+ let tcGlobals = bootstrapInfo.TcGlobals
+ let tcImports = bootstrapInfo.TcImports
+
+ let capturingDiagnosticsLogger = CapturingDiagnosticsLogger("TypeCheck")
+ let diagnosticsLogger = GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, capturingDiagnosticsLogger)
+ use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
+
+ //beforeFileChecked.Trigger fileName
+
+ ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider) |> ignore
+ let sink = TcResultsSinkImpl(tcGlobals)
+ let hadParseErrors = not (Array.isEmpty parseErrors)
+ let input, moduleNamesDict = DeduplicateParsedInputModuleName prevTcInfo.moduleNamesDict input
+
+ let! (tcEnvAtEndOfFile, topAttribs, implFile, ccuSigForFile), tcState =
+ CheckOneInput (
+ (fun () -> hadParseErrors || diagnosticsLogger.ErrorCount > 0),
+ tcConfig, tcImports,
+ tcGlobals,
+ None,
+ TcResultsSink.WithSink sink,
+ prevTcInfo.tcState, input )
+ |> NodeCode.FromCancellable
+
+ //fileChecked.Trigger fileName
+
+ let newErrors = Array.append parseErrors (capturingDiagnosticsLogger.Diagnostics |> List.toArray)
+ let tcEnvAtEndOfFile = if keepAllBackgroundResolutions then tcEnvAtEndOfFile else tcState.TcEnvFromImpls
+
+ let tcInfo =
+ {
+ tcState = tcState
+ tcEnvAtEndOfFile = tcEnvAtEndOfFile
+ moduleNamesDict = moduleNamesDict
+ latestCcuSigForFile = Some ccuSigForFile
+ tcDiagnosticsRev = newErrors :: prevTcInfo.tcDiagnosticsRev
+ topAttribs = Some topAttribs
+ tcDependencyFiles = fileName :: prevTcInfo.tcDependencyFiles
+ sigNameOpt =
+ match input with
+ | ParsedInput.SigFile sigFile ->
+ Some(sigFile.FileName, sigFile.QualifiedName)
+ | _ ->
+ None
+ }
+ return tcInfo, sink, implFile, fileName
+
+
+ }
+
+
+
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) userOpName _key: NodeCode =
node {
@@ -546,11 +624,25 @@ type internal TransparentCompiler
|> NodeCode.Parallel
// compute dependency graph
- let graphKey = projectSnapshot.UpTo(file.Source.FileName).SourceFileNames
- let! _graph, _filePairs = DependencyGraphForLastFileCache.Get(graphKey, ComputeDependencyGraphForLastFile parsedInputs bootstrapInfo.TcConfig)
-
-
-
+ let graphKey = projectSnapshot.UpTo(file.Source.FileName).SourceFiles |> List.map (fun s -> s.Key)
+ let! graph, _filePairs = DependencyGraphForLastFileCache.Get(graphKey, ComputeDependencyGraphForLastFile parsedInputs bootstrapInfo.TcConfig)
+
+ // layers that can be processed in parallel
+ let layers = Graph.leafSequence graph
+
+ let rec processLayer (layers: Set list) state = node {
+ match layers with
+ | [] -> return state
+ | layer::rest ->
+ let! results =
+ layer
+ |> Seq.map (fun fileIndex ->
+ let key = projectSnapshot.UpTo(fileIndex).Key
+ TcIntermediateCache.Get(key, ComputeTcIntermediate parsedInputs[fileIndex] bootstrapInfo state))
+ |> NodeCode.Parallel
+ return! processLayer rest (combineResults state results)
+ }
+
return bootstrapInfo.InitialTcInfo
}
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
index 0c18032e33b..95d966441e1 100644
--- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
@@ -1,11 +1,15 @@
module FSharp.Compiler.ComponentTests.TypeChecks.Graph.GraphOperations
+open System.IO
open Xunit
open FSharp.Compiler.GraphChecking
+open FSharp.Test.ProjectGeneration
+open FSharp.Compiler.Text
+open FSharp.Compiler
[]
-let ``Transform graph to layers of leaves`` () =
+let ``Transform graph to layers of leaves`` () =
let g = Graph.make [
'B', [|'A'|]
@@ -14,17 +18,63 @@ let ``Transform graph to layers of leaves`` () =
'F', [|'C'; 'D'|]
]
- //let layers = g |> Graph.leaves |> Seq.toList
-
- let _expected = [
- [|'A'; 'D'|]
- [|'B'; 'C'|]
- [|'E'; 'F'|]
+ let expected = [
+ set [ 'A'; 'D' ]
+ set [ 'B'; 'C' ]
+ set [ 'E'; 'F' ]
]
- let _x = Graph.reverse g
+ let result = Graph.leafSequence g |> Seq.toList
+
+ Assert.Equal list>(expected, result)
+
+
+[]
+let ``See what this does`` () =
+
+ SyntheticProject.Create(
+ sourceFile "A" [] |> addSignatureFile,
+ sourceFile "B" ["A"] |> addSignatureFile,
+ sourceFile "C" ["A"] |> addSignatureFile,
+ sourceFile "D" [] |> addSignatureFile,
+ sourceFile "E" ["A"; "B"; "C"] |> addSignatureFile,
+ sourceFile "F" ["C"; "D"] |> addSignatureFile
+ ).Workflow {
+ withProject (fun project checker ->
+ async {
+ let options = project.GetProjectOptions checker
+ let options, _ = checker.GetParsingOptionsFromProjectOptions options
+ let! inputs =
+ project.SourceFilePaths
+ |> Seq.map (fun path -> path, File.ReadAllText path |> SourceText.ofString)
+ |> Seq.map (fun (path, text) -> checker.ParseFile(path, text, options))
+ |> Async.Parallel
+
+ let sourceFiles: FileInProject array =
+ inputs
+ |> Seq.map (fun x -> x.ParseTree)
+ |> Seq.toArray
+ |> Array.mapi (fun idx (input: Syntax.ParsedInput) ->
+ {
+ Idx = idx
+ FileName = input.FileName
+ ParsedInput = input
+ })
+
+ let filePairs = FilePairMap(sourceFiles)
+
+ let fullGraph =
+ DependencyResolution.mkGraph false filePairs sourceFiles
+ |> Graph.map (fun idx -> project.SourceFilePaths[idx] |> Path.GetFileName)
+
+ let subGraph = fullGraph |> Graph.subGraphFor "FileF.fs"
+
+ let layers = Graph.leafSequence subGraph |> Seq.toList
- ()
+ ignore layers
- //Assert.Equal(expected, layers)
+ return ()
+ }
+ )
+ }
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 37173dc901d..7a3ca688eb5 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -193,6 +193,11 @@ type SyntheticProject with
member this.GetFilePath fileId = this.Find fileId |> getFilePath this
member this.GetSignatureFilePath fileId = this.Find fileId |> getSignatureFilePath this
+ member this.SourceFilePaths =
+ [ for f in this.SourceFiles do
+ if f.HasSignatureFile then this.GetSignatureFilePath f.Id
+ this.GetFilePath f.Id ]
+
let private renderNamespaceModule (project: SyntheticProject) (f: SyntheticSourceFile) =
seq {
@@ -617,6 +622,14 @@ type ProjectWorkflowBuilder
if initialContext.IsNone then
this.DeleteProjectDir()
+ []
+ member this.WithProject(workflow: Async, f) =
+ workflow |> mapProjectAsync (fun project ->
+ async {
+ do! f project checker
+ return project
+ })
+
/// Change contents of given file using `processFile` function.
/// Does not save the file to disk.
[]
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
index dcbafaa0fa0..5fbb21edc2b 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
@@ -156,7 +156,8 @@ type internal FSharpWorkspaceServiceFactory [
Date: Thu, 27 Apr 2023 11:03:33 +0200
Subject: [PATCH 008/222] wip
---
src/Compiler/Service/TransparentCompiler.fs | 45 ++++++++++++---------
1 file changed, 27 insertions(+), 18 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 8d2825ee6c7..853632507a8 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -546,7 +546,7 @@ type internal TransparentCompiler
return graph, filePairs
}
- let ComputeTcIntermediate (parsedInput: ParsedInput) bootstrapInfo prevTcInfo _key =
+ let ComputeTcIntermediate (parsedInput: ParsedInput, parseErrors) bootstrapInfo prevTcInfo _key =
node {
let input = parsedInput
let fileName = input.FileName
@@ -586,9 +586,9 @@ type internal TransparentCompiler
tcEnvAtEndOfFile = tcEnvAtEndOfFile
moduleNamesDict = moduleNamesDict
latestCcuSigForFile = Some ccuSigForFile
- tcDiagnosticsRev = newErrors :: prevTcInfo.tcDiagnosticsRev
+ tcDiagnosticsRev = [newErrors]
topAttribs = Some topAttribs
- tcDependencyFiles = fileName :: prevTcInfo.tcDependencyFiles
+ tcDependencyFiles = [fileName]
sigNameOpt =
match input with
| ParsedInput.SigFile sigFile ->
@@ -597,12 +597,8 @@ type internal TransparentCompiler
None
}
return tcInfo, sink, implFile, fileName
-
-
}
-
-
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) userOpName _key: NodeCode =
node {
@@ -616,16 +612,13 @@ type internal TransparentCompiler
let! parsedInputs =
files
|> Seq.map (fun f ->
- node {
- let! _diagnostics, parsedInput, _anyErrors, _sourceText = ParseFileCache.Get((f.Source.Key, f.IsLastCompiland, f.IsExe), ComputeParseFile f projectSnapshot bootstrapInfo userOpName)
- // TODO: Do we need to do something here when we get parse errors?
- return parsedInput
- })
+ let key = f.Source.Key, f.IsLastCompiland, f.IsExe
+ ParseFileCache.Get(key, ComputeParseFile f bootstrapInfo))
|> NodeCode.Parallel
// compute dependency graph
let graphKey = projectSnapshot.UpTo(file.Source.FileName).SourceFiles |> List.map (fun s -> s.Key)
- let! graph, _filePairs = DependencyGraphForLastFileCache.Get(graphKey, ComputeDependencyGraphForLastFile parsedInputs bootstrapInfo.TcConfig)
+ let! graph, _filePairs = DependencyGraphForLastFileCache.Get(graphKey, ComputeDependencyGraphForLastFile (parsedInputs |> Seq.map fst) bootstrapInfo.TcConfig)
// layers that can be processed in parallel
let layers = Graph.leafSequence graph
@@ -642,7 +635,7 @@ type internal TransparentCompiler
|> NodeCode.Parallel
return! processLayer rest (combineResults state results)
}
-
+
return bootstrapInfo.InitialTcInfo
}
@@ -664,14 +657,30 @@ type internal TransparentCompiler
let priorSnapshot = projectSnapshot.UpTo fileName
let! tcInfo = TcPriorCache.Get(priorSnapshot.Key, ComputeTcPrior file bootstrapInfo priorSnapshot userOpName)
- let! parseDiagnostics, parseTree, anyErrors, sourceText = ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file projectSnapshot bootstrapInfo userOpName)
+ let! parseTree, parseDiagnostics = ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file bootstrapInfo)
- // TODO: check if we really need this in parse results
- let dependencyFiles = [||]
+ let parseDiagnostics =
+ DiagnosticHelpers.CreateDiagnostics(
+ bootstrapInfo.TcConfig.diagnosticsOptions,
+ false,
+ fileName,
+ parseDiagnostics,
+ suggestNamesForErrors
+ )
+
+ let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
let parseResults =
- FSharpParseFileResults(parseDiagnostics, parseTree, anyErrors, dependencyFiles)
+ FSharpParseFileResults(
+ diagnostics = diagnostics,
+ input = parseTree,
+ parseHadErrors = (parseDiagnostics.Length > 0),
+ // TODO: check if we really need this in parse results
+ dependencyFiles = [||]
+ )
+ // TODO: this might be replaced... probably should use intermediate TC result
+ let sourceText = Unchecked.defaultof<_>
let! checkResults =
FSharpCheckFileResults.CheckOneFile(
parseResults,
From e162b0a218f5464c997125640d2db592b8bfffa1 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 27 Apr 2023 12:52:58 +0200
Subject: [PATCH 009/222] wip
---
src/Compiler/Driver/GraphChecking/Graph.fs | 48 +-
src/Compiler/Service/FSharpCheckerResults.fs | 81 ++-
src/Compiler/Service/FSharpCheckerResults.fsi | 36 +-
src/Compiler/Service/IncrementalBuild.fs | 2 +-
src/Compiler/Service/IncrementalBuild.fsi | 9 +-
src/Compiler/Service/TransparentCompiler.fs | 630 +++++++++++-------
src/Compiler/Service/service.fs | 8 +-
7 files changed, 502 insertions(+), 312 deletions(-)
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fs b/src/Compiler/Driver/GraphChecking/Graph.fs
index c3e6de9731c..688fffc29bb 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fs
+++ b/src/Compiler/Driver/GraphChecking/Graph.fs
@@ -41,7 +41,7 @@ module internal Graph =
dfs node
visited |> Seq.toArray
- let transitive<'Node when 'Node: equality> (graph: Graph<'Node>) : Graph<'Node> =
+ let transitive<'Node when 'Node: equality> (graph: Graph<'Node>) : Graph<'Node> =
graph.Keys
|> Seq.toArray
|> Array.Parallel.map (fun node -> node, graph |> transitiveDeps node)
@@ -51,12 +51,15 @@ module internal Graph =
let subGraphFor node graph =
let allDeps = graph |> transitiveDeps node
let relevant n = n = node || allDeps |> Array.contains n
+
graph
|> Seq.choose (fun (KeyValue (src, deps)) ->
- if relevant src then Some (src, deps |> Array.filter relevant) else None)
+ if relevant src then
+ Some(src, deps |> Array.filter relevant)
+ else
+ None)
|> make
-
/// Create a reverse of the graph
let reverse (originalGraph: Graph<'Node>) : Graph<'Node> =
originalGraph
@@ -71,21 +74,44 @@ module internal Graph =
/// Returns leaves of the graph and the remaining graph without the leaves.
let cutLeaves (graph: Graph<'Node>) =
- let notLeaves = set [ for (KeyValue (node, deps)) in graph do if deps.Length > 0 then node ]
- let leaves =
- set [ for (KeyValue (node, deps)) in graph do
- if deps.Length = 0 then node
- yield! deps |> Array.filter (notLeaves.Contains >> not) ]
- leaves, seq { for (KeyValue (node, deps)) in graph do
+ let notLeaves =
+ set
+ [
+ for (KeyValue (node, deps)) in graph do
if deps.Length > 0 then
- node, deps |> Array.filter (leaves.Contains >> not) } |> make
+ node
+ ]
+
+ let leaves =
+ set
+ [
+ for (KeyValue (node, deps)) in graph do
+ if deps.Length = 0 then
+ node
+
+ yield! deps |> Array.filter (notLeaves.Contains >> not)
+ ]
+
+ leaves,
+ seq {
+ for (KeyValue (node, deps)) in graph do
+ if deps.Length > 0 then
+ node, deps |> Array.filter (leaves.Contains >> not)
+ }
+ |> make
/// Returns layers of leaves repeatedly removed from the graph until there's nothing left
let leafSequence (graph: Graph<'Node>) =
let rec loop (graph: Graph<'Node>) acc =
match graph |> cutLeaves with
| leaves, _ when leaves.IsEmpty -> acc
- | leaves, graph -> seq { yield! acc; leaves } |> loop graph
+ | leaves, graph ->
+ seq {
+ yield! acc
+ leaves
+ }
+ |> loop graph
+
loop graph Seq.empty
let printCustom (graph: Graph<'Node>) (nodePrinter: 'Node -> string) : unit =
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 9c3855789e0..bf6480fd8df 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -115,8 +115,6 @@ type internal DelayedILModuleReader =
}
| _ -> cancellable.Return(Some this.result)
-
-
type FSharpFileKey = string * string
type FSharpProjectSnapshotKey =
@@ -132,12 +130,15 @@ type FSharpProjectSnapshotKey =
}
[]
-type FSharpFileSnapshot = {
- FileName: string
- Version: string
- GetSource: unit -> Task
-} with
+type FSharpFileSnapshot =
+ {
+ FileName: string
+ Version: string
+ GetSource: unit -> Task
+ }
+
member this.Key = this.FileName, this.Version
+
override this.Equals(o) =
match o with
| :? FSharpFileSnapshot as o -> o.FileName = this.FileName && o.Version = this.Version
@@ -145,7 +146,6 @@ type FSharpFileSnapshot = {
override this.GetHashCode() = this.Key.GetHashCode()
-
[]
type FSharpProjectSnapshot =
{
@@ -161,6 +161,7 @@ type FSharpProjectSnapshot =
OriginalLoadReferences: (range * string * string) list
Stamp: int64 option
}
+
static member UseSameProject(options1, options2) =
match options1.ProjectId, options2.ProjectId with
| Some (projectId1), Some (projectId2) when
@@ -193,20 +194,26 @@ type FSharpProjectSnapshot =
member po.ProjectDirectory = Path.GetDirectoryName(po.ProjectFileName)
member this.UpTo fileIndex =
- { this with SourceFiles = this.SourceFiles[..fileIndex] }
+ { this with
+ SourceFiles = this.SourceFiles[..fileIndex]
+ }
member this.UpTo fileName =
let fileIndex = this.SourceFiles |> List.findIndex (fun x -> x.FileName = fileName)
this.UpTo fileIndex
- member this.Key = {
- ProjectFileName = this.ProjectFileName
- SourceFiles = this.SourceFiles |> List.map (fun x -> x.Key)
- OtherOptions = this.OtherOptions
- ReferencedProjects = this.ReferencedProjects |> List.map (function FSharpReference (_, x) -> x.Key)
- IsIncompleteTypeCheckEnvironment = this.IsIncompleteTypeCheckEnvironment
- UseScriptResolutionRules = this.UseScriptResolutionRules
- }
+ member this.Key =
+ {
+ ProjectFileName = this.ProjectFileName
+ SourceFiles = this.SourceFiles |> List.map (fun x -> x.Key)
+ OtherOptions = this.OtherOptions
+ ReferencedProjects =
+ this.ReferencedProjects
+ |> List.map (function
+ | FSharpReference (_, x) -> x.Key)
+ IsIncompleteTypeCheckEnvironment = this.IsIncompleteTypeCheckEnvironment
+ UseScriptResolutionRules = this.UseScriptResolutionRules
+ }
member this.SourceFileNames = this.SourceFiles |> List.map (fun x -> x.FileName)
@@ -226,14 +233,17 @@ and [] public FSharpReferencedProjectSnapshot =
/// The fully qualified path to the output of the referenced project. This should be the same value as the -r
/// reference in the project options for this referenced project.
///
- member this.OutputFile = match this with FSharpReference (projectOutputFile, _) -> projectOutputFile
+ member this.OutputFile =
+ match this with
+ | FSharpReference (projectOutputFile, _) -> projectOutputFile
///
/// Creates a reference for an F# project. The physical data for it is stored/cached inside of the compiler service.
///
/// The fully qualified path to the output of the referenced project. This should be the same value as the -r reference in the project options for this referenced project.
/// The Project Options for this F# project
- static member CreateFSharp(projectOutputFile, options: FSharpProjectSnapshot) = FSharpReference (projectOutputFile, options)
+ static member CreateFSharp(projectOutputFile, options: FSharpProjectSnapshot) =
+ FSharpReference(projectOutputFile, options)
override this.Equals(o) =
match o with
@@ -246,7 +256,6 @@ and [] public FSharpReferencedProjectSnapshot =
override this.GetHashCode() = this.OutputFile.GetHashCode()
-
[]
type FSharpReferencedProject =
| FSharpReference of projectOutputFile: string * options: FSharpProjectOptions
@@ -336,19 +345,25 @@ and FSharpProjectOptions =
"FSharpProjectOptions(" + this.ProjectFileName + ")"
type FSharpProjectSnapshot with
- member this.ToOptions (): FSharpProjectOptions = {
- ProjectFileName = this.ProjectFileName
- ProjectId = this.ProjectId
- SourceFiles = this.SourceFiles |> Seq.map (fun x -> x.FileName) |> Seq.toArray
- OtherOptions = this.OtherOptions |> List.toArray
- ReferencedProjects = this.ReferencedProjects |> Seq.map (function FSharpReference (name, opts) -> FSharpReferencedProject.FSharpReference (name, opts.ToOptions())) |> Seq.toArray
- IsIncompleteTypeCheckEnvironment = this.IsIncompleteTypeCheckEnvironment
- UseScriptResolutionRules = this.UseScriptResolutionRules
- LoadTime = this.LoadTime
- UnresolvedReferences = this.UnresolvedReferences
- OriginalLoadReferences = this.OriginalLoadReferences
- Stamp = this.Stamp
- }
+
+ member this.ToOptions() : FSharpProjectOptions =
+ {
+ ProjectFileName = this.ProjectFileName
+ ProjectId = this.ProjectId
+ SourceFiles = this.SourceFiles |> Seq.map (fun x -> x.FileName) |> Seq.toArray
+ OtherOptions = this.OtherOptions |> List.toArray
+ ReferencedProjects =
+ this.ReferencedProjects
+ |> Seq.map (function
+ | FSharpReference (name, opts) -> FSharpReferencedProject.FSharpReference(name, opts.ToOptions()))
+ |> Seq.toArray
+ IsIncompleteTypeCheckEnvironment = this.IsIncompleteTypeCheckEnvironment
+ UseScriptResolutionRules = this.UseScriptResolutionRules
+ LoadTime = this.LoadTime
+ UnresolvedReferences = this.UnresolvedReferences
+ OriginalLoadReferences = this.OriginalLoadReferences
+ Stamp = this.Stamp
+ }
[]
module internal FSharpCheckerResultsSettings =
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index cf7f6f45714..04e6667ca06 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -39,27 +39,25 @@ type internal DelayedILModuleReader =
/// Unused in this API
type public FSharpUnresolvedReferencesSet = internal FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list
-
type FSharpFileKey = string * string
type FSharpProjectSnapshotKey =
- {
- ProjectFileName: string
- SourceFiles: FSharpFileKey list
- OtherOptions: string list
- ReferencedProjects: FSharpProjectSnapshotKey list
+ { ProjectFileName: string
+ SourceFiles: FSharpFileKey list
+ OtherOptions: string list
+ ReferencedProjects: FSharpProjectSnapshotKey list
- // Do we need these?
- IsIncompleteTypeCheckEnvironment: bool
- UseScriptResolutionRules: bool
- }
+ // Do we need these?
+ IsIncompleteTypeCheckEnvironment: bool
+ UseScriptResolutionRules: bool }
[]
-type FSharpFileSnapshot = {
- FileName: string
- Version: string
- GetSource: unit -> System.Threading.Tasks.Task
-} with member Key: FSharpFileKey
+type FSharpFileSnapshot =
+ { FileName: string
+ Version: string
+ GetSource: unit -> System.Threading.Tasks.Task }
+
+ member Key: FSharpFileKey
[]
type FSharpProjectSnapshot =
@@ -124,7 +122,6 @@ type FSharpProjectSnapshot =
member Key: FSharpProjectSnapshotKey
-
and [] public FSharpReferencedProjectSnapshot =
internal
| FSharpReference of projectOutputFile: string * options: FSharpProjectSnapshot
@@ -145,9 +142,8 @@ and [] public FSharpReferencedProjectSnapshot =
///
/// The fully qualified path to the output of the referenced project. This should be the same value as the -r reference in the project options for this referenced project.
/// The Project Options for this F# project
- static member CreateFSharp: projectOutputFile: string * options: FSharpProjectSnapshot -> FSharpReferencedProjectSnapshot
-
-
+ static member CreateFSharp:
+ projectOutputFile: string * options: FSharpProjectSnapshot -> FSharpReferencedProjectSnapshot
/// A set of information describing a project or script build configuration.
type public FSharpProjectOptions =
@@ -248,8 +244,8 @@ and [] public FSharpReferencedProject =
FSharpReferencedProject
type FSharpProjectSnapshot with
- member ToOptions: unit -> FSharpProjectOptions
+ member ToOptions: unit -> FSharpProjectOptions
/// Represents the use of an F# symbol from F# source code
[]
diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs
index 6d579ebcd12..0977a2fe129 100644
--- a/src/Compiler/Service/IncrementalBuild.fs
+++ b/src/Compiler/Service/IncrementalBuild.fs
@@ -247,7 +247,7 @@ type BoundModel private (
syntaxTreeOpt: SyntaxTree option,
?tcStateOpt: GraphNode * GraphNode
) =
-
+
let getTypeCheck (syntaxTree: SyntaxTree) : NodeCode =
node {
let! input, _sourceRange, fileName, parseErrors = syntaxTree.ParseNode.GetOrComputeValue()
diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi
index 1ecd34a4b85..252f2b57a83 100644
--- a/src/Compiler/Service/IncrementalBuild.fsi
+++ b/src/Compiler/Service/IncrementalBuild.fsi
@@ -23,8 +23,13 @@ open FSharp.Compiler.Text
open FSharp.Compiler.TypedTree
open FSharp.Compiler.BuildGraph
-
-type FrameworkImportsCacheKey = FrameworkImportsCacheKey of resolvedpath: string list * assemblyName: string * targetFrameworkDirectories: string list * fsharpBinaries: string * langVersion: decimal
+type FrameworkImportsCacheKey =
+ | FrameworkImportsCacheKey of
+ resolvedpath: string list *
+ assemblyName: string *
+ targetFrameworkDirectories: string list *
+ fsharpBinaries: string *
+ langVersion: decimal
/// Lookup the global static cache for building the FrameworkTcImports
type internal FrameworkImportsCache =
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 853632507a8..6a4d503f569 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -31,26 +31,28 @@ open FSharp.Compiler.GraphChecking
open FSharp.Compiler.Syntax
open FSharp.Compiler.CompilerDiagnostics
open FSharp.Compiler.NameResolution
-
-
-type internal FSharpFile = {
- Range: range
- Source: FSharpFileSnapshot
- IsLastCompiland: bool
- IsExe: bool
-}
+open Internal.Utilities.Library.Extras
+
+type internal FSharpFile =
+ {
+ Range: range
+ Source: FSharpFileSnapshot
+ IsLastCompiland: bool
+ IsExe: bool
+ }
/// Things we need to start parsing and checking files for a given project snapshot
-type internal BootstrapInfo = {
- TcConfig: TcConfig
- TcImports: TcImports
- TcGlobals: TcGlobals
- InitialTcInfo: TcInfo
- SourceFiles: FSharpFile list
- LoadClosure: LoadClosure option
-}
+type internal BootstrapInfo =
+ {
+ TcConfig: TcConfig
+ TcImports: TcImports
+ TcGlobals: TcGlobals
+ InitialTcInfo: TcInfo
+ SourceFiles: FSharpFile list
+ LoadClosure: LoadClosure option
+ }
-//type ParseResults
+//type ParseResults
type internal TransparentCompiler
(
@@ -131,7 +133,12 @@ type internal TransparentCompiler
member x.EvaluateRawContents() =
node {
Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm)
- return! backgroundCompiler.GetAssemblyData(opts.ToOptions(), userOpName + ".CheckReferencedProject(" + nm + ")")
+
+ return!
+ backgroundCompiler.GetAssemblyData(
+ opts.ToOptions(),
+ userOpName + ".CheckReferencedProject(" + nm + ")"
+ )
}
member x.TryGetLogicalTimeStamp(cache) =
@@ -142,89 +149,109 @@ type internal TransparentCompiler
}
]
-
- let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions _key = node {
- let tcConfigP = TcConfigProvider.Constant tcConfig
- return! TcImports.BuildFrameworkTcImports (tcConfigP, frameworkDLLs, nonFrameworkResolutions)
- }
+ let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions _key =
+ node {
+ let tcConfigP = TcConfigProvider.Constant tcConfig
+ return! TcImports.BuildFrameworkTcImports(tcConfigP, frameworkDLLs, nonFrameworkResolutions)
+ }
// Link all the assemblies together and produce the input typecheck accumulator
- let CombineImportedAssembliesTask (
- assemblyName,
- tcConfig: TcConfig,
- tcConfigP,
- tcGlobals,
- frameworkTcImports,
- nonFrameworkResolutions,
- unresolvedReferences,
- dependencyProvider,
- loadClosureOpt: LoadClosure option,
- basicDependencies
-#if !NO_TYPEPROVIDERS
- ,importsInvalidatedByTypeProvider: Event
-#endif
+ let CombineImportedAssembliesTask
+ (
+ assemblyName,
+ tcConfig: TcConfig,
+ tcConfigP,
+ tcGlobals,
+ frameworkTcImports,
+ nonFrameworkResolutions,
+ unresolvedReferences,
+ dependencyProvider,
+ loadClosureOpt: LoadClosure option,
+ basicDependencies,
+ importsInvalidatedByTypeProvider: Event
+ //#endif
) =
- node {
- let diagnosticsLogger = CompilationDiagnosticLogger("CombineImportedAssembliesTask", tcConfig.diagnosticsOptions)
- use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
-
- let! tcImports =
- node {
- try
- let! tcImports = TcImports.BuildNonFrameworkTcImports(tcConfigP, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, dependencyProvider)
-#if !NO_TYPEPROVIDERS
- tcImports.GetCcusExcludingBase() |> Seq.iter (fun ccu ->
- // When a CCU reports an invalidation, merge them together and just report a
- // general "imports invalidated". This triggers a rebuild.
- //
- // We are explicit about what the handler closure captures to help reason about the
- // lifetime of captured objects, especially in case the type provider instance gets leaked
- // or keeps itself alive mistakenly, e.g. via some global state in the type provider instance.
- //
- // The handler only captures
- // 1. a weak reference to the importsInvalidated event.
- //
- // The IncrementalBuilder holds the strong reference the importsInvalidated event.
- //
- // In the invalidation handler we use a weak reference to allow the IncrementalBuilder to
- // be collected if, for some reason, a TP instance is not disposed or not GC'd.
- let capturedImportsInvalidated = WeakReference<_>(importsInvalidatedByTypeProvider)
- ccu.Deref.InvalidateEvent.Add(fun _ ->
- match capturedImportsInvalidated.TryGetTarget() with
- | true, tg -> tg.Trigger()
- | _ -> ()))
-#endif
- return tcImports
- with exn ->
- Debug.Assert(false, sprintf "Could not BuildAllReferencedDllTcImports %A" exn)
- diagnosticsLogger.Warning exn
- return frameworkTcImports
- }
-
- let tcInitial, openDecls0 = GetInitialTcEnv (assemblyName, rangeStartup, tcConfig, tcImports, tcGlobals)
- let tcState = GetInitialTcState (rangeStartup, assemblyName, tcConfig, tcGlobals, tcImports, tcInitial, openDecls0)
- let loadClosureErrors =
- [ match loadClosureOpt with
- | None -> ()
- | Some loadClosure ->
- for inp in loadClosure.Inputs do
- yield! inp.MetaCommandDiagnostics ]
-
- let initialErrors = Array.append (Array.ofList loadClosureErrors) (diagnosticsLogger.GetDiagnostics())
- let tcInfo =
- {
- tcState=tcState
- tcEnvAtEndOfFile=tcInitial
- topAttribs=None
- latestCcuSigForFile=None
- tcDiagnosticsRev = [ initialErrors ]
- moduleNamesDict = Map.empty
- tcDependencyFiles = basicDependencies
- sigNameOpt = None
- }
- return tcImports, tcInfo
- }
+ node {
+ let diagnosticsLogger =
+ CompilationDiagnosticLogger("CombineImportedAssembliesTask", tcConfig.diagnosticsOptions)
+
+ use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+
+ let! tcImports =
+ node {
+ try
+ let! tcImports =
+ TcImports.BuildNonFrameworkTcImports(
+ tcConfigP,
+ frameworkTcImports,
+ nonFrameworkResolutions,
+ unresolvedReferences,
+ dependencyProvider
+ )
+ //#if !NO_TYPEPROVIDERS
+ tcImports.GetCcusExcludingBase()
+ |> Seq.iter (fun ccu ->
+ // When a CCU reports an invalidation, merge them together and just report a
+ // general "imports invalidated". This triggers a rebuild.
+ //
+ // We are explicit about what the handler closure captures to help reason about the
+ // lifetime of captured objects, especially in case the type provider instance gets leaked
+ // or keeps itself alive mistakenly, e.g. via some global state in the type provider instance.
+ //
+ // The handler only captures
+ // 1. a weak reference to the importsInvalidated event.
+ //
+ // The IncrementalBuilder holds the strong reference the importsInvalidated event.
+ //
+ // In the invalidation handler we use a weak reference to allow the IncrementalBuilder to
+ // be collected if, for some reason, a TP instance is not disposed or not GC'd.
+ let capturedImportsInvalidated = WeakReference<_>(importsInvalidatedByTypeProvider)
+
+ ccu.Deref.InvalidateEvent.Add(fun _ ->
+ match capturedImportsInvalidated.TryGetTarget() with
+ | true, tg -> tg.Trigger()
+ | _ -> ()))
+ //#endif
+ return tcImports
+ with exn ->
+ Debug.Assert(false, sprintf "Could not BuildAllReferencedDllTcImports %A" exn)
+ diagnosticsLogger.Warning exn
+ return frameworkTcImports
+ }
+
+ let tcInitial, openDecls0 =
+ GetInitialTcEnv(assemblyName, rangeStartup, tcConfig, tcImports, tcGlobals)
+
+ let tcState =
+ GetInitialTcState(rangeStartup, assemblyName, tcConfig, tcGlobals, tcImports, tcInitial, openDecls0)
+
+ let loadClosureErrors =
+ [
+ match loadClosureOpt with
+ | None -> ()
+ | Some loadClosure ->
+ for inp in loadClosure.Inputs do
+ yield! inp.MetaCommandDiagnostics
+ ]
+
+ let initialErrors =
+ Array.append (Array.ofList loadClosureErrors) (diagnosticsLogger.GetDiagnostics())
+
+ let tcInfo =
+ {
+ tcState = tcState
+ tcEnvAtEndOfFile = tcInitial
+ topAttribs = None
+ latestCcuSigForFile = None
+ tcDiagnosticsRev = [ initialErrors ]
+ moduleNamesDict = Map.empty
+ tcDependencyFiles = basicDependencies
+ sigNameOpt = None
+ }
+
+ return tcImports, tcInfo
+ }
let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
node {
@@ -241,8 +268,8 @@ type internal TransparentCompiler
let tcConfigB, sourceFiles =
let getSwitchValue (switchString: string) =
- match commandLineArgs |> List.tryFindIndex(fun s -> s.StartsWithOrdinal switchString) with
- | Some idx -> Some(commandLineArgs[idx].Substring(switchString.Length))
+ match commandLineArgs |> List.tryFindIndex (fun s -> s.StartsWithOrdinal switchString) with
+ | Some idx -> Some(commandLineArgs[ idx ].Substring(switchString.Length))
| _ -> None
let sdkDirOverride =
@@ -252,16 +279,18 @@ type internal TransparentCompiler
// see also fsc.fs: runFromCommandLineToImportingAssemblies(), as there are many similarities to where the PS creates a tcConfigB
let tcConfigB =
- TcConfigBuilder.CreateNew(legacyReferenceResolver,
- defaultFSharpBinariesDir,
- implicitIncludeDir=projectSnapshot.ProjectDirectory,
- reduceMemoryUsage=ReduceMemoryFlag.Yes,
- isInteractive=useScriptResolutionRules,
- isInvalidationSupported=true,
- defaultCopyFSharpCore=CopyFSharpCoreFlag.No,
- tryGetMetadataSnapshot=tryGetMetadataSnapshot,
- sdkDirOverride=sdkDirOverride,
- rangeForErrors=range0)
+ TcConfigBuilder.CreateNew(
+ legacyReferenceResolver,
+ defaultFSharpBinariesDir,
+ implicitIncludeDir = projectSnapshot.ProjectDirectory,
+ reduceMemoryUsage = ReduceMemoryFlag.Yes,
+ isInteractive = useScriptResolutionRules,
+ isInvalidationSupported = true,
+ defaultCopyFSharpCore = CopyFSharpCoreFlag.No,
+ tryGetMetadataSnapshot = tryGetMetadataSnapshot,
+ sdkDirOverride = sdkDirOverride,
+ rangeForErrors = range0
+ )
tcConfigB.primaryAssembly <-
match loadClosureOpt with
@@ -275,7 +304,12 @@ type internal TransparentCompiler
tcConfigB.resolutionEnvironment <- (LegacyResolutionEnvironment.EditingOrCompilation true)
tcConfigB.conditionalDefines <-
- let define = if useScriptResolutionRules then "INTERACTIVE" else "COMPILED"
+ let define =
+ if useScriptResolutionRules then
+ "INTERACTIVE"
+ else
+ "COMPILED"
+
define :: tcConfigB.conditionalDefines
tcConfigB.projectReferences <- projectReferences
@@ -283,7 +317,8 @@ type internal TransparentCompiler
tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome
// Apply command-line arguments and collect more source files if they are in the arguments
- let sourceFilesNew = ApplyCommandLineArgs(tcConfigB, projectSnapshot.SourceFileNames, commandLineArgs)
+ let sourceFilesNew =
+ ApplyCommandLineArgs(tcConfigB, projectSnapshot.SourceFileNames, commandLineArgs)
// Never open PDB files for the language service, even if --standalone is specified
tcConfigB.openDebugInformationForLaterStaticLinking <- false
@@ -312,35 +347,48 @@ type internal TransparentCompiler
match loadClosureOpt with
| Some loadClosure ->
let dllReferences =
- [for reference in tcConfigB.referencedDLLs do
- // If there's (one or more) resolutions of closure references then yield them all
- match loadClosure.References |> List.tryFind (fun (resolved, _)->resolved=reference.Text) with
- | Some (resolved, closureReferences) ->
- for closureReference in closureReferences do
- yield AssemblyReference(closureReference.originalReference.Range, resolved, None)
- | None -> yield reference]
+ [
+ for reference in tcConfigB.referencedDLLs do
+ // If there's (one or more) resolutions of closure references then yield them all
+ match
+ loadClosure.References
+ |> List.tryFind (fun (resolved, _) -> resolved = reference.Text)
+ with
+ | Some (resolved, closureReferences) ->
+ for closureReference in closureReferences do
+ yield AssemblyReference(closureReference.originalReference.Range, resolved, None)
+ | None -> yield reference
+ ]
+
tcConfigB.referencedDLLs <- []
- tcConfigB.primaryAssembly <- (if loadClosure.UseDesktopFramework then PrimaryAssembly.Mscorlib else PrimaryAssembly.System_Runtime)
+
+ tcConfigB.primaryAssembly <-
+ (if loadClosure.UseDesktopFramework then
+ PrimaryAssembly.Mscorlib
+ else
+ PrimaryAssembly.System_Runtime)
// Add one by one to remove duplicates
- dllReferences |> List.iter (fun dllReference ->
- tcConfigB.AddReferencedAssemblyByPath(dllReference.Range, dllReference.Text))
+ dllReferences
+ |> List.iter (fun dllReference -> tcConfigB.AddReferencedAssemblyByPath(dllReference.Range, dllReference.Text))
+
tcConfigB.knownUnresolvedReferences <- loadClosure.UnresolvedReferences
| None -> ()
- setupConfigFromLoadClosure()
+ setupConfigFromLoadClosure ()
- let tcConfig = TcConfig.Create(tcConfigB, validate=true)
+ let tcConfig = TcConfig.Create(tcConfigB, validate = true)
let _outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
// Resolve assemblies and create the framework TcImports. This caches a level of "system" references. No type providers are
// included in these references.
- let frameworkDLLs, nonFrameworkResolutions, unresolvedReferences = TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig)
+ let frameworkDLLs, nonFrameworkResolutions, unresolvedReferences =
+ TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig)
let frameworkDLLsKey =
frameworkDLLs
- |> List.map (fun ar->ar.resolvedPath) // The cache key. Just the minimal data.
- |> List.sort // Sort to promote cache hits.
+ |> List.map (fun ar -> ar.resolvedPath) // The cache key. Just the minimal data.
+ |> List.sort // Sort to promote cache hits.
// Prepare the frameworkTcImportsCache
//
@@ -348,17 +396,22 @@ type internal TransparentCompiler
// the import of a set of framework DLLs into F# CCUs. That is, the F# CCUs that result from a set of DLLs (including
// FSharp.Core.dll and mscorlib.dll) must be logically invariant of all the other compiler configuration parameters.
let key =
- FrameworkImportsCacheKey(frameworkDLLsKey,
- tcConfig.primaryAssembly.Name,
- tcConfig.GetTargetFrameworkDirectories(),
- tcConfig.fsharpBinariesDir,
- tcConfig.langVersion.SpecifiedVersion)
+ FrameworkImportsCacheKey(
+ frameworkDLLsKey,
+ tcConfig.primaryAssembly.Name,
+ tcConfig.GetTargetFrameworkDirectories(),
+ tcConfig.fsharpBinariesDir,
+ tcConfig.langVersion.SpecifiedVersion
+ )
- let! tcGlobals, frameworkTcImports = FrameworkImportsCache.Get(key, ComputeFrameworkImports tcConfig frameworkDLLs nonFrameworkResolutions)
+ let! tcGlobals, frameworkTcImports =
+ FrameworkImportsCache.Get(key, ComputeFrameworkImports tcConfig frameworkDLLs nonFrameworkResolutions)
// Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
// This is ok because not much can actually go wrong here.
- let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
+ let diagnosticsLogger =
+ CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
+
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
// TODO: might need to put something like this somewhere
@@ -382,12 +435,14 @@ type internal TransparentCompiler
let tcConfigP = TcConfigProvider.Constant tcConfig
- #if !NO_TYPEPROVIDERS
+ //#if !NO_TYPEPROVIDERS
let importsInvalidatedByTypeProvider = Event()
- #endif
+ //#endif
// Check for the existence of loaded sources and prepend them to the sources list if present.
- let sourceFiles = tcConfig.GetAvailableLoadedSources() @ (sourceFiles |> List.map (fun s -> rangeStartup, s))
+ let sourceFiles =
+ tcConfig.GetAvailableLoadedSources()
+ @ (sourceFiles |> List.map (fun s -> rangeStartup, s))
// Mark up the source files with an indicator flag indicating if they are the last source file in the project
let sourceFiles =
@@ -395,23 +450,31 @@ type internal TransparentCompiler
((sourceFiles, flags) ||> List.map2 (fun (m, nm) flag -> (m, nm, (flag, isExe))))
let basicDependencies =
- [ for UnresolvedAssemblyReference(referenceText, _) in unresolvedReferences do
- // Exclude things that are definitely not a file name
- if not(FileSystem.IsInvalidPathShim referenceText) then
- let file = if FileSystem.IsPathRootedShim referenceText then referenceText else Path.Combine(projectSnapshot.ProjectDirectory, referenceText)
- yield file
-
- for r in nonFrameworkResolutions do
- yield r.resolvedPath ]
+ [
+ for UnresolvedAssemblyReference (referenceText, _) in unresolvedReferences do
+ // Exclude things that are definitely not a file name
+ if not (FileSystem.IsInvalidPathShim referenceText) then
+ let file =
+ if FileSystem.IsPathRootedShim referenceText then
+ referenceText
+ else
+ Path.Combine(projectSnapshot.ProjectDirectory, referenceText)
+
+ yield file
+
+ for r in nonFrameworkResolutions do
+ yield r.resolvedPath
+ ]
// For scripts, the dependency provider is already available.
// For projects create a fresh one for the project.
let dependencyProvider =
- if projectSnapshot.UseScriptResolutionRules
- then dependencyProviderForScripts
- else new DependencyProvider()
+ if projectSnapshot.UseScriptResolutionRules then
+ dependencyProviderForScripts
+ else
+ new DependencyProvider()
- let! tcImports, initialTcInfo =
+ let! tcImports, initialTcInfo =
CombineImportedAssembliesTask(
assemblyName,
tcConfig,
@@ -422,10 +485,10 @@ type internal TransparentCompiler
unresolvedReferences,
dependencyProvider,
loadClosureOpt,
- basicDependencies
- #if !NO_TYPEPROVIDERS
- ,importsInvalidatedByTypeProvider
- #endif
+ basicDependencies,
+ //#if !NO_TYPEPROVIDERS
+ importsInvalidatedByTypeProvider
+ //#endif
)
let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
@@ -442,16 +505,24 @@ type internal TransparentCompiler
Version = (FileSystem.GetLastWriteTimeShim fileName).Ticks.ToString()
GetSource = (fun () -> fileName |> File.ReadAllText |> SourceText.ofString |> Task.FromResult)
})
- { Range = m; Source = source; IsLastCompiland = isLastCompiland; IsExe = isExe })
-
- return Some {
- TcConfig = tcConfig
- TcImports = tcImports
- TcGlobals = tcGlobals
- InitialTcInfo = initialTcInfo
- SourceFiles = sourceFiles
- LoadClosure = loadClosureOpt
- }
+
+ {
+ Range = m
+ Source = source
+ IsLastCompiland = isLastCompiland
+ IsExe = isExe
+ })
+
+ return
+ Some
+ {
+ TcConfig = tcConfig
+ TcImports = tcImports
+ TcGlobals = tcGlobals
+ InitialTcInfo = initialTcInfo
+ SourceFiles = sourceFiles
+ LoadClosure = loadClosureOpt
+ }
}
let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) _key =
@@ -474,44 +545,53 @@ type internal TransparentCompiler
match bootstrapInfoOpt with
| Some bootstrapInfo ->
let diagnosticsOptions = bootstrapInfo.TcConfig.diagnosticsOptions
- let diagnosticsLogger = CompilationDiagnosticLogger("IncrementalBuilderCreation", diagnosticsOptions)
+
+ let diagnosticsLogger =
+ CompilationDiagnosticLogger("IncrementalBuilderCreation", diagnosticsOptions)
+
delayedLogger.CommitDelayedDiagnostics diagnosticsLogger
diagnosticsLogger.GetDiagnostics()
- | _ ->
- Array.ofList delayedLogger.Diagnostics
+ | _ -> Array.ofList delayedLogger.Diagnostics
|> Array.map (fun (diagnostic, severity) ->
FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, suggestNamesForErrors))
+
return bootstrapInfoOpt, diagnostics
}
- let ComputeParseFile' (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) bootstrapInfo userOpName _key = node {
+ let ComputeParseFile' (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) bootstrapInfo userOpName _key =
+ node {
- let parsingOptions =
- FSharpParsingOptions.FromTcConfig(
- bootstrapInfo.TcConfig,
- projectSnapshot.SourceFiles |> Seq.map (fun f -> f.FileName) |> Array.ofSeq,
- projectSnapshot.UseScriptResolutionRules
- )
+ let parsingOptions =
+ FSharpParsingOptions.FromTcConfig(
+ bootstrapInfo.TcConfig,
+ projectSnapshot.SourceFiles |> Seq.map (fun f -> f.FileName) |> Array.ofSeq,
+ projectSnapshot.UseScriptResolutionRules
+ )
- // TODO: what is this?
- // GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
+ // TODO: what is this?
+ // GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
- let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
- let diagnostics, parsedInput, anyErrors = ParseAndCheckFile.parseFile(
- sourceText,
- file.Source.FileName,
- parsingOptions,
- userOpName,
- suggestNamesForErrors,
- captureIdentifiersWhenParsing
- )
- return diagnostics, parsedInput, anyErrors, sourceText
- }
+ let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
+
+ let diagnostics, parsedInput, anyErrors =
+ ParseAndCheckFile.parseFile (
+ sourceText,
+ file.Source.FileName,
+ parsingOptions,
+ userOpName,
+ suggestNamesForErrors,
+ captureIdentifiersWhenParsing
+ )
+
+ return diagnostics, parsedInput, anyErrors, sourceText
+ }
let ComputeParseFile (file: FSharpFile) bootstrapInfo _key =
node {
let tcConfig = bootstrapInfo.TcConfig
- let diagnosticsLogger = CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions)
+
+ let diagnosticsLogger =
+ CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions)
// Return the disposable object that cleans up
use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse)
@@ -519,7 +599,8 @@ type internal TransparentCompiler
let fileName = file.Source.FileName
let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
- let input = ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, flags, diagnosticsLogger, sourceText)
+ let input =
+ ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, flags, diagnosticsLogger, sourceText)
return input, diagnosticsLogger.GetDiagnostics()
}
@@ -555,30 +636,51 @@ type internal TransparentCompiler
let tcImports = bootstrapInfo.TcImports
let capturingDiagnosticsLogger = CapturingDiagnosticsLogger("TypeCheck")
- let diagnosticsLogger = GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, capturingDiagnosticsLogger)
+
+ let diagnosticsLogger =
+ GetDiagnosticsLoggerFilteringByScopedPragmas(
+ false,
+ input.ScopedPragmas,
+ tcConfig.diagnosticsOptions,
+ capturingDiagnosticsLogger
+ )
+
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
//beforeFileChecked.Trigger fileName
- ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider) |> ignore
+ ApplyMetaCommandsFromInputToTcConfig(tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider)
+ |> ignore
+
let sink = TcResultsSinkImpl(tcGlobals)
let hadParseErrors = not (Array.isEmpty parseErrors)
- let input, moduleNamesDict = DeduplicateParsedInputModuleName prevTcInfo.moduleNamesDict input
+
+ let input, moduleNamesDict =
+ DeduplicateParsedInputModuleName prevTcInfo.moduleNamesDict input
let! (tcEnvAtEndOfFile, topAttribs, implFile, ccuSigForFile), tcState =
- CheckOneInput (
- (fun () -> hadParseErrors || diagnosticsLogger.ErrorCount > 0),
- tcConfig, tcImports,
- tcGlobals,
- None,
- TcResultsSink.WithSink sink,
- prevTcInfo.tcState, input )
+ CheckOneInput(
+ (fun () -> hadParseErrors || diagnosticsLogger.ErrorCount > 0),
+ tcConfig,
+ tcImports,
+ tcGlobals,
+ None,
+ TcResultsSink.WithSink sink,
+ prevTcInfo.tcState,
+ input
+ )
|> NodeCode.FromCancellable
//fileChecked.Trigger fileName
- let newErrors = Array.append parseErrors (capturingDiagnosticsLogger.Diagnostics |> List.toArray)
- let tcEnvAtEndOfFile = if keepAllBackgroundResolutions then tcEnvAtEndOfFile else tcState.TcEnvFromImpls
+ let newErrors =
+ Array.append parseErrors (capturingDiagnosticsLogger.Diagnostics |> List.toArray)
+
+ let tcEnvAtEndOfFile =
+ if keepAllBackgroundResolutions then
+ tcEnvAtEndOfFile
+ else
+ tcState.TcEnvFromImpls
let tcInfo =
{
@@ -586,28 +688,47 @@ type internal TransparentCompiler
tcEnvAtEndOfFile = tcEnvAtEndOfFile
moduleNamesDict = moduleNamesDict
latestCcuSigForFile = Some ccuSigForFile
- tcDiagnosticsRev = [newErrors]
+ tcDiagnosticsRev = [ newErrors ]
topAttribs = Some topAttribs
- tcDependencyFiles = [fileName]
+ tcDependencyFiles = [ fileName ]
sigNameOpt =
match input with
- | ParsedInput.SigFile sigFile ->
- Some(sigFile.FileName, sigFile.QualifiedName)
- | _ ->
- None
+ | ParsedInput.SigFile sigFile -> Some(sigFile.FileName, sigFile.QualifiedName)
+ | _ -> None
}
+
return tcInfo, sink, implFile, fileName
}
+ let mergeTcInfos =
+ Array.fold (fun a b ->
+ { a with
+ tcState = b.tcState
+ tcEnvAtEndOfFile = b.tcEnvAtEndOfFile
+ moduleNamesDict = b.moduleNamesDict
+ latestCcuSigForFile = b.latestCcuSigForFile
+ tcDiagnosticsRev = b.tcDiagnosticsRev @ a.tcDiagnosticsRev
+ topAttribs = b.topAttribs
+ tcDependencyFiles = b.tcDependencyFiles
+ sigNameOpt = b.sigNameOpt
+ })
+
// Type check everything that is needed to check given file
- let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) userOpName _key: NodeCode =
+ let ComputeTcPrior
+ (file: FSharpFile)
+ (bootstrapInfo: BootstrapInfo)
+ (projectSnapshot: FSharpProjectSnapshot)
+ _userOpName
+ _key
+ : NodeCode =
node {
// parse required files
- let files = seq {
- yield! bootstrapInfo.SourceFiles |> Seq.takeWhile ((<>) file)
- file
- }
+ let files =
+ seq {
+ yield! bootstrapInfo.SourceFiles |> Seq.takeWhile ((<>) file)
+ file
+ }
let! parsedInputs =
files
@@ -617,26 +738,36 @@ type internal TransparentCompiler
|> NodeCode.Parallel
// compute dependency graph
- let graphKey = projectSnapshot.UpTo(file.Source.FileName).SourceFiles |> List.map (fun s -> s.Key)
- let! graph, _filePairs = DependencyGraphForLastFileCache.Get(graphKey, ComputeDependencyGraphForLastFile (parsedInputs |> Seq.map fst) bootstrapInfo.TcConfig)
+ let graphKey =
+ projectSnapshot.UpTo(file.Source.FileName).SourceFiles
+ |> List.map (fun s -> s.Key)
+
+ let! graph, _filePairs =
+ DependencyGraphForLastFileCache.Get(
+ graphKey,
+ ComputeDependencyGraphForLastFile (parsedInputs |> Seq.map fst) bootstrapInfo.TcConfig
+ )
// layers that can be processed in parallel
- let layers = Graph.leafSequence graph
-
- let rec processLayer (layers: Set list) state = node {
- match layers with
- | [] -> return state
- | layer::rest ->
- let! results =
- layer
- |> Seq.map (fun fileIndex ->
- let key = projectSnapshot.UpTo(fileIndex).Key
- TcIntermediateCache.Get(key, ComputeTcIntermediate parsedInputs[fileIndex] bootstrapInfo state))
- |> NodeCode.Parallel
- return! processLayer rest (combineResults state results)
- }
-
- return bootstrapInfo.InitialTcInfo
+ let layers = Graph.leafSequence graph |> Seq.toList
+
+ let rec processLayer (layers: Set list) state =
+ node {
+ match layers with
+ | [] -> return state
+ | layer :: rest ->
+ let! results =
+ layer
+ |> Seq.map (fun fileIndex ->
+ let key = projectSnapshot.UpTo(fileIndex).Key
+ TcIntermediateCache.Get(key, ComputeTcIntermediate parsedInputs[fileIndex] bootstrapInfo state))
+ |> NodeCode.Parallel
+
+ return! processLayer rest (mergeTcInfos state (results |> Array.map p14))
+ }
+
+ let! tcInfo = processLayer layers bootstrapInfo.InitialTcInfo
+ return tcInfo
}
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
@@ -652,12 +783,14 @@ type internal TransparentCompiler
| Some bootstrapInfo ->
- let file = bootstrapInfo.SourceFiles |> List.find (fun f -> f.Source.FileName = fileName)
+ let file =
+ bootstrapInfo.SourceFiles |> List.find (fun f -> f.Source.FileName = fileName)
let priorSnapshot = projectSnapshot.UpTo fileName
let! tcInfo = TcPriorCache.Get(priorSnapshot.Key, ComputeTcPrior file bootstrapInfo priorSnapshot userOpName)
- let! parseTree, parseDiagnostics = ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file bootstrapInfo)
+ let! parseTree, parseDiagnostics =
+ ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file bootstrapInfo)
let parseDiagnostics =
DiagnosticHelpers.CreateDiagnostics(
@@ -681,6 +814,7 @@ type internal TransparentCompiler
// TODO: this might be replaced... probably should use intermediate TC result
let sourceText = Unchecked.defaultof<_>
+
let! checkResults =
FSharpCheckFileResults.CheckOneFile(
parseResults,
@@ -708,17 +842,12 @@ type internal TransparentCompiler
return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
}
- member _.ParseAndCheckFileInProject
- (
- fileName: string,
- projectSnapshot: FSharpProjectSnapshot,
- userOpName: string
- ) = node {
+ member _.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) =
+ node {
let key = fileName, projectSnapshot.Key
return! ParseAndCheckFileInProjectCache.Get(key, ComputeParseAndCheckFileInProject fileName projectSnapshot userOpName)
}
-
interface IBackgroundCompiler with
member this.BeforeBackgroundFileCheck: IEvent =
backgroundCompiler.BeforeBackgroundFileCheck
@@ -743,13 +872,26 @@ type internal TransparentCompiler
options: FSharpProjectOptions,
userOpName: string
) : NodeCode =
- backgroundCompiler.CheckFileInProjectAllowingStaleCachedResults(parseResults, fileName, fileVersion, sourceText, options, userOpName)
+ backgroundCompiler.CheckFileInProjectAllowingStaleCachedResults(
+ parseResults,
+ fileName,
+ fileVersion,
+ sourceText,
+ options,
+ userOpName
+ )
+
+ member _.ClearCache(options: seq, userOpName: string) : unit =
+ backgroundCompiler.ClearCache(options, userOpName)
- member _.ClearCache(options: seq, userOpName: string) : unit = backgroundCompiler.ClearCache(options, userOpName)
member _.ClearCaches() : unit = backgroundCompiler.ClearCaches()
member _.DownsizeCaches() : unit = backgroundCompiler.DownsizeCaches()
- member _.FileChecked: IEvent = backgroundCompiler.FileChecked
- member _.FileParsed: IEvent = backgroundCompiler.FileParsed
+
+ member _.FileChecked: IEvent =
+ backgroundCompiler.FileChecked
+
+ member _.FileParsed: IEvent =
+ backgroundCompiler.FileParsed
member _.FindReferencesInFile
(
@@ -761,7 +903,8 @@ type internal TransparentCompiler
) : NodeCode> =
backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
- member _.FrameworkImportsCache: FrameworkImportsCache = backgroundCompiler.FrameworkImportsCache
+ member _.FrameworkImportsCache: FrameworkImportsCache =
+ backgroundCompiler.FrameworkImportsCache
member _.GetAssemblyData(options: FSharpProjectOptions, userOpName: string) : NodeCode =
backgroundCompiler.GetAssemblyData(options, userOpName)
@@ -860,7 +1003,8 @@ type internal TransparentCompiler
) : Async =
backgroundCompiler.ParseFile(fileName, sourceText, options, cache, userOpName)
- member _.ProjectChecked: IEvent = backgroundCompiler.ProjectChecked
+ member _.ProjectChecked: IEvent =
+ backgroundCompiler.ProjectChecked
member _.TryGetRecentCheckResultsForFile
(
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index 22d9e69da7d..0dd0083f706 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -149,7 +149,9 @@ type FSharpChecker
captureIdentifiersWhenParsing,
getSource,
useChangeNotifications,
- useSyntaxTreeCache) :> IBackgroundCompiler
+ useSyntaxTreeCache
+ )
+ :> IBackgroundCompiler
else
BackgroundCompiler(
legacyReferenceResolver,
@@ -165,7 +167,9 @@ type FSharpChecker
captureIdentifiersWhenParsing,
getSource,
useChangeNotifications,
- useSyntaxTreeCache) :> IBackgroundCompiler
+ useSyntaxTreeCache
+ )
+ :> IBackgroundCompiler
static let globalInstance = lazy FSharpChecker.Create()
From e8ea40cd7ffcd9268e8893ff1bb12ff68baa81b1 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 28 Apr 2023 15:34:43 +0200
Subject: [PATCH 010/222] wip
---
src/Compiler/Service/BackgroundCompiler.fs | 13 +++
src/Compiler/Service/FSharpCheckerResults.fs | 1 +
src/Compiler/Service/FSharpCheckerResults.fsi | 3 +-
src/Compiler/Service/IncrementalBuild.fs | 4 +-
src/Compiler/Service/TransparentCompiler.fs | 65 +++++++-------
src/Compiler/Service/service.fs | 6 ++
src/Compiler/Service/service.fsi | 4 +
.../LanguageService/LanguageService.fs | 5 +-
.../LanguageService/WorkspaceExtensions.fs | 85 ++++++++++++++++---
.../FSharp.Editor/Options/EditorOptions.fs | 5 ++
.../AdvancedOptionsControl.xaml | 4 +
.../FSharp.UIResources/Strings.Designer.cs | 18 ++++
.../src/FSharp.UIResources/Strings.resx | 6 ++
.../src/FSharp.UIResources/xlf/Strings.cs.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.de.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.es.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.fr.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.it.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.ja.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.ko.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.pl.xlf | 10 +++
.../FSharp.UIResources/xlf/Strings.pt-BR.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.ru.xlf | 10 +++
.../src/FSharp.UIResources/xlf/Strings.tr.xlf | 10 +++
.../xlf/Strings.zh-Hans.xlf | 10 +++
.../xlf/Strings.zh-Hant.xlf | 10 +++
26 files changed, 298 insertions(+), 51 deletions(-)
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index 36758b75afc..ddf9d3f0c04 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -124,6 +124,10 @@ type internal IBackgroundCompiler =
fileName: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string ->
NodeCode
+ abstract member ParseAndCheckFileInProject:
+ fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string ->
+ NodeCode
+
/// Parse and typecheck the whole project.
abstract member ParseAndCheckProject: options: FSharpProjectOptions * userOpName: string -> NodeCode
@@ -1373,6 +1377,7 @@ type internal BackgroundCompiler
static member ActualCheckFileCount = actualCheckFileCount
interface IBackgroundCompiler with
+
member _.BeforeBackgroundFileCheck = self.BeforeBackgroundFileCheck
member _.CheckFileInProject
@@ -1498,6 +1503,14 @@ type internal BackgroundCompiler
) : NodeCode =
self.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName)
+ member this.ParseAndCheckFileInProject
+ (
+ _fileName: string,
+ _projectSnapshot: FSharpProjectSnapshot,
+ _userOpName: string
+ ) : NodeCode =
+ raise (System.NotImplementedException())
+
member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode =
self.ParseAndCheckProject(options, userOpName)
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index a5767cd3564..5b2dbb3cd54 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -117,6 +117,7 @@ type internal DelayedILModuleReader =
type FSharpFileKey = string * string
+// TODO: use stamp if we have it?
type FSharpProjectSnapshotKey =
{
ProjectFileName: string
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 04e6667ca06..20ecde853ea 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -5,6 +5,7 @@ namespace FSharp.Compiler.CodeAnalysis
open System
open System.IO
open System.Threading
+open System.Threading.Tasks
open Internal.Utilities.Library
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.AbstractIL.ILBinaryReader
@@ -55,7 +56,7 @@ type FSharpProjectSnapshotKey =
type FSharpFileSnapshot =
{ FileName: string
Version: string
- GetSource: unit -> System.Threading.Tasks.Task }
+ GetSource: unit -> Task }
member Key: FSharpFileKey
diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs
index 3178af6868b..8d48ec4503b 100644
--- a/src/Compiler/Service/IncrementalBuild.fs
+++ b/src/Compiler/Service/IncrementalBuild.fs
@@ -250,7 +250,7 @@ type BoundModel private (
syntaxTreeOpt: SyntaxTree option,
?tcStateOpt: GraphNode * GraphNode
) =
-
+
let getTypeCheck (syntaxTree: SyntaxTree) : NodeCode =
node {
let! input, _sourceRange, fileName, parseErrors = syntaxTree.ParseNode.GetOrComputeValue()
@@ -262,7 +262,7 @@ type BoundModel private (
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
beforeFileChecked.Trigger fileName
-
+
ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider) |> ignore
let sink = TcResultsSinkImpl(tcGlobals)
let hadParseErrors = not (Array.isEmpty parseErrors)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index dd24c89ed3d..81a2406d811 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -52,8 +52,6 @@ type internal BootstrapInfo =
LoadClosure: LoadClosure option
}
-//type ParseResults
-
type internal TransparentCompiler
(
legacyReferenceResolver,
@@ -168,8 +166,9 @@ type internal TransparentCompiler
dependencyProvider,
loadClosureOpt: LoadClosure option,
basicDependencies,
+#if !NO_TYPEPROVIDERS
importsInvalidatedByTypeProvider: Event
- //#endif
+#endif
) =
node {
@@ -189,7 +188,7 @@ type internal TransparentCompiler
unresolvedReferences,
dependencyProvider
)
- //#if !NO_TYPEPROVIDERS
+#if !NO_TYPEPROVIDERS
tcImports.GetCcusExcludingBase()
|> Seq.iter (fun ccu ->
// When a CCU reports an invalidation, merge them together and just report a
@@ -212,7 +211,7 @@ type internal TransparentCompiler
match capturedImportsInvalidated.TryGetTarget() with
| true, tg -> tg.Trigger()
| _ -> ()))
- //#endif
+#endif
return tcImports
with exn ->
Debug.Assert(false, sprintf "Could not BuildAllReferencedDllTcImports %A" exn)
@@ -435,9 +434,9 @@ type internal TransparentCompiler
let tcConfigP = TcConfigProvider.Constant tcConfig
- //#if !NO_TYPEPROVIDERS
+#if !NO_TYPEPROVIDERS
let importsInvalidatedByTypeProvider = Event()
- //#endif
+#endif
// Check for the existence of loaded sources and prepend them to the sources list if present.
let sourceFiles =
@@ -486,9 +485,9 @@ type internal TransparentCompiler
dependencyProvider,
loadClosureOpt,
basicDependencies,
- //#if !NO_TYPEPROVIDERS
+#if !NO_TYPEPROVIDERS
importsInvalidatedByTypeProvider
- //#endif
+#endif
)
let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
@@ -602,7 +601,7 @@ type internal TransparentCompiler
let input =
ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, flags, diagnosticsLogger, sourceText)
- return input, diagnosticsLogger.GetDiagnostics()
+ return input, diagnosticsLogger.GetDiagnostics(), sourceText
}
let ComputeDependencyGraphForLastFile parsedInputs (tcConfig: TcConfig) _key =
@@ -691,10 +690,8 @@ type internal TransparentCompiler
tcDiagnosticsRev = [ newErrors ]
topAttribs = Some topAttribs
tcDependencyFiles = [ fileName ]
- sigNameOpt =
- match input with
- | ParsedInput.SigFile sigFile -> Some(sigFile.FileName, sigFile.QualifiedName)
- | _ -> None
+ // we shouldn't need this with graph checking (?)
+ sigNameOpt = None
}
return tcInfo, sink, implFile, fileName
@@ -709,18 +706,13 @@ type internal TransparentCompiler
latestCcuSigForFile = b.latestCcuSigForFile
tcDiagnosticsRev = b.tcDiagnosticsRev @ a.tcDiagnosticsRev
topAttribs = b.topAttribs
- tcDependencyFiles = b.tcDependencyFiles
- sigNameOpt = b.sigNameOpt
+ tcDependencyFiles = b.tcDependencyFiles @ a.tcDependencyFiles
+ // we shouldn't need this with graph checking (?)
+ sigNameOpt = None
})
// Type check everything that is needed to check given file
- let ComputeTcPrior
- (file: FSharpFile)
- (bootstrapInfo: BootstrapInfo)
- (projectSnapshot: FSharpProjectSnapshot)
- _userOpName
- _key
- : NodeCode =
+ let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName _key =
node {
// parse required files
@@ -745,29 +737,32 @@ type internal TransparentCompiler
let! graph, _filePairs =
DependencyGraphForLastFileCache.Get(
graphKey,
- ComputeDependencyGraphForLastFile (parsedInputs |> Seq.map fst) bootstrapInfo.TcConfig
+ ComputeDependencyGraphForLastFile (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
)
// layers that can be processed in parallel
let layers = Graph.leafSequence graph |> Seq.toList
- let rec processLayer (layers: Set list) state =
+ // remove the final layer, which should be the target file
+ let layers = layers |> List.take (layers.Length - 1)
+
+ let rec processLayer (layers: Set list) tcInfo =
node {
match layers with
- | [] -> return state
+ | [] -> return tcInfo
| layer :: rest ->
let! results =
layer
|> Seq.map (fun fileIndex ->
let key = projectSnapshot.UpTo(fileIndex).Key
- TcIntermediateCache.Get(key, ComputeTcIntermediate parsedInputs[fileIndex] bootstrapInfo state))
+ let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
+ TcIntermediateCache.Get(key, ComputeTcIntermediate (parsedInput, parseErrors) bootstrapInfo tcInfo))
|> NodeCode.Parallel
- return! processLayer rest (mergeTcInfos state (results |> Array.map p14))
+ return! processLayer rest (mergeTcInfos tcInfo (results |> Array.map p14))
}
- let! tcInfo = processLayer layers bootstrapInfo.InitialTcInfo
- return tcInfo
+ return! processLayer layers bootstrapInfo.InitialTcInfo
}
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
@@ -789,7 +784,8 @@ type internal TransparentCompiler
let priorSnapshot = projectSnapshot.UpTo fileName
let! tcInfo = TcPriorCache.Get(priorSnapshot.Key, ComputeTcPrior file bootstrapInfo priorSnapshot userOpName)
- let! parseTree, parseDiagnostics =
+ // We could also bubble this through ComputeTcPrior
+ let! parseTree, parseDiagnostics, sourceText =
ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file bootstrapInfo)
let parseDiagnostics =
@@ -812,9 +808,6 @@ type internal TransparentCompiler
dependencyFiles = [||]
)
- // TODO: this might be replaced... probably should use intermediate TC result
- let sourceText = Unchecked.defaultof<_>
-
let! checkResults =
FSharpCheckFileResults.CheckOneFile(
parseResults,
@@ -849,6 +842,7 @@ type internal TransparentCompiler
}
interface IBackgroundCompiler with
+
member this.BeforeBackgroundFileCheck: IEvent =
backgroundCompiler.BeforeBackgroundFileCheck
@@ -990,6 +984,9 @@ type internal TransparentCompiler
backgroundCompiler.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName)
+ member this.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) =
+ this.ParseAndCheckFileInProject(fileName, projectSnapshot, userOpName)
+
member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode =
backgroundCompiler.ParseAndCheckProject(options, userOpName)
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index fdbf6a1df36..69b6f7186dc 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -431,6 +431,12 @@ type FSharpChecker
backgroundCompiler.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName)
|> Async.AwaitNodeCode
+ member _.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, ?userOpName: string) =
+ let userOpName = defaultArg userOpName "Unknown"
+
+ backgroundCompiler.ParseAndCheckFileInProject(fileName, projectSnapshot, userOpName)
+ |> Async.AwaitNodeCode
+
member _.ParseAndCheckProject(options, ?userOpName: string) =
let userOpName = defaultArg userOpName "Unknown"
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index 9a7472c0841..45522fa3126 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -193,6 +193,10 @@ type public FSharpChecker =
?userOpName: string ->
Async
+ member ParseAndCheckFileInProject:
+ fileName: string * projectSnapshot: FSharpProjectSnapshot * ?userOpName: string ->
+ Async
+
///
/// Parse and typecheck all files in a project.
/// All files are read from the FileSystem API
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
index 6b8fd616027..a9680b20653 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
@@ -143,6 +143,8 @@ type internal FSharpWorkspaceServiceFactory [ Seq.map (fun d -> d.FilePath, d) |> Map
+
+ let! sourceFiles =
+ options.SourceFiles
+ |> Seq.map (fun path ->
+ async {
+ let document = documents[path]
+ let! version = document.GetTextVersionAsync() |> Async.AwaitTask
+
+ let getSource () =
+ task {
+ let! sourceText = document.GetTextAsync()
+ return sourceText.ToFSharpSourceText()
+ }
+
+ return
+ {
+ FileName = path
+ Version = version.ToString()
+ GetSource = getSource
+ }
+ })
+ |> Async.Parallel
+
+ // TODO: referenced projects
+ let referencedProjects = []
+
+ let projectSnapshot: FSharpProjectSnapshot =
+ {
+ ProjectFileName = options.ProjectFileName
+ ProjectId = options.ProjectId
+ SourceFiles = sourceFiles |> List.ofArray
+ OtherOptions = options.OtherOptions |> List.ofArray
+ ReferencedProjects = referencedProjects
+ IsIncompleteTypeCheckEnvironment = options.IsIncompleteTypeCheckEnvironment
+ UseScriptResolutionRules = options.UseScriptResolutionRules
+ LoadTime = options.LoadTime
+ UnresolvedReferences = options.UnresolvedReferences
+ OriginalLoadReferences = options.OriginalLoadReferences
+ Stamp = options.Stamp
+ }
+
+ let! (parseResults, checkFileAnswer) = checker.ParseAndCheckFileInProject(fileName, projectSnapshot, userOpName)
+
+ return
+ match checkFileAnswer with
+ | FSharpCheckFileAnswer.Aborted -> None
+ | FSharpCheckFileAnswer.Succeeded (checkFileResults) -> Some(parseResults, checkFileResults)
+ }
+
/// Parse and check the source text from the Roslyn document with possible stale results.
member checker.ParseAndCheckDocumentWithPossibleStaleResults
(
@@ -77,11 +136,6 @@ module private CheckerExtensions =
return None // worker is cancelled at this point, we cannot return it and wait its completion anymore
}
- let bindParsedInput (results: (FSharpParseFileResults * FSharpCheckFileResults) option) =
- match results with
- | Some (parseResults, checkResults) -> Some(parseResults, parseResults.ParseTree, checkResults)
- | None -> None
-
if allowStaleResults then
let! freshResults = tryGetFreshResultsWithTimeout ()
@@ -95,10 +149,10 @@ module private CheckerExtensions =
| None -> return! parseAndCheckFile
}
- return bindParsedInput results
+ return results
else
let! results = parseAndCheckFile
- return bindParsedInput results
+ return results
}
/// Parse and check the source text from the Roslyn document.
@@ -110,12 +164,17 @@ module private CheckerExtensions =
?allowStaleResults: bool
) =
async {
- let allowStaleResults =
- match allowStaleResults with
- | Some b -> b
- | _ -> document.Project.IsFSharpStaleCompletionResultsEnabled
- return! checker.ParseAndCheckDocumentWithPossibleStaleResults(document, options, allowStaleResults, userOpName = userOpName)
+ if document.Project.UseTransparentCompiiler then
+ return! checker.ParseAndCheckDocumentUsingTransparentCompiler(document, options, userOpName)
+ else
+ let allowStaleResults =
+ match allowStaleResults with
+ | Some b -> b
+ | _ -> document.Project.IsFSharpStaleCompletionResultsEnabled
+
+ return!
+ checker.ParseAndCheckDocumentWithPossibleStaleResults(document, options, allowStaleResults, userOpName = userOpName)
}
[]
@@ -215,7 +274,7 @@ type Document with
let! checker, _, _, projectOptions = this.GetFSharpCompilationOptionsAsync(userOpName)
match! checker.ParseAndCheckDocument(this, projectOptions, userOpName, allowStaleResults = false) with
- | Some (parseResults, _, checkResults) -> return (parseResults, checkResults)
+ | Some results -> return results
| _ -> return raise (System.OperationCanceledException("Unable to get FSharp parse and check results."))
}
diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
index 9ecda0ff396..cd07b46b18e 100644
--- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
+++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
@@ -105,6 +105,7 @@ type AdvancedOptions =
IsInlineParameterNameHintsEnabled: bool
IsInlineReturnTypeHintsEnabled: bool
IsLiveBuffersEnabled: bool
+ UseTransparentCompiler: bool
}
static member Default =
@@ -115,6 +116,7 @@ type AdvancedOptions =
IsInlineParameterNameHintsEnabled = false
IsInlineReturnTypeHintsEnabled = false
IsLiveBuffersEnabled = FSharpExperimentalFeaturesEnabledAutomatically
+ UseTransparentCompiler = false
}
[]
@@ -238,3 +240,6 @@ module EditorOptionsExtensions =
member this.IsFastFindReferencesEnabled =
this.EditorOptions.LanguageServicePerformance.EnableFastFindReferencesAndRename
+
+ member this.UseTransparentCompiiler =
+ this.EditorOptions.Advanced.UseTransparentCompiler
diff --git a/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml b/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml
index 78afe373f84..7ecefa11f6f 100644
--- a/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml
+++ b/vsintegration/src/FSharp.UIResources/AdvancedOptionsControl.xaml
@@ -38,6 +38,10 @@
+
+
+
diff --git a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs
index 05c26ae57a3..5185ce665cc 100644
--- a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs
+++ b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs
@@ -447,6 +447,15 @@ public static string Tooltip_preferred_description_width_in_characters {
}
}
+ ///
+ /// Looks up a localized string similar to Transparent Compiler (experimental).
+ ///
+ public static string TransparentCompiler {
+ get {
+ return ResourceManager.GetString("TransparentCompiler", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Analyze and suggest fixes for unused values.
///
@@ -473,5 +482,14 @@ public static string Use_syntax_tree_cache {
return ResourceManager.GetString("Use_syntax_tree_cache", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to Use Transparent Compiler (restart required).
+ ///
+ public static string Use_Transparent_Compiler {
+ get {
+ return ResourceManager.GetString("Use_Transparent_Compiler", resourceCulture);
+ }
+ }
}
}
diff --git a/vsintegration/src/FSharp.UIResources/Strings.resx b/vsintegration/src/FSharp.UIResources/Strings.resx
index 98d089b053b..3db260b4c0f 100644
--- a/vsintegration/src/FSharp.UIResources/Strings.resx
+++ b/vsintegration/src/FSharp.UIResources/Strings.resx
@@ -255,4 +255,10 @@
Display return type hints (preview)
+
+ Transparent Compiler (experimental)
+
+
+ Use Transparent Compiler (restart required)
+
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf
index 8d56d2adbdd..5853389fa82 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf
@@ -147,6 +147,11 @@
Umožňuje formátovat podpis na danou šířku přidáním konců řádků odpovídajících pravidlům syntaxe F#.
+
+
+ Transparent Compiler (experimental)
+
+
Odebrat nepoužívané otevřené výkazy
@@ -227,6 +232,11 @@
Navrhovat názvy pro nerozpoznané identifikátory
+
+
+ Use Transparent Compiler (restart required)
+
+
Výsledky analýzy mezipaměti (experimentální)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf
index ea47f390c09..7d86580264b 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf
@@ -147,6 +147,11 @@
Formatieren Sie die Signatur in der angegebenen Breite, indem Sie Zeilenumbrüche hinzufügen, die F#-Syntaxregeln entsprechen.
+
+
+ Transparent Compiler (experimental)
+
+
Nicht verwendete "open"-Anweisungen entfernen
@@ -227,6 +232,11 @@
Namen für nicht aufgelöste Bezeichner vorschlagen
+
+
+ Use Transparent Compiler (restart required)
+
+
Cacheanalyseergebnisse (experimentell)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf
index d58237d68ba..49697e5b010 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf
@@ -147,6 +147,11 @@
Da formato a la firma al ancho dado agregando saltos de línea conforme a las reglas de sintaxis de F#.
+
+
+ Transparent Compiler (experimental)
+
+
Quitar instrucciones open no usadas
@@ -227,6 +232,11 @@
Sugerir nombres para los identificadores no resueltos
+
+
+ Use Transparent Compiler (restart required)
+
+
Resultados del análisis de la caché (experimental)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf
index 30ee652da68..4aa94e96d46 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf
@@ -147,6 +147,11 @@
Formatez la signature à la largeur donnée en ajoutant des sauts de ligne conformes aux règles de syntaxe F#.
+
+
+ Transparent Compiler (experimental)
+
+
Supprimer les instructions open inutilisées
@@ -227,6 +232,11 @@
Suggérer des noms pour les identificateurs non résolus
+
+
+ Use Transparent Compiler (restart required)
+
+
Résultats de l'analyse du cache (expérimental)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf
index 6b4009249b8..c146e523ef4 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf
@@ -147,6 +147,11 @@
Consente di formattare la firma in base alla larghezza specificata aggiungendo interruzioni di riga conformi alle regole di sintassi F#.
+
+
+ Transparent Compiler (experimental)
+
+
Rimuovi istruzioni OPEN inutilizzate
@@ -227,6 +232,11 @@
Suggerisci nomi per gli identificatori non risolti
+
+
+ Use Transparent Compiler (restart required)
+
+
Risultati dell'analisi della cache (sperimentale)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf
index 074852e1f72..1367bd628ff 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf
@@ -147,6 +147,11 @@
F# 構文規則に準拠した改行を追加して、署名を指定された幅に書式設定します。
+
+
+ Transparent Compiler (experimental)
+
+
未使用の Open ステートメントを削除する
@@ -227,6 +232,11 @@
未解決の識別子の名前を提案します
+
+
+ Use Transparent Compiler (restart required)
+
+
キャッシュ解析の結果 (試験段階)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf
index 369dc3d81cc..ce8eeb81b88 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf
@@ -147,6 +147,11 @@
F# 구문 규칙에 맞는 줄 바꿈을 추가하여 지정된 너비에 시그니처의 서식을 지정합니다.
+
+
+ Transparent Compiler (experimental)
+
+
사용되지 않는 open 문 제거
@@ -227,6 +232,11 @@
확인되지 않은 식별자의 이름 제안
+
+
+ Use Transparent Compiler (restart required)
+
+
캐시 구문 분석 결과(실험적)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf
index 8f85bfb4f67..947a7bfff5f 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf
@@ -147,6 +147,11 @@
Sformatuj sygnaturę na daną szerokość, dodając podziały wierszy zgodne z regułami składni języka F#.
+
+
+ Transparent Compiler (experimental)
+
+
Usuń nieużywane otwarte instrukcje
@@ -227,6 +232,11 @@
Sugeruj nazwy w przypadku nierozpoznanych identyfikatorów
+
+
+ Use Transparent Compiler (restart required)
+
+
Wyniki analizy pamięci podręcznej (eksperymentalne)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf
index 257b0f3f57a..9064b2678ff 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf
@@ -147,6 +147,11 @@
Formate a assinatura para a largura fornecida adicionando quebras de linha em conformidade com as regras de sintaxe F#.
+
+
+ Transparent Compiler (experimental)
+
+
Remover instruções abertas não usadas
@@ -227,6 +232,11 @@
Sugerir nomes para identificadores não resolvidos
+
+
+ Use Transparent Compiler (restart required)
+
+
Resultados da análise de cache (experimental)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf
index ed978ec293a..0c1210c1d2b 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf
@@ -147,6 +147,11 @@
Форматирование подписи до заданной ширины путем добавления разрывов строк, соответствующих правилам синтаксиса F#.
+
+
+ Transparent Compiler (experimental)
+
+
Удалить неиспользуемые открытые операторы
@@ -227,6 +232,11 @@
Предлагать имена для неразрешенных идентификаторов
+
+
+ Use Transparent Compiler (restart required)
+
+
Результаты анализа кэша (экспериментальная функция)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf
index 181076a632d..aea8a281677 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf
@@ -147,6 +147,11 @@
F# söz dizimi kurallarına uyan satır sonları ekleyerek imzayı belirtilen genişliğe biçimlendirin.
+
+
+ Transparent Compiler (experimental)
+
+
Kullanılmayan açık deyimleri kaldır
@@ -227,6 +232,11 @@
Çözümlenmemiş tanımlayıcılar için ad öner
+
+
+ Use Transparent Compiler (restart required)
+
+
Ayrıştırma sonuçlarını önbelleğe al (deneysel)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf
index 4fc3ff63c93..6012f77e8b7 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf
@@ -147,6 +147,11 @@
通过添加符合 F# 语法规则的换行符,将签名设置为给定宽度的格式。
+
+
+ Transparent Compiler (experimental)
+
+
删除未使用的 open 语句
@@ -227,6 +232,11 @@
为未解析标识符建议名称
+
+
+ Use Transparent Compiler (restart required)
+
+
缓存分析结果(实验性)
diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf
index 1b0248ea005..a62f9671cd9 100644
--- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf
+++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf
@@ -147,6 +147,11 @@
透過新增符合 F# 語法規則的分行符號,將簽章格式設定為指定寬度。
+
+
+ Transparent Compiler (experimental)
+
+
移除未使用的 open 陳述式
@@ -227,6 +232,11 @@
為未解析的識別碼建議名稱
+
+
+ Use Transparent Compiler (restart required)
+
+
快取剖析結果 (實驗性)
From c3fd50cf674f42419c3b14de7e151e5e7c07d36a Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Tue, 2 May 2023 12:11:45 +0200
Subject: [PATCH 011/222] wip
---
src/Compiler/Service/FSharpCheckerResults.fs | 35 +++++++++
src/Compiler/Service/FSharpCheckerResults.fsi | 2 +
src/Compiler/Service/service.fs | 2 +
src/Compiler/Service/service.fsi | 3 +
.../FSharp.Compiler.ComponentTests.fsproj | 13 ++--
.../ProjectGeneration.fs | 36 +++++++++-
.../LanguageService/WorkspaceExtensions.fs | 71 ++++++++-----------
7 files changed, 111 insertions(+), 51 deletions(-)
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 5b2dbb3cd54..5e419ab9431 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -366,6 +366,41 @@ type FSharpProjectSnapshot with
Stamp = this.Stamp
}
+ static member FromOptions(options: FSharpProjectOptions, getFileSnapshot) =
+ async {
+ let! sourceFiles =
+ options.SourceFiles
+ |> Seq.map (getFileSnapshot options)
+ |> Async.Parallel
+
+ let! referencedProjects =
+ options.ReferencedProjects
+ |> Seq.choose (function
+ | FSharpReferencedProject.FSharpReference (outputName, options) -> Some (
+ async {
+ let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
+ return FSharpReferencedProjectSnapshot.FSharpReference (outputName, snapshot)
+ })
+ // TODO: other types
+ | _ -> None)
+ |> Async.Parallel
+
+ return
+ {
+ ProjectFileName = options.ProjectFileName
+ ProjectId = options.ProjectId
+ SourceFiles = sourceFiles |> List.ofArray
+ OtherOptions = options.OtherOptions |> List.ofArray
+ ReferencedProjects = referencedProjects |> List.ofArray
+ IsIncompleteTypeCheckEnvironment = options.IsIncompleteTypeCheckEnvironment
+ UseScriptResolutionRules = options.UseScriptResolutionRules
+ LoadTime = options.LoadTime
+ UnresolvedReferences = options.UnresolvedReferences
+ OriginalLoadReferences = options.OriginalLoadReferences
+ Stamp = options.Stamp
+ }
+ }
+
[]
module internal FSharpCheckerResultsSettings =
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 20ecde853ea..e07f31afe90 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -248,6 +248,8 @@ type FSharpProjectSnapshot with
member ToOptions: unit -> FSharpProjectOptions
+ static member FromOptions: options: FSharpProjectOptions * getFileSnapshot: (FSharpProjectOptions -> string -> Async) -> Async
+
/// Represents the use of an F# symbol from F# source code
[]
type public FSharpSymbolUse =
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index 69b6f7186dc..83a005c258e 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -269,6 +269,8 @@ type FSharpChecker
useTransparentCompiler
)
+ member _.UsesTransparentCompiler = useTransparentCompiler = Some true
+
member _.ReferenceResolver = legacyReferenceResolver
member _.MatchBraces(fileName, sourceText: ISourceText, options: FSharpParsingOptions, ?userOpName: string) =
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index 45522fa3126..97bde85058f 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -60,6 +60,9 @@ type public FSharpChecker =
[] ?useTransparentCompiler: bool ->
FSharpChecker
+ []
+ member UsesTransparentCompiler: bool
+
///
/// Parse a source code file, returning information about brace matching in the file.
/// Return an enumeration of the matching parenthetical tokens in the file.
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
index bc4a072aee6..b47712251d2 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
+++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
@@ -222,12 +222,9 @@
-
-
-
-
- %(RelativeDir)TestSource\%(Filename)%(Extension)
-
+
+
+
@@ -249,8 +246,12 @@
+
+
+ %(RelativeDir)TestSource\%(Filename)%(Extension)
+
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index c43e0c88446..a395002d2b0 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -17,6 +17,7 @@ module FSharp.Test.ProjectGeneration
open System
open System.IO
+open System.Threading.Tasks
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.Text
@@ -328,7 +329,7 @@ module ProjectOperations =
let addSignatureFile f =
{ f with SignatureFile = AutoGenerated }
- let checkFile fileId (project: SyntheticProject) (checker: FSharpChecker) =
+ let checkFileWithIncrementalBuilder fileId (project: SyntheticProject) (checker: FSharpChecker) =
let file = project.Find fileId
let contents = renderSourceFile project file
let absFileName = getFilePath project file
@@ -340,6 +341,33 @@ module ProjectOperations =
project.GetProjectOptions checker
)
+ let getFileSnapshot (project: SyntheticProject) _options path =
+ async {
+ let file = project.FindByPath path
+ let version = $"{file.PublicVersion}.{file.InternalVersion}.{file.Source.GetHashCode()}.{file.ExtraSource.GetHashCode()}"
+
+ return {
+ FileName = file.FileName
+ Version = version
+ GetSource = fun () -> renderSourceFile project file |> SourceText.ofString |> Task.FromResult
+ }
+ }
+
+ let checkFileWithTransparentCompiler fileId (project: SyntheticProject) (checker: FSharpChecker) =
+ async {
+ let file = project.Find fileId
+ let absFileName = getFilePath project file
+ let options = project.GetProjectOptions checker
+ let! projectSnapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot project)
+ return! checker.ParseAndCheckFileInProject(absFileName, projectSnapshot)
+ }
+
+ let checkFile fileId (project: SyntheticProject) (checker: FSharpChecker) =
+ (if checker.UsesTransparentCompiler then
+ checkFileWithTransparentCompiler
+ else
+ checkFileWithIncrementalBuilder) fileId project checker
+
let getTypeCheckResult (parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileAnswer) =
Assert.True(not parseResults.ParseHadErrors)
@@ -545,11 +573,13 @@ type ProjectWorkflowBuilder
?checker: FSharpChecker,
?useGetSource,
?useChangeNotifications,
- ?useSyntaxTreeCache
+ ?useSyntaxTreeCache,
+ ?useTransparentCompiler
) =
let useGetSource = defaultArg useGetSource false
let useChangeNotifications = defaultArg useChangeNotifications false
+ let useTransparentCompiler = defaultArg useTransparentCompiler false
let mutable latestProject = initialProject
@@ -579,7 +609,7 @@ type ProjectWorkflowBuilder
captureIdentifiersWhenParsing = true,
documentSource = (if useGetSource then DocumentSource.Custom getSource else DocumentSource.FileSystem),
useSyntaxTreeCache = defaultArg useSyntaxTreeCache false,
- useTransparentCompiler = true
+ useTransparentCompiler = useTransparentCompiler
))
let mapProjectAsync f workflow =
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
index d7053340933..4e9f681dc96 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
@@ -31,51 +31,38 @@ module private CheckerExtensions =
userOpName: string
) =
async {
- let fileName = document.FilePath
+
let project = document.Project
- let documents = project.Documents |> Seq.map (fun d -> d.FilePath, d) |> Map
-
- let! sourceFiles =
- options.SourceFiles
- |> Seq.map (fun path ->
- async {
- let document = documents[path]
- let! version = document.GetTextVersionAsync() |> Async.AwaitTask
-
- let getSource () =
- task {
- let! sourceText = document.GetTextAsync()
- return sourceText.ToFSharpSourceText()
- }
-
- return
- {
- FileName = path
- Version = version.ToString()
- GetSource = getSource
- }
- })
- |> Async.Parallel
-
- // TODO: referenced projects
- let referencedProjects = []
-
- let projectSnapshot: FSharpProjectSnapshot =
- {
- ProjectFileName = options.ProjectFileName
- ProjectId = options.ProjectId
- SourceFiles = sourceFiles |> List.ofArray
- OtherOptions = options.OtherOptions |> List.ofArray
- ReferencedProjects = referencedProjects
- IsIncompleteTypeCheckEnvironment = options.IsIncompleteTypeCheckEnvironment
- UseScriptResolutionRules = options.UseScriptResolutionRules
- LoadTime = options.LoadTime
- UnresolvedReferences = options.UnresolvedReferences
- OriginalLoadReferences = options.OriginalLoadReferences
- Stamp = options.Stamp
+ let solution = project.Solution
+ // TODO cache?
+ let projects =
+ solution.Projects
+ |> Seq.map (fun p -> p.FilePath, p.Documents |> Seq.map (fun d -> d.FilePath, d) |> Map)
+ |> Map
+
+ let getFileSnapshot (options: FSharpProjectOptions) path =
+ async {
+ let project = projects[options.ProjectFileName]
+ let document = project[path]
+ let! version = document.GetTextVersionAsync() |> Async.AwaitTask
+
+ let getSource () =
+ task {
+ let! sourceText = document.GetTextAsync()
+ return sourceText.ToFSharpSourceText()
+ }
+
+ return
+ {
+ FileName = path
+ Version = version.ToString()
+ GetSource = getSource
+ }
}
- let! (parseResults, checkFileAnswer) = checker.ParseAndCheckFileInProject(fileName, projectSnapshot, userOpName)
+ let! projectSnapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
+
+ let! (parseResults, checkFileAnswer) = checker.ParseAndCheckFileInProject(document.FilePath, projectSnapshot, userOpName)
return
match checkFileAnswer with
From 831ed47840851823248ac49244fbe5338fb17a4c Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Tue, 2 May 2023 18:15:15 +0200
Subject: [PATCH 012/222] wip
---
src/Compiler/Facilities/AsyncMemoize.fs | 9 +-
src/Compiler/Service/TransparentCompiler.fs | 19 ++--
.../CompilerService/AsyncMemoize.fs | 7 +-
.../FSharpChecker/CommonWorkflows.fs | 1 -
.../FSharpChecker/TransparentCompiler.fs | 91 +++++++++++++++++++
.../ProjectGeneration.fs | 24 +++--
6 files changed, 126 insertions(+), 25 deletions(-)
create mode 100644 tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
index 960d2d0eeda..220c27c8e96 100644
--- a/src/Compiler/Facilities/AsyncMemoize.fs
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -3,6 +3,7 @@ namespace Internal.Utilities.Collections
open FSharp.Compiler.BuildGraph
open System.Threading
open System.Collections.Generic
+open FSharp.Compiler.Diagnostics
type internal Action<'TKey, 'TValue> =
| GetOrCompute of ('TKey -> NodeCode<'TValue>) * CancellationToken
@@ -26,10 +27,12 @@ type internal JobEvent<'TKey> =
| Finished key -> key
| Canceled key -> key
-type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?eventLog: ResizeArray>) =
+type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobEvent<'TKey> -> unit), ?name: string) =
let tok = obj ()
+ let name = name |> Option.defaultValue "Unnamed"
+
let cache =
MruCache<_, 'TKey, Job<'TValue>>(keepStrongly = 10, areSame = (fun (x, y) -> x = y))
@@ -46,7 +49,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?eventLog: Resiz
inbox.PostAndAsyncReply(fun rc -> key, msg, rc) |> Async.Ignore |> Async.Start
let log event =
- eventLog |> Option.iter (fun log -> log.Add event)
+ logEvent |> Option.iter ((|>) event)
let agent =
MailboxProcessor.Start(fun (inbox: MailboxProcessor>) ->
@@ -74,6 +77,8 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?eventLog: Resiz
Async.StartAsTask(
Async.AwaitNodeCode(
node {
+ use _ = Activity.start $"AsyncMemoize.{name}" [| |]
+
let! result = computation key
post key JobCompleted
return result
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 81a2406d811..2ee026bc7aa 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -73,13 +73,13 @@ type internal TransparentCompiler
// Is having just one of these ok?
let lexResourceManager = Lexhelp.LexResourceManager()
- let ParseFileCache = AsyncMemoize()
- let ParseAndCheckFileInProjectCache = AsyncMemoize()
- let FrameworkImportsCache = AsyncMemoize()
- let BootstrapInfoCache = AsyncMemoize()
- let TcPriorCache = AsyncMemoize()
- let TcIntermediateCache = AsyncMemoize()
- let DependencyGraphForLastFileCache = AsyncMemoize()
+ let ParseFileCache = AsyncMemoize(name = "ParseFile")
+ let ParseAndCheckFileInProjectCache = AsyncMemoize(name = "ParseAndCheckFileInProject")
+ let FrameworkImportsCache = AsyncMemoize(name = "FrameworkImports")
+ let BootstrapInfoCache = AsyncMemoize(name = "BootstrapInfo")
+ let TcPriorCache = AsyncMemoize(name = "TcPrior")
+ let TcIntermediateCache = AsyncMemoize(name = "TcIntermediate")
+ let DependencyGraphForLastFileCache = AsyncMemoize(name = "DependencyGraphForLastFile")
// We currently share one global dependency provider for all scripts for the FSharpChecker.
// For projects, one is used per project.
@@ -699,6 +699,7 @@ type internal TransparentCompiler
let mergeTcInfos =
Array.fold (fun a b ->
+ // TODO: proper merge
{ a with
tcState = b.tcState
tcEnvAtEndOfFile = b.tcEnvAtEndOfFile
@@ -768,7 +769,7 @@ type internal TransparentCompiler
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
node {
- let! bootstrapInfoOpt, creationDiags = BootstrapInfoCache.Get(projectSnapshot.Key, ComputeBootstrapInfo projectSnapshot) // probably cache
+ let! bootstrapInfoOpt, creationDiags = BootstrapInfoCache.Get(projectSnapshot.Key, ComputeBootstrapInfo projectSnapshot)
match bootstrapInfoOpt with
| None ->
@@ -779,7 +780,7 @@ type internal TransparentCompiler
| Some bootstrapInfo ->
let file =
- bootstrapInfo.SourceFiles |> List.find (fun f -> f.Source.FileName = fileName)
+ bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
let priorSnapshot = projectSnapshot.UpTo fileName
let! tcInfo = TcPriorCache.Get(priorSnapshot.Key, ComputeTcPrior file bootstrapInfo priorSnapshot userOpName)
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
index 78123ef4efd..4d18dbbbbac 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -18,7 +18,7 @@ let ``Basics``() =
let eventLog = ResizeArray()
- let memoize = AsyncMemoize(eventLog)
+ let memoize = AsyncMemoize(eventLog.Add)
let task =
NodeCode.Parallel(seq {
@@ -50,7 +50,7 @@ let ``We can cancel a job`` () =
}
let eventLog = ResizeArray()
- let memoize = AsyncMemoize(eventLog)
+ let memoize = AsyncMemoize(eventLog.Add)
use cts1 = new CancellationTokenSource()
use cts2 = new CancellationTokenSource()
@@ -91,7 +91,7 @@ let ``Job keeps running even if first requestor cancels`` () =
}
let eventLog = ResizeArray()
- let memoize = AsyncMemoize(eventLog)
+ let memoize = AsyncMemoize(eventLog.Add)
use cts1 = new CancellationTokenSource()
use cts2 = new CancellationTokenSource()
@@ -111,5 +111,6 @@ let ``Job keeps running even if first requestor cancels`` () =
let result = _task2.Result
Assert.Equal(2, result)
+ Thread.Sleep 1 // Wait for event log to be updated
Assert.Equal array>([| Started key; Finished key |], eventLog |> Seq.toArray )
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs
index 7aa8dfc25a3..21864e64ed4 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs
@@ -132,4 +132,3 @@ let ``Using getSource and notifications instead of filesystem`` () =
checkFile middle expectSignatureChanged
checkFile last expectSignatureChanged
}
-
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
new file mode 100644
index 00000000000..4c93a1b4d0c
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -0,0 +1,91 @@
+module FSharp.Compiler.ComponentTests.FSharpChecker.TransparentCompiler
+
+open System
+open System.IO
+open System.Diagnostics
+
+open Xunit
+
+open FSharp.Test.ProjectGeneration
+open FSharp.Compiler.Text
+open FSharp.Compiler.CodeAnalysis
+
+module Activity =
+ let listen (filter: string) =
+ let indent (activity: Activity) =
+ let rec loop (activity: Activity) n =
+ if activity.Parent <> null then
+ loop (activity.Parent) (n + 1)
+ else
+ n
+
+ String.replicate (loop activity 0) " "
+
+ let collectTags (activity: Activity) =
+ [ for tag in activity.Tags -> $"{tag.Key}: %A{tag.Value}" ]
+ |> String.concat ", "
+
+ let listener =
+ new ActivityListener(
+ ShouldListenTo = (fun source -> source.Name = FSharp.Compiler.Diagnostics.ActivityNames.FscSourceName),
+ Sample =
+ (fun context ->
+ if context.Name.Contains(filter) then
+ ActivitySamplingResult.AllDataAndRecorded
+ else
+ ActivitySamplingResult.None),
+ ActivityStarted = (fun a -> Trace.TraceInformation $"{indent a}{a.OperationName} {collectTags a}")
+ )
+
+ ActivitySource.AddActivityListener(listener)
+
+ let listenToAll () = listen ""
+
+
+[]
+let ``Use Transparent Compiler`` () =
+
+ let _logger = Activity.listenToAll ()
+
+ let size = 20
+
+ let project =
+ { SyntheticProject.Create() with
+ SourceFiles = [
+ sourceFile $"File%03d{0}" []
+ for i in 1..size do
+ sourceFile $"File%03d{i}" [$"File%03d{i-1}"]
+ ]
+ }
+
+ let first = "File001"
+ let middle = $"File%03d{size / 2}"
+ let last = $"File%03d{size}"
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ updateFile first updatePublicSurface
+ checkFile first expectSignatureChanged
+ checkFile last expectSignatureChanged
+ updateFile middle updatePublicSurface
+ checkFile last expectSignatureChanged
+ addFileAbove middle (sourceFile "addedFile" [first])
+ updateFile middle (addDependency "addedFile")
+ checkFile middle expectSignatureChanged
+ checkFile last expectSignatureChanged
+ }
+
+[]
+let ``Parallel processing`` () =
+
+ let _logger = Activity.listenToAll ()
+
+ let project = SyntheticProject.Create(
+ sourceFile "A" [],
+ sourceFile "B" ["A"],
+ sourceFile "C" ["A"],
+ sourceFile "D" ["A"],
+ sourceFile "E" ["B"; "C"; "D"])
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ checkFile "E" expectOk
+ }
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index a395002d2b0..73082a5df5f 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -344,10 +344,11 @@ module ProjectOperations =
let getFileSnapshot (project: SyntheticProject) _options path =
async {
let file = project.FindByPath path
- let version = $"{file.PublicVersion}.{file.InternalVersion}.{file.Source.GetHashCode()}.{file.ExtraSource.GetHashCode()}"
+ let dependencies = file.DependsOn |> String.concat "|"
+ let version = $"{file.PublicVersion}.{file.InternalVersion}.{file.Source.GetHashCode()}.{file.ExtraSource.GetHashCode()}.{dependencies}"
return {
- FileName = file.FileName
+ FileName = getFilePath project file
Version = version
GetSource = fun () -> renderSourceFile project file |> SourceText.ofString |> Task.FromResult
}
@@ -551,14 +552,17 @@ let SaveAndCheckProject project checker =
if not (Array.isEmpty results.Diagnostics) then
failwith $"Project {project.Name} failed initial check: \n%A{results.Diagnostics}"
- let! signatures =
- Async.Sequential
- [ for file in project.SourceFiles do
- async {
- let! result = checkFile file.Id project checker
- let signature = getSignature result
- return file.Id, signature
- } ]
+ // TODO: re-enable
+ //let! signatures =
+ // Async.Sequential
+ // [ for file in project.SourceFiles do
+ // async {
+ // let! result = checkFile file.Id project checker
+ // let signature = getSignature result
+ // return file.Id, signature
+ // } ]
+
+ let signatures = [ for file in project.SourceFiles -> file.Id, "" ]
return
{ Project = project
From 88593d0949316875708997b4ebe8c98a17f74acc Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Wed, 3 May 2023 13:23:42 +0200
Subject: [PATCH 013/222] wip
---
src/Compiler/Service/IncrementalBuild.fs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs
index 8d48ec4503b..dc27983338e 100644
--- a/src/Compiler/Service/IncrementalBuild.fs
+++ b/src/Compiler/Service/IncrementalBuild.fs
@@ -262,7 +262,7 @@ type BoundModel private (
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
beforeFileChecked.Trigger fileName
-
+
ApplyMetaCommandsFromInputToTcConfig (tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider) |> ignore
let sink = TcResultsSinkImpl(tcGlobals)
let hadParseErrors = not (Array.isEmpty parseErrors)
@@ -328,7 +328,7 @@ type BoundModel private (
let getTcInfoExtras (typeCheck: GraphNode) =
node {
- let! _x , sink, implFile, fileName = typeCheck.GetOrComputeValue()
+ let! _ , sink, implFile, fileName = typeCheck.GetOrComputeValue()
// Build symbol keys
let itemKeyStore, semanticClassification =
if enableBackgroundItemKeyStoreAndSemanticClassification then
From 0dcc16393f0056ea37679fd68c34447019670640 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Wed, 3 May 2023 17:56:35 +0200
Subject: [PATCH 014/222] wip
---
src/Compiler/Service/TransparentCompiler.fs | 29 +--------------------
1 file changed, 1 insertion(+), 28 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 2ee026bc7aa..de41d47b82b 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -557,34 +557,6 @@ type internal TransparentCompiler
return bootstrapInfoOpt, diagnostics
}
- let ComputeParseFile' (file: FSharpFile) (projectSnapshot: FSharpProjectSnapshot) bootstrapInfo userOpName _key =
- node {
-
- let parsingOptions =
- FSharpParsingOptions.FromTcConfig(
- bootstrapInfo.TcConfig,
- projectSnapshot.SourceFiles |> Seq.map (fun f -> f.FileName) |> Array.ofSeq,
- projectSnapshot.UseScriptResolutionRules
- )
-
- // TODO: what is this?
- // GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang
-
- let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
-
- let diagnostics, parsedInput, anyErrors =
- ParseAndCheckFile.parseFile (
- sourceText,
- file.Source.FileName,
- parsingOptions,
- userOpName,
- suggestNamesForErrors,
- captureIdentifiersWhenParsing
- )
-
- return diagnostics, parsedInput, anyErrors, sourceText
- }
-
let ComputeParseFile (file: FSharpFile) bootstrapInfo _key =
node {
let tcConfig = bootstrapInfo.TcConfig
@@ -621,6 +593,7 @@ type internal TransparentCompiler
// TODO: we will probably want to cache and re-use larger graphs if available
let graph =
DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
+ |> fst
|> Graph.subGraphFor (sourceFiles |> Array.last).Idx
return graph, filePairs
From 68c1c03b4e988bff9030097ff3c13f541246230e Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Thu, 4 May 2023 16:22:43 +0200
Subject: [PATCH 015/222] wip
---
src/Compiler/Driver/ParseAndCheckInputs.fsi | 13 +++++++
src/Compiler/Service/TransparentCompiler.fs | 37 ++++++++++++++-----
.../TypeChecks/Graph/GraphOperations.fs | 1 +
3 files changed, 42 insertions(+), 9 deletions(-)
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi
index 745afa51be4..307236f8014 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fsi
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi
@@ -13,6 +13,7 @@ open FSharp.Compiler.CompilerImports
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.DependencyManager
open FSharp.Compiler.DiagnosticsLogger
+open FSharp.Compiler.NameResolution
open FSharp.Compiler.Syntax
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
@@ -151,6 +152,18 @@ val CheckOneInput:
input: ParsedInput ->
Cancellable<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState>
+val AddCheckResultsToTcState:
+ tcGlobals: TcGlobals *
+ amap: Import.ImportMap *
+ hadSig: bool *
+ prefixPathOpt: LongIdent option *
+ tcSink: TcResultsSink *
+ tcImplEnv: TcEnv *
+ qualNameOfFile: QualifiedNameOfFile *
+ implFileSigType: ModuleOrNamespaceType ->
+ tcState: TcState ->
+ ModuleOrNamespaceType * TcState
+
/// Finish the checking of multiple inputs
val CheckMultipleInputsFinish:
(TcEnv * TopAttribs * 'T option * 'U) list * TcState -> (TcEnv * TopAttribs * 'T list * 'U list) * TcState
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index de41d47b82b..ccd2b065f7e 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -32,6 +32,7 @@ open FSharp.Compiler.Syntax
open FSharp.Compiler.CompilerDiagnostics
open FSharp.Compiler.NameResolution
open Internal.Utilities.Library.Extras
+open FSharp.Compiler.TypedTree
type internal FSharpFile =
{
@@ -52,6 +53,8 @@ type internal BootstrapInfo =
LoadClosure: LoadClosure option
}
+type internal TcIntermediateResult = TcInfo * TcResultsSinkImpl * CheckedImplFile option * string
+
type internal TransparentCompiler
(
legacyReferenceResolver,
@@ -165,9 +168,9 @@ type internal TransparentCompiler
unresolvedReferences,
dependencyProvider,
loadClosureOpt: LoadClosure option,
- basicDependencies,
+ basicDependencies
#if !NO_TYPEPROVIDERS
- importsInvalidatedByTypeProvider: Event
+ ,importsInvalidatedByTypeProvider: Event
#endif
) =
@@ -484,9 +487,9 @@ type internal TransparentCompiler
unresolvedReferences,
dependencyProvider,
loadClosureOpt,
- basicDependencies,
+ basicDependencies
#if !NO_TYPEPROVIDERS
- importsInvalidatedByTypeProvider
+ ,importsInvalidatedByTypeProvider
#endif
)
@@ -670,11 +673,27 @@ type internal TransparentCompiler
return tcInfo, sink, implFile, fileName
}
- let mergeTcInfos =
- Array.fold (fun a b ->
+ let mergeIntermediateResults bootstrapInfo =
+ Array.reduce (fun (a: TcInfo, _: TcResultsSinkImpl, _, _) (b, bSink, implFileOpt: CheckedImplFile option, name) ->
// TODO: proper merge
+
+ let amap = bootstrapInfo.TcImports.GetImportMap()
+
+ // TODO: figure out
+ let hadSig = false
+
+ let prefixPathOpt = None
+
+ // TODO:
+ let implFile = implFileOpt.Value
+
+ let _ccuSigForFile, tcState =
+ AddCheckResultsToTcState
+ (bootstrapInfo.TcGlobals, amap, hadSig, prefixPathOpt, TcResultsSink.NoSink, b.tcState.TcEnvFromImpls, implFile.QualifiedNameOfFile, implFile.Signature)
+ a.tcState
+
{ a with
- tcState = b.tcState
+ tcState = tcState
tcEnvAtEndOfFile = b.tcEnvAtEndOfFile
moduleNamesDict = b.moduleNamesDict
latestCcuSigForFile = b.latestCcuSigForFile
@@ -683,7 +702,7 @@ type internal TransparentCompiler
tcDependencyFiles = b.tcDependencyFiles @ a.tcDependencyFiles
// we shouldn't need this with graph checking (?)
sigNameOpt = None
- })
+ }, bSink, Some implFile, name)
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName _key =
@@ -733,7 +752,7 @@ type internal TransparentCompiler
TcIntermediateCache.Get(key, ComputeTcIntermediate (parsedInput, parseErrors) bootstrapInfo tcInfo))
|> NodeCode.Parallel
- return! processLayer rest (mergeTcInfos tcInfo (results |> Array.map p14))
+ return! processLayer rest (mergeIntermediateResults bootstrapInfo results |> p14)
}
return! processLayer layers bootstrapInfo.InitialTcInfo
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
index 95d966441e1..f8e58f352a9 100644
--- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
@@ -65,6 +65,7 @@ let ``See what this does`` () =
let fullGraph =
DependencyResolution.mkGraph false filePairs sourceFiles
+ |> fst
|> Graph.map (fun idx -> project.SourceFilePaths[idx] |> Path.GetFileName)
let subGraph = fullGraph |> Graph.subGraphFor "FileF.fs"
From 09a522fc7482b92b826dddbfe028864911699ae6 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 4 May 2023 17:49:25 +0200
Subject: [PATCH 016/222] wip
---
src/Compiler/Service/TransparentCompiler.fs | 14 +++++++-------
.../FSharpChecker/TransparentCompiler.fs | 4 ++--
.../ProjectGeneration.fs | 19 ++++++++-----------
3 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index ccd2b065f7e..9775fc871e4 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -674,7 +674,7 @@ type internal TransparentCompiler
}
let mergeIntermediateResults bootstrapInfo =
- Array.reduce (fun (a: TcInfo, _: TcResultsSinkImpl, _, _) (b, bSink, implFileOpt: CheckedImplFile option, name) ->
+ Array.fold (fun (a: TcInfo, _, _, _) (b, sink, implFileOpt: CheckedImplFile option, name) ->
// TODO: proper merge
let amap = bootstrapInfo.TcImports.GetImportMap()
@@ -687,22 +687,22 @@ type internal TransparentCompiler
// TODO:
let implFile = implFileOpt.Value
- let _ccuSigForFile, tcState =
+ let ccuSigForFile, tcState =
AddCheckResultsToTcState
- (bootstrapInfo.TcGlobals, amap, hadSig, prefixPathOpt, TcResultsSink.NoSink, b.tcState.TcEnvFromImpls, implFile.QualifiedNameOfFile, implFile.Signature)
- a.tcState
+ (bootstrapInfo.TcGlobals, amap, hadSig, prefixPathOpt, TcResultsSink.NoSink, a.tcState.TcEnvFromImpls, implFile.QualifiedNameOfFile, implFile.Signature)
+ b.tcState
{ a with
tcState = tcState
tcEnvAtEndOfFile = b.tcEnvAtEndOfFile
moduleNamesDict = b.moduleNamesDict
- latestCcuSigForFile = b.latestCcuSigForFile
+ latestCcuSigForFile = Some ccuSigForFile
tcDiagnosticsRev = b.tcDiagnosticsRev @ a.tcDiagnosticsRev
topAttribs = b.topAttribs
tcDependencyFiles = b.tcDependencyFiles @ a.tcDependencyFiles
// we shouldn't need this with graph checking (?)
sigNameOpt = None
- }, bSink, Some implFile, name)
+ }, sink, Some implFile, name)
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName _key =
@@ -752,7 +752,7 @@ type internal TransparentCompiler
TcIntermediateCache.Get(key, ComputeTcIntermediate (parsedInput, parseErrors) bootstrapInfo tcInfo))
|> NodeCode.Parallel
- return! processLayer rest (mergeIntermediateResults bootstrapInfo results |> p14)
+ return! processLayer rest (mergeIntermediateResults bootstrapInfo (tcInfo, Unchecked.defaultof<_>, None, "") results |> p14)
}
return! processLayer layers bootstrapInfo.InitialTcInfo
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 4c93a1b4d0c..d619d9e45c1 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -45,7 +45,7 @@ module Activity =
[]
let ``Use Transparent Compiler`` () =
- let _logger = Activity.listenToAll ()
+ Activity.listenToAll ()
let size = 20
@@ -77,7 +77,7 @@ let ``Use Transparent Compiler`` () =
[]
let ``Parallel processing`` () =
- let _logger = Activity.listenToAll ()
+ Activity.listenToAll ()
let project = SyntheticProject.Create(
sourceFile "A" [],
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 73082a5df5f..16d42718f1e 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -552,17 +552,14 @@ let SaveAndCheckProject project checker =
if not (Array.isEmpty results.Diagnostics) then
failwith $"Project {project.Name} failed initial check: \n%A{results.Diagnostics}"
- // TODO: re-enable
- //let! signatures =
- // Async.Sequential
- // [ for file in project.SourceFiles do
- // async {
- // let! result = checkFile file.Id project checker
- // let signature = getSignature result
- // return file.Id, signature
- // } ]
-
- let signatures = [ for file in project.SourceFiles -> file.Id, "" ]
+ let! signatures =
+ Async.Sequential
+ [ for file in project.SourceFiles do
+ async {
+ let! result = checkFile file.Id project checker
+ let signature = getSignature result
+ return file.Id, signature
+ } ]
return
{ Project = project
From dd518d825e12006fd01856528940646073a29e7f Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 4 May 2023 17:53:14 +0200
Subject: [PATCH 017/222] fantomas
---
.fantomasignore | 1 +
src/Compiler/Driver/ParseAndCheckInputs.fsi | 2 +-
src/Compiler/Facilities/AsyncMemoize.fs | 5 ++---
src/Compiler/Service/FSharpCheckerResults.fs | 17 ++++++++---------
src/Compiler/Service/FSharpCheckerResults.fsi | 4 +++-
5 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/.fantomasignore b/.fantomasignore
index d2f57d7fc7f..f9924a137aa 100644
--- a/.fantomasignore
+++ b/.fantomasignore
@@ -91,6 +91,7 @@ src/FSharp.Core/seqcore.fs
src/Compiler/AbstractIL/ilwrite.fs
src/Compiler/Utilities/lib.fs
src/Compiler/Service/IncrementalBuild.fs
+src/Compiler/Service/TransparentCompiler.fs
src/Compiler/Service/ServiceAssemblyContent.fs
src/Compiler/Service/ServiceDeclarationLists.fs
src/Compiler/Service/ServiceErrorResolutionHints.fs
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi
index 307236f8014..9d2bb5b9e41 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fsi
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi
@@ -162,7 +162,7 @@ val AddCheckResultsToTcState:
qualNameOfFile: QualifiedNameOfFile *
implFileSigType: ModuleOrNamespaceType ->
tcState: TcState ->
- ModuleOrNamespaceType * TcState
+ ModuleOrNamespaceType * TcState
/// Finish the checking of multiple inputs
val CheckMultipleInputsFinish:
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
index 220c27c8e96..8cb38c9540d 100644
--- a/src/Compiler/Facilities/AsyncMemoize.fs
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -48,8 +48,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
let sendAsync (inbox: MailboxProcessor<_>) key msg =
inbox.PostAndAsyncReply(fun rc -> key, msg, rc) |> Async.Ignore |> Async.Start
- let log event =
- logEvent |> Option.iter ((|>) event)
+ let log event = logEvent |> Option.iter ((|>) event)
let agent =
MailboxProcessor.Start(fun (inbox: MailboxProcessor>) ->
@@ -77,7 +76,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
Async.StartAsTask(
Async.AwaitNodeCode(
node {
- use _ = Activity.start $"AsyncMemoize.{name}" [| |]
+ use _ = Activity.start $"AsyncMemoize.{name}" [||]
let! result = computation key
post key JobCompleted
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 5e419ab9431..9f7973d90c7 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -368,19 +368,18 @@ type FSharpProjectSnapshot with
static member FromOptions(options: FSharpProjectOptions, getFileSnapshot) =
async {
- let! sourceFiles =
- options.SourceFiles
- |> Seq.map (getFileSnapshot options)
- |> Async.Parallel
+ let! sourceFiles = options.SourceFiles |> Seq.map (getFileSnapshot options) |> Async.Parallel
let! referencedProjects =
options.ReferencedProjects
|> Seq.choose (function
- | FSharpReferencedProject.FSharpReference (outputName, options) -> Some (
- async {
- let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
- return FSharpReferencedProjectSnapshot.FSharpReference (outputName, snapshot)
- })
+ | FSharpReferencedProject.FSharpReference (outputName, options) ->
+ Some(
+ async {
+ let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
+ return FSharpReferencedProjectSnapshot.FSharpReference(outputName, snapshot)
+ }
+ )
// TODO: other types
| _ -> None)
|> Async.Parallel
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index e07f31afe90..43052e69f9c 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -248,7 +248,9 @@ type FSharpProjectSnapshot with
member ToOptions: unit -> FSharpProjectOptions
- static member FromOptions: options: FSharpProjectOptions * getFileSnapshot: (FSharpProjectOptions -> string -> Async) -> Async
+ static member FromOptions:
+ options: FSharpProjectOptions * getFileSnapshot: (FSharpProjectOptions -> string -> Async) ->
+ Async
/// Represents the use of an F# symbol from F# source code
[]
From f2bd3494e017f994aeb9cf72256c9990182d2a35 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 4 May 2023 19:34:39 +0200
Subject: [PATCH 018/222] tests
---
.../CompilerService/AsyncMemoize.fs | 2 +
...ervice.SurfaceArea.netstandard20.debug.bsl | 126 +++++++++++++++++-
...vice.SurfaceArea.netstandard20.release.bsl | 123 ++++++++++++++++-
3 files changed, 248 insertions(+), 3 deletions(-)
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
index 4d18dbbbbac..2dae1fab2e4 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -69,6 +69,8 @@ let ``We can cancel a job`` () =
cts1.Cancel()
cts2.Cancel()
+ Thread.Sleep 10
+
Assert.Equal array>([| Started key |], eventLog |> Seq.toArray )
cts3.Cancel()
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
index 7b5b7a8f4dd..32d9d761d36 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
@@ -1961,6 +1961,16 @@ FSharp.Compiler.CodeAnalysis.DocumentSource: FSharp.Compiler.CodeAnalysis.Docume
FSharp.Compiler.CodeAnalysis.DocumentSource: Int32 Tag
FSharp.Compiler.CodeAnalysis.DocumentSource: Int32 get_Tag()
FSharp.Compiler.CodeAnalysis.DocumentSource: System.String ToString()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 braceMatchCacheSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 checkFileInProjectCacheSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 frameworkTcImportsCacheStrongSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_braceMatchCacheSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_checkFileInProjectCacheSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_frameworkTcImportsCacheStrongSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_parseFileCacheSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_projectCacheSizeDefault()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 parseFileCacheSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 projectCacheSizeDefault
FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults Item
FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_Item()
FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Tags: Int32 Aborted
@@ -2031,7 +2041,9 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols.
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles()
-FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Boolean UsesTransparentCompiler
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Boolean get_UsesTransparentCompiler()
+FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance()
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
@@ -2050,6 +2062,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyFileChanged(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2073,6 +2086,18 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Void ClearCache(System.Collections.G
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void InvalidateAll()
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void InvalidateConfiguration(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]] GetSource
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]] get_GetSource()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String FileName
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String Version
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_FileName()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_Version()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] Key
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] get_Key()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Void .ctor(System.String, System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]])
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPosContainedInApplication(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPositionContainedInACurriedParameter(FSharp.Compiler.Text.Position)
@@ -2165,6 +2190,65 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: System.String[] SourceFiles
FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: System.String[] get_OtherOptions()
FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: System.String[] get_SourceFiles()
FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], System.String[], System.String[], FSharp.Compiler.CodeAnalysis.FSharpReferencedProject[], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64])
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean Equals(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean IsIncompleteTypeCheckEnvironment
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean UseScriptResolutionRules
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_IsIncompleteTypeCheckEnvironment()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_UseScriptResolutionRules()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ToOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(Int32)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey Key
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] SourceFiles
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] get_SourceFiles()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot] ReferencedProjects
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot] get_ReferencedProjects()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] SourceFileNames
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_SourceFileNames()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] OriginalLoadReferences
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] get_OriginalLoadReferences()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot]]])
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet] UnresolvedReferences
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet] get_UnresolvedReferences()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.Int64] Stamp
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.Int64] get_Stamp()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] ProjectId
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_ProjectId()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.DateTime LoadTime
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.DateTime get_LoadTime()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ProjectFileName
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String get_ProjectFileName()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64])
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean IsIncompleteTypeCheckEnvironment
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean UseScriptResolutionRules
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_IsIncompleteTypeCheckEnvironment()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_UseScriptResolutionRules()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] ReferencedProjects
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] get_ReferencedProjects()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] SourceFiles
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] get_SourceFiles()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ProjectFileName
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String get_ProjectFileName()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey], Boolean, Boolean)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Boolean Equals(System.Object)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFromILModuleReader(System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader])
@@ -2173,6 +2257,12 @@ FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: System.String OutputFile
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: System.String get_OutputFile()
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot)
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: System.String OutputFile
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: System.String get_OutputFile()
FSharp.Compiler.CodeAnalysis.FSharpSymbolUse: Boolean IsFromAttribute
FSharp.Compiler.CodeAnalysis.FSharpSymbolUse: Boolean IsFromComputationExpression
FSharp.Compiler.CodeAnalysis.FSharpSymbolUse: Boolean IsFromDefinition
@@ -2210,6 +2300,35 @@ FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Boolean Equals(Syste
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey NewFrameworkImportsCacheKey(Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.Decimal)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 Tag
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 get_Tag()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_resolvedpath()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_targetFrameworkDirectories()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] resolvedpath
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] targetFrameworkDirectories
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal get_langVersion()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal langVersion
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String assemblyName
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String fsharpBinaries
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_assemblyName()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_fsharpBinaries()
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking3(System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForParsing[a](System.Tuple`3[System.String,System.Int64,a], System.Tuple`3[System.String,System.Int64,a])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSimilarForParsing[a,b,c,d,e](System.Tuple`3[a,b,c], System.Tuple`3[a,d,e])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable3[a,b](System.Tuple`3[System.String,a,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,b,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean NamesContainAttribute(FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Collections.FSharpSet`1[System.String])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: FSharp.Compiler.CodeAnalysis.LegacyResolvedFile[] Resolve(FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, System.Tuple`2[System.String,System.String][], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.FSharpFunc`2[System.Boolean,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit]]])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String DotNetFrameworkReferenceAssembliesRootDirectory
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String HighestInstalledNetFrameworkVersion()
@@ -2253,6 +2372,8 @@ FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: System.String get_baggage()
FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: System.String get_itemSpec()
FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: System.String itemSpec
FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.String],System.String], System.String)
+FSharp.Compiler.CodeAnalysis.ParseCacheLockToken: Void .ctor()
+FSharp.Compiler.CodeAnalysis.ScriptClosureCacheToken: Void .ctor()
FSharp.Compiler.CompilerEnvironment: Boolean IsCheckerSupportedSubcategory(System.String)
FSharp.Compiler.CompilerEnvironment: Boolean IsCompilable(System.String)
FSharp.Compiler.CompilerEnvironment: Boolean IsScriptFile(System.String)
@@ -10133,7 +10254,7 @@ FSharp.Compiler.Tokenization.FSharpLineTokenizer: FSharp.Compiler.Tokenization.F
FSharp.Compiler.Tokenization.FSharpLineTokenizer: System.Tuple`2[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Tokenization.FSharpTokenInfo],FSharp.Compiler.Tokenization.FSharpTokenizerLexState] ScanToken(FSharp.Compiler.Tokenization.FSharpTokenizerLexState)
FSharp.Compiler.Tokenization.FSharpSourceTokenizer: FSharp.Compiler.Tokenization.FSharpLineTokenizer CreateBufferTokenizer(Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`3[System.Char[],System.Int32,System.Int32],System.Int32])
FSharp.Compiler.Tokenization.FSharpSourceTokenizer: FSharp.Compiler.Tokenization.FSharpLineTokenizer CreateLineTokenizer(System.String)
-FSharp.Compiler.Tokenization.FSharpSourceTokenizer: Void .ctor(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.Tokenization.FSharpSourceTokenizer: Void .ctor(Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.Tokenization.FSharpToken: Boolean IsCommentTrivia
FSharp.Compiler.Tokenization.FSharpToken: Boolean IsIdentifier
FSharp.Compiler.Tokenization.FSharpToken: Boolean IsKeyword
@@ -11302,6 +11423,7 @@ FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokeniza
FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokenization.FSharpTokenizerColorState Comment
FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokenization.FSharpTokenizerColorState EndLineThenSkip
FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokenization.FSharpTokenizerColorState EndLineThenToken
+FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokenization.FSharpTokenizerColorState ExtendedInterpolatedString
FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokenization.FSharpTokenizerColorState IfDefSkip
FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokenization.FSharpTokenizerColorState InitialState
FSharp.Compiler.Tokenization.FSharpTokenizerColorState: FSharp.Compiler.Tokenization.FSharpTokenizerColorState SingleLineComment
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
index f8b2c9dbd40..32d9d761d36 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
@@ -1961,6 +1961,16 @@ FSharp.Compiler.CodeAnalysis.DocumentSource: FSharp.Compiler.CodeAnalysis.Docume
FSharp.Compiler.CodeAnalysis.DocumentSource: Int32 Tag
FSharp.Compiler.CodeAnalysis.DocumentSource: Int32 get_Tag()
FSharp.Compiler.CodeAnalysis.DocumentSource: System.String ToString()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 braceMatchCacheSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 checkFileInProjectCacheSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 frameworkTcImportsCacheStrongSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_braceMatchCacheSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_checkFileInProjectCacheSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_frameworkTcImportsCacheStrongSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_parseFileCacheSize()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 get_projectCacheSizeDefault()
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 parseFileCacheSize
+FSharp.Compiler.CodeAnalysis.EnvMisc: Int32 projectCacheSizeDefault
FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults Item
FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Succeeded: FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults get_Item()
FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer+Tags: Int32 Aborted
@@ -2031,7 +2041,9 @@ FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: FSharp.Compiler.Symbols.
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] DependencyFiles
FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults: System.String[] get_DependencyFiles()
-FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Boolean UsesTransparentCompiler
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Boolean get_UsesTransparentCompiler()
+FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Create(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.DateTime],Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.IntPtr,System.Int32]]]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker Instance
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpChecker get_Instance()
FSharp.Compiler.CodeAnalysis.FSharpChecker: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions GetProjectOptionsFromCommandLineArgs(System.String, System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean])
@@ -2050,6 +2062,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyFileChanged(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2073,6 +2086,18 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Void ClearCache(System.Collections.G
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void InvalidateAll()
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void InvalidateConfiguration(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]] GetSource
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]] get_GetSource()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String FileName
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String Version
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_FileName()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_Version()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] Key
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] get_Key()
+FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Void .ctor(System.String, System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]])
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPosContainedInApplication(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPositionContainedInACurriedParameter(FSharp.Compiler.Text.Position)
@@ -2165,6 +2190,65 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: System.String[] SourceFiles
FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: System.String[] get_OtherOptions()
FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: System.String[] get_SourceFiles()
FSharp.Compiler.CodeAnalysis.FSharpProjectOptions: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], System.String[], System.String[], FSharp.Compiler.CodeAnalysis.FSharpReferencedProject[], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64])
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean Equals(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean IsIncompleteTypeCheckEnvironment
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean UseScriptResolutionRules
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_IsIncompleteTypeCheckEnvironment()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_UseScriptResolutionRules()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ToOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(Int32)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey Key
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] SourceFiles
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] get_SourceFiles()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot] ReferencedProjects
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot] get_ReferencedProjects()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] SourceFileNames
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_SourceFileNames()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] OriginalLoadReferences
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]] get_OriginalLoadReferences()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot]]])
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet] UnresolvedReferences
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet] get_UnresolvedReferences()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.Int64] Stamp
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.Int64] get_Stamp()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] ProjectId
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Core.FSharpOption`1[System.String] get_ProjectId()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.DateTime LoadTime
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.DateTime get_LoadTime()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ProjectFileName
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String get_ProjectFileName()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64])
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean IsIncompleteTypeCheckEnvironment
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean UseScriptResolutionRules
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_IsIncompleteTypeCheckEnvironment()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_UseScriptResolutionRules()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] ReferencedProjects
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] get_ReferencedProjects()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] SourceFiles
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] get_SourceFiles()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ProjectFileName
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String get_ProjectFileName()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey], Boolean, Boolean)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Boolean Equals(System.Object)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFromILModuleReader(System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader])
@@ -2173,6 +2257,12 @@ FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: System.String OutputFile
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: System.String get_OutputFile()
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot)
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: System.String OutputFile
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot: System.String get_OutputFile()
FSharp.Compiler.CodeAnalysis.FSharpSymbolUse: Boolean IsFromAttribute
FSharp.Compiler.CodeAnalysis.FSharpSymbolUse: Boolean IsFromComputationExpression
FSharp.Compiler.CodeAnalysis.FSharpSymbolUse: Boolean IsFromDefinition
@@ -2210,6 +2300,35 @@ FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Boolean Equals(Syste
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey NewFrameworkImportsCacheKey(Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.Decimal)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 Tag
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 get_Tag()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_resolvedpath()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_targetFrameworkDirectories()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] resolvedpath
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] targetFrameworkDirectories
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal get_langVersion()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal langVersion
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String ToString()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String assemblyName
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String fsharpBinaries
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_assemblyName()
+FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_fsharpBinaries()
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking3(System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForParsing[a](System.Tuple`3[System.String,System.Int64,a], System.Tuple`3[System.String,System.Int64,a])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSimilarForParsing[a,b,c,d,e](System.Tuple`3[a,b,c], System.Tuple`3[a,d,e])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable3[a,b](System.Tuple`3[System.String,a,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,b,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
+FSharp.Compiler.CodeAnalysis.Helpers: Boolean NamesContainAttribute(FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Collections.FSharpSet`1[System.String])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: FSharp.Compiler.CodeAnalysis.LegacyResolvedFile[] Resolve(FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, System.Tuple`2[System.String,System.String][], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.FSharpFunc`2[System.Boolean,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit]]])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String DotNetFrameworkReferenceAssembliesRootDirectory
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String HighestInstalledNetFrameworkVersion()
@@ -2253,6 +2372,8 @@ FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: System.String get_baggage()
FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: System.String get_itemSpec()
FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: System.String itemSpec
FSharp.Compiler.CodeAnalysis.LegacyResolvedFile: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.String,System.String],System.String], System.String)
+FSharp.Compiler.CodeAnalysis.ParseCacheLockToken: Void .ctor()
+FSharp.Compiler.CodeAnalysis.ScriptClosureCacheToken: Void .ctor()
FSharp.Compiler.CompilerEnvironment: Boolean IsCheckerSupportedSubcategory(System.String)
FSharp.Compiler.CompilerEnvironment: Boolean IsCompilable(System.String)
FSharp.Compiler.CompilerEnvironment: Boolean IsScriptFile(System.String)
From b3e8b236ea8f067a4faf6656491311d6f0a2bbc8 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 5 May 2023 13:25:06 +0200
Subject: [PATCH 019/222] try to deflake test
---
.../CompilerService/AsyncMemoize.fs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
index 2dae1fab2e4..a2e6c84bdc7 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -43,7 +43,10 @@ let ``Basics``() =
[]
let ``We can cancel a job`` () =
+ let resetEvent = new ManualResetEvent(false)
+
let computation key = node {
+ resetEvent.Set() |> ignore
do! Async.Sleep 1000 |> NodeCode.AwaitAsync
failwith "Should be canceled before it gets here"
return key * 2
@@ -62,7 +65,7 @@ let ``We can cancel a job`` () =
let _task2 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts2.Token)
let _task3 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts3.Token)
- Thread.Sleep 10
+ resetEvent.WaitOne() |> ignore
Assert.Equal array>([| Started key |], eventLog |> Seq.toArray )
From a3739866bafc94c0322bde7274354576ad338628 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 5 May 2023 14:23:03 +0200
Subject: [PATCH 020/222] fix fsproj
---
src/Compiler/FSharp.Compiler.Service.fsproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj
index 1cd12ec49ae..5eaf378da62 100644
--- a/src/Compiler/FSharp.Compiler.Service.fsproj
+++ b/src/Compiler/FSharp.Compiler.Service.fsproj
@@ -470,7 +470,7 @@
-
+
From 9902755342a6c1966bfcc51cf94ab81f77427803 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 5 May 2023 15:08:05 +0200
Subject: [PATCH 021/222] tests
---
src/Compiler/Facilities/AsyncMemoize.fs | 4 +-
.../FSharpChecker/TransparentCompiler.fs | 81 +++++++++++++++++++
.../ProjectGeneration.fs | 55 ++++++++-----
3 files changed, 116 insertions(+), 24 deletions(-)
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
index 8cb38c9540d..941cacb8013 100644
--- a/src/Compiler/Facilities/AsyncMemoize.fs
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -77,7 +77,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
Async.AwaitNodeCode(
node {
use _ = Activity.start $"AsyncMemoize.{name}" [||]
-
+ log (Started key)
let! result = computation key
post key JobCompleted
return result
@@ -86,8 +86,6 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
cancellationToken = cts.Token
)
- log (Started key)
-
let job = NodeCode.AwaitTask startedComputation
cache.Set(tok, key, (Running(job, cts)))
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index d619d9e45c1..4fa464d9bac 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -89,3 +89,84 @@ let ``Parallel processing`` () =
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
checkFile "E" expectOk
}
+
+
+let makeTestProject () =
+ SyntheticProject.Create(
+ sourceFile "First" [],
+ sourceFile "Second" ["First"],
+ sourceFile "Third" ["First"],
+ { sourceFile "Last" ["Second"; "Third"] with EntryPoint = true })
+
+let testWorkflow () =
+ ProjectWorkflowBuilder(makeTestProject(), useTransparentCompiler = true)
+
+[]
+let ``Edit file, check it, then check dependent file`` () =
+ testWorkflow() {
+ updateFile "First" breakDependentFiles
+ checkFile "First" expectSignatureChanged
+ checkFile "Second" expectErrors
+ }
+
+[]
+let ``Edit file, don't check it, check dependent file`` () =
+ testWorkflow() {
+ updateFile "First" breakDependentFiles
+ checkFile "Second" expectErrors
+ }
+
+[]
+let ``Check transitive dependency`` () =
+ testWorkflow() {
+ updateFile "First" breakDependentFiles
+ checkFile "Last" expectSignatureChanged
+ }
+
+[]
+let ``Change multiple files at once`` () =
+ testWorkflow() {
+ updateFile "First" (setPublicVersion 2)
+ updateFile "Second" (setPublicVersion 2)
+ updateFile "Third" (setPublicVersion 2)
+ checkFile "Last" (expectSignatureContains "val f: x: 'a -> (ModuleFirst.TFirstV_2<'a> * ModuleSecond.TSecondV_2<'a>) * (ModuleFirst.TFirstV_2<'a> * ModuleThird.TThirdV_2<'a>) * TLastV_1<'a>")
+ }
+
+// TODO: []
+let ``Files depend on signature file if present`` () =
+ let project = makeTestProject() |> updateFile "First" addSignatureFile
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ updateFile "First" breakDependentFiles
+ saveFile "First"
+ checkFile "Second" expectNoChanges
+ }
+
+[]
+let ``Adding a file`` () =
+ testWorkflow() {
+ addFileAbove "Second" (sourceFile "New" [])
+ updateFile "Second" (addDependency "New")
+ checkFile "Last" (expectSignatureContains "val f: x: 'a -> (ModuleNew.TNewV_1<'a> * ModuleFirst.TFirstV_1<'a> * ModuleSecond.TSecondV_1<'a>) * (ModuleFirst.TFirstV_1<'a> * ModuleThird.TThirdV_1<'a>) * TLastV_1<'a>")
+ }
+
+[]
+let ``Removing a file`` () =
+ testWorkflow() {
+ removeFile "Second"
+ checkFile "Last" expectErrors
+ }
+
+[]
+let ``Changes in a referenced project`` () =
+ let library = SyntheticProject.Create("library", sourceFile "Library" [])
+
+ let project =
+ { makeTestProject() with DependsOn = [library] }
+ |> updateFile "First" (addDependency "Library")
+
+ project.Workflow {
+ updateFile "Library" updatePublicSurface
+ saveFile "Library"
+ checkFile "Last" expectSignatureChanged
+ }
\ No newline at end of file
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 16d42718f1e..388e16185d4 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -341,16 +341,43 @@ module ProjectOperations =
project.GetProjectOptions checker
)
- let getFileSnapshot (project: SyntheticProject) _options path =
+ let getSourceText (project: SyntheticProject) (filePath: string) =
+ if filePath.EndsWith(".fsi") then
+ let implFilePath = filePath[..filePath.Length - 2]
+ let source = project.FindByPath implFilePath
+ match source.SignatureFile with
+ | No -> failwith $"{implFilePath} does not have a signature file"
+ | Custom _ -> renderCustomSignatureFile project source
+ | AutoGenerated ->
+ if File.Exists filePath then
+ // TODO: could be outdated
+ File.ReadAllText filePath
+ else
+ failwith "AutoGenerated signatures not yet supported for getSource workflow"
+ else
+ filePath
+ |> project.FindByPath
+ |> renderSourceFile project
+ |> SourceText.ofString
+
+ let getFileSnapshot (project: SyntheticProject) _options (path: string) =
async {
- let file = project.FindByPath path
+ let file, filePath =
+ if path.EndsWith(".fsi") then
+ let implFilePath = path[..path.Length - 2]
+ let f = project.FindByPath implFilePath
+ f, getSignatureFilePath project f
+ else
+ let f = project.FindByPath path
+ f, getFilePath project f
+
let dependencies = file.DependsOn |> String.concat "|"
- let version = $"{file.PublicVersion}.{file.InternalVersion}.{file.Source.GetHashCode()}.{file.ExtraSource.GetHashCode()}.{dependencies}"
+ let version = $"{file.PublicVersion}|{file.InternalVersion}|{file.FunctionName}|{file.Source.GetHashCode()}|{file.ExtraSource.GetHashCode()}|{dependencies}"
return {
- FileName = getFilePath project file
+ FileName = filePath
Version = version
- GetSource = fun () -> renderSourceFile project file |> SourceText.ofString |> Task.FromResult
+ GetSource = fun () -> getSourceText project path |> Task.FromResult
}
}
@@ -457,7 +484,7 @@ module ProjectOperations =
match file.SignatureFile with
| AutoGenerated when generateSignatureFiles ->
- let project = { p with SourceFiles = p.SourceFiles[0..i] }
+ let project = { p with SourceFiles = p.SourceFiles[0..i - 1] @ [ { file with SignatureFile = No }] }
let! results = checkFile file.Id project checker
let signature = getSignature results
writeFileIfChanged signatureFileName signature
@@ -584,21 +611,7 @@ type ProjectWorkflowBuilder
let mutable latestProject = initialProject
- let getSource (filePath: string) =
- if filePath.EndsWith(".fsi") then
- let implFilePath = filePath[..filePath.Length - 2]
- let source = latestProject.FindByPath implFilePath
- match source.SignatureFile with
- | No -> failwith $"{implFilePath} does not have a signature file"
- | Custom _ -> renderCustomSignatureFile latestProject source
- | AutoGenerated -> failwith "AutoGenerated signatures not yet supported for getSource workflow"
- else
- filePath
- |> latestProject.FindByPath
- |> renderSourceFile latestProject
- |> SourceText.ofString
- |> Some
- |> async.Return
+ let getSource f = f |> getSourceText latestProject |> Some |> async.Return
let checker =
defaultArg
From a2d7e567a5f77ce8ce99bb3bab6f3a859cd32210 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 5 May 2023 17:09:08 +0200
Subject: [PATCH 022/222] wip
---
src/Compiler/Service/TransparentCompiler.fs | 20 +++++++++++--------
.../CompilerService/AsyncMemoize.fs | 2 +-
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 9775fc871e4..38a5a56fdbc 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -684,25 +684,29 @@ type internal TransparentCompiler
let prefixPathOpt = None
- // TODO:
- let implFile = implFileOpt.Value
-
let ccuSigForFile, tcState =
- AddCheckResultsToTcState
- (bootstrapInfo.TcGlobals, amap, hadSig, prefixPathOpt, TcResultsSink.NoSink, a.tcState.TcEnvFromImpls, implFile.QualifiedNameOfFile, implFile.Signature)
- b.tcState
+ match implFileOpt with
+ | Some implFile ->
+
+ let ccuSigForFile, tcState =
+ AddCheckResultsToTcState
+ (bootstrapInfo.TcGlobals, amap, hadSig, prefixPathOpt, TcResultsSink.NoSink, a.tcState.TcEnvFromImpls, implFile.QualifiedNameOfFile, implFile.Signature)
+ b.tcState
+ Some ccuSigForFile, tcState
+ | None ->
+ b.latestCcuSigForFile, b.tcState
{ a with
tcState = tcState
tcEnvAtEndOfFile = b.tcEnvAtEndOfFile
moduleNamesDict = b.moduleNamesDict
- latestCcuSigForFile = Some ccuSigForFile
+ latestCcuSigForFile = ccuSigForFile
tcDiagnosticsRev = b.tcDiagnosticsRev @ a.tcDiagnosticsRev
topAttribs = b.topAttribs
tcDependencyFiles = b.tcDependencyFiles @ a.tcDependencyFiles
// we shouldn't need this with graph checking (?)
sigNameOpt = None
- }, sink, Some implFile, name)
+ }, sink, implFileOpt, name)
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName _key =
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
index a2e6c84bdc7..41880ac0d96 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -78,7 +78,7 @@ let ``We can cancel a job`` () =
cts3.Cancel()
- Thread.Sleep 10
+ Thread.Sleep 100
Assert.Equal array>([| Started key; Canceled key |], eventLog |> Seq.toArray )
From f1eb8080eddd5e1949b6268798cc99b281e9feb3 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Tue, 9 May 2023 12:05:24 +0200
Subject: [PATCH 023/222] wip
---
src/Compiler/Driver/ParseAndCheckInputs.fs | 73 ++++++++++---------
src/Compiler/Driver/ParseAndCheckInputs.fsi | 33 +++++++++
.../FSharpChecker/TransparentCompiler.fs | 2 +-
.../TypeChecks/Graph/GraphOperations.fs | 9 ++-
4 files changed, 77 insertions(+), 40 deletions(-)
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs
index 55b9736ad56..171cc639580 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fs
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fs
@@ -1608,6 +1608,42 @@ let AddSignatureResultToTcImplEnv (tcImports: TcImports, tcGlobals, prefixPathOp
tcState.tcsTcSigEnv, EmptyTopAttrs, None, ccuSigForFile
partialResult, tcState
+let TransformDependencyGraph (graph: Graph, filePairs: FilePairMap) =
+ let mkArtificialImplFile n = NodeToTypeCheck.ArtificialImplFile n
+ let mkPhysicalFile n = NodeToTypeCheck.PhysicalFile n
+
+ /// Map any signature dependencies to the ArtificialImplFile counterparts,
+ /// unless the signature dependency is the backing file of the current (implementation) file.
+ let mapDependencies idx deps =
+ Array.map
+ (fun dep ->
+ if filePairs.IsSignature dep then
+ let implIdx = filePairs.GetImplementationIndex dep
+
+ if implIdx = idx then
+ // This is the matching signature for the implementation.
+ // Retain the direct dependency onto the signature file.
+ mkPhysicalFile dep
+ else
+ mkArtificialImplFile dep
+ else
+ mkPhysicalFile dep)
+ deps
+
+ // Transform the graph to include ArtificialImplFile nodes when necessary.
+ graph
+ |> Seq.collect (fun (KeyValue (fileIdx, deps)) ->
+ if filePairs.IsSignature fileIdx then
+ // Add an additional ArtificialImplFile node for the signature file.
+ [|
+ // Mark the current file as physical and map the dependencies.
+ mkPhysicalFile fileIdx, mapDependencies fileIdx deps
+ // Introduce a new node that depends on the signature.
+ mkArtificialImplFile fileIdx, [| mkPhysicalFile fileIdx |]
+ |]
+ else
+ [| mkPhysicalFile fileIdx, mapDependencies fileIdx deps |])
+ |> Graph.make
/// Constructs a file dependency graph and type-checks the files in parallel where possible.
let CheckMultipleInputsUsingGraphMode
@@ -1630,42 +1666,7 @@ let CheckMultipleInputsUsingGraphMode
let graph, trie =
DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
- let nodeGraph =
- let mkArtificialImplFile n = NodeToTypeCheck.ArtificialImplFile n
- let mkPhysicalFile n = NodeToTypeCheck.PhysicalFile n
-
- /// Map any signature dependencies to the ArtificialImplFile counterparts,
- /// unless the signature dependency is the backing file of the current (implementation) file.
- let mapDependencies idx deps =
- Array.map
- (fun dep ->
- if filePairs.IsSignature dep then
- let implIdx = filePairs.GetImplementationIndex dep
-
- if implIdx = idx then
- // This is the matching signature for the implementation.
- // Retain the direct dependency onto the signature file.
- mkPhysicalFile dep
- else
- mkArtificialImplFile dep
- else
- mkPhysicalFile dep)
- deps
-
- // Transform the graph to include ArtificialImplFile nodes when necessary.
- graph
- |> Seq.collect (fun (KeyValue (fileIdx, deps)) ->
- if filePairs.IsSignature fileIdx then
- // Add an additional ArtificialImplFile node for the signature file.
- [|
- // Mark the current file as physical and map the dependencies.
- mkPhysicalFile fileIdx, mapDependencies fileIdx deps
- // Introduce a new node that depends on the signature.
- mkArtificialImplFile fileIdx, [| mkPhysicalFile fileIdx |]
- |]
- else
- [| mkPhysicalFile fileIdx, mapDependencies fileIdx deps |])
- |> Graph.make
+ let nodeGraph = TransformDependencyGraph (graph, filePairs)
// Persist the graph to a Mermaid diagram if specified.
if tcConfig.typeCheckingConfig.DumpGraph then
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi
index 9d2bb5b9e41..813f99e8c2d 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fsi
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi
@@ -13,6 +13,7 @@ open FSharp.Compiler.CompilerImports
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.DependencyManager
open FSharp.Compiler.DiagnosticsLogger
+open FSharp.Compiler.GraphChecking
open FSharp.Compiler.NameResolution
open FSharp.Compiler.Syntax
open FSharp.Compiler.TcGlobals
@@ -20,6 +21,36 @@ open FSharp.Compiler.Text
open FSharp.Compiler.TypedTree
open FSharp.Compiler.UnicodeLexing
+/// Auxiliary type for re-using signature information in TcEnvFromImpls.
+///
+/// TcState has two typing environments: TcEnvFromSignatures && TcEnvFromImpls
+/// When type checking a file, depending on the type (implementation or signature), it will use one of these typing environments (TcEnv).
+/// Checking a file will populate the respective TcEnv.
+///
+/// When a file has a dependencies, the information of the signature file in case a pair (implementation file backed by a signature) will suffice to type-check that file.
+/// Example: if `B.fs` has a dependency on `A`, the information of `A.fsi` is enough for `B.fs` to type-check, on condition that information is available in the TcEnvFromImpls.
+/// We introduce a special ArtificialImplFile node in the graph to satisfy this. `B.fs -> [ A.fsi ]` becomes `B.fs -> [ ArtificialImplFile A ].
+/// The `ArtificialImplFile A` node will duplicate the signature information which A.fsi provided earlier.
+/// Processing a `ArtificialImplFile` node will add the information from the TcEnvFromSignatures to the TcEnvFromImpls.
+/// This means `A` will be known in both TcEnvs and therefor `B.fs` can be type-checked.
+/// By doing this, we can speed up the graph processing as type checking a signature file is less expensive than its implementation counterpart.
+///
+/// When we need to actually type-check an implementation file backed by a signature, we cannot have the duplicate information of the signature file present in TcEnvFromImpls.
+/// Example `A.fs -> [ A.fsi ]`. An implementation file always depends on its signature.
+/// Type-checking `A.fs` will add the actual information to TcEnvFromImpls and we do not depend on the `ArtificialImplFile A` for `A.fs`.
+///
+/// In order to deal correctly with the `ArtificialImplFile` logic, we need to transform the resolved graph to contain the additional pair nodes.
+/// After we have type-checked the graph, we exclude the ArtificialImplFile nodes as they are not actual physical files in our project.
+[]
+type NodeToTypeCheck =
+ /// A real physical file in the current project.
+ /// This can be either an implementation or a signature file.
+ | PhysicalFile of fileIndex: FileIndex
+ /// An artificial node that will add the earlier processed signature information to the TcEnvFromImpls.
+ /// Dependants on this type of node will perceive that a file is known in both TcEnvFromSignatures and TcEnvFromImpls.
+ /// Even though the actual implementation file was not type-checked.
+ | ArtificialImplFile of signatureFileIndex: FileIndex
+
val IsScript: string -> bool
val ComputeQualifiedNameOfFileFromUniquePath: range * string list -> QualifiedNameOfFile
@@ -163,6 +194,8 @@ val AddCheckResultsToTcState:
implFileSigType: ModuleOrNamespaceType ->
tcState: TcState ->
ModuleOrNamespaceType * TcState
+
+val TransformDependencyGraph: graph: Graph * filePairs: FilePairMap -> Graph
/// Finish the checking of multiple inputs
val CheckMultipleInputsFinish:
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 4fa464d9bac..e4ee36efc92 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -132,7 +132,7 @@ let ``Change multiple files at once`` () =
checkFile "Last" (expectSignatureContains "val f: x: 'a -> (ModuleFirst.TFirstV_2<'a> * ModuleSecond.TSecondV_2<'a>) * (ModuleFirst.TFirstV_2<'a> * ModuleThird.TThirdV_2<'a>) * TLastV_1<'a>")
}
-// TODO: []
+[]
let ``Files depend on signature file if present`` () =
let project = makeTestProject() |> updateFile "First" addSignatureFile
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
index f8e58f352a9..757248d8add 100644
--- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
@@ -6,6 +6,7 @@ open FSharp.Compiler.GraphChecking
open FSharp.Test.ProjectGeneration
open FSharp.Compiler.Text
open FSharp.Compiler
+open FSharp.Compiler.ParseAndCheckInputs
[]
@@ -66,13 +67,15 @@ let ``See what this does`` () =
let fullGraph =
DependencyResolution.mkGraph false filePairs sourceFiles
|> fst
- |> Graph.map (fun idx -> project.SourceFilePaths[idx] |> Path.GetFileName)
+ //|> Graph.map (fun idx -> project.SourceFilePaths[idx] |> Path.GetFileName)
- let subGraph = fullGraph |> Graph.subGraphFor "FileF.fs"
+ let subGraph = fullGraph |> Graph.subGraphFor 9 //"FileF.fs"
let layers = Graph.leafSequence subGraph |> Seq.toList
- ignore layers
+ let transformed = TransformDependencyGraph (subGraph, filePairs)
+
+ ignore (layers, transformed)
return ()
}
From 20ea96d085bdb36bc6196c9fffd0914e3d250e75 Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Tue, 9 May 2023 18:11:36 +0200
Subject: [PATCH 024/222] wip
---
src/Compiler/Driver/GraphChecking/Graph.fs | 6 ++-
src/Compiler/Driver/GraphChecking/Graph.fsi | 4 +-
src/Compiler/Driver/ParseAndCheckInputs.fs | 5 +-
src/Compiler/Driver/ParseAndCheckInputs.fsi | 14 +++++-
src/Compiler/Service/TransparentCompiler.fs | 48 ++++++++++++++++---
.../FSharpChecker/TransparentCompiler.fs | 19 ++++++++
.../TypeChecks/Graph/GraphOperations.fs | 2 +-
.../TypeChecks/Graph/TypedTreeGraph.fs | 4 +-
.../ProjectGeneration.fs | 2 +
9 files changed, 88 insertions(+), 16 deletions(-)
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fs b/src/Compiler/Driver/GraphChecking/Graph.fs
index 688fffc29bb..9cbce0b4b9b 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fs
+++ b/src/Compiler/Driver/GraphChecking/Graph.fs
@@ -124,7 +124,7 @@ module internal Graph =
let print (graph: Graph<'Node>) : unit =
printCustom graph (fun node -> node.ToString())
- let serialiseToMermaid path (graph: Graph) =
+ let serialiseToMermaid (graph: Graph) =
let sb = StringBuilder()
let appendLine (line: string) = sb.AppendLine(line) |> ignore
@@ -139,8 +139,10 @@ module internal Graph =
appendLine $" %i{idx} --> %i{depIdx}"
appendLine "```"
+ sb.ToString()
+ let writeMermaidToFile path (graph: Graph) =
use out =
FileSystem.OpenFileForWriteShim(path, fileMode = System.IO.FileMode.Create)
- out.WriteAllText(sb.ToString())
+ graph |> serialiseToMermaid |> out.WriteAllText
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fsi b/src/Compiler/Driver/GraphChecking/Graph.fsi
index 8c6b9c29079..7d885f5c96a 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fsi
+++ b/src/Compiler/Driver/GraphChecking/Graph.fsi
@@ -21,5 +21,7 @@ module internal Graph =
val leafSequence: graph: Graph<'Node> -> Set<'Node> seq
/// Print the contents of the graph to the standard output.
val print: graph: Graph<'Node> -> unit
+ /// Create a simple Mermaid graph
+ val serialiseToMermaid: graph: Graph -> string
/// Create a simple Mermaid graph and save it under the path specified.
- val serialiseToMermaid: path: string -> graph: Graph -> unit
+ val writeMermaidToFile: path: string -> graph: Graph -> unit
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs
index 171cc639580..7a70b6f5c51 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fs
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fs
@@ -1608,6 +1608,7 @@ let AddSignatureResultToTcImplEnv (tcImports: TcImports, tcGlobals, prefixPathOp
tcState.tcsTcSigEnv, EmptyTopAttrs, None, ccuSigForFile
partialResult, tcState
+
let TransformDependencyGraph (graph: Graph, filePairs: FilePairMap) =
let mkArtificialImplFile n = NodeToTypeCheck.ArtificialImplFile n
let mkPhysicalFile n = NodeToTypeCheck.PhysicalFile n
@@ -1666,7 +1667,7 @@ let CheckMultipleInputsUsingGraphMode
let graph, trie =
DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
- let nodeGraph = TransformDependencyGraph (graph, filePairs)
+ let nodeGraph = TransformDependencyGraph(graph, filePairs)
// Persist the graph to a Mermaid diagram if specified.
if tcConfig.typeCheckingConfig.DumpGraph then
@@ -1686,7 +1687,7 @@ let CheckMultipleInputsUsingGraphMode
.TrimStart([| '\\'; '/' |])
(idx, friendlyFileName))
- |> Graph.serialiseToMermaid graphFile)
+ |> Graph.writeMermaidToFile graphFile)
let _ = ctok // TODO Use it
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi
index 813f99e8c2d..718a9e3d746 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fsi
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi
@@ -194,7 +194,19 @@ val AddCheckResultsToTcState:
implFileSigType: ModuleOrNamespaceType ->
tcState: TcState ->
ModuleOrNamespaceType * TcState
-
+
+type PartialResult = TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType
+
+val AddSignatureResultToTcImplEnv:
+ tcImports: TcImports *
+ tcGlobals: TcGlobals *
+ prefixPathOpt: LongIdent option *
+ tcSink: TcResultsSink *
+ tcState: TcState *
+ input: ParsedInput ->
+ (TcState ->
+ PartialResult * TcState)
+
val TransformDependencyGraph: graph: Graph * filePairs: FilePairMap -> Graph
/// Finish the checking of multiple inputs
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 38a5a56fdbc..bf11cc15829 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -599,7 +599,7 @@ type internal TransparentCompiler
|> fst
|> Graph.subGraphFor (sourceFiles |> Array.last).Idx
- return graph, filePairs
+ return TransformDependencyGraph(graph, filePairs), filePairs
}
let ComputeTcIntermediate (parsedInput: ParsedInput, parseErrors) bootstrapInfo prevTcInfo _key =
@@ -737,25 +737,59 @@ type internal TransparentCompiler
ComputeDependencyGraphForLastFile (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
)
+ let fileNames =
+ parsedInputs
+ |> Seq.mapi (fun idx (input, _, _) -> idx, Path.GetFileName input.FileName)
+ |> Map.ofSeq
+
+ let debugGraph =
+ graph
+ |> Graph.map (function NodeToTypeCheck.PhysicalFile i -> i, fileNames[i] | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
+
+ Trace.TraceInformation("\n" + (debugGraph |> Graph.serialiseToMermaid))
+
// layers that can be processed in parallel
let layers = Graph.leafSequence graph |> Seq.toList
// remove the final layer, which should be the target file
let layers = layers |> List.take (layers.Length - 1)
- let rec processLayer (layers: Set list) tcInfo =
+ let rec processLayer (layers: Set list) tcInfo =
node {
match layers with
| [] -> return tcInfo
| layer :: rest ->
let! results =
layer
- |> Seq.map (fun fileIndex ->
- let key = projectSnapshot.UpTo(fileIndex).Key
- let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
- TcIntermediateCache.Get(key, ComputeTcIntermediate (parsedInput, parseErrors) bootstrapInfo tcInfo))
+ |> Seq.map (fun fileNode ->
+
+ match fileNode with
+ | NodeToTypeCheck.PhysicalFile fileIndex ->
+ let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
+ let key = projectSnapshot.UpTo(fileIndex).Key
+ TcIntermediateCache.Get(key, ComputeTcIntermediate (parsedInput, parseErrors) bootstrapInfo tcInfo)
+ | NodeToTypeCheck.ArtificialImplFile fileIndex ->
+ let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
+ let tcState = tcInfo.tcState
+ let prefixPathOpt = None
+
+ let (tcEnv , topAttribs , checkedImplFileOpt , _moduleOrNamespaceType), newTcState =
+ // Retrieve the type-checked signature information and add it to the TcEnvFromImpls.
+ AddSignatureResultToTcImplEnv(bootstrapInfo.TcImports, bootstrapInfo.TcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, parsedInput) tcState
+ let tcInfo =
+ { tcInfo with
+ tcState = newTcState
+ tcEnvAtEndOfFile = tcEnv
+
+ topAttribs = Some topAttribs
+ // we shouldn't need this with graph checking (?)
+ sigNameOpt = None
+ }
+
+ node.Return(tcInfo, Unchecked.defaultof<_>, checkedImplFileOpt, parsedInput.FileName))
|> NodeCode.Parallel
-
+ let nodes = layer |> Seq.map (function NodeToTypeCheck.PhysicalFile i -> fileNames[i] | NodeToTypeCheck.ArtificialImplFile i -> $"AIF : {fileNames[i]}") |> String.concat " "
+ Trace.TraceInformation $"Processed layer {nodes}"
return! processLayer rest (mergeIntermediateResults bootstrapInfo (tcInfo, Unchecked.defaultof<_>, None, "") results |> p14)
}
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index e4ee36efc92..ea679f5476d 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -91,6 +91,25 @@ let ``Parallel processing`` () =
}
+[]
+let ``Parallel processing with signatures`` () =
+
+ Activity.listenToAll ()
+
+ let project = SyntheticProject.Create(
+ sourceFile "A" [] |> addSignatureFile,
+ sourceFile "B" ["A"] |> addSignatureFile,
+ sourceFile "C" ["A"] |> addSignatureFile,
+ sourceFile "D" ["A"] |> addSignatureFile,
+ sourceFile "E" ["B"; "C"; "D"] |> addSignatureFile)
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ checkFile "C" expectOk
+ //updateFile "A" updatePublicSurface
+ //checkFile "E" expectSignatureChanged
+ }
+
+
let makeTestProject () =
SyntheticProject.Create(
sourceFile "First" [],
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
index 757248d8add..dedac14ba76 100644
--- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
@@ -76,7 +76,7 @@ let ``See what this does`` () =
let transformed = TransformDependencyGraph (subGraph, filePairs)
ignore (layers, transformed)
-
+
return ()
}
)
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TypedTreeGraph.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TypedTreeGraph.fs
index 284946eee9f..0eef5c79673 100644
--- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TypedTreeGraph.fs
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TypedTreeGraph.fs
@@ -140,7 +140,7 @@ let ``Create Graph from typed tree`` (projectArgumentsFilePath: string) =
graphFromTypedTree
|> Graph.map (fun n -> n,files.[n].File)
- |> Graph.serialiseToMermaid $"{fileName}.typed-tree.deps.md"
+ |> Graph.writeMermaidToFile $"{fileName}.typed-tree.deps.md"
let collectAllDeps (graph: Graph) =
(Map.empty, [ 0 .. (sourceFiles.Length - 1) ])
@@ -162,7 +162,7 @@ let ``Create Graph from typed tree`` (projectArgumentsFilePath: string) =
graphFromHeuristic
|> Graph.map (fun n -> n, files.[n].File)
- |> Graph.serialiseToMermaid $"{fileName}.heuristic-tree.deps.md"
+ |> Graph.writeMermaidToFile $"{fileName}.heuristic-tree.deps.md"
let heuristicMap = collectAllDeps graphFromHeuristic
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 388e16185d4..0acd065dbe6 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -571,6 +571,8 @@ type WorkflowContext =
let SaveAndCheckProject project checker =
async {
+ use _ =
+ Activity.start "SaveAndCheckProject" [ Activity.Tags.project, project.Name ]
do! saveProject project true checker
From 91fad38a78148758fd5b416a18d8023e9304b1c4 Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Wed, 10 May 2023 18:28:55 +0200
Subject: [PATCH 025/222] wip
---
src/Compiler/Driver/ParseAndCheckInputs.fsi | 20 ++-
src/Compiler/Service/TransparentCompiler.fs | 121 ++++++++----------
.../FSharpChecker/TransparentCompiler.fs | 30 ++++-
.../ProjectGeneration.fs | 15 +++
4 files changed, 109 insertions(+), 77 deletions(-)
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi
index 718a9e3d746..37e76d82d48 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fsi
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi
@@ -163,6 +163,9 @@ type TcState =
member CreatesGeneratedProvidedTypes: bool
+
+type PartialResult = TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType
+
/// Get the initial type checking state for a set of inputs
val GetInitialTcState: range * string * TcConfig * TcGlobals * TcImports * TcEnv * OpenDeclaration list -> TcState
@@ -183,6 +186,18 @@ val CheckOneInput:
input: ParsedInput ->
Cancellable<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState>
+val CheckOneInputWithCallback:
+ checkForErrors: (unit -> bool) *
+ tcConfig: TcConfig *
+ tcImports: TcImports *
+ tcGlobals: TcGlobals *
+ prefixPathOpt: LongIdent option *
+ tcSink: TcResultsSink *
+ tcState: TcState *
+ input: ParsedInput *
+ _skipImplIfSigExists: bool -> Cancellable>
+
+
val AddCheckResultsToTcState:
tcGlobals: TcGlobals *
amap: Import.ImportMap *
@@ -195,8 +210,6 @@ val AddCheckResultsToTcState:
tcState: TcState ->
ModuleOrNamespaceType * TcState
-type PartialResult = TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType
-
val AddSignatureResultToTcImplEnv:
tcImports: TcImports *
tcGlobals: TcGlobals *
@@ -204,8 +217,7 @@ val AddSignatureResultToTcImplEnv:
tcSink: TcResultsSink *
tcState: TcState *
input: ParsedInput ->
- (TcState ->
- PartialResult * TcState)
+ (TcState -> PartialResult * TcState)
val TransformDependencyGraph: graph: Graph * filePairs: FilePairMap -> Graph
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index bf11cc15829..8df2390ea49 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -33,6 +33,7 @@ open FSharp.Compiler.CompilerDiagnostics
open FSharp.Compiler.NameResolution
open Internal.Utilities.Library.Extras
open FSharp.Compiler.TypedTree
+open FSharp.Compiler.CheckDeclarations
type internal FSharpFile =
{
@@ -55,6 +56,23 @@ type internal BootstrapInfo =
type internal TcIntermediateResult = TcInfo * TcResultsSinkImpl * CheckedImplFile option * string
+
+/// Accumulated results of type checking. The minimum amount of state in order to continue type-checking following files.
+[]
+type internal TcIntermediate =
+ {
+ finisher: Finisher
+ //tcEnvAtEndOfFile: TcEnv
+
+ /// Disambiguation table for module names
+ moduleNamesDict: ModuleNamesDict
+
+ /// Accumulated diagnostics, last file first
+ tcDiagnosticsRev:(PhasedDiagnostic * FSharpDiagnosticSeverity)[] list
+
+ tcDependencyFiles: string list
+ }
+
type internal TransparentCompiler
(
legacyReferenceResolver,
@@ -602,7 +620,7 @@ type internal TransparentCompiler
return TransformDependencyGraph(graph, filePairs), filePairs
}
- let ComputeTcIntermediate (parsedInput: ParsedInput, parseErrors) bootstrapInfo prevTcInfo _key =
+ let ComputeTcIntermediate (parsedInput: ParsedInput, parseErrors) bootstrapInfo (prevTcInfo: TcInfo) _key =
node {
let input = parsedInput
let fileName = input.FileName
@@ -633,8 +651,8 @@ type internal TransparentCompiler
let input, moduleNamesDict =
DeduplicateParsedInputModuleName prevTcInfo.moduleNamesDict input
- let! (tcEnvAtEndOfFile, topAttribs, implFile, ccuSigForFile), tcState =
- CheckOneInput(
+ let! finisher =
+ CheckOneInputWithCallback(
(fun () -> hadParseErrors || diagnosticsLogger.ErrorCount > 0),
tcConfig,
tcImports,
@@ -642,7 +660,8 @@ type internal TransparentCompiler
None,
TcResultsSink.WithSink sink,
prevTcInfo.tcState,
- input
+ input,
+ false
)
|> NodeCode.FromCancellable
@@ -651,62 +670,27 @@ type internal TransparentCompiler
let newErrors =
Array.append parseErrors (capturingDiagnosticsLogger.Diagnostics |> List.toArray)
- let tcEnvAtEndOfFile =
- if keepAllBackgroundResolutions then
- tcEnvAtEndOfFile
- else
- tcState.TcEnvFromImpls
-
- let tcInfo =
+ return
{
- tcState = tcState
- tcEnvAtEndOfFile = tcEnvAtEndOfFile
+ finisher = finisher
moduleNamesDict = moduleNamesDict
- latestCcuSigForFile = Some ccuSigForFile
tcDiagnosticsRev = [ newErrors ]
- topAttribs = Some topAttribs
tcDependencyFiles = [ fileName ]
- // we shouldn't need this with graph checking (?)
- sigNameOpt = None
}
-
- return tcInfo, sink, implFile, fileName
}
- let mergeIntermediateResults bootstrapInfo =
- Array.fold (fun (a: TcInfo, _, _, _) (b, sink, implFileOpt: CheckedImplFile option, name) ->
- // TODO: proper merge
-
- let amap = bootstrapInfo.TcImports.GetImportMap()
-
- // TODO: figure out
- let hadSig = false
-
- let prefixPathOpt = None
-
- let ccuSigForFile, tcState =
- match implFileOpt with
- | Some implFile ->
-
- let ccuSigForFile, tcState =
- AddCheckResultsToTcState
- (bootstrapInfo.TcGlobals, amap, hadSig, prefixPathOpt, TcResultsSink.NoSink, a.tcState.TcEnvFromImpls, implFile.QualifiedNameOfFile, implFile.Signature)
- b.tcState
- Some ccuSigForFile, tcState
- | None ->
- b.latestCcuSigForFile, b.tcState
-
- { a with
+ let mergeIntermediateResults =
+ Array.fold (fun (tcInfo: TcInfo) (tcIntermediate: TcIntermediate) ->
+ let (tcEnv, topAttribs, _checkImplFileOpt, ccuSigForFile), tcState = tcInfo.tcState |> tcIntermediate.finisher.Invoke
+ let tcEnvAtEndOfFile = if keepAllBackgroundResolutions then tcEnv else tcState.TcEnvFromImpls
+ { tcInfo with
tcState = tcState
- tcEnvAtEndOfFile = b.tcEnvAtEndOfFile
- moduleNamesDict = b.moduleNamesDict
- latestCcuSigForFile = ccuSigForFile
- tcDiagnosticsRev = b.tcDiagnosticsRev @ a.tcDiagnosticsRev
- topAttribs = b.topAttribs
- tcDependencyFiles = b.tcDependencyFiles @ a.tcDependencyFiles
- // we shouldn't need this with graph checking (?)
- sigNameOpt = None
- }, sink, implFileOpt, name)
+ tcEnvAtEndOfFile = tcEnvAtEndOfFile
+ topAttribs = Some topAttribs
+ tcDiagnosticsRev = tcIntermediate.tcDiagnosticsRev @ tcInfo.tcDiagnosticsRev
+ tcDependencyFiles = tcIntermediate.tcDependencyFiles @ tcInfo.tcDependencyFiles
+ latestCcuSigForFile = Some ccuSigForFile })
+
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName _key =
@@ -769,28 +753,25 @@ type internal TransparentCompiler
let key = projectSnapshot.UpTo(fileIndex).Key
TcIntermediateCache.Get(key, ComputeTcIntermediate (parsedInput, parseErrors) bootstrapInfo tcInfo)
| NodeToTypeCheck.ArtificialImplFile fileIndex ->
- let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
- let tcState = tcInfo.tcState
- let prefixPathOpt = None
-
- let (tcEnv , topAttribs , checkedImplFileOpt , _moduleOrNamespaceType), newTcState =
+
+ let finisher tcState =
+ let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
+ let prefixPathOpt = None
// Retrieve the type-checked signature information and add it to the TcEnvFromImpls.
AddSignatureResultToTcImplEnv(bootstrapInfo.TcImports, bootstrapInfo.TcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, parsedInput) tcState
- let tcInfo =
- { tcInfo with
- tcState = newTcState
- tcEnvAtEndOfFile = tcEnv
-
- topAttribs = Some topAttribs
- // we shouldn't need this with graph checking (?)
- sigNameOpt = None
+ let tcIntermediate =
+ {
+ finisher = finisher
+ moduleNamesDict = tcInfo.moduleNamesDict
+ tcDiagnosticsRev = []
+ tcDependencyFiles = []
}
- node.Return(tcInfo, Unchecked.defaultof<_>, checkedImplFileOpt, parsedInput.FileName))
+ node.Return(tcIntermediate))
|> NodeCode.Parallel
- let nodes = layer |> Seq.map (function NodeToTypeCheck.PhysicalFile i -> fileNames[i] | NodeToTypeCheck.ArtificialImplFile i -> $"AIF : {fileNames[i]}") |> String.concat " "
- Trace.TraceInformation $"Processed layer {nodes}"
- return! processLayer rest (mergeIntermediateResults bootstrapInfo (tcInfo, Unchecked.defaultof<_>, None, "") results |> p14)
+ //let nodes = layer |> Seq.map (function NodeToTypeCheck.PhysicalFile i -> fileNames[i] | NodeToTypeCheck.ArtificialImplFile i -> $"AIF : {fileNames[i]}") |> String.concat " "
+ //Trace.TraceInformation $"Processed layer {nodes}"
+ return! processLayer rest (mergeIntermediateResults tcInfo results)
}
return! processLayer layers bootstrapInfo.InitialTcInfo
@@ -836,7 +817,7 @@ type internal TransparentCompiler
input = parseTree,
parseHadErrors = (parseDiagnostics.Length > 0),
// TODO: check if we really need this in parse results
- dependencyFiles = [||]
+ dependencyFiles = Array.ofList tcInfo.tcDependencyFiles
)
let! checkResults =
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index ea679f5476d..636e7cd7a64 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -41,6 +41,8 @@ module Activity =
let listenToAll () = listen ""
+open Activity
+
[]
let ``Use Transparent Compiler`` () =
@@ -88,6 +90,8 @@ let ``Parallel processing`` () =
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
checkFile "E" expectOk
+ updateFile "A" updatePublicSurface
+ checkFile "E" expectSignatureChanged
}
@@ -104,9 +108,15 @@ let ``Parallel processing with signatures`` () =
sourceFile "E" ["B"; "C"; "D"] |> addSignatureFile)
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
- checkFile "C" expectOk
- //updateFile "A" updatePublicSurface
- //checkFile "E" expectSignatureChanged
+ checkFile "E" expectOk
+ updateFile "A" updatePublicSurface
+ checkFile "E" expectNoChanges
+ regenerateSignature "A"
+ regenerateSignature "B"
+ regenerateSignature "C"
+ regenerateSignature "D"
+ regenerateSignature "E"
+ checkFile "E" expectSignatureChanged
}
@@ -161,6 +171,20 @@ let ``Files depend on signature file if present`` () =
checkFile "Second" expectNoChanges
}
+[]
+let ``Signature update`` () =
+ listenToAll ()
+
+ let project = makeTestProject() |> updateFile "First" addSignatureFile
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ updateFile "First" updatePublicSurface
+ saveFile "First"
+ checkFile "Second" expectNoChanges
+ regenerateSignature "First"
+ checkFile "Second" expectSignatureChanged
+ }
+
[]
let ``Adding a file`` () =
testWorkflow() {
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 0acd065dbe6..4f8a36ebf06 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -696,6 +696,21 @@ type ProjectWorkflowBuilder
return project
})
+ []
+ member this.RegenerateSignature(workflow: Async, fileId: string) =
+ workflow
+ |> mapProjectAsync (fun project ->
+ async {
+ use _ =
+ Activity.start "ProjectWorkflowBuilder.RegenerateSignature" [ Activity.Tags.project, project.Name; "fileId", fileId ]
+ let project, file = project.FindInAllProjects fileId
+ let! result = checkFile fileId project checker
+ let signature = getSignature result
+ let signatureFileName = getSignatureFilePath project file
+ writeFileIfChanged signatureFileName signature
+ return project
+ })
+
/// Add a file above given file in the project.
[]
member this.AddFileAbove(workflow: Async, addAboveId: string, newFile) =
From 2273ffe93c9f17db26256d2735b7d2d422d90dd0 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 11 May 2023 12:48:54 +0200
Subject: [PATCH 026/222] wip
---
src/Compiler/Driver/ParseAndCheckInputs.fsi | 21 +++++++++----------
.../FSharpChecker/TransparentCompiler.fs | 17 ++++++++-------
.../TypeChecks/Graph/GraphOperations.fs | 2 +-
.../ProjectGeneration.fs | 17 ++++++++-------
4 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi
index 37e76d82d48..9758fc5d0b0 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fsi
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi
@@ -163,7 +163,6 @@ type TcState =
member CreatesGeneratedProvidedTypes: bool
-
type PartialResult = TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType
/// Get the initial type checking state for a set of inputs
@@ -187,16 +186,16 @@ val CheckOneInput:
Cancellable<(TcEnv * TopAttribs * CheckedImplFile option * ModuleOrNamespaceType) * TcState>
val CheckOneInputWithCallback:
- checkForErrors: (unit -> bool) *
- tcConfig: TcConfig *
- tcImports: TcImports *
- tcGlobals: TcGlobals *
- prefixPathOpt: LongIdent option *
- tcSink: TcResultsSink *
- tcState: TcState *
- input: ParsedInput *
- _skipImplIfSigExists: bool -> Cancellable>
-
+ checkForErrors: (unit -> bool) *
+ tcConfig: TcConfig *
+ tcImports: TcImports *
+ tcGlobals: TcGlobals *
+ prefixPathOpt: LongIdent option *
+ tcSink: TcResultsSink *
+ tcState: TcState *
+ input: ParsedInput *
+ _skipImplIfSigExists: bool ->
+ Cancellable>
val AddCheckResultsToTcState:
tcGlobals: TcGlobals *
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 636e7cd7a64..d474f5f0734 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -41,8 +41,6 @@ module Activity =
let listenToAll () = listen ""
-open Activity
-
[]
let ``Use Transparent Compiler`` () =
@@ -173,15 +171,18 @@ let ``Files depend on signature file if present`` () =
[]
let ``Signature update`` () =
- listenToAll ()
+ Activity.listenToAll ()
- let project = makeTestProject() |> updateFile "First" addSignatureFile
+ let project = SyntheticProject.Create(
+ { sourceFile "First" [] with
+ Source = "let f x = x"
+ SignatureFile = Custom "val f: x: int -> int" },
+ { sourceFile "Second" ["First"] with
+ Source = "let a x = ModuleFirst.f x" })
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
- updateFile "First" updatePublicSurface
- saveFile "First"
- checkFile "Second" expectNoChanges
- regenerateSignature "First"
+ checkFile "Second" expectOk
+ updateFile "First" (fun f -> { f with SignatureFile = Custom "val f: x: string -> string" })
checkFile "Second" expectSignatureChanged
}
diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
index dedac14ba76..b71add124ca 100644
--- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
+++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/GraphOperations.fs
@@ -41,7 +41,7 @@ let ``See what this does`` () =
sourceFile "E" ["A"; "B"; "C"] |> addSignatureFile,
sourceFile "F" ["C"; "D"] |> addSignatureFile
).Workflow {
- withProject (fun project checker ->
+ withProject (fun project checker ->
async {
let options = project.GetProjectOptions checker
let options, _ = checker.GetParsingOptionsFromProjectOptions options
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 4f8a36ebf06..8e1eac488e8 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -23,6 +23,7 @@ open FSharp.Compiler.Diagnostics
open FSharp.Compiler.Text
open Xunit
open System.Collections.Concurrent
+open System.Text
#nowarn "57" // Experimental feature use
@@ -362,22 +363,24 @@ module ProjectOperations =
let getFileSnapshot (project: SyntheticProject) _options (path: string) =
async {
- let file, filePath =
+ let filePath =
if path.EndsWith(".fsi") then
let implFilePath = path[..path.Length - 2]
let f = project.FindByPath implFilePath
- f, getSignatureFilePath project f
+ getSignatureFilePath project f
else
let f = project.FindByPath path
- f, getFilePath project f
+ getFilePath project f
- let dependencies = file.DependsOn |> String.concat "|"
- let version = $"{file.PublicVersion}|{file.InternalVersion}|{file.FunctionName}|{file.Source.GetHashCode()}|{file.ExtraSource.GetHashCode()}|{dependencies}"
+ let source = getSourceText project path
+ use md5 = System.Security.Cryptography.MD5.Create()
+ let inputBytes = Encoding.UTF8.GetBytes(source.ToString())
+ let hash = md5.ComputeHash(inputBytes) |> Array.map (fun b -> b.ToString("X2")) |> String.concat ""
return {
FileName = filePath
- Version = version
- GetSource = fun () -> getSourceText project path |> Task.FromResult
+ Version = hash
+ GetSource = fun () -> source |> Task.FromResult
}
}
From ff4d5e615b7f7e67915ff8f9ffa29788822870ef Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 12 May 2023 13:55:31 +0200
Subject: [PATCH 027/222] BootstrapInfoStatic, activity reorganization
---
src/Compiler/Facilities/AsyncMemoize.fs | 27 +++-------
src/Compiler/Service/BackgroundCompiler.fs | 6 +++
src/Compiler/Service/FSharpCheckerResults.fs | 5 ++
src/Compiler/Service/FSharpCheckerResults.fsi | 3 ++
src/Compiler/Service/TransparentCompiler.fs | 54 ++++++++++++++-----
src/Compiler/Service/service.fs | 2 +
src/Compiler/Service/service.fsi | 2 +
src/Compiler/Utilities/Activity.fs | 1 +
src/Compiler/Utilities/Activity.fsi | 1 +
.../CompilerService/AsyncMemoize.fs | 12 ++---
.../FSharpChecker/TransparentCompiler.fs | 11 ++--
11 files changed, 80 insertions(+), 44 deletions(-)
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
index 941cacb8013..8211228e711 100644
--- a/src/Compiler/Facilities/AsyncMemoize.fs
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -3,7 +3,6 @@ namespace Internal.Utilities.Collections
open FSharp.Compiler.BuildGraph
open System.Threading
open System.Collections.Generic
-open FSharp.Compiler.Diagnostics
type internal Action<'TKey, 'TValue> =
| GetOrCompute of ('TKey -> NodeCode<'TValue>) * CancellationToken
@@ -16,23 +15,15 @@ type internal Job<'TValue> =
| Running of NodeCode<'TValue> * CancellationTokenSource
| Completed of NodeCode<'TValue>
-type internal JobEvent<'TKey> =
- | Started of 'TKey
- | Finished of 'TKey
- | Canceled of 'TKey
+type internal JobEventType =
+ | Started
+ | Finished
+ | Canceled
- member this.Key =
- match this with
- | Started key -> key
- | Finished key -> key
- | Canceled key -> key
-
-type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobEvent<'TKey> -> unit), ?name: string) =
+type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobEventType * 'TKey -> unit)) =
let tok = obj ()
- let name = name |> Option.defaultValue "Unnamed"
-
let cache =
MruCache<_, 'TKey, Job<'TValue>>(keepStrongly = 10, areSame = (fun (x, y) -> x = y))
@@ -76,8 +67,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
Async.StartAsTask(
Async.AwaitNodeCode(
node {
- use _ = Activity.start $"AsyncMemoize.{name}" [||]
- log (Started key)
+ log (Started, key)
let! result = computation key
post key JobCompleted
return result
@@ -106,7 +96,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
cts.Cancel()
cache.RemoveAnySimilar(tok, key)
requestCounts.Remove key |> ignore
- log (Canceled key)
+ log (Canceled, key)
| CancelRequest, None
| CancelRequest, Some (Completed _) -> ()
@@ -115,10 +105,9 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
// TODO: should we re-wrap the result?
cache.Set(tok, key, (Completed job))
requestCounts.Remove key |> ignore
- log (Finished key)
+ log (Finished, key)
| JobCompleted, _ -> failwith "If this happens there's a bug"
-
})
member _.Get(key, computation) =
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index ddf9d3f0c04..3b1039066eb 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -150,6 +150,8 @@ type internal IBackgroundCompiler =
abstract member ProjectChecked: IEvent
+ abstract member CacheEvent: IEvent
+
type ParseCacheLockToken() =
interface LockToken
@@ -234,6 +236,8 @@ type internal BackgroundCompiler
let fileChecked = Event()
let projectChecked = Event()
+ let cacheEvent = Event()
+
// STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.scriptClosureCache
/// Information about the derived script closure.
let scriptClosureCache =
@@ -1378,6 +1382,8 @@ type internal BackgroundCompiler
interface IBackgroundCompiler with
+ member _.CacheEvent = cacheEvent.Publish
+
member _.BeforeBackgroundFileCheck = self.BeforeBackgroundFileCheck
member _.CheckFileInProject
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 9f7973d90c7..8a92f3b229d 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -218,6 +218,11 @@ type FSharpProjectSnapshot =
member this.SourceFileNames = this.SourceFiles |> List.map (fun x -> x.FileName)
+ member this.WithoutFileVersions =
+ { this with
+ SourceFiles = this.SourceFiles |> List.map (fun x -> { x with Version = "" })
+ }
+
override this.ToString() =
"FSharpProjectSnapshot(" + this.ProjectFileName + ")"
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 43052e69f9c..2bd4cbbd990 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -121,6 +121,9 @@ type FSharpProjectSnapshot =
/// A snapshot of the same project but only up to the given file (including).
member UpTo: fileName: string -> FSharpProjectSnapshot
+ /// A snapshot of the same project with file versions removed.
+ member WithoutFileVersions: FSharpProjectSnapshot
+
member Key: FSharpProjectSnapshotKey
and [] public FSharpReferencedProjectSnapshot =
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 8df2390ea49..03f70792a0d 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -94,13 +94,17 @@ type internal TransparentCompiler
// Is having just one of these ok?
let lexResourceManager = Lexhelp.LexResourceManager()
- let ParseFileCache = AsyncMemoize(name = "ParseFile")
- let ParseAndCheckFileInProjectCache = AsyncMemoize(name = "ParseAndCheckFileInProject")
- let FrameworkImportsCache = AsyncMemoize(name = "FrameworkImports")
- let BootstrapInfoCache = AsyncMemoize(name = "BootstrapInfo")
- let TcPriorCache = AsyncMemoize(name = "TcPrior")
- let TcIntermediateCache = AsyncMemoize(name = "TcIntermediate")
- let DependencyGraphForLastFileCache = AsyncMemoize(name = "DependencyGraphForLastFile")
+ let cacheEvent = new Event()
+
+ let ParseFileCache =
+ AsyncMemoize(logEvent = fun (e, ((fileName, version), _, _)) -> cacheEvent.Trigger("ParseFile", e, [| fileName; version |] ))
+ let ParseAndCheckFileInProjectCache = AsyncMemoize()
+ let FrameworkImportsCache = AsyncMemoize()
+ let BootstrapInfoStaticCache = AsyncMemoize()
+ let BootstrapInfoCache = AsyncMemoize()
+ let TcPriorCache = AsyncMemoize()
+ let TcIntermediateCache = AsyncMemoize()
+ let DependencyGraphForLastFileCache = AsyncMemoize()
// We currently share one global dependency provider for all scripts for the FSharpChecker.
// For projects, one is used per project.
@@ -170,6 +174,7 @@ type internal TransparentCompiler
let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions _key =
node {
+ use _ = Activity.start "ComputeFrameworkImports" []
let tcConfigP = TcConfigProvider.Constant tcConfig
return! TcImports.BuildFrameworkTcImports(tcConfigP, frameworkDLLs, nonFrameworkResolutions)
}
@@ -273,8 +278,11 @@ type internal TransparentCompiler
return tcImports, tcInfo
}
- let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
+ /// Bootstrap info that does not depend on contents of the files
+ let ComputeBootstrapInfoStatic (projectSnapshot: FSharpProjectSnapshot) _key =
node {
+ use _ = Activity.start "ComputeBootstrapInfoStatic" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
+
let useSimpleResolutionSwitch = "--simpleresolution"
let commandLineArgs = projectSnapshot.OtherOptions
let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir
@@ -455,9 +463,9 @@ type internal TransparentCompiler
let tcConfigP = TcConfigProvider.Constant tcConfig
-#if !NO_TYPEPROVIDERS
+ #if !NO_TYPEPROVIDERS
let importsInvalidatedByTypeProvider = Event()
-#endif
+ #endif
// Check for the existence of loaded sources and prepend them to the sources list if present.
let sourceFiles =
@@ -506,10 +514,18 @@ type internal TransparentCompiler
dependencyProvider,
loadClosureOpt,
basicDependencies
-#if !NO_TYPEPROVIDERS
+ #if !NO_TYPEPROVIDERS
,importsInvalidatedByTypeProvider
-#endif
+ #endif
)
+ return sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt
+ }
+
+ let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
+ node {
+ let bootstrapStaticKey = projectSnapshot.WithoutFileVersions.Key
+
+ let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt = BootstrapInfoStaticCache.Get(bootstrapStaticKey, ComputeBootstrapInfoStatic projectSnapshot)
let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
@@ -547,6 +563,7 @@ type internal TransparentCompiler
let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) _key =
node {
+ use _ = Activity.start "ComputeBootstrapInfo" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
// Trap and report diagnostics from creation.
let delayedLogger = CapturingDiagnosticsLogger("IncrementalBuilderCreation")
@@ -580,6 +597,8 @@ type internal TransparentCompiler
let ComputeParseFile (file: FSharpFile) bootstrapInfo _key =
node {
+ use _ = Activity.start "ComputeParseFile" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName; Activity.Tags.version, file.Source.Version |]
+
let tcConfig = bootstrapInfo.TcConfig
let diagnosticsLogger =
@@ -599,6 +618,7 @@ type internal TransparentCompiler
let ComputeDependencyGraphForLastFile parsedInputs (tcConfig: TcConfig) _key =
node {
+
let sourceFiles: FileInProject array =
parsedInputs
|> Seq.toArray
@@ -609,6 +629,8 @@ type internal TransparentCompiler
ParsedInput = input
})
+ use _ = Activity.start "ComputeDependencyGraphForLastFile" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
+
let filePairs = FilePairMap(sourceFiles)
// TODO: we will probably want to cache and re-use larger graphs if available
@@ -624,6 +646,9 @@ type internal TransparentCompiler
node {
let input = parsedInput
let fileName = input.FileName
+
+ use _ = Activity.start "ComputeTcIntermediate" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+
let tcConfig = bootstrapInfo.TcConfig
let tcGlobals = bootstrapInfo.TcGlobals
let tcImports = bootstrapInfo.TcImports
@@ -695,6 +720,8 @@ type internal TransparentCompiler
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName _key =
node {
+
+ use _ = Activity.start "ComputeTcPrior" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName |]
// parse required files
let files =
@@ -779,6 +806,8 @@ type internal TransparentCompiler
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
node {
+
+ use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
let! bootstrapInfoOpt, creationDiags = BootstrapInfoCache.Get(projectSnapshot.Key, ComputeBootstrapInfo projectSnapshot)
@@ -854,6 +883,7 @@ type internal TransparentCompiler
}
interface IBackgroundCompiler with
+ member _.CacheEvent = cacheEvent.Publish
member this.BeforeBackgroundFileCheck: IEvent =
backgroundCompiler.BeforeBackgroundFileCheck
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index 83a005c258e..dacc23cd47f 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -586,6 +586,8 @@ type FSharpChecker
member _.ProjectChecked = backgroundCompiler.ProjectChecked
+ member _.CacheEvent = backgroundCompiler.CacheEvent
+
static member ActualParseFileCount = BackgroundCompiler.ActualParseFileCount
static member ActualCheckFileCount = BackgroundCompiler.ActualCheckFileCount
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index 97bde85058f..d52e0c1f44e 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -428,6 +428,8 @@ type public FSharpChecker =
/// The event may be raised on a background thread.
member ProjectChecked: IEvent
+ member internal CacheEvent: IEvent
+
[]
static member Instance: FSharpChecker
member internal FrameworkImportsCache: FrameworkImportsCache
diff --git a/src/Compiler/Utilities/Activity.fs b/src/Compiler/Utilities/Activity.fs
index e3b29dd6fd0..b64100a02fd 100644
--- a/src/Compiler/Utilities/Activity.fs
+++ b/src/Compiler/Utilities/Activity.fs
@@ -33,6 +33,7 @@ module internal Activity =
let gc2 = "gc2"
let outputDllFile = "outputDllFile"
let buildPhase = "buildPhase"
+ let version = "version"
let AllKnownTags =
[|
diff --git a/src/Compiler/Utilities/Activity.fsi b/src/Compiler/Utilities/Activity.fsi
index 94784c97f00..b05f0c4ba54 100644
--- a/src/Compiler/Utilities/Activity.fsi
+++ b/src/Compiler/Utilities/Activity.fsi
@@ -29,6 +29,7 @@ module internal Activity =
val length: string
val cache: string
val buildPhase: string
+ val version: string
module Events =
val cacheHit: string
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
index 41880ac0d96..0def4960fd6 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -35,10 +35,10 @@ let ``Basics``() =
Assert.Equal(expected, result)
- let groups = eventLog |> Seq.groupBy (fun e -> e.Key) |> Seq.toList
+ let groups = eventLog |> Seq.groupBy snd |> Seq.toList
Assert.Equal(3, groups.Length)
for key, events in groups do
- Assert.Equal array>([| Started key; Finished key |], events |> Seq.toArray)
+ Assert.Equal<(JobEventType * int) array>([| Started, key; Finished, key |], events |> Seq.toArray)
[]
let ``We can cancel a job`` () =
@@ -67,20 +67,20 @@ let ``We can cancel a job`` () =
resetEvent.WaitOne() |> ignore
- Assert.Equal array>([| Started key |], eventLog |> Seq.toArray )
+ Assert.Equal<(JobEventType * int) array>([| Started, key |], eventLog |> Seq.toArray )
cts1.Cancel()
cts2.Cancel()
Thread.Sleep 10
- Assert.Equal array>([| Started key |], eventLog |> Seq.toArray )
+ Assert.Equal<(JobEventType * int) array>([| Started, key |], eventLog |> Seq.toArray )
cts3.Cancel()
Thread.Sleep 100
- Assert.Equal array>([| Started key; Canceled key |], eventLog |> Seq.toArray )
+ Assert.Equal<(JobEventType * int) array>([| Started, key; Canceled, key |], eventLog |> Seq.toArray )
try
Task.WaitAll(_task1, _task2, _task3)
@@ -117,5 +117,5 @@ let ``Job keeps running even if first requestor cancels`` () =
Assert.Equal(2, result)
Thread.Sleep 1 // Wait for event log to be updated
- Assert.Equal array>([| Started key; Finished key |], eventLog |> Seq.toArray )
+ Assert.Equal<(JobEventType * int) array>([| Started, key; Finished, key |], eventLog |> Seq.toArray )
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index d474f5f0734..9951aedfdb7 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -1,14 +1,11 @@
module FSharp.Compiler.ComponentTests.FSharpChecker.TransparentCompiler
-open System
-open System.IO
+open System.Collections.Concurrent
open System.Diagnostics
open Xunit
open FSharp.Test.ProjectGeneration
-open FSharp.Compiler.Text
-open FSharp.Compiler.CodeAnalysis
module Activity =
let listen (filter: string) =
@@ -41,7 +38,6 @@ module Activity =
let listenToAll () = listen ""
-
[]
let ``Use Transparent Compiler`` () =
@@ -92,7 +88,6 @@ let ``Parallel processing`` () =
checkFile "E" expectSignatureChanged
}
-
[]
let ``Parallel processing with signatures`` () =
@@ -105,7 +100,10 @@ let ``Parallel processing with signatures`` () =
sourceFile "D" ["A"] |> addSignatureFile,
sourceFile "E" ["B"; "C"; "D"] |> addSignatureFile)
+ let cacheEvents = ConcurrentBag<_>()
+
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
checkFile "E" expectOk
updateFile "A" updatePublicSurface
checkFile "E" expectNoChanges
@@ -117,7 +115,6 @@ let ``Parallel processing with signatures`` () =
checkFile "E" expectSignatureChanged
}
-
let makeTestProject () =
SyntheticProject.Create(
sourceFile "First" [],
From 0b93dd14a9d2c0dc8bebf7214c259dd105d43760 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 12 May 2023 16:32:10 +0200
Subject: [PATCH 028/222] ...
---
tests/FSharp.Test.Utilities/ProjectGeneration.fs | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 8e1eac488e8..2c223126984 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -680,6 +680,14 @@ type ProjectWorkflowBuilder
return project
})
+ []
+ member this.WithChecker(workflow: Async, f) =
+ async {
+ let! ctx = workflow
+ f checker
+ return ctx
+ }
+
/// Change contents of given file using `processFile` function.
/// Does not save the file to disk.
[]
@@ -737,10 +745,11 @@ type ProjectWorkflowBuilder
[]
member this.CheckFile(workflow: Async, fileId: string, processResults) =
async {
+ let! ctx = workflow
+
use _ =
Activity.start "ProjectWorkflowBuilder.CheckFile" [ Activity.Tags.project, initialProject.Name; "fileId", fileId ]
- let! ctx = workflow
let! results = checkFile fileId ctx.Project checker
let oldSignature = ctx.Signatures[fileId]
@@ -753,10 +762,10 @@ type ProjectWorkflowBuilder
member this.CheckFile(workflow: Async, fileId: string, processResults) =
async {
+ let! ctx = workflow
use _ =
Activity.start "ProjectWorkflowBuilder.CheckFile" [ Activity.Tags.project, initialProject.Name; "fileId", fileId ]
- let! ctx = workflow
let! results = checkFile fileId ctx.Project checker
let typeCheckResults = getTypeCheckResult results
From c088cbbace76170941b2e0b25e3c647baf1822b7 Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Mon, 15 May 2023 14:24:41 +0200
Subject: [PATCH 029/222] Local activity tracing for tests
---
eng/Versions.props | 2 +-
.../FSharp.Test.Utilities.fsproj | 5 ++--
.../ProjectGeneration.fs | 29 ++++++++++++++++---
3 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/eng/Versions.props b/eng/Versions.props
index 9a57897d2ad..2f81dd45ef5 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -97,7 +97,7 @@
4.5.1
6.0.0
1.6.0
- 6.0.0
+ 7.0.0
4.5.5
4.7.0
6.0.1
diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
index 0cd32d852f9..b6c455a5499 100644
--- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
+++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj
@@ -66,7 +66,7 @@
-
+
@@ -78,6 +78,7 @@
+
@@ -107,6 +108,4 @@
-
-
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index cd873ddbb0d..4501af8ffc1 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -23,6 +23,10 @@ open FSharp.Compiler.Text
open Xunit
open System.Collections.Concurrent
+open OpenTelemetry
+open OpenTelemetry.Resources
+open OpenTelemetry.Trace
+
#nowarn "57" // Experimental feature use
let private projectRoot = "test-projects"
@@ -546,6 +550,8 @@ type ProjectWorkflowBuilder
let useChangeNotifications = defaultArg useChangeNotifications false
let mutable latestProject = initialProject
+ let mutable activity = None
+ let mutable tracerProvider = None
let getSource (filePath: string) =
if filePath.EndsWith(".fsi") then
@@ -600,10 +606,21 @@ type ProjectWorkflowBuilder
member this.Checker = checker
- member this.Yield _ =
- match initialContext with
- | Some ctx -> async.Return ctx
- | _ -> SaveAndCheckProject initialProject checker
+ member this.Yield _ = async {
+ let! ctx =
+ match initialContext with
+ | Some ctx -> async.Return ctx
+ | _ -> SaveAndCheckProject initialProject checker
+ tracerProvider <-
+ Sdk.CreateTracerProviderBuilder()
+ .AddSource("fsc")
+ .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName="F#", serviceVersion = "1"))
+ .AddJaegerExporter()
+ .Build()
+ |> Some
+ activity <- Activity.start ctx.Project.Name [ Activity.Tags.project, ctx.Project.Name ] |> Some
+ return ctx
+ }
member this.DeleteProjectDir() =
if Directory.Exists initialProject.ProjectDir then
@@ -615,6 +632,10 @@ type ProjectWorkflowBuilder
finally
if initialContext.IsNone then
this.DeleteProjectDir()
+ activity |> Option.iter (fun x -> x.Dispose())
+ tracerProvider |> Option.iter (fun x ->
+ x.ForceFlush() |> ignore
+ x.Dispose())
/// Change contents of given file using `processFile` function.
/// Does not save the file to disk.
From 33afd1f516f5392cd8db9d7f728fcb02ada0d5a0 Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Mon, 15 May 2023 17:54:26 +0200
Subject: [PATCH 030/222] wip
---
src/Compiler/Facilities/AsyncMemoize.fs | 4 +-
src/Compiler/Service/BackgroundCompiler.fs | 7 ++
src/Compiler/Service/TransparentCompiler.fs | 59 ++++++++++++--
src/Compiler/Service/service.fs | 5 ++
src/Compiler/Service/service.fsi | 3 +
.../CompilerService/AsyncMemoize.fs | 24 +++---
.../FSharpChecker/TransparentCompiler.fs | 2 +-
.../LanguageService/WorkspaceExtensions.fs | 80 +++++++++++--------
.../FSharp.Editor/Options/EditorOptions.fs | 2 +-
9 files changed, 129 insertions(+), 57 deletions(-)
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
index 8211228e711..581e6201193 100644
--- a/src/Compiler/Facilities/AsyncMemoize.fs
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -5,7 +5,7 @@ open System.Threading
open System.Collections.Generic
type internal Action<'TKey, 'TValue> =
- | GetOrCompute of ('TKey -> NodeCode<'TValue>) * CancellationToken
+ | GetOrCompute of NodeCode<'TValue> * CancellationToken
| CancelRequest
| JobCompleted
@@ -68,7 +68,7 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
Async.AwaitNodeCode(
node {
log (Started, key)
- let! result = computation key
+ let! result = computation
post key JobCompleted
return result
}
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index 3b1039066eb..72bba6b4bc3 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -134,6 +134,10 @@ type internal IBackgroundCompiler =
abstract member ParseFile:
fileName: string * sourceText: ISourceText * options: FSharpParsingOptions * cache: bool * userOpName: string ->
Async
+
+ abstract member ParseFile:
+ fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string ->
+ NodeCode
/// Try to get recent approximate type check results for a file.
abstract member TryGetRecentCheckResultsForFile:
@@ -1530,6 +1534,9 @@ type internal BackgroundCompiler
) : Async =
self.ParseFile(fileName, sourceText, options, cache, userOpName)
+ member _.ParseFile(_fileName: string, _projectSnapshot: FSharpProjectSnapshot, _userOpName: string) =
+ raise (System.NotImplementedException())
+
member _.ProjectChecked: IEvent = self.ProjectChecked
member _.TryGetRecentCheckResultsForFile
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 03f70792a0d..771d707e43f 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -172,7 +172,7 @@ type internal TransparentCompiler
}
]
- let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions _key =
+ let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions =
node {
use _ = Activity.start "ComputeFrameworkImports" []
let tcConfigP = TcConfigProvider.Constant tcConfig
@@ -279,7 +279,7 @@ type internal TransparentCompiler
}
/// Bootstrap info that does not depend on contents of the files
- let ComputeBootstrapInfoStatic (projectSnapshot: FSharpProjectSnapshot) _key =
+ let ComputeBootstrapInfoStatic (projectSnapshot: FSharpProjectSnapshot) =
node {
use _ = Activity.start "ComputeBootstrapInfoStatic" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
@@ -561,7 +561,7 @@ type internal TransparentCompiler
}
}
- let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) _key =
+ let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) =
node {
use _ = Activity.start "ComputeBootstrapInfo" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
@@ -595,7 +595,7 @@ type internal TransparentCompiler
return bootstrapInfoOpt, diagnostics
}
- let ComputeParseFile (file: FSharpFile) bootstrapInfo _key =
+ let ComputeParseFile (file: FSharpFile) bootstrapInfo =
node {
use _ = Activity.start "ComputeParseFile" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName; Activity.Tags.version, file.Source.Version |]
@@ -616,7 +616,7 @@ type internal TransparentCompiler
return input, diagnosticsLogger.GetDiagnostics(), sourceText
}
- let ComputeDependencyGraphForLastFile parsedInputs (tcConfig: TcConfig) _key =
+ let ComputeDependencyGraphForLastFile parsedInputs (tcConfig: TcConfig) =
node {
let sourceFiles: FileInProject array =
@@ -642,7 +642,7 @@ type internal TransparentCompiler
return TransformDependencyGraph(graph, filePairs), filePairs
}
- let ComputeTcIntermediate (parsedInput: ParsedInput, parseErrors) bootstrapInfo (prevTcInfo: TcInfo) _key =
+ let ComputeTcIntermediate (parsedInput: ParsedInput, parseErrors) bootstrapInfo (prevTcInfo: TcInfo) =
node {
let input = parsedInput
let fileName = input.FileName
@@ -718,7 +718,7 @@ type internal TransparentCompiler
// Type check everything that is needed to check given file
- let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName _key =
+ let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName =
node {
use _ = Activity.start "ComputeTcPrior" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName |]
@@ -804,7 +804,7 @@ type internal TransparentCompiler
return! processLayer layers bootstrapInfo.InitialTcInfo
}
- let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName _key =
+ let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName =
node {
use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
@@ -876,6 +876,46 @@ type internal TransparentCompiler
return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
}
+ member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
+ node {
+ use _ = Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+
+ let! bootstrapInfoOpt, creationDiags = BootstrapInfoCache.Get(projectSnapshot.Key, ComputeBootstrapInfo projectSnapshot)
+
+ match bootstrapInfoOpt with
+ | None ->
+ let parseTree = EmptyParsedInput(fileName, (false, false))
+ return FSharpParseFileResults(creationDiags, parseTree, true, [||])
+
+ | Some bootstrapInfo ->
+
+ let file =
+ bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
+
+ let! parseTree, parseDiagnostics, _sourceText =
+ ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file bootstrapInfo)
+
+ let parseDiagnostics =
+ DiagnosticHelpers.CreateDiagnostics(
+ bootstrapInfo.TcConfig.diagnosticsOptions,
+ false,
+ fileName,
+ parseDiagnostics,
+ suggestNamesForErrors
+ )
+
+ let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
+
+ return
+ FSharpParseFileResults(
+ diagnostics = diagnostics,
+ input = parseTree,
+ parseHadErrors = (parseDiagnostics.Length > 0),
+ // TODO: check if we really need this in parse results
+ dependencyFiles = [||]
+ )
+ }
+
member _.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) =
node {
let key = fileName, projectSnapshot.Key
@@ -1031,6 +1071,9 @@ type internal TransparentCompiler
member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode =
backgroundCompiler.ParseAndCheckProject(options, userOpName)
+
+ member this.ParseFile(fileName, projectSnapshot, userOpName) =
+ this.ParseFile(fileName, projectSnapshot, userOpName)
member _.ParseFile
(
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index dacc23cd47f..723ddeee6b1 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -307,6 +307,11 @@ type FSharpChecker
let userOpName = defaultArg userOpName "Unknown"
backgroundCompiler.ParseFile(fileName, sourceText, options, cache, userOpName)
+ member _.ParseFile(fileName, projectSnapshot, ?userOpName) =
+ let userOpName = defaultArg userOpName "Unknown"
+ backgroundCompiler.ParseFile(fileName, projectSnapshot, userOpName)
+ |> Async.AwaitNodeCode
+
member ic.ParseFileInProject(fileName, source: string, options, ?cache: bool, ?userOpName: string) =
let parsingOptions, _ = ic.GetParsingOptionsFromProjectOptions(options)
ic.ParseFile(fileName, SourceText.ofString source, parsingOptions, ?cache = cache, ?userOpName = userOpName)
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index d52e0c1f44e..98d5c429680 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -103,6 +103,9 @@ type public FSharpChecker =
fileName: string * sourceText: ISourceText * options: FSharpParsingOptions * ?cache: bool * ?userOpName: string ->
Async
+ member ParseFile: fileName: string * projectSnapshot: FSharpProjectSnapshot * ?userOpName: string ->
+ Async
+
///
/// Parses a source code for a file. Returns an AST that can be traversed for various features.
///
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
index 0def4960fd6..80c137cc603 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -22,12 +22,12 @@ let ``Basics``() =
let task =
NodeCode.Parallel(seq {
- memoize.Get(5, computation)
- memoize.Get(5, computation)
- memoize.Get(2, computation)
- memoize.Get(5, computation)
- memoize.Get(3, computation)
- memoize.Get(2, computation)
+ memoize.Get(5, computation 5)
+ memoize.Get(5, computation 5)
+ memoize.Get(2, computation 2)
+ memoize.Get(5, computation 5)
+ memoize.Get(3, computation 3)
+ memoize.Get(2, computation 2)
}) |> NodeCode.StartAsTask_ForTesting
let result = task.Result
@@ -61,9 +61,9 @@ let ``We can cancel a job`` () =
let key = 1
- let _task1 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts1.Token)
- let _task2 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts2.Token)
- let _task3 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts3.Token)
+ let _task1 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation key), cts1.Token)
+ let _task2 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation key), cts2.Token)
+ let _task3 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation key), cts3.Token)
resetEvent.WaitOne() |> ignore
@@ -104,9 +104,9 @@ let ``Job keeps running even if first requestor cancels`` () =
let key = 1
- let _task1 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts1.Token)
- let _task2 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts2.Token)
- let _task3 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation), cts3.Token)
+ let _task1 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation key), cts1.Token)
+ let _task2 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation key), cts2.Token)
+ let _task3 = NodeCode.StartAsTask_ForTesting(memoize.Get(key, computation key), cts3.Token)
Thread.Sleep 10
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 9951aedfdb7..d50980ce575 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -206,7 +206,7 @@ let ``Changes in a referenced project`` () =
{ makeTestProject() with DependsOn = [library] }
|> updateFile "First" (addDependency "Library")
- project.Workflow {
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
updateFile "Library" updatePublicSurface
saveFile "Library"
checkFile "Last" expectSignatureChanged
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
index 4e9f681dc96..5e623b51469 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
@@ -13,6 +13,40 @@ open FSharp.Compiler.Symbols
[]
module private CheckerExtensions =
+ let getProjectSnapshot (document: Document, options: FSharpProjectOptions) =
+ async {
+ let project = document.Project
+ let solution = project.Solution
+ // TODO cache?
+ let projects =
+ solution.Projects
+ |> Seq.map (fun p -> p.FilePath, p.Documents |> Seq.map (fun d -> d.FilePath, d) |> Map)
+ |> Map
+
+ let getFileSnapshot (options: FSharpProjectOptions) path =
+ async {
+ let project = projects[options.ProjectFileName]
+ let document = project[path]
+ let! version = document.GetTextVersionAsync() |> Async.AwaitTask
+
+ let getSource () =
+ task {
+ let! sourceText = document.GetTextAsync()
+ return sourceText.ToFSharpSourceText()
+ }
+
+ return
+ {
+ FileName = path
+ Version = version.ToString()
+ GetSource = getSource
+ }
+ }
+
+ return! FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
+ }
+
+
type FSharpChecker with
/// Parse the source text from the Roslyn document.
@@ -24,6 +58,12 @@ module private CheckerExtensions =
return! checker.ParseFile(document.FilePath, sourceText.ToFSharpSourceText(), parsingOptions, userOpName = userOpName)
}
+ member checker.ParseDocumentUsingTransparentCompiler(document: Document, options: FSharpProjectOptions, userOpName: string) =
+ async {
+ let! projectSnapshot = getProjectSnapshot(document, options)
+ return! checker.ParseFile(document.FilePath, projectSnapshot, userOpName = userOpName)
+ }
+
member checker.ParseAndCheckDocumentUsingTransparentCompiler
(
document: Document,
@@ -31,36 +71,7 @@ module private CheckerExtensions =
userOpName: string
) =
async {
-
- let project = document.Project
- let solution = project.Solution
- // TODO cache?
- let projects =
- solution.Projects
- |> Seq.map (fun p -> p.FilePath, p.Documents |> Seq.map (fun d -> d.FilePath, d) |> Map)
- |> Map
-
- let getFileSnapshot (options: FSharpProjectOptions) path =
- async {
- let project = projects[options.ProjectFileName]
- let document = project[path]
- let! version = document.GetTextVersionAsync() |> Async.AwaitTask
-
- let getSource () =
- task {
- let! sourceText = document.GetTextAsync()
- return sourceText.ToFSharpSourceText()
- }
-
- return
- {
- FileName = path
- Version = version.ToString()
- GetSource = getSource
- }
- }
-
- let! projectSnapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
+ let! projectSnapshot = getProjectSnapshot(document, options)
let! (parseResults, checkFileAnswer) = checker.ParseAndCheckFileInProject(document.FilePath, projectSnapshot, userOpName)
@@ -152,7 +163,7 @@ module private CheckerExtensions =
) =
async {
- if document.Project.UseTransparentCompiiler then
+ if document.Project.UseTransparentCompiler then
return! checker.ParseAndCheckDocumentUsingTransparentCompiler(document, options, userOpName)
else
let allowStaleResults =
@@ -251,8 +262,11 @@ type Document with
/// Parses the given F# document.
member this.GetFSharpParseResultsAsync(userOpName) =
async {
- let! checker, _, parsingOptions, _ = this.GetFSharpCompilationOptionsAsync(userOpName)
- return! checker.ParseDocument(this, parsingOptions, userOpName)
+ let! checker, _, parsingOptions, options = this.GetFSharpCompilationOptionsAsync(userOpName)
+ if this.Project.UseTransparentCompiler then
+ return! checker.ParseDocumentUsingTransparentCompiler(this, options, userOpName)
+ else
+ return! checker.ParseDocument(this, parsingOptions, userOpName)
}
/// Parses and checks the given F# document.
diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
index cd07b46b18e..bcc51aa6561 100644
--- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
+++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
@@ -241,5 +241,5 @@ module EditorOptionsExtensions =
member this.IsFastFindReferencesEnabled =
this.EditorOptions.LanguageServicePerformance.EnableFastFindReferencesAndRename
- member this.UseTransparentCompiiler =
+ member this.UseTransparentCompiler =
this.EditorOptions.Advanced.UseTransparentCompiler
From 83ee2043bb15bc75c3dcd2833ad6491d0e7f1dc9 Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Tue, 16 May 2023 17:17:21 +0200
Subject: [PATCH 031/222] wip
---
src/Compiler/Service/BackgroundCompiler.fs | 5 +-
src/Compiler/Service/service.fs | 1 +
src/Compiler/Service/service.fsi | 4 +-
.../FSharpChecker/TransparentCompiler.fs | 37 -----------
...ervice.SurfaceArea.netstandard20.debug.bsl | 3 +
...vice.SurfaceArea.netstandard20.release.bsl | 3 +
.../ProjectGeneration.fs | 15 +++--
.../LanguageService/LanguageService.fs | 3 +-
.../LanguageService/WorkspaceExtensions.fs | 64 +++++++++----------
.../FSharp.Editor/Options/EditorOptions.fs | 3 +-
10 files changed, 56 insertions(+), 82 deletions(-)
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index 72bba6b4bc3..a7e6924d3cb 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -134,10 +134,9 @@ type internal IBackgroundCompiler =
abstract member ParseFile:
fileName: string * sourceText: ISourceText * options: FSharpParsingOptions * cache: bool * userOpName: string ->
Async
-
+
abstract member ParseFile:
- fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string ->
- NodeCode
+ fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> NodeCode
/// Try to get recent approximate type check results for a file.
abstract member TryGetRecentCheckResultsForFile:
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index 723ddeee6b1..a12bfdccdf8 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -309,6 +309,7 @@ type FSharpChecker
member _.ParseFile(fileName, projectSnapshot, ?userOpName) =
let userOpName = defaultArg userOpName "Unknown"
+
backgroundCompiler.ParseFile(fileName, projectSnapshot, userOpName)
|> Async.AwaitNodeCode
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index 98d5c429680..fe484532dfa 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -103,8 +103,8 @@ type public FSharpChecker =
fileName: string * sourceText: ISourceText * options: FSharpParsingOptions * ?cache: bool * ?userOpName: string ->
Async
- member ParseFile: fileName: string * projectSnapshot: FSharpProjectSnapshot * ?userOpName: string ->
- Async
+ member ParseFile:
+ fileName: string * projectSnapshot: FSharpProjectSnapshot * ?userOpName: string -> Async
///
/// Parses a source code for a file. Returns an AST that can be traversed for various features.
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index d50980ce575..23edbee1cfe 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -7,42 +7,10 @@ open Xunit
open FSharp.Test.ProjectGeneration
-module Activity =
- let listen (filter: string) =
- let indent (activity: Activity) =
- let rec loop (activity: Activity) n =
- if activity.Parent <> null then
- loop (activity.Parent) (n + 1)
- else
- n
-
- String.replicate (loop activity 0) " "
-
- let collectTags (activity: Activity) =
- [ for tag in activity.Tags -> $"{tag.Key}: %A{tag.Value}" ]
- |> String.concat ", "
-
- let listener =
- new ActivityListener(
- ShouldListenTo = (fun source -> source.Name = FSharp.Compiler.Diagnostics.ActivityNames.FscSourceName),
- Sample =
- (fun context ->
- if context.Name.Contains(filter) then
- ActivitySamplingResult.AllDataAndRecorded
- else
- ActivitySamplingResult.None),
- ActivityStarted = (fun a -> Trace.TraceInformation $"{indent a}{a.OperationName} {collectTags a}")
- )
-
- ActivitySource.AddActivityListener(listener)
-
- let listenToAll () = listen ""
[]
let ``Use Transparent Compiler`` () =
- Activity.listenToAll ()
-
let size = 20
let project =
@@ -73,8 +41,6 @@ let ``Use Transparent Compiler`` () =
[]
let ``Parallel processing`` () =
- Activity.listenToAll ()
-
let project = SyntheticProject.Create(
sourceFile "A" [],
sourceFile "B" ["A"],
@@ -91,8 +57,6 @@ let ``Parallel processing`` () =
[]
let ``Parallel processing with signatures`` () =
- Activity.listenToAll ()
-
let project = SyntheticProject.Create(
sourceFile "A" [] |> addSignatureFile,
sourceFile "B" ["A"] |> addSignatureFile,
@@ -168,7 +132,6 @@ let ``Files depend on signature file if present`` () =
[]
let ``Signature update`` () =
- Activity.listenToAll ()
let project = SyntheticProject.Create(
{ sourceFile "First" [] with
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
index 011026eee11..03aeafb299a 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
@@ -2055,6 +2055,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Int32 get_ActualParseFileCount()
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer] CheckFileInProject(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults] ParseAndCheckProject(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] GetBackgroundParseResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFile(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFileInProject(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] CheckFileInProjectAllowingStaleCachedResults(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2200,6 +2201,8 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_UseScriptResolut
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ToOptions()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(Int32)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot WithoutFileVersions
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot get_WithoutFileVersions()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey Key
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
index 011026eee11..03aeafb299a 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
@@ -2055,6 +2055,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Int32 get_ActualParseFileCount()
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer] CheckFileInProject(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpCheckProjectResults] ParseAndCheckProject(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] GetBackgroundParseResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFile(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFileInProject(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] CheckFileInProjectAllowingStaleCachedResults(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2200,6 +2201,8 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_UseScriptResolut
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ToOptions()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(Int32)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot WithoutFileVersions
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot get_WithoutFileVersions()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey Key
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 74356203b27..29e845d1ed8 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -126,6 +126,11 @@ type SyntheticProject =
|> List.tryFind (fun f -> this.ProjectDir ++ f.FileName = path)
|> Option.defaultWith (fun () -> failwith $"File {path} not found in project {this.Name}.")
+ member this.FindInAllProjectsByPath path =
+ this.GetAllFiles()
+ |> List.tryFind (fun (p, f) -> p.ProjectDir ++ f.FileName = path)
+ |> Option.defaultWith (fun () -> failwith $"File {path} not found in any project.")
+
member this.ProjectFileName = this.ProjectDir ++ $"{this.Name}.fsproj"
member this.OutputFilename = this.ProjectDir ++ $"{this.Name}.dll"
@@ -367,14 +372,14 @@ module ProjectOperations =
let getFileSnapshot (project: SyntheticProject) _options (path: string) =
async {
- let filePath =
+ let project, filePath =
if path.EndsWith(".fsi") then
let implFilePath = path[..path.Length - 2]
- let f = project.FindByPath implFilePath
- getSignatureFilePath project f
+ let p, f = project.FindInAllProjectsByPath implFilePath
+ p, getSignatureFilePath p f
else
- let f = project.FindByPath path
- getFilePath project f
+ let p, f = project.FindInAllProjectsByPath path
+ p, getFilePath p f
let source = getSourceText project path
use md5 = System.Security.Cryptography.MD5.Create()
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
index 1501fac454a..5d4ebce7420 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs
@@ -177,7 +177,8 @@ type internal FSharpWorkspaceServiceFactory [
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
index 5e623b51469..15304a77a34 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
@@ -15,38 +15,37 @@ module private CheckerExtensions =
let getProjectSnapshot (document: Document, options: FSharpProjectOptions) =
async {
- let project = document.Project
- let solution = project.Solution
- // TODO cache?
- let projects =
- solution.Projects
- |> Seq.map (fun p -> p.FilePath, p.Documents |> Seq.map (fun d -> d.FilePath, d) |> Map)
- |> Map
-
- let getFileSnapshot (options: FSharpProjectOptions) path =
- async {
- let project = projects[options.ProjectFileName]
- let document = project[path]
- let! version = document.GetTextVersionAsync() |> Async.AwaitTask
-
- let getSource () =
- task {
- let! sourceText = document.GetTextAsync()
- return sourceText.ToFSharpSourceText()
- }
-
- return
- {
- FileName = path
- Version = version.ToString()
- GetSource = getSource
- }
- }
-
- return! FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
+ let project = document.Project
+ let solution = project.Solution
+ // TODO cache?
+ let projects =
+ solution.Projects
+ |> Seq.map (fun p -> p.FilePath, p.Documents |> Seq.map (fun d -> d.FilePath, d) |> Map)
+ |> Map
+
+ let getFileSnapshot (options: FSharpProjectOptions) path =
+ async {
+ let project = projects[options.ProjectFileName]
+ let document = project[path]
+ let! version = document.GetTextVersionAsync() |> Async.AwaitTask
+
+ let getSource () =
+ task {
+ let! sourceText = document.GetTextAsync()
+ return sourceText.ToFSharpSourceText()
+ }
+
+ return
+ {
+ FileName = path
+ Version = version.ToString()
+ GetSource = getSource
+ }
+ }
+
+ return! FSharpProjectSnapshot.FromOptions(options, getFileSnapshot)
}
-
type FSharpChecker with
/// Parse the source text from the Roslyn document.
@@ -60,7 +59,7 @@ module private CheckerExtensions =
member checker.ParseDocumentUsingTransparentCompiler(document: Document, options: FSharpProjectOptions, userOpName: string) =
async {
- let! projectSnapshot = getProjectSnapshot(document, options)
+ let! projectSnapshot = getProjectSnapshot (document, options)
return! checker.ParseFile(document.FilePath, projectSnapshot, userOpName = userOpName)
}
@@ -71,7 +70,7 @@ module private CheckerExtensions =
userOpName: string
) =
async {
- let! projectSnapshot = getProjectSnapshot(document, options)
+ let! projectSnapshot = getProjectSnapshot (document, options)
let! (parseResults, checkFileAnswer) = checker.ParseAndCheckFileInProject(document.FilePath, projectSnapshot, userOpName)
@@ -263,6 +262,7 @@ type Document with
member this.GetFSharpParseResultsAsync(userOpName) =
async {
let! checker, _, parsingOptions, options = this.GetFSharpCompilationOptionsAsync(userOpName)
+
if this.Project.UseTransparentCompiler then
return! checker.ParseDocumentUsingTransparentCompiler(this, options, userOpName)
else
diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
index b965e5595d8..ee9b6c65b65 100644
--- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
+++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs
@@ -243,5 +243,4 @@ module EditorOptionsExtensions =
member this.IsFastFindReferencesEnabled =
this.EditorOptions.LanguageServicePerformance.EnableFastFindReferencesAndRename
- member this.UseTransparentCompiler =
- this.EditorOptions.Advanced.UseTransparentCompiler
+ member this.UseTransparentCompiler = this.EditorOptions.Advanced.UseTransparentCompiler
From 348d6203fabeac70a7e7d2abf0b9f98d1423b1af Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Tue, 16 May 2023 18:15:10 +0200
Subject: [PATCH 032/222] move cache key creation
---
src/Compiler/Service/TransparentCompiler.fs | 170 +++++++++-----------
1 file changed, 79 insertions(+), 91 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 771d707e43f..50daf0beafd 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -96,7 +96,7 @@ type internal TransparentCompiler
let cacheEvent = new Event()
- let ParseFileCache =
+ let ParseFileCache =
AsyncMemoize(logEvent = fun (e, ((fileName, version), _, _)) -> cacheEvent.Trigger("ParseFile", e, [| fileName; version |] ))
let ParseAndCheckFileInProjectCache = AsyncMemoize()
let FrameworkImportsCache = AsyncMemoize()
@@ -173,11 +173,28 @@ type internal TransparentCompiler
]
let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions =
- node {
+ let frameworkDLLsKey =
+ frameworkDLLs
+ |> List.map (fun ar -> ar.resolvedPath) // The cache key. Just the minimal data.
+ |> List.sort // Sort to promote cache hits.
+
+ // The data elements in this key are very important. There should be nothing else in the TcConfig that logically affects
+ // the import of a set of framework DLLs into F# CCUs. That is, the F# CCUs that result from a set of DLLs (including
+ // FSharp.Core.dll and mscorlib.dll) must be logically invariant of all the other compiler configuration parameters.
+ let key =
+ FrameworkImportsCacheKey(
+ frameworkDLLsKey,
+ tcConfig.primaryAssembly.Name,
+ tcConfig.GetTargetFrameworkDirectories(),
+ tcConfig.fsharpBinariesDir,
+ tcConfig.langVersion.SpecifiedVersion
+ )
+
+ FrameworkImportsCache.Get(key, node {
use _ = Activity.start "ComputeFrameworkImports" []
let tcConfigP = TcConfigProvider.Constant tcConfig
return! TcImports.BuildFrameworkTcImports(tcConfigP, frameworkDLLs, nonFrameworkResolutions)
- }
+ })
// Link all the assemblies together and produce the input typecheck accumulator
let CombineImportedAssembliesTask
@@ -280,7 +297,10 @@ type internal TransparentCompiler
/// Bootstrap info that does not depend on contents of the files
let ComputeBootstrapInfoStatic (projectSnapshot: FSharpProjectSnapshot) =
- node {
+
+ let key = projectSnapshot.WithoutFileVersions.Key
+
+ BootstrapInfoStaticCache.Get(key, node {
use _ = Activity.start "ComputeBootstrapInfoStatic" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
let useSimpleResolutionSwitch = "--simpleresolution"
@@ -413,27 +433,8 @@ type internal TransparentCompiler
let frameworkDLLs, nonFrameworkResolutions, unresolvedReferences =
TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig)
- let frameworkDLLsKey =
- frameworkDLLs
- |> List.map (fun ar -> ar.resolvedPath) // The cache key. Just the minimal data.
- |> List.sort // Sort to promote cache hits.
-
// Prepare the frameworkTcImportsCache
- //
- // The data elements in this key are very important. There should be nothing else in the TcConfig that logically affects
- // the import of a set of framework DLLs into F# CCUs. That is, the F# CCUs that result from a set of DLLs (including
- // FSharp.Core.dll and mscorlib.dll) must be logically invariant of all the other compiler configuration parameters.
- let key =
- FrameworkImportsCacheKey(
- frameworkDLLsKey,
- tcConfig.primaryAssembly.Name,
- tcConfig.GetTargetFrameworkDirectories(),
- tcConfig.fsharpBinariesDir,
- tcConfig.langVersion.SpecifiedVersion
- )
-
- let! tcGlobals, frameworkTcImports =
- FrameworkImportsCache.Get(key, ComputeFrameworkImports tcConfig frameworkDLLs nonFrameworkResolutions)
+ let! tcGlobals, frameworkTcImports = ComputeFrameworkImports tcConfig frameworkDLLs nonFrameworkResolutions
// Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
// This is ok because not much can actually go wrong here.
@@ -519,13 +520,11 @@ type internal TransparentCompiler
#endif
)
return sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt
- }
+ })
let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
node {
- let bootstrapStaticKey = projectSnapshot.WithoutFileVersions.Key
-
- let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt = BootstrapInfoStaticCache.Get(bootstrapStaticKey, ComputeBootstrapInfoStatic projectSnapshot)
+ let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt = ComputeBootstrapInfoStatic projectSnapshot
let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
@@ -562,7 +561,7 @@ type internal TransparentCompiler
}
let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) =
- node {
+ BootstrapInfoCache.Get(projectSnapshot.Key, node {
use _ = Activity.start "ComputeBootstrapInfo" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
// Trap and report diagnostics from creation.
@@ -593,12 +592,13 @@ type internal TransparentCompiler
FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, suggestNamesForErrors))
return bootstrapInfoOpt, diagnostics
- }
+ })
- let ComputeParseFile (file: FSharpFile) bootstrapInfo =
- node {
+ let ComputeParseFile bootstrapInfo (file: FSharpFile) =
+ let key = file.Source.Key, file.IsLastCompiland, file.IsExe
+ ParseFileCache.Get(key, node {
use _ = Activity.start "ComputeParseFile" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName; Activity.Tags.version, file.Source.Version |]
-
+
let tcConfig = bootstrapInfo.TcConfig
let diagnosticsLogger =
@@ -614,10 +614,11 @@ type internal TransparentCompiler
ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, flags, diagnosticsLogger, sourceText)
return input, diagnosticsLogger.GetDiagnostics(), sourceText
- }
+ })
- let ComputeDependencyGraphForLastFile parsedInputs (tcConfig: TcConfig) =
- node {
+ let ComputeDependencyGraphForLastFile (priorSnapshot: FSharpProjectSnapshot) parsedInputs (tcConfig: TcConfig) =
+ let key = priorSnapshot.SourceFiles |> List.map (fun s -> s.Key)
+ DependencyGraphForLastFileCache.Get(key, node {
let sourceFiles: FileInProject array =
parsedInputs
@@ -629,8 +630,8 @@ type internal TransparentCompiler
ParsedInput = input
})
- use _ = Activity.start "ComputeDependencyGraphForLastFile" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
-
+ use _ = Activity.start "ComputeDependencyGraphForLastFile" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
+
let filePairs = FilePairMap(sourceFiles)
// TODO: we will probably want to cache and re-use larger graphs if available
@@ -639,16 +640,18 @@ type internal TransparentCompiler
|> fst
|> Graph.subGraphFor (sourceFiles |> Array.last).Idx
- return TransformDependencyGraph(graph, filePairs), filePairs
- }
+ return TransformDependencyGraph(graph, filePairs)
+ })
- let ComputeTcIntermediate (parsedInput: ParsedInput, parseErrors) bootstrapInfo (prevTcInfo: TcInfo) =
- node {
+ let ComputeTcIntermediate (projectSnapshot: FSharpProjectSnapshot) (fileIndex: FileIndex) (parsedInput: ParsedInput, parseErrors) bootstrapInfo (prevTcInfo: TcInfo) =
+ // TODO: we need to construct cache key based on only relevant files from the dependency graph
+ let key = projectSnapshot.UpTo(fileIndex).Key
+ TcIntermediateCache.Get(key, node {
let input = parsedInput
let fileName = input.FileName
-
+
use _ = Activity.start "ComputeTcIntermediate" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
-
+
let tcConfig = bootstrapInfo.TcConfig
let tcGlobals = bootstrapInfo.TcGlobals
let tcImports = bootstrapInfo.TcImports
@@ -702,10 +705,10 @@ type internal TransparentCompiler
tcDiagnosticsRev = [ newErrors ]
tcDependencyFiles = [ fileName ]
}
- }
+ })
let mergeIntermediateResults =
- Array.fold (fun (tcInfo: TcInfo) (tcIntermediate: TcIntermediate) ->
+ Array.fold (fun (tcInfo: TcInfo) (tcIntermediate: TcIntermediate) ->
let (tcEnv, topAttribs, _checkImplFileOpt, ccuSigForFile), tcState = tcInfo.tcState |> tcIntermediate.finisher.Invoke
let tcEnvAtEndOfFile = if keepAllBackgroundResolutions then tcEnv else tcState.TcEnvFromImpls
{ tcInfo with
@@ -716,11 +719,13 @@ type internal TransparentCompiler
tcDependencyFiles = tcIntermediate.tcDependencyFiles @ tcInfo.tcDependencyFiles
latestCcuSigForFile = Some ccuSigForFile })
-
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName =
- node {
-
+
+ let priorSnapshot = projectSnapshot.UpTo file.Source.FileName
+ let key = priorSnapshot.Key
+
+ TcPriorCache.Get(key, node {
use _ = Activity.start "ComputeTcPrior" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName |]
// parse required files
@@ -732,28 +737,17 @@ type internal TransparentCompiler
let! parsedInputs =
files
- |> Seq.map (fun f ->
- let key = f.Source.Key, f.IsLastCompiland, f.IsExe
- ParseFileCache.Get(key, ComputeParseFile f bootstrapInfo))
+ |> Seq.map (ComputeParseFile bootstrapInfo)
|> NodeCode.Parallel
- // compute dependency graph
- let graphKey =
- projectSnapshot.UpTo(file.Source.FileName).SourceFiles
- |> List.map (fun s -> s.Key)
-
- let! graph, _filePairs =
- DependencyGraphForLastFileCache.Get(
- graphKey,
- ComputeDependencyGraphForLastFile (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
- )
+ let! graph = ComputeDependencyGraphForLastFile priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
- let fileNames =
- parsedInputs
+ let fileNames =
+ parsedInputs
|> Seq.mapi (fun idx (input, _, _) -> idx, Path.GetFileName input.FileName)
|> Map.ofSeq
- let debugGraph =
+ let debugGraph =
graph
|> Graph.map (function NodeToTypeCheck.PhysicalFile i -> i, fileNames[i] | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
@@ -777,11 +771,10 @@ type internal TransparentCompiler
match fileNode with
| NodeToTypeCheck.PhysicalFile fileIndex ->
let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
- let key = projectSnapshot.UpTo(fileIndex).Key
- TcIntermediateCache.Get(key, ComputeTcIntermediate (parsedInput, parseErrors) bootstrapInfo tcInfo)
+ ComputeTcIntermediate projectSnapshot fileIndex (parsedInput, parseErrors) bootstrapInfo tcInfo
| NodeToTypeCheck.ArtificialImplFile fileIndex ->
- let finisher tcState =
+ let finisher tcState =
let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
let prefixPathOpt = None
// Retrieve the type-checked signature information and add it to the TcEnvFromImpls.
@@ -796,20 +789,20 @@ type internal TransparentCompiler
node.Return(tcIntermediate))
|> NodeCode.Parallel
- //let nodes = layer |> Seq.map (function NodeToTypeCheck.PhysicalFile i -> fileNames[i] | NodeToTypeCheck.ArtificialImplFile i -> $"AIF : {fileNames[i]}") |> String.concat " "
- //Trace.TraceInformation $"Processed layer {nodes}"
+
return! processLayer rest (mergeIntermediateResults tcInfo results)
}
return! processLayer layers bootstrapInfo.InitialTcInfo
- }
+ })
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName =
- node {
-
+ let key = fileName, projectSnapshot.Key
+ ParseAndCheckFileInProjectCache.Get(key, node {
+
use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
- let! bootstrapInfoOpt, creationDiags = BootstrapInfoCache.Get(projectSnapshot.Key, ComputeBootstrapInfo projectSnapshot)
+ let! bootstrapInfoOpt, creationDiags = ComputeBootstrapInfo projectSnapshot
match bootstrapInfoOpt with
| None ->
@@ -822,12 +815,10 @@ type internal TransparentCompiler
let file =
bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
- let priorSnapshot = projectSnapshot.UpTo fileName
- let! tcInfo = TcPriorCache.Get(priorSnapshot.Key, ComputeTcPrior file bootstrapInfo priorSnapshot userOpName)
+ let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot userOpName
// We could also bubble this through ComputeTcPrior
- let! parseTree, parseDiagnostics, sourceText =
- ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file bootstrapInfo)
+ let! parseTree, parseDiagnostics, sourceText = ComputeParseFile bootstrapInfo file
let parseDiagnostics =
DiagnosticHelpers.CreateDiagnostics(
@@ -874,13 +865,13 @@ type internal TransparentCompiler
|> NodeCode.FromCancellable
return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
- }
+ })
- member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
+ member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
node {
use _ = Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
-
- let! bootstrapInfoOpt, creationDiags = BootstrapInfoCache.Get(projectSnapshot.Key, ComputeBootstrapInfo projectSnapshot)
+
+ let! bootstrapInfoOpt, creationDiags = ComputeBootstrapInfo projectSnapshot
match bootstrapInfoOpt with
| None ->
@@ -888,12 +879,11 @@ type internal TransparentCompiler
return FSharpParseFileResults(creationDiags, parseTree, true, [||])
| Some bootstrapInfo ->
-
+
let file =
bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
- let! parseTree, parseDiagnostics, _sourceText =
- ParseFileCache.Get((file.Source.Key, file.IsLastCompiland, file.IsExe), ComputeParseFile file bootstrapInfo)
+ let! parseTree, parseDiagnostics, _sourceText = ComputeParseFile bootstrapInfo file
let parseDiagnostics =
DiagnosticHelpers.CreateDiagnostics(
@@ -917,10 +907,8 @@ type internal TransparentCompiler
}
member _.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) =
- node {
- let key = fileName, projectSnapshot.Key
- return! ParseAndCheckFileInProjectCache.Get(key, ComputeParseAndCheckFileInProject fileName projectSnapshot userOpName)
- }
+ ComputeParseAndCheckFileInProject fileName projectSnapshot userOpName
+
interface IBackgroundCompiler with
member _.CacheEvent = cacheEvent.Publish
@@ -1071,8 +1059,8 @@ type internal TransparentCompiler
member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode =
backgroundCompiler.ParseAndCheckProject(options, userOpName)
-
- member this.ParseFile(fileName, projectSnapshot, userOpName) =
+
+ member this.ParseFile(fileName, projectSnapshot, userOpName) =
this.ParseFile(fileName, projectSnapshot, userOpName)
member _.ParseFile
From 35135ceb8f676872404a380e808978c76c218c30 Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Wed, 17 May 2023 16:52:57 +0200
Subject: [PATCH 033/222] Background semantic classification
---
src/Compiler/Service/BackgroundCompiler.fs | 16 +++-
src/Compiler/Service/FSharpCheckerResults.fs | 11 ++-
src/Compiler/Service/FSharpCheckerResults.fsi | 4 +
src/Compiler/Service/TransparentCompiler.fs | 79 ++++++++++++++-----
src/Compiler/Service/service.fs | 6 ++
src/Compiler/Service/service.fsi | 13 ++-
.../FSharpChecker/TransparentCompiler.fs | 34 +++++++-
...vice.SurfaceArea.netstandard20.release.bsl | 4 +
.../LanguageService/WorkspaceExtensions.fs | 13 ++-
9 files changed, 152 insertions(+), 28 deletions(-)
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index a7e6924d3cb..0fcf7918cc2 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -113,6 +113,10 @@ type internal IBackgroundCompiler =
fileName: string * options: FSharpProjectOptions * userOpName: string ->
NodeCode
+ abstract member GetSemanticClassificationForFile:
+ fileName: string * snapshot: FSharpProjectSnapshot * userOpName: string ->
+ NodeCode
+
abstract member InvalidateConfiguration: options: FSharpProjectOptions * userOpName: string -> unit
abstract member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode
@@ -153,7 +157,7 @@ type internal IBackgroundCompiler =
abstract member ProjectChecked: IEvent
- abstract member CacheEvent: IEvent
+ abstract member CacheEvent: IEvent
type ParseCacheLockToken() =
interface LockToken
@@ -239,7 +243,7 @@ type internal BackgroundCompiler
let fileChecked = Event()
let projectChecked = Event()
- let cacheEvent = Event()
+ let cacheEvent = Event()
// STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.backgroundCompiler.scriptClosureCache
/// Information about the derived script closure.
@@ -1493,6 +1497,14 @@ type internal BackgroundCompiler
) : NodeCode =
self.GetSemanticClassificationForFile(fileName, options, userOpName)
+ member _.GetSemanticClassificationForFile
+ (
+ fileName: string,
+ snapshot: FSharpProjectSnapshot,
+ userOpName: string
+ ) : NodeCode =
+ self.GetSemanticClassificationForFile(fileName, snapshot.ToOptions(), userOpName)
+
member _.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string) : unit =
self.InvalidateConfiguration(options, userOpName)
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 673e08d0807..ab2d2f554d5 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -129,6 +129,8 @@ type FSharpProjectSnapshotKey =
IsIncompleteTypeCheckEnvironment: bool
UseScriptResolutionRules: bool
}
+ member this.LastFile = this.SourceFiles |> List.last
+
[]
type FSharpFileSnapshot =
@@ -194,14 +196,17 @@ type FSharpProjectSnapshot =
member po.ProjectDirectory = Path.GetDirectoryName(po.ProjectFileName)
+ member this.IndexOf fileName =
+ this.SourceFiles
+ |> List.tryFindIndex (fun x -> x.FileName = fileName)
+ |> Option.defaultWith (fun () -> failwith (sprintf "Unable to find file %s in project %s" fileName this.ProjectFileName))
+
member this.UpTo fileIndex =
{ this with
SourceFiles = this.SourceFiles[..fileIndex]
}
- member this.UpTo fileName =
- let fileIndex = this.SourceFiles |> List.findIndex (fun x -> x.FileName = fileName)
- this.UpTo fileIndex
+ member this.UpTo fileName = this.UpTo (this.IndexOf fileName)
member this.Key =
{
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index 2bd4cbbd990..ea55a296ec4 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -52,6 +52,8 @@ type FSharpProjectSnapshotKey =
IsIncompleteTypeCheckEnvironment: bool
UseScriptResolutionRules: bool }
+ member LastFile: FSharpFileKey
+
[]
type FSharpFileSnapshot =
{ FileName: string
@@ -115,6 +117,8 @@ type FSharpProjectSnapshot =
member SourceFileNames: string list
+ member IndexOf: fileName: string -> FileIndex
+
/// A snapshot of the same project but only up to the given file index (including).
member UpTo: fileIndex: int -> FSharpProjectSnapshot
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 50daf0beafd..0ccd19d7846 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -34,6 +34,7 @@ open FSharp.Compiler.NameResolution
open Internal.Utilities.Library.Extras
open FSharp.Compiler.TypedTree
open FSharp.Compiler.CheckDeclarations
+open FSharp.Compiler.EditorServices
type internal FSharpFile =
{
@@ -71,6 +72,8 @@ type internal TcIntermediate =
tcDiagnosticsRev:(PhasedDiagnostic * FSharpDiagnosticSeverity)[] list
tcDependencyFiles: string list
+
+ sink: TcResultsSinkImpl
}
type internal TransparentCompiler
@@ -94,17 +97,19 @@ type internal TransparentCompiler
// Is having just one of these ok?
let lexResourceManager = Lexhelp.LexResourceManager()
- let cacheEvent = new Event()
+ let cacheEvent = new Event()
+ let triggerCacheEvent name (e, k) = cacheEvent.Trigger(name, e, k)
let ParseFileCache =
- AsyncMemoize(logEvent = fun (e, ((fileName, version), _, _)) -> cacheEvent.Trigger("ParseFile", e, [| fileName; version |] ))
- let ParseAndCheckFileInProjectCache = AsyncMemoize()
- let FrameworkImportsCache = AsyncMemoize()
- let BootstrapInfoStaticCache = AsyncMemoize()
- let BootstrapInfoCache = AsyncMemoize()
- let TcPriorCache = AsyncMemoize()
- let TcIntermediateCache = AsyncMemoize()
- let DependencyGraphForLastFileCache = AsyncMemoize()
+ AsyncMemoize(triggerCacheEvent "ParseFile")
+ let ParseAndCheckFileInProjectCache = AsyncMemoize(triggerCacheEvent "ParseAndCheckFileInProject")
+ let FrameworkImportsCache = AsyncMemoize(triggerCacheEvent "FrameworkImports")
+ let BootstrapInfoStaticCache = AsyncMemoize(triggerCacheEvent "BootstrapInfoStatic")
+ let BootstrapInfoCache = AsyncMemoize(triggerCacheEvent "BootstrapInfo")
+ let TcPriorCache = AsyncMemoize(triggerCacheEvent "TcPrior")
+ let TcIntermediateCache = AsyncMemoize(triggerCacheEvent "TcIntermediate")
+ let DependencyGraphForLastFileCache = AsyncMemoize(triggerCacheEvent "DependencyGraphForLastFile")
+ let SemanticClassificationCache = AsyncMemoize(triggerCacheEvent "SemanticClassification")
// We currently share one global dependency provider for all scripts for the FSharpChecker.
// For projects, one is used per project.
@@ -704,6 +709,7 @@ type internal TransparentCompiler
moduleNamesDict = moduleNamesDict
tcDiagnosticsRev = [ newErrors ]
tcDependencyFiles = [ fileName ]
+ sink = sink
}
})
@@ -720,7 +726,7 @@ type internal TransparentCompiler
latestCcuSigForFile = Some ccuSigForFile })
// Type check everything that is needed to check given file
- let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) _userOpName =
+ let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) =
let priorSnapshot = projectSnapshot.UpTo file.Source.FileName
let key = priorSnapshot.Key
@@ -785,6 +791,7 @@ type internal TransparentCompiler
moduleNamesDict = tcInfo.moduleNamesDict
tcDiagnosticsRev = []
tcDependencyFiles = []
+ sink = Unchecked.defaultof<_>
}
node.Return(tcIntermediate))
@@ -796,26 +803,24 @@ type internal TransparentCompiler
return! processLayer layers bootstrapInfo.InitialTcInfo
})
- let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) userOpName =
+ let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) =
let key = fileName, projectSnapshot.Key
ParseAndCheckFileInProjectCache.Get(key, node {
use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
- let! bootstrapInfoOpt, creationDiags = ComputeBootstrapInfo projectSnapshot
-
- match bootstrapInfoOpt with
- | None ->
+ match! ComputeBootstrapInfo projectSnapshot with
+ | None, creationDiags ->
let parseTree = EmptyParsedInput(fileName, (false, false))
let parseResults = FSharpParseFileResults(creationDiags, parseTree, true, [||])
return (parseResults, FSharpCheckFileAnswer.Aborted)
- | Some bootstrapInfo ->
+ | Some bootstrapInfo, creationDiags ->
let file =
bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
- let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot userOpName
+ let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
// We could also bubble this through ComputeTcPrior
let! parseTree, parseDiagnostics, sourceText = ComputeParseFile bootstrapInfo file
@@ -867,6 +872,34 @@ type internal TransparentCompiler
return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
})
+ let ComputeSemanticClassification(fileName: string, projectSnapshot: FSharpProjectSnapshot): NodeCode =
+ let key = (projectSnapshot.UpTo fileName).Key
+ SemanticClassificationCache.Get(key, node {
+ use _ = Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+
+ match! ComputeBootstrapInfo projectSnapshot with
+ | None, _ -> return None
+ | Some bootstrapInfo, _creationDiags ->
+
+ let file =
+ bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
+
+ let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
+ let! parseTree, parseDiagnostics, _sourceText = ComputeParseFile bootstrapInfo file
+
+ let fileIndex = projectSnapshot.IndexOf fileName
+ let! { sink = sink } = ComputeTcIntermediate projectSnapshot fileIndex (parseTree, parseDiagnostics) bootstrapInfo tcInfo
+
+ let sResolutions = sink.GetResolutions()
+
+ let semanticClassification = sResolutions.GetSemanticClassification(bootstrapInfo.TcGlobals, bootstrapInfo.TcImports.GetImportMap(), sink.GetFormatSpecifierLocations(), None)
+
+ let sckBuilder = SemanticClassificationKeyStoreBuilder()
+ sckBuilder.WriteAll semanticClassification
+
+ return sckBuilder.TryBuildAndReset() |> Option.map (fun sck -> sck.GetView())
+ })
+
member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
node {
use _ = Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
@@ -907,7 +940,8 @@ type internal TransparentCompiler
}
member _.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) =
- ComputeParseAndCheckFileInProject fileName projectSnapshot userOpName
+ ignore userOpName
+ ComputeParseAndCheckFileInProject fileName projectSnapshot
interface IBackgroundCompiler with
@@ -1026,6 +1060,15 @@ type internal TransparentCompiler
userOpName
)
+ member _.GetSemanticClassificationForFile
+ (
+ fileName: string,
+ snapshot: FSharpProjectSnapshot,
+ userOpName: string
+ ) =
+ ignore userOpName
+ ComputeSemanticClassification(fileName, snapshot)
+
member _.GetSemanticClassificationForFile
(
fileName: string,
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index a12bfdccdf8..ae15a32bb00 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -485,6 +485,12 @@ type FSharpChecker
backgroundCompiler.GetSemanticClassificationForFile(fileName, options, userOpName)
|> Async.AwaitNodeCode
+ member _.GetBackgroundSemanticClassificationForFile(fileName: string, snapshot: FSharpProjectSnapshot, ?userOpName) =
+ let userOpName = defaultArg userOpName "Unknown"
+
+ backgroundCompiler.GetSemanticClassificationForFile(fileName, snapshot, userOpName)
+ |> Async.AwaitNodeCode
+
/// For a given script file, get the ProjectOptions implied by the #load closure
member _.GetProjectOptionsFromScript
(
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index fe484532dfa..f7a035d9471 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -346,6 +346,17 @@ type public FSharpChecker =
fileName: string * options: FSharpProjectOptions * ?userOpName: string ->
Async
+ ///
+ /// Get semantic classification for a file.
+ ///
+ ///
+ /// The file name for the file.
+ /// The project snapshot for which we want to get the semantic classification.
+ /// An optional string used for tracing compiler operations associated with this request.
+ member GetBackgroundSemanticClassificationForFile:
+ fileName: string * snapshot: FSharpProjectSnapshot * ?userOpName: string ->
+ Async
+
///
/// Compile using the given flags. Source files names are resolved via the FileSystem API.
/// The output file must be given by a -o flag.
@@ -431,7 +442,7 @@ type public FSharpChecker =
/// The event may be raised on a background thread.
member ProjectChecked: IEvent
- member internal CacheEvent: IEvent
+ member internal CacheEvent: IEvent
[]
static member Instance: FSharpChecker
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 23edbee1cfe..acb508dea41 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -2,10 +2,13 @@
open System.Collections.Concurrent
open System.Diagnostics
+open FSharp.Compiler.CodeAnalysis
+open Internal.Utilities.Collections
open Xunit
open FSharp.Test.ProjectGeneration
+open System.IO
[]
@@ -173,4 +176,33 @@ let ``Changes in a referenced project`` () =
updateFile "Library" updatePublicSurface
saveFile "Library"
checkFile "Last" expectSignatureChanged
- }
\ No newline at end of file
+ }
+
+[]
+let ``We don't check files that are not depended on`` () =
+ let project = SyntheticProject.Create(
+ sourceFile "First" [],
+ sourceFile "Second" ["First"],
+ sourceFile "Third" ["First"],
+ sourceFile "Last" ["Third"])
+
+ let cacheEvents = ResizeArray()
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
+ updateFile "First" updatePublicSurface
+ checkFile "Last" expectOk
+ } |> ignore
+
+ let intermediateTypeChecks =
+ cacheEvents
+ |> Seq.choose (function
+ | ("TcIntermediate", e, k) -> Some ((k :?> FSharpProjectSnapshotKey).LastFile |> fst |> Path.GetFileName, e)
+ | _ -> None)
+ |> Seq.groupBy fst
+ |> Seq.map (fun (k, g) -> k, g |> Seq.map snd |> Seq.toList)
+ |> Map
+
+ Assert.Equal([Started; Finished], intermediateTypeChecks["FileFirst.fs"])
+ Assert.Equal([Started; Finished], intermediateTypeChecks["FileThird.fs"])
+ Assert.False (intermediateTypeChecks.ContainsKey "FileSecond.fs")
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
index 03aeafb299a..5415b502e06 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
@@ -2060,6 +2060,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFileInProject(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] CheckFileInProjectAllowingStaleCachedResults(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.SemanticClassificationView]] GetBackgroundSemanticClassificationForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.SemanticClassificationView]] GetBackgroundSemanticClassificationForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyFileChanged(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2207,6 +2208,7 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 IndexOf(System.String)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] SourceFiles
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] get_SourceFiles()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot] ReferencedProjects
@@ -2251,6 +2253,8 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collecti
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ProjectFileName
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String get_ProjectFileName()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] LastFile
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] get_LastFile()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey], Boolean, Boolean)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Boolean Equals(System.Object)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions)
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
index 15304a77a34..beeb7465daa 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
@@ -284,9 +284,16 @@ type Document with
async {
let! checker, _, _, projectOptions = this.GetFSharpCompilationOptionsAsync(userOpName)
- match! checker.GetBackgroundSemanticClassificationForFile(this.FilePath, projectOptions) with
- | Some results -> return results
- | _ -> return raise (System.OperationCanceledException("Unable to get FSharp semantic classification."))
+ let! result =
+ if this.Project.UseTransparentCompiler then
+ async {
+ let! projectSnapshot = getProjectSnapshot (this, projectOptions)
+ return! checker.GetBackgroundSemanticClassificationForFile(this.FilePath, projectSnapshot)
+ }
+ else
+ checker.GetBackgroundSemanticClassificationForFile(this.FilePath, projectOptions)
+
+ return result |> Option.defaultWith (fun _ -> raise (System.OperationCanceledException("Unable to get FSharp semantic classification.")))
}
/// Find F# references in the given F# document.
From 6cb3b2f33a68f87159a1a40cac20c348852a8a8c Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Wed, 17 May 2023 17:47:18 +0200
Subject: [PATCH 034/222] ..
---
src/Compiler/Service/FSharpCheckerResults.fs | 4 ++--
.../src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs | 4 +++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index ab2d2f554d5..c2271aa1de4 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -129,8 +129,8 @@ type FSharpProjectSnapshotKey =
IsIncompleteTypeCheckEnvironment: bool
UseScriptResolutionRules: bool
}
- member this.LastFile = this.SourceFiles |> List.last
+ member this.LastFile = this.SourceFiles |> List.last
[]
type FSharpFileSnapshot =
@@ -206,7 +206,7 @@ type FSharpProjectSnapshot =
SourceFiles = this.SourceFiles[..fileIndex]
}
- member this.UpTo fileName = this.UpTo (this.IndexOf fileName)
+ member this.UpTo fileName = this.UpTo(this.IndexOf fileName)
member this.Key =
{
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
index beeb7465daa..6d696487345 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
@@ -293,7 +293,9 @@ type Document with
else
checker.GetBackgroundSemanticClassificationForFile(this.FilePath, projectOptions)
- return result |> Option.defaultWith (fun _ -> raise (System.OperationCanceledException("Unable to get FSharp semantic classification.")))
+ return
+ result
+ |> Option.defaultWith (fun _ -> raise (System.OperationCanceledException("Unable to get FSharp semantic classification.")))
}
/// Find F# references in the given F# document.
From cbbb2bb023d616714a8cb1a3ac5dd32080e93d7a Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Wed, 17 May 2023 20:09:34 +0200
Subject: [PATCH 035/222] find references
---
src/Compiler/Service/BackgroundCompiler.fs | 7 ++
src/Compiler/Service/TransparentCompiler.fs | 68 ++++++++++++++++---
src/Compiler/Service/service.fs | 16 +++++
src/Compiler/Service/service.fsi | 4 ++
.../LanguageService/WorkspaceExtensions.fs | 21 ++++--
5 files changed, 101 insertions(+), 15 deletions(-)
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index 0fcf7918cc2..cc25ed2bed3 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -80,6 +80,10 @@ type internal IBackgroundCompiler =
userOpName: string ->
NodeCode>
+ abstract member FindReferencesInFile:
+ fileName: string * projectSnapshot: FSharpProjectSnapshot * symbol: FSharp.Compiler.Symbols.FSharpSymbol * userOpName: string ->
+ NodeCode>
+
abstract member GetAssemblyData:
options: FSharpProjectOptions * userOpName: string -> NodeCode
@@ -1431,6 +1435,9 @@ type internal BackgroundCompiler
) : NodeCode> =
self.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
+ member this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName) =
+ this.FindReferencesInFile(fileName, projectSnapshot.ToOptions(), symbol, true, userOpName)
+
member _.FrameworkImportsCache: FrameworkImportsCache = self.FrameworkImportsCache
member _.GetAssemblyData(options: FSharpProjectOptions, userOpName: string) : NodeCode =
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 0ccd19d7846..d7affa00913 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -1,6 +1,7 @@
namespace FSharp.Compiler.CodeAnalysis.TransparentCompiler
open System
+open System.Collections.Generic
open System.Diagnostics
open System.IO
@@ -35,6 +36,7 @@ open Internal.Utilities.Library.Extras
open FSharp.Compiler.TypedTree
open FSharp.Compiler.CheckDeclarations
open FSharp.Compiler.EditorServices
+open FSharp.Compiler.CodeAnalysis
type internal FSharpFile =
{
@@ -110,6 +112,7 @@ type internal TransparentCompiler
let TcIntermediateCache = AsyncMemoize(triggerCacheEvent "TcIntermediate")
let DependencyGraphForLastFileCache = AsyncMemoize(triggerCacheEvent "DependencyGraphForLastFile")
let SemanticClassificationCache = AsyncMemoize(triggerCacheEvent "SemanticClassification")
+ let ItemKeyStoreCache = AsyncMemoize(triggerCacheEvent "ItemKeyStore")
// We currently share one global dependency provider for all scripts for the FSharpChecker.
// For projects, one is used per project.
@@ -872,9 +875,8 @@ type internal TransparentCompiler
return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
})
- let ComputeSemanticClassification(fileName: string, projectSnapshot: FSharpProjectSnapshot): NodeCode =
- let key = (projectSnapshot.UpTo fileName).Key
- SemanticClassificationCache.Get(key, node {
+ let tryGetSink fileName (projectSnapshot: FSharpProjectSnapshot) =
+ node {
use _ = Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
match! ComputeBootstrapInfo projectSnapshot with
@@ -890,14 +892,48 @@ type internal TransparentCompiler
let fileIndex = projectSnapshot.IndexOf fileName
let! { sink = sink } = ComputeTcIntermediate projectSnapshot fileIndex (parseTree, parseDiagnostics) bootstrapInfo tcInfo
- let sResolutions = sink.GetResolutions()
+ return Some (sink, bootstrapInfo)
+ }
+
+ let ComputeSemanticClassification(fileName: string, projectSnapshot: FSharpProjectSnapshot) =
+ let key = (projectSnapshot.UpTo fileName).Key
+ SemanticClassificationCache.Get(key, node {
+ use _ = Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+ let! sinkOpt = tryGetSink fileName projectSnapshot
+ return
+ sinkOpt
+ |> Option.bind (fun (sink, bootstrapInfo) ->
+ let sResolutions = sink.GetResolutions()
+ let semanticClassification = sResolutions.GetSemanticClassification(bootstrapInfo.TcGlobals, bootstrapInfo.TcImports.GetImportMap(), sink.GetFormatSpecifierLocations(), None)
- let semanticClassification = sResolutions.GetSemanticClassification(bootstrapInfo.TcGlobals, bootstrapInfo.TcImports.GetImportMap(), sink.GetFormatSpecifierLocations(), None)
+ let sckBuilder = SemanticClassificationKeyStoreBuilder()
+ sckBuilder.WriteAll semanticClassification
- let sckBuilder = SemanticClassificationKeyStoreBuilder()
- sckBuilder.WriteAll semanticClassification
+ sckBuilder.TryBuildAndReset())
+ |> Option.map (fun sck -> sck.GetView())
+ })
- return sckBuilder.TryBuildAndReset() |> Option.map (fun sck -> sck.GetView())
+ let ComputeItemKeyStore(fileName: string, projectSnapshot: FSharpProjectSnapshot) =
+ let key = (projectSnapshot.UpTo fileName).Key
+ ItemKeyStoreCache.Get(key, node {
+ use _ = Activity.start "ComputeItemKeyStore" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+ let! sinkOpt = tryGetSink fileName projectSnapshot
+ return
+ sinkOpt
+ |> Option.bind (fun (sink, _) ->
+ let sResolutions = sink.GetResolutions()
+
+ let builder = ItemKeyStoreBuilder()
+ let preventDuplicates = HashSet({ new IEqualityComparer with
+ member _.Equals((s1, e1): struct(pos * pos), (s2, e2): struct(pos * pos)) = Position.posEq s1 s2 && Position.posEq e1 e2
+ member _.GetHashCode o = o.GetHashCode() })
+ sResolutions.CapturedNameResolutions
+ |> Seq.iter (fun cnr ->
+ let r = cnr.Range
+ if preventDuplicates.Add struct(r.Start, r.End) then
+ builder.Write(cnr.Range, cnr.Item))
+
+ builder.TryBuildAndReset())
})
member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
@@ -943,8 +979,22 @@ type internal TransparentCompiler
ignore userOpName
ComputeParseAndCheckFileInProject fileName projectSnapshot
+ member _.FindReferencesInFile
+ (
+ fileName: string,
+ projectSnapshot: FSharpProjectSnapshot,
+ symbol: FSharpSymbol,
+ userOpName: string
+ ) =
+ ignore userOpName
+ node {
+ match! ComputeItemKeyStore(fileName, projectSnapshot) with
+ | None -> return Seq.empty
+ | Some itemKeyStore -> return itemKeyStore.FindAll symbol.Item
+ }
interface IBackgroundCompiler with
+
member _.CacheEvent = cacheEvent.Publish
member this.BeforeBackgroundFileCheck: IEvent =
@@ -1001,6 +1051,8 @@ type internal TransparentCompiler
) : NodeCode> =
backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
+ member this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName) = this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName)
+
member _.FrameworkImportsCache: FrameworkImportsCache =
backgroundCompiler.FrameworkImportsCache
diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs
index ae15a32bb00..ad2d1d0ee2a 100644
--- a/src/Compiler/Service/service.fs
+++ b/src/Compiler/Service/service.fs
@@ -479,6 +479,22 @@ type FSharpChecker
}
|> Async.AwaitNodeCode
+ member _.FindBackgroundReferencesInFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, symbol: FSharpSymbol, ?userOpName: string) =
+ let userOpName = defaultArg userOpName "Unknown"
+
+ node {
+ let! parseResults = backgroundCompiler.ParseFile(fileName, projectSnapshot, userOpName)
+
+ if
+ parseResults.ParseTree.Identifiers |> Set.contains symbol.DisplayNameCore
+ || parseResults.ParseTree.Identifiers |> NamesContainAttribute symbol
+ then
+ return! backgroundCompiler.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName)
+ else
+ return Seq.empty
+ }
+ |> Async.AwaitNodeCode
+
member _.GetBackgroundSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, ?userOpName) =
let userOpName = defaultArg userOpName "Unknown"
diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi
index f7a035d9471..30ce574813f 100644
--- a/src/Compiler/Service/service.fsi
+++ b/src/Compiler/Service/service.fsi
@@ -333,6 +333,10 @@ type public FSharpChecker =
?userOpName: string ->
Async
+ member FindBackgroundReferencesInFile:
+ fileName: string * projectSnapshot: FSharpProjectSnapshot * symbol: FSharpSymbol * ?userOpName: string ->
+ Async
+
///
/// Get semantic classification for a file.
/// All files are read from the FileSystem API, including the file being checked.
diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
index 6d696487345..2c015d68e11 100644
--- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
+++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs
@@ -304,13 +304,20 @@ type Document with
let! checker, _, _, projectOptions = this.GetFSharpCompilationOptionsAsync(userOpName)
let! symbolUses =
- checker.FindBackgroundReferencesInFile(
- this.FilePath,
- projectOptions,
- symbol,
- canInvalidateProject = false,
- fastCheck = this.Project.IsFastFindReferencesEnabled
- )
+
+ if this.Project.UseTransparentCompiler then
+ async {
+ let! projectSnapshot = getProjectSnapshot (this, projectOptions)
+ return! checker.FindBackgroundReferencesInFile(this.FilePath, projectSnapshot, symbol)
+ }
+ else
+ checker.FindBackgroundReferencesInFile(
+ this.FilePath,
+ projectOptions,
+ symbol,
+ canInvalidateProject = false,
+ fastCheck = this.Project.IsFastFindReferencesEnabled
+ )
for symbolUse in symbolUses do
do! onFound symbolUse
From 371ee99d24f4af65cb31a8f46320b7b98229e824 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 18 May 2023 11:26:30 +0200
Subject: [PATCH 036/222] wip
---
src/Compiler/Service/TransparentCompiler.fs | 128 +++++++++-----------
1 file changed, 54 insertions(+), 74 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index d7affa00913..8ef1500f04e 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -57,6 +57,10 @@ type internal BootstrapInfo =
LoadClosure: LoadClosure option
}
+ member this.GetFile fileName =
+ this.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (this.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
+
+
type internal TcIntermediateResult = TcInfo * TcResultsSinkImpl * CheckedImplFile option * string
@@ -216,10 +220,8 @@ type internal TransparentCompiler
unresolvedReferences,
dependencyProvider,
loadClosureOpt: LoadClosure option,
- basicDependencies
-#if !NO_TYPEPROVIDERS
- ,importsInvalidatedByTypeProvider: Event
-#endif
+ basicDependencies,
+ importsInvalidatedByTypeProvider: Event
) =
node {
@@ -240,6 +242,7 @@ type internal TransparentCompiler
dependencyProvider
)
#if !NO_TYPEPROVIDERS
+ // TODO: review and handle the event
tcImports.GetCcusExcludingBase()
|> Seq.iter (fun ccu ->
// When a CCU reports an invalidation, merge them together and just report a
@@ -472,9 +475,9 @@ type internal TransparentCompiler
let tcConfigP = TcConfigProvider.Constant tcConfig
- #if !NO_TYPEPROVIDERS
+
let importsInvalidatedByTypeProvider = Event()
- #endif
+
// Check for the existence of loaded sources and prepend them to the sources list if present.
let sourceFiles =
@@ -522,17 +525,15 @@ type internal TransparentCompiler
unresolvedReferences,
dependencyProvider,
loadClosureOpt,
- basicDependencies
- #if !NO_TYPEPROVIDERS
- ,importsInvalidatedByTypeProvider
- #endif
+ basicDependencies,
+ importsInvalidatedByTypeProvider
)
- return sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt
+ return sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, importsInvalidatedByTypeProvider
})
let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
node {
- let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt = ComputeBootstrapInfoStatic projectSnapshot
+ let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, _importsInvalidatedByTypeProvider = ComputeBootstrapInfoStatic projectSnapshot
let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
@@ -565,6 +566,7 @@ type internal TransparentCompiler
InitialTcInfo = initialTcInfo
SourceFiles = sourceFiles
LoadClosure = loadClosureOpt
+ //ImportsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider
}
}
@@ -806,6 +808,37 @@ type internal TransparentCompiler
return! processLayer layers bootstrapInfo.InitialTcInfo
})
+ let getParseResult (bootstrapInfo: BootstrapInfo) creationDiags fileName =
+ node {
+ let file = bootstrapInfo.GetFile fileName
+
+ let! parseTree, parseDiagnostics, sourceText = ComputeParseFile bootstrapInfo file
+
+ let parseDiagnostics =
+ DiagnosticHelpers.CreateDiagnostics(
+ bootstrapInfo.TcConfig.diagnosticsOptions,
+ false,
+ fileName,
+ parseDiagnostics,
+ suggestNamesForErrors
+ )
+
+ let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
+
+ return
+ FSharpParseFileResults(
+ diagnostics = diagnostics,
+ input = parseTree,
+ parseHadErrors = (parseDiagnostics.Length > 0),
+ // TODO: check if we really need this in parse results
+ dependencyFiles = [||]
+ ), sourceText
+ }
+
+ let emptyParseResult fileName diagnostics =
+ let parseTree = EmptyParsedInput(fileName, (false, false))
+ FSharpParseFileResults(diagnostics, parseTree, true, [||])
+
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) =
let key = fileName, projectSnapshot.Key
ParseAndCheckFileInProjectCache.Get(key, node {
@@ -814,39 +847,15 @@ type internal TransparentCompiler
match! ComputeBootstrapInfo projectSnapshot with
| None, creationDiags ->
- let parseTree = EmptyParsedInput(fileName, (false, false))
- let parseResults = FSharpParseFileResults(creationDiags, parseTree, true, [||])
- return (parseResults, FSharpCheckFileAnswer.Aborted)
+ return emptyParseResult fileName creationDiags, FSharpCheckFileAnswer.Aborted
| Some bootstrapInfo, creationDiags ->
- let file =
- bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
-
- let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
+ let file = bootstrapInfo.GetFile fileName
- // We could also bubble this through ComputeTcPrior
- let! parseTree, parseDiagnostics, sourceText = ComputeParseFile bootstrapInfo file
+ let! parseResults, sourceText = getParseResult bootstrapInfo creationDiags fileName
- let parseDiagnostics =
- DiagnosticHelpers.CreateDiagnostics(
- bootstrapInfo.TcConfig.diagnosticsOptions,
- false,
- fileName,
- parseDiagnostics,
- suggestNamesForErrors
- )
-
- let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
-
- let parseResults =
- FSharpParseFileResults(
- diagnostics = diagnostics,
- input = parseTree,
- parseHadErrors = (parseDiagnostics.Length > 0),
- // TODO: check if we really need this in parse results
- dependencyFiles = Array.ofList tcInfo.tcDependencyFiles
- )
+ let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
let! checkResults =
FSharpCheckFileResults.CheckOneFile(
@@ -939,40 +948,11 @@ type internal TransparentCompiler
member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
node {
use _ = Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
-
- let! bootstrapInfoOpt, creationDiags = ComputeBootstrapInfo projectSnapshot
-
- match bootstrapInfoOpt with
- | None ->
- let parseTree = EmptyParsedInput(fileName, (false, false))
- return FSharpParseFileResults(creationDiags, parseTree, true, [||])
-
- | Some bootstrapInfo ->
-
- let file =
- bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
-
- let! parseTree, parseDiagnostics, _sourceText = ComputeParseFile bootstrapInfo file
-
- let parseDiagnostics =
- DiagnosticHelpers.CreateDiagnostics(
- bootstrapInfo.TcConfig.diagnosticsOptions,
- false,
- fileName,
- parseDiagnostics,
- suggestNamesForErrors
- )
-
- let diagnostics = [| yield! creationDiags; yield! parseDiagnostics |]
-
- return
- FSharpParseFileResults(
- diagnostics = diagnostics,
- input = parseTree,
- parseHadErrors = (parseDiagnostics.Length > 0),
- // TODO: check if we really need this in parse results
- dependencyFiles = [||]
- )
+ match! ComputeBootstrapInfo projectSnapshot with
+ | None, creationDiags -> return emptyParseResult fileName creationDiags
+ | Some bootstrapInfo, creationDiags ->
+ let! parseResult, _ = getParseResult bootstrapInfo creationDiags fileName
+ return parseResult
}
member _.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) =
From 3c6d3420f52cc4eb7d9bb37f47954383dda27201 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 18 May 2023 11:28:06 +0200
Subject: [PATCH 037/222] fantomas
---
.fantomasignore | 1 -
src/Compiler/Service/TransparentCompiler.fs | 1116 ++++++++++---------
2 files changed, 611 insertions(+), 506 deletions(-)
diff --git a/.fantomasignore b/.fantomasignore
index 8b224eb8f65..45eb387fa16 100644
--- a/.fantomasignore
+++ b/.fantomasignore
@@ -95,7 +95,6 @@ src/FSharp.Core/seqcore.fs
src/Compiler/AbstractIL/ilwrite.fs
src/Compiler/Utilities/lib.fs
src/Compiler/Service/IncrementalBuild.fs
-src/Compiler/Service/TransparentCompiler.fs
src/Compiler/Service/ServiceAssemblyContent.fs
src/Compiler/Service/ServiceDeclarationLists.fs
src/Compiler/Service/ServiceErrorResolutionHints.fs
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 8ef1500f04e..bd0aa272ae8 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -58,12 +58,16 @@ type internal BootstrapInfo =
}
member this.GetFile fileName =
- this.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (this.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
-
+ this.SourceFiles
+ |> List.tryFind (fun f -> f.Source.FileName = fileName)
+ |> Option.defaultWith (fun _ ->
+ failwith (
+ $"File {fileName} not found in project snapshot. Files in project: \n\n"
+ + (this.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")
+ ))
type internal TcIntermediateResult = TcInfo * TcResultsSinkImpl * CheckedImplFile option * string
-
/// Accumulated results of type checking. The minimum amount of state in order to continue type-checking following files.
[]
type internal TcIntermediate =
@@ -75,7 +79,7 @@ type internal TcIntermediate =
moduleNamesDict: ModuleNamesDict
/// Accumulated diagnostics, last file first
- tcDiagnosticsRev:(PhasedDiagnostic * FSharpDiagnosticSeverity)[] list
+ tcDiagnosticsRev: (PhasedDiagnostic * FSharpDiagnosticSeverity)[] list
tcDependencyFiles: string list
@@ -106,16 +110,23 @@ type internal TransparentCompiler
let cacheEvent = new Event()
let triggerCacheEvent name (e, k) = cacheEvent.Trigger(name, e, k)
- let ParseFileCache =
- AsyncMemoize(triggerCacheEvent "ParseFile")
- let ParseAndCheckFileInProjectCache = AsyncMemoize(triggerCacheEvent "ParseAndCheckFileInProject")
+ let ParseFileCache = AsyncMemoize(triggerCacheEvent "ParseFile")
+
+ let ParseAndCheckFileInProjectCache =
+ AsyncMemoize(triggerCacheEvent "ParseAndCheckFileInProject")
+
let FrameworkImportsCache = AsyncMemoize(triggerCacheEvent "FrameworkImports")
let BootstrapInfoStaticCache = AsyncMemoize(triggerCacheEvent "BootstrapInfoStatic")
let BootstrapInfoCache = AsyncMemoize(triggerCacheEvent "BootstrapInfo")
let TcPriorCache = AsyncMemoize(triggerCacheEvent "TcPrior")
let TcIntermediateCache = AsyncMemoize(triggerCacheEvent "TcIntermediate")
- let DependencyGraphForLastFileCache = AsyncMemoize(triggerCacheEvent "DependencyGraphForLastFile")
- let SemanticClassificationCache = AsyncMemoize(triggerCacheEvent "SemanticClassification")
+
+ let DependencyGraphForLastFileCache =
+ AsyncMemoize(triggerCacheEvent "DependencyGraphForLastFile")
+
+ let SemanticClassificationCache =
+ AsyncMemoize(triggerCacheEvent "SemanticClassification")
+
let ItemKeyStoreCache = AsyncMemoize(triggerCacheEvent "ItemKeyStore")
// We currently share one global dependency provider for all scripts for the FSharpChecker.
@@ -202,11 +213,14 @@ type internal TransparentCompiler
tcConfig.langVersion.SpecifiedVersion
)
- FrameworkImportsCache.Get(key, node {
- use _ = Activity.start "ComputeFrameworkImports" []
- let tcConfigP = TcConfigProvider.Constant tcConfig
- return! TcImports.BuildFrameworkTcImports(tcConfigP, frameworkDLLs, nonFrameworkResolutions)
- })
+ FrameworkImportsCache.Get(
+ key,
+ node {
+ use _ = Activity.start "ComputeFrameworkImports" []
+ let tcConfigP = TcConfigProvider.Constant tcConfig
+ return! TcImports.BuildFrameworkTcImports(tcConfigP, frameworkDLLs, nonFrameworkResolutions)
+ }
+ )
// Link all the assemblies together and produce the input typecheck accumulator
let CombineImportedAssembliesTask
@@ -311,229 +325,235 @@ type internal TransparentCompiler
let key = projectSnapshot.WithoutFileVersions.Key
- BootstrapInfoStaticCache.Get(key, node {
- use _ = Activity.start "ComputeBootstrapInfoStatic" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
-
- let useSimpleResolutionSwitch = "--simpleresolution"
- let commandLineArgs = projectSnapshot.OtherOptions
- let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir
- let useScriptResolutionRules = projectSnapshot.UseScriptResolutionRules
-
- let projectReferences = getProjectReferences projectSnapshot "ComputeBootstrapInfo"
-
- // TODO: script support
- let loadClosureOpt: LoadClosure option = None
-
- let tcConfigB, sourceFiles =
-
- let getSwitchValue (switchString: string) =
- match commandLineArgs |> List.tryFindIndex (fun s -> s.StartsWithOrdinal switchString) with
- | Some idx -> Some(commandLineArgs[ idx ].Substring(switchString.Length))
- | _ -> None
-
- let sdkDirOverride =
- match loadClosureOpt with
- | None -> None
- | Some loadClosure -> loadClosure.SdkDirOverride
-
- // see also fsc.fs: runFromCommandLineToImportingAssemblies(), as there are many similarities to where the PS creates a tcConfigB
- let tcConfigB =
- TcConfigBuilder.CreateNew(
- legacyReferenceResolver,
- defaultFSharpBinariesDir,
- implicitIncludeDir = projectSnapshot.ProjectDirectory,
- reduceMemoryUsage = ReduceMemoryFlag.Yes,
- isInteractive = useScriptResolutionRules,
- isInvalidationSupported = true,
- defaultCopyFSharpCore = CopyFSharpCoreFlag.No,
- tryGetMetadataSnapshot = tryGetMetadataSnapshot,
- sdkDirOverride = sdkDirOverride,
- rangeForErrors = range0
- )
-
- tcConfigB.primaryAssembly <-
- match loadClosureOpt with
- | None -> PrimaryAssembly.Mscorlib
- | Some loadClosure ->
- if loadClosure.UseDesktopFramework then
- PrimaryAssembly.Mscorlib
- else
- PrimaryAssembly.System_Runtime
-
- tcConfigB.resolutionEnvironment <- (LegacyResolutionEnvironment.EditingOrCompilation true)
-
- tcConfigB.conditionalDefines <-
- let define =
- if useScriptResolutionRules then
- "INTERACTIVE"
- else
- "COMPILED"
-
- define :: tcConfigB.conditionalDefines
-
- tcConfigB.projectReferences <- projectReferences
-
- tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome
-
- // Apply command-line arguments and collect more source files if they are in the arguments
- let sourceFilesNew =
- ApplyCommandLineArgs(tcConfigB, projectSnapshot.SourceFileNames, commandLineArgs)
-
- // Never open PDB files for the language service, even if --standalone is specified
- tcConfigB.openDebugInformationForLaterStaticLinking <- false
-
- tcConfigB.xmlDocInfoLoader <-
- { new IXmlDocumentationInfoLoader with
- /// Try to load xml documentation associated with an assembly by the same file path with the extension ".xml".
- member _.TryLoad(assemblyFileName) =
- let xmlFileName = Path.ChangeExtension(assemblyFileName, ".xml")
-
- // REVIEW: File IO - Will eventually need to change this to use a file system interface of some sort.
- XmlDocumentationInfo.TryCreateFromFile(xmlFileName)
- }
- |> Some
-
- tcConfigB.parallelReferenceResolution <- parallelReferenceResolution
- tcConfigB.captureIdentifiersWhenParsing <- captureIdentifiersWhenParsing
-
- tcConfigB, sourceFilesNew
-
- // If this is a builder for a script, re-apply the settings inferred from the
- // script and its load closure to the configuration.
- //
- // NOTE: it would probably be cleaner and more accurate to re-run the load closure at this point.
- let setupConfigFromLoadClosure () =
- match loadClosureOpt with
- | Some loadClosure ->
- let dllReferences =
- [
- for reference in tcConfigB.referencedDLLs do
- // If there's (one or more) resolutions of closure references then yield them all
- match
- loadClosure.References
- |> List.tryFind (fun (resolved, _) -> resolved = reference.Text)
- with
- | Some (resolved, closureReferences) ->
- for closureReference in closureReferences do
- yield AssemblyReference(closureReference.originalReference.Range, resolved, None)
- | None -> yield reference
- ]
-
- tcConfigB.referencedDLLs <- []
+ BootstrapInfoStaticCache.Get(
+ key,
+ node {
+ use _ =
+ Activity.start
+ "ComputeBootstrapInfoStatic"
+ [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
+
+ let useSimpleResolutionSwitch = "--simpleresolution"
+ let commandLineArgs = projectSnapshot.OtherOptions
+ let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir
+ let useScriptResolutionRules = projectSnapshot.UseScriptResolutionRules
+
+ let projectReferences = getProjectReferences projectSnapshot "ComputeBootstrapInfo"
+
+ // TODO: script support
+ let loadClosureOpt: LoadClosure option = None
+
+ let tcConfigB, sourceFiles =
+
+ let getSwitchValue (switchString: string) =
+ match commandLineArgs |> List.tryFindIndex (fun s -> s.StartsWithOrdinal switchString) with
+ | Some idx -> Some(commandLineArgs[ idx ].Substring(switchString.Length))
+ | _ -> None
+
+ let sdkDirOverride =
+ match loadClosureOpt with
+ | None -> None
+ | Some loadClosure -> loadClosure.SdkDirOverride
+
+ // see also fsc.fs: runFromCommandLineToImportingAssemblies(), as there are many similarities to where the PS creates a tcConfigB
+ let tcConfigB =
+ TcConfigBuilder.CreateNew(
+ legacyReferenceResolver,
+ defaultFSharpBinariesDir,
+ implicitIncludeDir = projectSnapshot.ProjectDirectory,
+ reduceMemoryUsage = ReduceMemoryFlag.Yes,
+ isInteractive = useScriptResolutionRules,
+ isInvalidationSupported = true,
+ defaultCopyFSharpCore = CopyFSharpCoreFlag.No,
+ tryGetMetadataSnapshot = tryGetMetadataSnapshot,
+ sdkDirOverride = sdkDirOverride,
+ rangeForErrors = range0
+ )
tcConfigB.primaryAssembly <-
- (if loadClosure.UseDesktopFramework then
- PrimaryAssembly.Mscorlib
- else
- PrimaryAssembly.System_Runtime)
- // Add one by one to remove duplicates
- dllReferences
- |> List.iter (fun dllReference -> tcConfigB.AddReferencedAssemblyByPath(dllReference.Range, dllReference.Text))
-
- tcConfigB.knownUnresolvedReferences <- loadClosure.UnresolvedReferences
- | None -> ()
-
- setupConfigFromLoadClosure ()
-
- let tcConfig = TcConfig.Create(tcConfigB, validate = true)
- let _outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
+ match loadClosureOpt with
+ | None -> PrimaryAssembly.Mscorlib
+ | Some loadClosure ->
+ if loadClosure.UseDesktopFramework then
+ PrimaryAssembly.Mscorlib
+ else
+ PrimaryAssembly.System_Runtime
- // Resolve assemblies and create the framework TcImports. This caches a level of "system" references. No type providers are
- // included in these references.
+ tcConfigB.resolutionEnvironment <- (LegacyResolutionEnvironment.EditingOrCompilation true)
- let frameworkDLLs, nonFrameworkResolutions, unresolvedReferences =
- TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig)
+ tcConfigB.conditionalDefines <-
+ let define =
+ if useScriptResolutionRules then
+ "INTERACTIVE"
+ else
+ "COMPILED"
- // Prepare the frameworkTcImportsCache
- let! tcGlobals, frameworkTcImports = ComputeFrameworkImports tcConfig frameworkDLLs nonFrameworkResolutions
-
- // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
- // This is ok because not much can actually go wrong here.
- let diagnosticsLogger =
- CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
-
- use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+ define :: tcConfigB.conditionalDefines
- // TODO: might need to put something like this somewhere
- //// Get the names and time stamps of all the non-framework referenced assemblies, which will act
- //// as inputs to one of the nodes in the build.
- ////
- //// This operation is done when constructing the builder itself, rather than as an incremental task.
- //let nonFrameworkAssemblyInputs =
- // // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
- // // This is ok because not much can actually go wrong here.
- // let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
- // // Return the disposable object that cleans up
- // use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+ tcConfigB.projectReferences <- projectReferences
- // [ for r in nonFrameworkResolutions do
- // let fileName = r.resolvedPath
- // yield (Choice1Of2 fileName, (fun (cache: TimeStampCache) -> cache.GetFileTimeStamp fileName))
+ tcConfigB.useSimpleResolution <- (getSwitchValue useSimpleResolutionSwitch) |> Option.isSome
- // for pr in projectReferences do
- // yield Choice2Of2 pr, (fun (cache: TimeStampCache) -> cache.GetProjectReferenceTimeStamp pr) ]
+ // Apply command-line arguments and collect more source files if they are in the arguments
+ let sourceFilesNew =
+ ApplyCommandLineArgs(tcConfigB, projectSnapshot.SourceFileNames, commandLineArgs)
- let tcConfigP = TcConfigProvider.Constant tcConfig
+ // Never open PDB files for the language service, even if --standalone is specified
+ tcConfigB.openDebugInformationForLaterStaticLinking <- false
+ tcConfigB.xmlDocInfoLoader <-
+ { new IXmlDocumentationInfoLoader with
+ /// Try to load xml documentation associated with an assembly by the same file path with the extension ".xml".
+ member _.TryLoad(assemblyFileName) =
+ let xmlFileName = Path.ChangeExtension(assemblyFileName, ".xml")
- let importsInvalidatedByTypeProvider = Event()
+ // REVIEW: File IO - Will eventually need to change this to use a file system interface of some sort.
+ XmlDocumentationInfo.TryCreateFromFile(xmlFileName)
+ }
+ |> Some
+ tcConfigB.parallelReferenceResolution <- parallelReferenceResolution
+ tcConfigB.captureIdentifiersWhenParsing <- captureIdentifiersWhenParsing
- // Check for the existence of loaded sources and prepend them to the sources list if present.
- let sourceFiles =
- tcConfig.GetAvailableLoadedSources()
- @ (sourceFiles |> List.map (fun s -> rangeStartup, s))
+ tcConfigB, sourceFilesNew
- // Mark up the source files with an indicator flag indicating if they are the last source file in the project
- let sourceFiles =
- let flags, isExe = tcConfig.ComputeCanContainEntryPoint(sourceFiles |> List.map snd)
- ((sourceFiles, flags) ||> List.map2 (fun (m, nm) flag -> (m, nm, (flag, isExe))))
+ // If this is a builder for a script, re-apply the settings inferred from the
+ // script and its load closure to the configuration.
+ //
+ // NOTE: it would probably be cleaner and more accurate to re-run the load closure at this point.
+ let setupConfigFromLoadClosure () =
+ match loadClosureOpt with
+ | Some loadClosure ->
+ let dllReferences =
+ [
+ for reference in tcConfigB.referencedDLLs do
+ // If there's (one or more) resolutions of closure references then yield them all
+ match
+ loadClosure.References
+ |> List.tryFind (fun (resolved, _) -> resolved = reference.Text)
+ with
+ | Some (resolved, closureReferences) ->
+ for closureReference in closureReferences do
+ yield AssemblyReference(closureReference.originalReference.Range, resolved, None)
+ | None -> yield reference
+ ]
+
+ tcConfigB.referencedDLLs <- []
+
+ tcConfigB.primaryAssembly <-
+ (if loadClosure.UseDesktopFramework then
+ PrimaryAssembly.Mscorlib
+ else
+ PrimaryAssembly.System_Runtime)
+ // Add one by one to remove duplicates
+ dllReferences
+ |> List.iter (fun dllReference -> tcConfigB.AddReferencedAssemblyByPath(dllReference.Range, dllReference.Text))
+
+ tcConfigB.knownUnresolvedReferences <- loadClosure.UnresolvedReferences
+ | None -> ()
- let basicDependencies =
- [
- for UnresolvedAssemblyReference (referenceText, _) in unresolvedReferences do
- // Exclude things that are definitely not a file name
- if not (FileSystem.IsInvalidPathShim referenceText) then
- let file =
- if FileSystem.IsPathRootedShim referenceText then
- referenceText
- else
- Path.Combine(projectSnapshot.ProjectDirectory, referenceText)
-
- yield file
-
- for r in nonFrameworkResolutions do
- yield r.resolvedPath
- ]
+ setupConfigFromLoadClosure ()
+
+ let tcConfig = TcConfig.Create(tcConfigB, validate = true)
+ let _outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
+
+ // Resolve assemblies and create the framework TcImports. This caches a level of "system" references. No type providers are
+ // included in these references.
+
+ let frameworkDLLs, nonFrameworkResolutions, unresolvedReferences =
+ TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig)
+
+ // Prepare the frameworkTcImportsCache
+ let! tcGlobals, frameworkTcImports = ComputeFrameworkImports tcConfig frameworkDLLs nonFrameworkResolutions
+
+ // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
+ // This is ok because not much can actually go wrong here.
+ let diagnosticsLogger =
+ CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
+
+ use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+
+ // TODO: might need to put something like this somewhere
+ //// Get the names and time stamps of all the non-framework referenced assemblies, which will act
+ //// as inputs to one of the nodes in the build.
+ ////
+ //// This operation is done when constructing the builder itself, rather than as an incremental task.
+ //let nonFrameworkAssemblyInputs =
+ // // Note we are not calling diagnosticsLogger.GetDiagnostics() anywhere for this task.
+ // // This is ok because not much can actually go wrong here.
+ // let diagnosticsLogger = CompilationDiagnosticLogger("nonFrameworkAssemblyInputs", tcConfig.diagnosticsOptions)
+ // // Return the disposable object that cleans up
+ // use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter)
+
+ // [ for r in nonFrameworkResolutions do
+ // let fileName = r.resolvedPath
+ // yield (Choice1Of2 fileName, (fun (cache: TimeStampCache) -> cache.GetFileTimeStamp fileName))
+
+ // for pr in projectReferences do
+ // yield Choice2Of2 pr, (fun (cache: TimeStampCache) -> cache.GetProjectReferenceTimeStamp pr) ]
+
+ let tcConfigP = TcConfigProvider.Constant tcConfig
+
+ let importsInvalidatedByTypeProvider = Event()
+
+ // Check for the existence of loaded sources and prepend them to the sources list if present.
+ let sourceFiles =
+ tcConfig.GetAvailableLoadedSources()
+ @ (sourceFiles |> List.map (fun s -> rangeStartup, s))
+
+ // Mark up the source files with an indicator flag indicating if they are the last source file in the project
+ let sourceFiles =
+ let flags, isExe = tcConfig.ComputeCanContainEntryPoint(sourceFiles |> List.map snd)
+ ((sourceFiles, flags) ||> List.map2 (fun (m, nm) flag -> (m, nm, (flag, isExe))))
+
+ let basicDependencies =
+ [
+ for UnresolvedAssemblyReference (referenceText, _) in unresolvedReferences do
+ // Exclude things that are definitely not a file name
+ if not (FileSystem.IsInvalidPathShim referenceText) then
+ let file =
+ if FileSystem.IsPathRootedShim referenceText then
+ referenceText
+ else
+ Path.Combine(projectSnapshot.ProjectDirectory, referenceText)
+
+ yield file
+
+ for r in nonFrameworkResolutions do
+ yield r.resolvedPath
+ ]
+
+ // For scripts, the dependency provider is already available.
+ // For projects create a fresh one for the project.
+ let dependencyProvider =
+ if projectSnapshot.UseScriptResolutionRules then
+ dependencyProviderForScripts
+ else
+ new DependencyProvider()
+
+ let! tcImports, initialTcInfo =
+ CombineImportedAssembliesTask(
+ assemblyName,
+ tcConfig,
+ tcConfigP,
+ tcGlobals,
+ frameworkTcImports,
+ nonFrameworkResolutions,
+ unresolvedReferences,
+ dependencyProvider,
+ loadClosureOpt,
+ basicDependencies,
+ importsInvalidatedByTypeProvider
+ )
- // For scripts, the dependency provider is already available.
- // For projects create a fresh one for the project.
- let dependencyProvider =
- if projectSnapshot.UseScriptResolutionRules then
- dependencyProviderForScripts
- else
- new DependencyProvider()
-
- let! tcImports, initialTcInfo =
- CombineImportedAssembliesTask(
- assemblyName,
- tcConfig,
- tcConfigP,
- tcGlobals,
- frameworkTcImports,
- nonFrameworkResolutions,
- unresolvedReferences,
- dependencyProvider,
- loadClosureOpt,
- basicDependencies,
- importsInvalidatedByTypeProvider
- )
- return sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, importsInvalidatedByTypeProvider
- })
+ return sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, importsInvalidatedByTypeProvider
+ }
+ )
let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
node {
- let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, _importsInvalidatedByTypeProvider = ComputeBootstrapInfoStatic projectSnapshot
+ let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, _importsInvalidatedByTypeProvider =
+ ComputeBootstrapInfoStatic projectSnapshot
let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
@@ -566,169 +586,207 @@ type internal TransparentCompiler
InitialTcInfo = initialTcInfo
SourceFiles = sourceFiles
LoadClosure = loadClosureOpt
- //ImportsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider
+ //ImportsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider
}
}
let ComputeBootstrapInfo (projectSnapshot: FSharpProjectSnapshot) =
- BootstrapInfoCache.Get(projectSnapshot.Key, node {
- use _ = Activity.start "ComputeBootstrapInfo" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
-
- // Trap and report diagnostics from creation.
- let delayedLogger = CapturingDiagnosticsLogger("IncrementalBuilderCreation")
- use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter)
-
- let! bootstrapInfoOpt =
- node {
- try
- return! computeBootstrapInfoInner projectSnapshot
- with exn ->
- errorRecoveryNoRange exn
- return None
- }
+ BootstrapInfoCache.Get(
+ projectSnapshot.Key,
+ node {
+ use _ =
+ Activity.start "ComputeBootstrapInfo" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
+
+ // Trap and report diagnostics from creation.
+ let delayedLogger = CapturingDiagnosticsLogger("IncrementalBuilderCreation")
+ use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter)
+
+ let! bootstrapInfoOpt =
+ node {
+ try
+ return! computeBootstrapInfoInner projectSnapshot
+ with exn ->
+ errorRecoveryNoRange exn
+ return None
+ }
- let diagnostics =
- match bootstrapInfoOpt with
- | Some bootstrapInfo ->
- let diagnosticsOptions = bootstrapInfo.TcConfig.diagnosticsOptions
+ let diagnostics =
+ match bootstrapInfoOpt with
+ | Some bootstrapInfo ->
+ let diagnosticsOptions = bootstrapInfo.TcConfig.diagnosticsOptions
- let diagnosticsLogger =
- CompilationDiagnosticLogger("IncrementalBuilderCreation", diagnosticsOptions)
+ let diagnosticsLogger =
+ CompilationDiagnosticLogger("IncrementalBuilderCreation", diagnosticsOptions)
- delayedLogger.CommitDelayedDiagnostics diagnosticsLogger
- diagnosticsLogger.GetDiagnostics()
- | _ -> Array.ofList delayedLogger.Diagnostics
- |> Array.map (fun (diagnostic, severity) ->
- FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, suggestNamesForErrors))
+ delayedLogger.CommitDelayedDiagnostics diagnosticsLogger
+ diagnosticsLogger.GetDiagnostics()
+ | _ -> Array.ofList delayedLogger.Diagnostics
+ |> Array.map (fun (diagnostic, severity) ->
+ FSharpDiagnostic.CreateFromException(diagnostic, severity, range.Zero, suggestNamesForErrors))
- return bootstrapInfoOpt, diagnostics
- })
+ return bootstrapInfoOpt, diagnostics
+ }
+ )
- let ComputeParseFile bootstrapInfo (file: FSharpFile) =
+ let ComputeParseFile bootstrapInfo (file: FSharpFile) =
let key = file.Source.Key, file.IsLastCompiland, file.IsExe
- ParseFileCache.Get(key, node {
- use _ = Activity.start "ComputeParseFile" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName; Activity.Tags.version, file.Source.Version |]
-
- let tcConfig = bootstrapInfo.TcConfig
-
- let diagnosticsLogger =
- CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions)
- // Return the disposable object that cleans up
- use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse)
- let flags = file.IsLastCompiland, file.IsExe
- let fileName = file.Source.FileName
- let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
-
- let input =
- ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, flags, diagnosticsLogger, sourceText)
-
- return input, diagnosticsLogger.GetDiagnostics(), sourceText
- })
+ ParseFileCache.Get(
+ key,
+ node {
+ use _ =
+ Activity.start
+ "ComputeParseFile"
+ [|
+ Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName
+ Activity.Tags.version, file.Source.Version
+ |]
+
+ let tcConfig = bootstrapInfo.TcConfig
+
+ let diagnosticsLogger =
+ CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions)
+ // Return the disposable object that cleans up
+ use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse)
+
+ let flags = file.IsLastCompiland, file.IsExe
+ let fileName = file.Source.FileName
+ let! sourceText = file.Source.GetSource() |> NodeCode.AwaitTask
+
+ let input =
+ ParseOneInputSourceText(tcConfig, lexResourceManager, fileName, flags, diagnosticsLogger, sourceText)
+
+ return input, diagnosticsLogger.GetDiagnostics(), sourceText
+ }
+ )
let ComputeDependencyGraphForLastFile (priorSnapshot: FSharpProjectSnapshot) parsedInputs (tcConfig: TcConfig) =
let key = priorSnapshot.SourceFiles |> List.map (fun s -> s.Key)
- DependencyGraphForLastFileCache.Get(key, node {
-
- let sourceFiles: FileInProject array =
- parsedInputs
- |> Seq.toArray
- |> Array.mapi (fun idx (input: ParsedInput) ->
- {
- Idx = idx
- FileName = input.FileName
- ParsedInput = input
- })
-
- use _ = Activity.start "ComputeDependencyGraphForLastFile" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
-
- let filePairs = FilePairMap(sourceFiles)
-
- // TODO: we will probably want to cache and re-use larger graphs if available
- let graph =
- DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
- |> fst
- |> Graph.subGraphFor (sourceFiles |> Array.last).Idx
- return TransformDependencyGraph(graph, filePairs)
- })
+ DependencyGraphForLastFileCache.Get(
+ key,
+ node {
+
+ let sourceFiles: FileInProject array =
+ parsedInputs
+ |> Seq.toArray
+ |> Array.mapi (fun idx (input: ParsedInput) ->
+ {
+ Idx = idx
+ FileName = input.FileName
+ ParsedInput = input
+ })
+
+ use _ =
+ Activity.start "ComputeDependencyGraphForLastFile" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
+
+ let filePairs = FilePairMap(sourceFiles)
+
+ // TODO: we will probably want to cache and re-use larger graphs if available
+ let graph =
+ DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
+ |> fst
+ |> Graph.subGraphFor (sourceFiles |> Array.last).Idx
+
+ return TransformDependencyGraph(graph, filePairs)
+ }
+ )
- let ComputeTcIntermediate (projectSnapshot: FSharpProjectSnapshot) (fileIndex: FileIndex) (parsedInput: ParsedInput, parseErrors) bootstrapInfo (prevTcInfo: TcInfo) =
+ let ComputeTcIntermediate
+ (projectSnapshot: FSharpProjectSnapshot)
+ (fileIndex: FileIndex)
+ (parsedInput: ParsedInput, parseErrors)
+ bootstrapInfo
+ (prevTcInfo: TcInfo)
+ =
// TODO: we need to construct cache key based on only relevant files from the dependency graph
let key = projectSnapshot.UpTo(fileIndex).Key
- TcIntermediateCache.Get(key, node {
- let input = parsedInput
- let fileName = input.FileName
- use _ = Activity.start "ComputeTcIntermediate" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+ TcIntermediateCache.Get(
+ key,
+ node {
+ let input = parsedInput
+ let fileName = input.FileName
- let tcConfig = bootstrapInfo.TcConfig
- let tcGlobals = bootstrapInfo.TcGlobals
- let tcImports = bootstrapInfo.TcImports
+ use _ =
+ Activity.start "ComputeTcIntermediate" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
- let capturingDiagnosticsLogger = CapturingDiagnosticsLogger("TypeCheck")
+ let tcConfig = bootstrapInfo.TcConfig
+ let tcGlobals = bootstrapInfo.TcGlobals
+ let tcImports = bootstrapInfo.TcImports
- let diagnosticsLogger =
- GetDiagnosticsLoggerFilteringByScopedPragmas(
- false,
- input.ScopedPragmas,
- tcConfig.diagnosticsOptions,
- capturingDiagnosticsLogger
- )
+ let capturingDiagnosticsLogger = CapturingDiagnosticsLogger("TypeCheck")
- use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
+ let diagnosticsLogger =
+ GetDiagnosticsLoggerFilteringByScopedPragmas(
+ false,
+ input.ScopedPragmas,
+ tcConfig.diagnosticsOptions,
+ capturingDiagnosticsLogger
+ )
- //beforeFileChecked.Trigger fileName
+ use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
- ApplyMetaCommandsFromInputToTcConfig(tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider)
- |> ignore
+ //beforeFileChecked.Trigger fileName
- let sink = TcResultsSinkImpl(tcGlobals)
- let hadParseErrors = not (Array.isEmpty parseErrors)
+ ApplyMetaCommandsFromInputToTcConfig(tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider)
+ |> ignore
- let input, moduleNamesDict =
- DeduplicateParsedInputModuleName prevTcInfo.moduleNamesDict input
+ let sink = TcResultsSinkImpl(tcGlobals)
+ let hadParseErrors = not (Array.isEmpty parseErrors)
- let! finisher =
- CheckOneInputWithCallback(
- (fun () -> hadParseErrors || diagnosticsLogger.ErrorCount > 0),
- tcConfig,
- tcImports,
- tcGlobals,
- None,
- TcResultsSink.WithSink sink,
- prevTcInfo.tcState,
- input,
- false
- )
- |> NodeCode.FromCancellable
+ let input, moduleNamesDict =
+ DeduplicateParsedInputModuleName prevTcInfo.moduleNamesDict input
- //fileChecked.Trigger fileName
+ let! finisher =
+ CheckOneInputWithCallback(
+ (fun () -> hadParseErrors || diagnosticsLogger.ErrorCount > 0),
+ tcConfig,
+ tcImports,
+ tcGlobals,
+ None,
+ TcResultsSink.WithSink sink,
+ prevTcInfo.tcState,
+ input,
+ false
+ )
+ |> NodeCode.FromCancellable
- let newErrors =
- Array.append parseErrors (capturingDiagnosticsLogger.Diagnostics |> List.toArray)
+ //fileChecked.Trigger fileName
- return
- {
- finisher = finisher
- moduleNamesDict = moduleNamesDict
- tcDiagnosticsRev = [ newErrors ]
- tcDependencyFiles = [ fileName ]
- sink = sink
- }
- })
+ let newErrors =
+ Array.append parseErrors (capturingDiagnosticsLogger.Diagnostics |> List.toArray)
+
+ return
+ {
+ finisher = finisher
+ moduleNamesDict = moduleNamesDict
+ tcDiagnosticsRev = [ newErrors ]
+ tcDependencyFiles = [ fileName ]
+ sink = sink
+ }
+ }
+ )
let mergeIntermediateResults =
Array.fold (fun (tcInfo: TcInfo) (tcIntermediate: TcIntermediate) ->
- let (tcEnv, topAttribs, _checkImplFileOpt, ccuSigForFile), tcState = tcInfo.tcState |> tcIntermediate.finisher.Invoke
- let tcEnvAtEndOfFile = if keepAllBackgroundResolutions then tcEnv else tcState.TcEnvFromImpls
+ let (tcEnv, topAttribs, _checkImplFileOpt, ccuSigForFile), tcState =
+ tcInfo.tcState |> tcIntermediate.finisher.Invoke
+
+ let tcEnvAtEndOfFile =
+ if keepAllBackgroundResolutions then
+ tcEnv
+ else
+ tcState.TcEnvFromImpls
+
{ tcInfo with
tcState = tcState
tcEnvAtEndOfFile = tcEnvAtEndOfFile
topAttribs = Some topAttribs
tcDiagnosticsRev = tcIntermediate.tcDiagnosticsRev @ tcInfo.tcDiagnosticsRev
tcDependencyFiles = tcIntermediate.tcDependencyFiles @ tcInfo.tcDependencyFiles
- latestCcuSigForFile = Some ccuSigForFile })
+ latestCcuSigForFile = Some ccuSigForFile
+ })
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) =
@@ -736,77 +794,88 @@ type internal TransparentCompiler
let priorSnapshot = projectSnapshot.UpTo file.Source.FileName
let key = priorSnapshot.Key
- TcPriorCache.Get(key, node {
- use _ = Activity.start "ComputeTcPrior" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName |]
-
- // parse required files
- let files =
- seq {
- yield! bootstrapInfo.SourceFiles |> Seq.takeWhile ((<>) file)
- file
- }
-
- let! parsedInputs =
- files
- |> Seq.map (ComputeParseFile bootstrapInfo)
- |> NodeCode.Parallel
-
- let! graph = ComputeDependencyGraphForLastFile priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
-
- let fileNames =
- parsedInputs
- |> Seq.mapi (fun idx (input, _, _) -> idx, Path.GetFileName input.FileName)
- |> Map.ofSeq
-
- let debugGraph =
- graph
- |> Graph.map (function NodeToTypeCheck.PhysicalFile i -> i, fileNames[i] | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
-
- Trace.TraceInformation("\n" + (debugGraph |> Graph.serialiseToMermaid))
-
- // layers that can be processed in parallel
- let layers = Graph.leafSequence graph |> Seq.toList
-
- // remove the final layer, which should be the target file
- let layers = layers |> List.take (layers.Length - 1)
+ TcPriorCache.Get(
+ key,
+ node {
+ use _ =
+ Activity.start "ComputeTcPrior" [| Activity.Tags.fileName, file.Source.FileName |> Path.GetFileName |]
+
+ // parse required files
+ let files =
+ seq {
+ yield! bootstrapInfo.SourceFiles |> Seq.takeWhile ((<>) file)
+ file
+ }
- let rec processLayer (layers: Set list) tcInfo =
- node {
- match layers with
- | [] -> return tcInfo
- | layer :: rest ->
- let! results =
- layer
- |> Seq.map (fun fileNode ->
-
- match fileNode with
- | NodeToTypeCheck.PhysicalFile fileIndex ->
- let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
- ComputeTcIntermediate projectSnapshot fileIndex (parsedInput, parseErrors) bootstrapInfo tcInfo
- | NodeToTypeCheck.ArtificialImplFile fileIndex ->
-
- let finisher tcState =
- let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
- let prefixPathOpt = None
- // Retrieve the type-checked signature information and add it to the TcEnvFromImpls.
- AddSignatureResultToTcImplEnv(bootstrapInfo.TcImports, bootstrapInfo.TcGlobals, prefixPathOpt, TcResultsSink.NoSink, tcState, parsedInput) tcState
- let tcIntermediate =
- {
- finisher = finisher
- moduleNamesDict = tcInfo.moduleNamesDict
- tcDiagnosticsRev = []
- tcDependencyFiles = []
- sink = Unchecked.defaultof<_>
- }
-
- node.Return(tcIntermediate))
- |> NodeCode.Parallel
-
- return! processLayer rest (mergeIntermediateResults tcInfo results)
- }
+ let! parsedInputs = files |> Seq.map (ComputeParseFile bootstrapInfo) |> NodeCode.Parallel
+
+ let! graph = ComputeDependencyGraphForLastFile priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
+
+ let fileNames =
+ parsedInputs
+ |> Seq.mapi (fun idx (input, _, _) -> idx, Path.GetFileName input.FileName)
+ |> Map.ofSeq
+
+ let debugGraph =
+ graph
+ |> Graph.map (function
+ | NodeToTypeCheck.PhysicalFile i -> i, fileNames[i]
+ | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
+
+ Trace.TraceInformation("\n" + (debugGraph |> Graph.serialiseToMermaid))
+
+ // layers that can be processed in parallel
+ let layers = Graph.leafSequence graph |> Seq.toList
+
+ // remove the final layer, which should be the target file
+ let layers = layers |> List.take (layers.Length - 1)
+
+ let rec processLayer (layers: Set list) tcInfo =
+ node {
+ match layers with
+ | [] -> return tcInfo
+ | layer :: rest ->
+ let! results =
+ layer
+ |> Seq.map (fun fileNode ->
+
+ match fileNode with
+ | NodeToTypeCheck.PhysicalFile fileIndex ->
+ let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
+ ComputeTcIntermediate projectSnapshot fileIndex (parsedInput, parseErrors) bootstrapInfo tcInfo
+ | NodeToTypeCheck.ArtificialImplFile fileIndex ->
+
+ let finisher tcState =
+ let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
+ let prefixPathOpt = None
+ // Retrieve the type-checked signature information and add it to the TcEnvFromImpls.
+ AddSignatureResultToTcImplEnv
+ (bootstrapInfo.TcImports,
+ bootstrapInfo.TcGlobals,
+ prefixPathOpt,
+ TcResultsSink.NoSink,
+ tcState,
+ parsedInput)
+ tcState
+
+ let tcIntermediate =
+ {
+ finisher = finisher
+ moduleNamesDict = tcInfo.moduleNamesDict
+ tcDiagnosticsRev = []
+ tcDependencyFiles = []
+ sink = Unchecked.defaultof<_>
+ }
+
+ node.Return(tcIntermediate))
+ |> NodeCode.Parallel
+
+ return! processLayer rest (mergeIntermediateResults tcInfo results)
+ }
- return! processLayer layers bootstrapInfo.InitialTcInfo
- })
+ return! processLayer layers bootstrapInfo.InitialTcInfo
+ }
+ )
let getParseResult (bootstrapInfo: BootstrapInfo) creationDiags fileName =
node {
@@ -832,7 +901,8 @@ type internal TransparentCompiler
parseHadErrors = (parseDiagnostics.Length > 0),
// TODO: check if we really need this in parse results
dependencyFiles = [||]
- ), sourceText
+ ),
+ sourceText
}
let emptyParseResult fileName diagnostics =
@@ -841,59 +911,72 @@ type internal TransparentCompiler
let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: FSharpProjectSnapshot) =
let key = fileName, projectSnapshot.Key
- ParseAndCheckFileInProjectCache.Get(key, node {
-
- use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
-
- match! ComputeBootstrapInfo projectSnapshot with
- | None, creationDiags ->
- return emptyParseResult fileName creationDiags, FSharpCheckFileAnswer.Aborted
-
- | Some bootstrapInfo, creationDiags ->
-
- let file = bootstrapInfo.GetFile fileName
-
- let! parseResults, sourceText = getParseResult bootstrapInfo creationDiags fileName
- let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
-
- let! checkResults =
- FSharpCheckFileResults.CheckOneFile(
- parseResults,
- sourceText,
- fileName,
- projectSnapshot.ProjectFileName,
- bootstrapInfo.TcConfig,
- bootstrapInfo.TcGlobals,
- bootstrapInfo.TcImports,
- tcInfo.tcState,
- tcInfo.moduleNamesDict,
- bootstrapInfo.LoadClosure,
- tcInfo.TcDiagnostics,
- projectSnapshot.IsIncompleteTypeCheckEnvironment,
- projectSnapshot.ToOptions(),
- None,
- Array.ofList tcInfo.tcDependencyFiles,
- creationDiags,
- parseResults.Diagnostics,
- keepAssemblyContents,
- suggestNamesForErrors
- )
- |> NodeCode.FromCancellable
-
- return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
- })
+ ParseAndCheckFileInProjectCache.Get(
+ key,
+ node {
+
+ use _ =
+ Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+
+ match! ComputeBootstrapInfo projectSnapshot with
+ | None, creationDiags -> return emptyParseResult fileName creationDiags, FSharpCheckFileAnswer.Aborted
+
+ | Some bootstrapInfo, creationDiags ->
+
+ let file = bootstrapInfo.GetFile fileName
+
+ let! parseResults, sourceText = getParseResult bootstrapInfo creationDiags fileName
+
+ let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
+
+ let! checkResults =
+ FSharpCheckFileResults.CheckOneFile(
+ parseResults,
+ sourceText,
+ fileName,
+ projectSnapshot.ProjectFileName,
+ bootstrapInfo.TcConfig,
+ bootstrapInfo.TcGlobals,
+ bootstrapInfo.TcImports,
+ tcInfo.tcState,
+ tcInfo.moduleNamesDict,
+ bootstrapInfo.LoadClosure,
+ tcInfo.TcDiagnostics,
+ projectSnapshot.IsIncompleteTypeCheckEnvironment,
+ projectSnapshot.ToOptions(),
+ None,
+ Array.ofList tcInfo.tcDependencyFiles,
+ creationDiags,
+ parseResults.Diagnostics,
+ keepAssemblyContents,
+ suggestNamesForErrors
+ )
+ |> NodeCode.FromCancellable
+
+ return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
+ }
+ )
let tryGetSink fileName (projectSnapshot: FSharpProjectSnapshot) =
node {
- use _ = Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+ use _ =
+ Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
match! ComputeBootstrapInfo projectSnapshot with
| None, _ -> return None
| Some bootstrapInfo, _creationDiags ->
let file =
- bootstrapInfo.SourceFiles |> List.tryFind (fun f -> f.Source.FileName = fileName) |> Option.defaultWith (fun _ -> failwith ($"File {fileName} not found in project snapshot. Files in project: \n\n" + (bootstrapInfo.SourceFiles |> Seq.map (fun f -> f.Source.FileName) |> String.concat " \n")))
+ bootstrapInfo.SourceFiles
+ |> List.tryFind (fun f -> f.Source.FileName = fileName)
+ |> Option.defaultWith (fun _ ->
+ failwith (
+ $"File {fileName} not found in project snapshot. Files in project: \n\n"
+ + (bootstrapInfo.SourceFiles
+ |> Seq.map (fun f -> f.Source.FileName)
+ |> String.concat " \n")
+ ))
let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
let! parseTree, parseDiagnostics, _sourceText = ComputeParseFile bootstrapInfo file
@@ -901,53 +984,85 @@ type internal TransparentCompiler
let fileIndex = projectSnapshot.IndexOf fileName
let! { sink = sink } = ComputeTcIntermediate projectSnapshot fileIndex (parseTree, parseDiagnostics) bootstrapInfo tcInfo
- return Some (sink, bootstrapInfo)
+ return Some(sink, bootstrapInfo)
}
- let ComputeSemanticClassification(fileName: string, projectSnapshot: FSharpProjectSnapshot) =
+ let ComputeSemanticClassification (fileName: string, projectSnapshot: FSharpProjectSnapshot) =
let key = (projectSnapshot.UpTo fileName).Key
- SemanticClassificationCache.Get(key, node {
- use _ = Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
- let! sinkOpt = tryGetSink fileName projectSnapshot
- return
- sinkOpt
- |> Option.bind (fun (sink, bootstrapInfo) ->
- let sResolutions = sink.GetResolutions()
- let semanticClassification = sResolutions.GetSemanticClassification(bootstrapInfo.TcGlobals, bootstrapInfo.TcImports.GetImportMap(), sink.GetFormatSpecifierLocations(), None)
- let sckBuilder = SemanticClassificationKeyStoreBuilder()
- sckBuilder.WriteAll semanticClassification
+ SemanticClassificationCache.Get(
+ key,
+ node {
+ use _ =
+ Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+
+ let! sinkOpt = tryGetSink fileName projectSnapshot
- sckBuilder.TryBuildAndReset())
- |> Option.map (fun sck -> sck.GetView())
- })
+ return
+ sinkOpt
+ |> Option.bind (fun (sink, bootstrapInfo) ->
+ let sResolutions = sink.GetResolutions()
- let ComputeItemKeyStore(fileName: string, projectSnapshot: FSharpProjectSnapshot) =
+ let semanticClassification =
+ sResolutions.GetSemanticClassification(
+ bootstrapInfo.TcGlobals,
+ bootstrapInfo.TcImports.GetImportMap(),
+ sink.GetFormatSpecifierLocations(),
+ None
+ )
+
+ let sckBuilder = SemanticClassificationKeyStoreBuilder()
+ sckBuilder.WriteAll semanticClassification
+
+ sckBuilder.TryBuildAndReset())
+ |> Option.map (fun sck -> sck.GetView())
+ }
+ )
+
+ let ComputeItemKeyStore (fileName: string, projectSnapshot: FSharpProjectSnapshot) =
let key = (projectSnapshot.UpTo fileName).Key
- ItemKeyStoreCache.Get(key, node {
- use _ = Activity.start "ComputeItemKeyStore" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
- let! sinkOpt = tryGetSink fileName projectSnapshot
- return
- sinkOpt
- |> Option.bind (fun (sink, _) ->
- let sResolutions = sink.GetResolutions()
-
- let builder = ItemKeyStoreBuilder()
- let preventDuplicates = HashSet({ new IEqualityComparer with
- member _.Equals((s1, e1): struct(pos * pos), (s2, e2): struct(pos * pos)) = Position.posEq s1 s2 && Position.posEq e1 e2
- member _.GetHashCode o = o.GetHashCode() })
- sResolutions.CapturedNameResolutions
- |> Seq.iter (fun cnr ->
- let r = cnr.Range
- if preventDuplicates.Add struct(r.Start, r.End) then
- builder.Write(cnr.Range, cnr.Item))
-
- builder.TryBuildAndReset())
- })
+
+ ItemKeyStoreCache.Get(
+ key,
+ node {
+ use _ =
+ Activity.start "ComputeItemKeyStore" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+
+ let! sinkOpt = tryGetSink fileName projectSnapshot
+
+ return
+ sinkOpt
+ |> Option.bind (fun (sink, _) ->
+ let sResolutions = sink.GetResolutions()
+
+ let builder = ItemKeyStoreBuilder()
+
+ let preventDuplicates =
+ HashSet(
+ { new IEqualityComparer with
+ member _.Equals((s1, e1): struct (pos * pos), (s2, e2): struct (pos * pos)) =
+ Position.posEq s1 s2 && Position.posEq e1 e2
+
+ member _.GetHashCode o = o.GetHashCode()
+ }
+ )
+
+ sResolutions.CapturedNameResolutions
+ |> Seq.iter (fun cnr ->
+ let r = cnr.Range
+
+ if preventDuplicates.Add struct (r.Start, r.End) then
+ builder.Write(cnr.Range, cnr.Item))
+
+ builder.TryBuildAndReset())
+ }
+ )
member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
node {
- use _ = Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+ use _ =
+ Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+
match! ComputeBootstrapInfo projectSnapshot with
| None, creationDiags -> return emptyParseResult fileName creationDiags
| Some bootstrapInfo, creationDiags ->
@@ -959,14 +1074,9 @@ type internal TransparentCompiler
ignore userOpName
ComputeParseAndCheckFileInProject fileName projectSnapshot
- member _.FindReferencesInFile
- (
- fileName: string,
- projectSnapshot: FSharpProjectSnapshot,
- symbol: FSharpSymbol,
- userOpName: string
- ) =
+ member _.FindReferencesInFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, symbol: FSharpSymbol, userOpName: string) =
ignore userOpName
+
node {
match! ComputeItemKeyStore(fileName, projectSnapshot) with
| None -> return Seq.empty
@@ -1031,7 +1141,8 @@ type internal TransparentCompiler
) : NodeCode> =
backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName)
- member this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName) = this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName)
+ member this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName) =
+ this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName)
member _.FrameworkImportsCache: FrameworkImportsCache =
backgroundCompiler.FrameworkImportsCache
@@ -1092,12 +1203,7 @@ type internal TransparentCompiler
userOpName
)
- member _.GetSemanticClassificationForFile
- (
- fileName: string,
- snapshot: FSharpProjectSnapshot,
- userOpName: string
- ) =
+ member _.GetSemanticClassificationForFile(fileName: string, snapshot: FSharpProjectSnapshot, userOpName: string) =
ignore userOpName
ComputeSemanticClassification(fileName, snapshot)
From c4329248c6d0601733cc149605d5ce428f02b743 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 18 May 2023 12:17:02 +0200
Subject: [PATCH 038/222] ...
---
src/Compiler/Service/TransparentCompiler.fs | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index bd0aa272ae8..0edb0c46172 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -279,6 +279,9 @@ type internal TransparentCompiler
match capturedImportsInvalidated.TryGetTarget() with
| true, tg -> tg.Trigger()
| _ -> ()))
+#endif
+#if NO_TYPEPROVIDERS
+ ignore importsInvalidatedByTypeProvider
#endif
return tcImports
with exn ->
@@ -924,10 +927,9 @@ type internal TransparentCompiler
| Some bootstrapInfo, creationDiags ->
- let file = bootstrapInfo.GetFile fileName
-
let! parseResults, sourceText = getParseResult bootstrapInfo creationDiags fileName
+ let file = bootstrapInfo.GetFile fileName
let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
let! checkResults =
@@ -954,7 +956,7 @@ type internal TransparentCompiler
)
|> NodeCode.FromCancellable
- return (parseResults, FSharpCheckFileAnswer.Succeeded checkResults)
+ return parseResults, FSharpCheckFileAnswer.Succeeded checkResults
}
)
@@ -967,16 +969,7 @@ type internal TransparentCompiler
| None, _ -> return None
| Some bootstrapInfo, _creationDiags ->
- let file =
- bootstrapInfo.SourceFiles
- |> List.tryFind (fun f -> f.Source.FileName = fileName)
- |> Option.defaultWith (fun _ ->
- failwith (
- $"File {fileName} not found in project snapshot. Files in project: \n\n"
- + (bootstrapInfo.SourceFiles
- |> Seq.map (fun f -> f.Source.FileName)
- |> String.concat " \n")
- ))
+ let file = bootstrapInfo.GetFile fileName
let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
let! parseTree, parseDiagnostics, _sourceText = ComputeParseFile bootstrapInfo file
From 127ed3b604d6c04513ae57f06575c82f508d5f0d Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 18 May 2023 13:54:52 +0200
Subject: [PATCH 039/222] Files that are not depended on don't ivalidate cache
---
src/Compiler/Service/FSharpCheckerResults.fs | 9 ++++
src/Compiler/Service/FSharpCheckerResults.fsi | 3 ++
src/Compiler/Service/TransparentCompiler.fs | 41 ++++++++++++-------
.../FSharpChecker/TransparentCompiler.fs | 39 ++++++++++++++++++
...ervice.SurfaceArea.netstandard20.debug.bsl | 6 +++
...vice.SurfaceArea.netstandard20.release.bsl | 2 +
6 files changed, 85 insertions(+), 15 deletions(-)
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index c2271aa1de4..449f50f45ba 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -208,6 +208,15 @@ type FSharpProjectSnapshot =
member this.UpTo fileName = this.UpTo(this.IndexOf fileName)
+ member this.OnlyWith fileIndexes =
+ { this with
+ SourceFiles =
+ fileIndexes
+ |> Set.toList
+ |> List.sort
+ |> List.choose (fun x -> this.SourceFiles |> List.tryItem x)
+ }
+
member this.Key =
{
ProjectFileName = this.ProjectFileName
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index ea55a296ec4..a84a9a7c3aa 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -125,6 +125,9 @@ type FSharpProjectSnapshot =
/// A snapshot of the same project but only up to the given file (including).
member UpTo: fileName: string -> FSharpProjectSnapshot
+ /// A snapshot of the same project but only with source files specified by given indexes.
+ member OnlyWith: fileIndexes: Set -> FSharpProjectSnapshot
+
/// A snapshot of the same project with file versions removed.
member WithoutFileVersions: FSharpProjectSnapshot
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 0edb0c46172..51be01b1d73 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -121,8 +121,7 @@ type internal TransparentCompiler
let TcPriorCache = AsyncMemoize(triggerCacheEvent "TcPrior")
let TcIntermediateCache = AsyncMemoize(triggerCacheEvent "TcIntermediate")
- let DependencyGraphForLastFileCache =
- AsyncMemoize(triggerCacheEvent "DependencyGraphForLastFile")
+ let DependencyGraphCache = AsyncMemoize(triggerCacheEvent "DependencyGraph")
let SemanticClassificationCache =
AsyncMemoize(triggerCacheEvent "SemanticClassification")
@@ -663,10 +662,10 @@ type internal TransparentCompiler
}
)
- let ComputeDependencyGraphForLastFile (priorSnapshot: FSharpProjectSnapshot) parsedInputs (tcConfig: TcConfig) =
+ let ComputeDependencyGraph (priorSnapshot: FSharpProjectSnapshot) parsedInputs (tcConfig: TcConfig) =
let key = priorSnapshot.SourceFiles |> List.map (fun s -> s.Key)
- DependencyGraphForLastFileCache.Get(
+ DependencyGraphCache.Get(
key,
node {
@@ -681,7 +680,7 @@ type internal TransparentCompiler
})
use _ =
- Activity.start "ComputeDependencyGraphForLastFile" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
+ Activity.start "ComputeDependencyGraph" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
let filePairs = FilePairMap(sourceFiles)
@@ -691,22 +690,24 @@ type internal TransparentCompiler
|> fst
|> Graph.subGraphFor (sourceFiles |> Array.last).Idx
- return TransformDependencyGraph(graph, filePairs)
+ let fileIndexes =
+ graph.Values |> Seq.collect id |> Seq.append graph.Keys |> Seq.distinct |> Set
+
+ return TransformDependencyGraph(graph, filePairs), fileIndexes
}
)
let ComputeTcIntermediate
(projectSnapshot: FSharpProjectSnapshot)
+ (dependencyFiles: Set)
(fileIndex: FileIndex)
(parsedInput: ParsedInput, parseErrors)
bootstrapInfo
(prevTcInfo: TcInfo)
=
- // TODO: we need to construct cache key based on only relevant files from the dependency graph
- let key = projectSnapshot.UpTo(fileIndex).Key
TcIntermediateCache.Get(
- key,
+ projectSnapshot.UpTo(fileIndex).OnlyWith(dependencyFiles).Key,
node {
let input = parsedInput
let fileName = input.FileName
@@ -812,7 +813,7 @@ type internal TransparentCompiler
let! parsedInputs = files |> Seq.map (ComputeParseFile bootstrapInfo) |> NodeCode.Parallel
- let! graph = ComputeDependencyGraphForLastFile priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
+ let! graph, dependencyFiles = ComputeDependencyGraph priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
let fileNames =
parsedInputs
@@ -845,7 +846,14 @@ type internal TransparentCompiler
match fileNode with
| NodeToTypeCheck.PhysicalFile fileIndex ->
let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
- ComputeTcIntermediate projectSnapshot fileIndex (parsedInput, parseErrors) bootstrapInfo tcInfo
+
+ ComputeTcIntermediate
+ projectSnapshot
+ dependencyFiles
+ fileIndex
+ (parsedInput, parseErrors)
+ bootstrapInfo
+ tcInfo
| NodeToTypeCheck.ArtificialImplFile fileIndex ->
let finisher tcState =
@@ -876,7 +884,8 @@ type internal TransparentCompiler
return! processLayer rest (mergeIntermediateResults tcInfo results)
}
- return! processLayer layers bootstrapInfo.InitialTcInfo
+ let! tcInfo = processLayer layers bootstrapInfo.InitialTcInfo
+ return tcInfo, dependencyFiles
}
)
@@ -930,7 +939,7 @@ type internal TransparentCompiler
let! parseResults, sourceText = getParseResult bootstrapInfo creationDiags fileName
let file = bootstrapInfo.GetFile fileName
- let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
+ let! tcInfo, _ = ComputeTcPrior file bootstrapInfo projectSnapshot
let! checkResults =
FSharpCheckFileResults.CheckOneFile(
@@ -971,11 +980,13 @@ type internal TransparentCompiler
let file = bootstrapInfo.GetFile fileName
- let! tcInfo = ComputeTcPrior file bootstrapInfo projectSnapshot
+ let! tcInfo, dependencyFiles = ComputeTcPrior file bootstrapInfo projectSnapshot
let! parseTree, parseDiagnostics, _sourceText = ComputeParseFile bootstrapInfo file
let fileIndex = projectSnapshot.IndexOf fileName
- let! { sink = sink } = ComputeTcIntermediate projectSnapshot fileIndex (parseTree, parseDiagnostics) bootstrapInfo tcInfo
+
+ let! { sink = sink } =
+ ComputeTcIntermediate projectSnapshot dependencyFiles fileIndex (parseTree, parseDiagnostics) bootstrapInfo tcInfo
return Some(sink, bootstrapInfo)
}
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index acb508dea41..44f7f6da304 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -206,3 +206,42 @@ let ``We don't check files that are not depended on`` () =
Assert.Equal([Started; Finished], intermediateTypeChecks["FileFirst.fs"])
Assert.Equal([Started; Finished], intermediateTypeChecks["FileThird.fs"])
Assert.False (intermediateTypeChecks.ContainsKey "FileSecond.fs")
+
+[]
+let ``Files that are not depended on don't ivalidate cache`` () =
+ let project = SyntheticProject.Create(
+ sourceFile "First" [],
+ sourceFile "Second" ["First"],
+ sourceFile "Third" ["First"],
+ sourceFile "Last" ["Third"])
+
+ let cacheEvents = ResizeArray()
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ checkFile "Last" expectOk
+ withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
+ updateFile "Second" updatePublicSurface
+ checkFile "Last" expectOk
+ } |> ignore
+
+ let intermediateTypeChecks =
+ cacheEvents
+ |> Seq.choose (function
+ | ("TcIntermediate", e, k) -> Some ((k :?> FSharpProjectSnapshotKey).LastFile |> fst |> Path.GetFileName, e)
+ | _ -> None)
+ |> Seq.groupBy fst
+ |> Seq.map (fun (k, g) -> k, g |> Seq.map snd |> Seq.toList)
+ |> Map
+
+ let graphConstructions =
+ cacheEvents
+ |> Seq.choose (function
+ | ("DependencyGraph", e, k) -> Some ((k :?> FSharpFileKey list) |> List.last |> fst |> Path.GetFileName, e)
+ | _ -> None)
+ |> Seq.groupBy fst
+ |> Seq.map (fun (k, g) -> k, g |> Seq.map snd |> Seq.toList)
+ |> Map
+
+ Assert.Equal([Started; Finished], graphConstructions["FileLast.fs"])
+
+ Assert.True intermediateTypeChecks.IsEmpty
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
index 03aeafb299a..3fb4db8a604 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
@@ -2060,9 +2060,11 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults] ParseFileInProject(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] CheckFileInProjectAllowingStaleCachedResults(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.SemanticClassificationView]] GetBackgroundSemanticClassificationForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.SemanticClassificationView]] GetBackgroundSemanticClassificationForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyFileChanged(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2199,6 +2201,7 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean UseScriptResolutionR
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_IsIncompleteTypeCheckEnvironment()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_UseScriptResolutionRules()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ToOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot OnlyWith(Microsoft.FSharp.Collections.FSharpSet`1[System.Int32])
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(Int32)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot WithoutFileVersions
@@ -2207,6 +2210,7 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 IndexOf(System.String)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] SourceFiles
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot] get_SourceFiles()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot] ReferencedProjects
@@ -2251,6 +2255,8 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collecti
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ProjectFileName
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String get_ProjectFileName()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] LastFile
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] get_LastFile()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey], Boolean, Boolean)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Boolean Equals(System.Object)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions)
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
index 5415b502e06..3fb4db8a604 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
@@ -2064,6 +2064,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyFileChanged(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2200,6 +2201,7 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean UseScriptResolutionR
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_IsIncompleteTypeCheckEnvironment()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Boolean get_UseScriptResolutionRules()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ToOptions()
+FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot OnlyWith(Microsoft.FSharp.Collections.FSharpSet`1[System.Int32])
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(Int32)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot WithoutFileVersions
From fe60fb2f02acd46b49e4be6a84b5162cc227ab37 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 18 May 2023 14:21:35 +0200
Subject: [PATCH 040/222] try deflake linux test
---
.../FSharpChecker/TransparentCompiler.fs | 8 ++++++--
tests/FSharp.Test.Utilities/ProjectGeneration.fs | 10 +++++++++-
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 44f7f6da304..842dcefaf5c 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -189,7 +189,11 @@ let ``We don't check files that are not depended on`` () =
let cacheEvents = ResizeArray()
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
- withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
+ withChecker (fun checker ->
+ async {
+ do! Async.Sleep 50 // wait for events from initial project check
+ checker.CacheEvent.Add cacheEvents.Add
+ })
updateFile "First" updatePublicSurface
checkFile "Last" expectOk
} |> ignore
@@ -208,7 +212,7 @@ let ``We don't check files that are not depended on`` () =
Assert.False (intermediateTypeChecks.ContainsKey "FileSecond.fs")
[]
-let ``Files that are not depended on don't ivalidate cache`` () =
+let ``Files that are not depended on don't invalidate cache`` () =
let project = SyntheticProject.Create(
sourceFile "First" [],
sourceFile "Second" ["First"],
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 29e845d1ed8..6861c256a26 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -700,7 +700,7 @@ type ProjectWorkflowBuilder
[]
member this.WithProject(workflow: Async, f) =
- workflow |> mapProjectAsync (fun project ->
+ workflow |> mapProjectAsync (fun project ->
async {
do! f project checker
return project
@@ -714,6 +714,14 @@ type ProjectWorkflowBuilder
return ctx
}
+ []
+ member this.WithChecker(workflow: Async, f) =
+ async {
+ let! ctx = workflow
+ do! f checker
+ return ctx
+ }
+
/// Change contents of given file using `processFile` function.
/// Does not save the file to disk.
[]
From 02717609200c2caebc31b7af61428fc30b301335 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Thu, 18 May 2023 19:21:03 +0200
Subject: [PATCH 041/222] reduce surface area
---
src/Compiler/Service/BackgroundCompiler.fs | 2 +-
src/Compiler/Service/FSharpCheckerResults.fsi | 8 +--
src/Compiler/Service/IncrementalBuild.fsi | 2 +-
...ervice.SurfaceArea.netstandard20.debug.bsl | 57 -------------------
...vice.SurfaceArea.netstandard20.release.bsl | 57 -------------------
5 files changed, 6 insertions(+), 120 deletions(-)
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index cc25ed2bed3..ed8675b41fb 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -184,7 +184,7 @@ module EnvMisc =
GetEnvInteger "FCS_frameworkTcImportsCacheStrongSizeDefault" 8
[]
-module Helpers =
+module internal Helpers =
/// Determine whether two (fileName,options) keys are identical w.r.t. affect on checking
let AreSameForChecking2 ((fileName1: string, options1: FSharpProjectOptions), (fileName2, options2)) =
diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi
index a84a9a7c3aa..6f77a0bcc99 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fsi
+++ b/src/Compiler/Service/FSharpCheckerResults.fsi
@@ -40,9 +40,9 @@ type internal DelayedILModuleReader =
/// Unused in this API
type public FSharpUnresolvedReferencesSet = internal FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list
-type FSharpFileKey = string * string
+type internal FSharpFileKey = string * string
-type FSharpProjectSnapshotKey =
+type internal FSharpProjectSnapshotKey =
{ ProjectFileName: string
SourceFiles: FSharpFileKey list
OtherOptions: string list
@@ -60,7 +60,7 @@ type FSharpFileSnapshot =
Version: string
GetSource: unit -> Task }
- member Key: FSharpFileKey
+ member internal Key: FSharpFileKey
[]
type FSharpProjectSnapshot =
@@ -131,7 +131,7 @@ type FSharpProjectSnapshot =
/// A snapshot of the same project with file versions removed.
member WithoutFileVersions: FSharpProjectSnapshot
- member Key: FSharpProjectSnapshotKey
+ member internal Key: FSharpProjectSnapshotKey
and [] public FSharpReferencedProjectSnapshot =
internal
diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi
index bd54cf4f3f5..50c7201195c 100644
--- a/src/Compiler/Service/IncrementalBuild.fsi
+++ b/src/Compiler/Service/IncrementalBuild.fsi
@@ -23,7 +23,7 @@ open FSharp.Compiler.Text
open FSharp.Compiler.TypedTree
open FSharp.Compiler.BuildGraph
-type FrameworkImportsCacheKey =
+type internal FrameworkImportsCacheKey =
| FrameworkImportsCacheKey of
resolvedpath: string list *
assemblyName: string *
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
index 3fb4db8a604..db548f930f9 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl
@@ -2098,8 +2098,6 @@ FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String Version
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_FileName()
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_Version()
-FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] Key
-FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] get_Key()
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Void .ctor(System.String, System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]])
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPosContainedInApplication(FSharp.Compiler.Text.Position)
@@ -2206,8 +2204,6 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot WithoutFileVersions
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot get_WithoutFileVersions()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey Key
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 IndexOf(System.String)
@@ -2234,30 +2230,6 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ProjectFileNam
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String get_ProjectFileName()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64])
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean IsIncompleteTypeCheckEnvironment
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean UseScriptResolutionRules
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_IsIncompleteTypeCheckEnvironment()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_UseScriptResolutionRules()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] ReferencedProjects
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] get_ReferencedProjects()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] SourceFiles
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] get_SourceFiles()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ProjectFileName
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ToString()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String get_ProjectFileName()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] LastFile
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] get_LastFile()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey], Boolean, Boolean)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Boolean Equals(System.Object)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFromILModuleReader(System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader])
@@ -2309,35 +2281,6 @@ FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Boolean Equals(Syste
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: System.String ToString()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey NewFrameworkImportsCacheKey(Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.Decimal)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 Tag
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 get_Tag()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_resolvedpath()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_targetFrameworkDirectories()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] resolvedpath
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] targetFrameworkDirectories
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal get_langVersion()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal langVersion
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String ToString()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String assemblyName
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String fsharpBinaries
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_assemblyName()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_fsharpBinaries()
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking3(System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForParsing[a](System.Tuple`3[System.String,System.Int64,a], System.Tuple`3[System.String,System.Int64,a])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSimilarForParsing[a,b,c,d,e](System.Tuple`3[a,b,c], System.Tuple`3[a,d,e])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable3[a,b](System.Tuple`3[System.String,a,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,b,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean NamesContainAttribute(FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Collections.FSharpSet`1[System.String])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: FSharp.Compiler.CodeAnalysis.LegacyResolvedFile[] Resolve(FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, System.Tuple`2[System.String,System.String][], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.FSharpFunc`2[System.Boolean,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit]]])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String DotNetFrameworkReferenceAssembliesRootDirectory
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String HighestInstalledNetFrameworkVersion()
diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
index 3fb4db8a604..db548f930f9 100644
--- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
+++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
@@ -2098,8 +2098,6 @@ FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String Version
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_FileName()
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.String get_Version()
-FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] Key
-FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: System.Tuple`2[System.String,System.String] get_Key()
FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot: Void .ctor(System.String, System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceText]])
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPosContainedInApplication(FSharp.Compiler.Text.Position)
@@ -2206,8 +2204,6 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot UpTo(System.String)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot WithoutFileVersions
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot get_WithoutFileVersions()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey Key
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey get_Key()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Int32 IndexOf(System.String)
@@ -2234,30 +2230,6 @@ FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ProjectFileNam
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String ToString()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: System.String get_ProjectFileName()
FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshot: Void .ctor(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpReferencedProjectSnapshot], Boolean, Boolean, System.DateTime, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet], Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Text.Range,System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Int64])
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean IsIncompleteTypeCheckEnvironment
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean UseScriptResolutionRules
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_IsIncompleteTypeCheckEnvironment()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Boolean get_UseScriptResolutionRules()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] ReferencedProjects
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey] get_ReferencedProjects()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] OtherOptions
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_OtherOptions()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] SourceFiles
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] get_SourceFiles()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ProjectFileName
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String ToString()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.String get_ProjectFileName()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] LastFile
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: System.Tuple`2[System.String,System.String] get_LastFile()
-FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.FSharpProjectSnapshotKey], Boolean, Boolean)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: Boolean Equals(System.Object)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFSharp(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions)
FSharp.Compiler.CodeAnalysis.FSharpReferencedProject: FSharp.Compiler.CodeAnalysis.FSharpReferencedProject CreateFromILModuleReader(System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader])
@@ -2309,35 +2281,6 @@ FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Boolean Equals(Syste
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode()
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.CodeAnalysis.FSharpUnresolvedReferencesSet: System.String ToString()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey NewFrameworkImportsCacheKey(Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.Decimal)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 CompareTo(System.Object, System.Collections.IComparer)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 GetHashCode(System.Collections.IEqualityComparer)
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 Tag
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Int32 get_Tag()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_resolvedpath()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_targetFrameworkDirectories()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] resolvedpath
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: Microsoft.FSharp.Collections.FSharpList`1[System.String] targetFrameworkDirectories
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal get_langVersion()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.Decimal langVersion
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String ToString()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String assemblyName
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String fsharpBinaries
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_assemblyName()
-FSharp.Compiler.CodeAnalysis.FrameworkImportsCacheKey: System.String get_fsharpBinaries()
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForChecking3(System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,System.Int64,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSameForParsing[a](System.Tuple`3[System.String,System.Int64,a], System.Tuple`3[System.String,System.Int64,a])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSimilarForParsing[a,b,c,d,e](System.Tuple`3[a,b,c], System.Tuple`3[a,d,e])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable2(System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`2[System.String,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean AreSubsumable3[a,b](System.Tuple`3[System.String,a,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions], System.Tuple`3[System.String,b,FSharp.Compiler.CodeAnalysis.FSharpProjectOptions])
-FSharp.Compiler.CodeAnalysis.Helpers: Boolean NamesContainAttribute(FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Collections.FSharpSet`1[System.String])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: FSharp.Compiler.CodeAnalysis.LegacyResolvedFile[] Resolve(FSharp.Compiler.CodeAnalysis.LegacyResolutionEnvironment, System.Tuple`2[System.String,System.String][], System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, System.String, Microsoft.FSharp.Collections.FSharpList`1[System.String], System.String, Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.FSharpFunc`2[System.Boolean,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.FSharpFunc`2[System.String,Microsoft.FSharp.Core.Unit]]])
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String DotNetFrameworkReferenceAssembliesRootDirectory
FSharp.Compiler.CodeAnalysis.ILegacyReferenceResolver: System.String HighestInstalledNetFrameworkVersion()
From b0758ed8d6260182848de78c65d1d8c9aa833fd3 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 19 May 2023 18:42:53 +0200
Subject: [PATCH 042/222] benchmark
---
src/Compiler/Service/TransparentCompiler.fs | 34 ++++--
.../ProjectGeneration.fs | 28 +++--
.../BackgroundCompilerBenchmarks.fs | 112 ++++++++++++++++++
3 files changed, 149 insertions(+), 25 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 51be01b1d73..5f32e4325cf 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -690,10 +690,30 @@ type internal TransparentCompiler
|> fst
|> Graph.subGraphFor (sourceFiles |> Array.last).Idx
+
let fileIndexes =
graph.Values |> Seq.collect id |> Seq.append graph.Keys |> Seq.distinct |> Set
- return TransformDependencyGraph(graph, filePairs), fileIndexes
+ let nodeGraph = TransformDependencyGraph(graph, filePairs)
+
+ let fileNames =
+ parsedInputs
+ |> Seq.mapi (fun idx input -> idx, Path.GetFileName input.FileName)
+ |> Map.ofSeq
+
+ let debugGraph =
+ nodeGraph
+ |> Graph.map (function
+ | NodeToTypeCheck.PhysicalFile i -> i, fileNames[i]
+ | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
+ |> Graph.serialiseToMermaid
+
+ Trace.TraceInformation("\n" + debugGraph)
+
+ if Activity.Current <> null then
+ Activity.Current.AddTag("graph", debugGraph) |> ignore
+
+ return nodeGraph, fileIndexes
}
)
@@ -815,18 +835,6 @@ type internal TransparentCompiler
let! graph, dependencyFiles = ComputeDependencyGraph priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
- let fileNames =
- parsedInputs
- |> Seq.mapi (fun idx (input, _, _) -> idx, Path.GetFileName input.FileName)
- |> Map.ofSeq
-
- let debugGraph =
- graph
- |> Graph.map (function
- | NodeToTypeCheck.PhysicalFile i -> i, fileNames[i]
- | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
-
- Trace.TraceInformation("\n" + (debugGraph |> Graph.serialiseToMermaid))
// layers that can be processed in parallel
let layers = Graph.leafSequence graph |> Seq.toList
diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
index 6861c256a26..0a001ec3b88 100644
--- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs
+++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs
@@ -616,12 +616,13 @@ type ProjectWorkflowBuilder
?useGetSource,
?useChangeNotifications,
?useSyntaxTreeCache,
- ?useTransparentCompiler
+ ?useTransparentCompiler,
+ ?runTimeout
) =
- let useGetSource = defaultArg useGetSource false
- let useChangeNotifications = defaultArg useChangeNotifications false
let useTransparentCompiler = defaultArg useTransparentCompiler false
+ let useGetSource = not useTransparentCompiler && defaultArg useGetSource false
+ let useChangeNotifications = not useTransparentCompiler && defaultArg useChangeNotifications false
let mutable latestProject = initialProject
let mutable activity = None
@@ -652,26 +653,29 @@ type ProjectWorkflowBuilder
let mapProject f = mapProjectAsync (f >> async.Return)
+ let getInitialContext() =
+ match initialContext with
+ | Some ctx -> async.Return ctx
+ | None -> SaveAndCheckProject initialProject checker
+
/// Creates a ProjectWorkflowBuilder which will already have the project
/// saved and checked so time won't be spent on that.
/// Also the project won't be deleted after the computation expression is evaluated
member this.CreateBenchmarkBuilder() =
- let ctx = this.Yield() |> Async.RunSynchronously
+ let ctx = getInitialContext() |> Async.RunSynchronously
ProjectWorkflowBuilder(
ctx.Project,
ctx,
useGetSource = useGetSource,
- useChangeNotifications = useChangeNotifications
- )
+ useChangeNotifications = useChangeNotifications,
+ useTransparentCompiler = useTransparentCompiler,
+ ?runTimeout = runTimeout)
member this.Checker = checker
member this.Yield _ = async {
- let! ctx =
- match initialContext with
- | Some ctx -> async.Return ctx
- | _ -> SaveAndCheckProject initialProject checker
+ let! ctx = getInitialContext()
tracerProvider <-
Sdk.CreateTracerProviderBuilder()
.AddSource("fsc")
@@ -679,7 +683,7 @@ type ProjectWorkflowBuilder
.AddJaegerExporter()
.Build()
|> Some
- activity <- Activity.start ctx.Project.Name [ Activity.Tags.project, ctx.Project.Name ] |> Some
+ activity <- Activity.start ctx.Project.Name [ Activity.Tags.project, ctx.Project.Name; "UsingTransparentCompiler", useTransparentCompiler.ToString() ] |> Some
return ctx
}
@@ -689,7 +693,7 @@ type ProjectWorkflowBuilder
member this.Run(workflow: Async) =
try
- Async.RunSynchronously workflow
+ Async.RunSynchronously(workflow, timeout = defaultArg runTimeout 60_000)
finally
if initialContext.IsNone then
this.DeleteProjectDir()
diff --git a/tests/benchmarks/FCSBenchmarks/CompilerServiceBenchmarks/BackgroundCompilerBenchmarks.fs b/tests/benchmarks/FCSBenchmarks/CompilerServiceBenchmarks/BackgroundCompilerBenchmarks.fs
index 3b44c1d37bf..b555ac27508 100644
--- a/tests/benchmarks/FCSBenchmarks/CompilerServiceBenchmarks/BackgroundCompilerBenchmarks.fs
+++ b/tests/benchmarks/FCSBenchmarks/CompilerServiceBenchmarks/BackgroundCompilerBenchmarks.fs
@@ -6,6 +6,7 @@ open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Text
open FSharp.Compiler.Diagnostics
open FSharp.Test.ProjectGeneration
+open BenchmarkDotNet.Engines
[]
@@ -221,3 +222,114 @@ type NoFileSystemCheckerBenchmark() =
[]
member this.Cleanup() =
benchmark.DeleteProjectDir()
+
+
+
+type TestProjectType =
+ | DependencyChain = 1
+ | DependentGroups = 2
+ | ParallelGroups = 3
+
+
+[]
+[]
+[]
+[]
+type TransparentCompilerBenchmark() =
+
+ let size = 30
+
+ let groups = 6
+ let filesPerGroup = size / groups
+ let somethingToCompile = File.ReadAllText (__SOURCE_DIRECTORY__ ++ "SomethingToCompileSmaller.fs")
+
+ let projects = Map [
+
+ TestProjectType.DependencyChain,
+ SyntheticProject.Create("SingleDependencyChain", [|
+ sourceFile $"File%03d{0}" []
+ for i in 1..size do
+ { sourceFile $"File%03d{i}" [$"File%03d{i-1}"] with ExtraSource = somethingToCompile }
+ |])
+
+ TestProjectType.DependentGroups,
+ SyntheticProject.Create("GroupDependenciesProject", [|
+ for group in 1..groups do
+ for i in 1..filesPerGroup do
+ { sourceFile $"G{group}_F%03d{i}" [
+ if group > 1 then $"G1_F%03d{1}"
+ if i > 1 then $"G{group}_F%03d{i - 1}" ]
+ with ExtraSource = somethingToCompile }
+ |])
+
+ TestProjectType.ParallelGroups,
+ SyntheticProject.Create("ParallelGroupsProject", [|
+ for group in 1..groups do
+ for i in 1..filesPerGroup do
+ { sourceFile $"G{group}_F%03d{i}" [
+ if group > 1 then
+ for i in 1..filesPerGroup do
+ $"G{group-1}_F%03d{i}" ]
+ with ExtraSource = somethingToCompile }
+ |])
+ ]
+
+ let mutable benchmark : ProjectWorkflowBuilder = Unchecked.defaultof<_>
+
+ member val UseGetSource = true with get,set
+
+ member val UseChangeNotifications = true with get,set
+
+ //[]
+ member val EmptyCache = false with get,set
+
+ []
+ member val UseTransparentCompiler = true with get,set
+
+ []
+ member val ProjectType = TestProjectType.ParallelGroups with get,set
+
+ member this.Project = projects[this.ProjectType]
+
+ []
+ member this.Setup() =
+ benchmark <-
+ ProjectWorkflowBuilder(
+ this.Project,
+ useGetSource = this.UseGetSource,
+ useChangeNotifications = this.UseChangeNotifications,
+ useTransparentCompiler = this.UseTransparentCompiler,
+ runTimeout = 15_000).CreateBenchmarkBuilder()
+
+ []
+ member this.EditFirstFile_OnlyInternalChange() =
+ if this.EmptyCache then
+ benchmark.Checker.InvalidateAll()
+ benchmark.Checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
+
+ []
+ member this.ExampleWorkflow() =
+
+ use _ = Activity.start "Benchmark" [
+ "UseTransparentCompiler", this.UseTransparentCompiler.ToString()
+ ]
+
+ let first = this.Project.SourceFiles[0].Id
+ let middle = this.Project.SourceFiles[size / 2].Id
+ let last = this.Project.SourceFiles |> List.last |> fun f -> f.Id
+
+ benchmark {
+ updateFile first updatePublicSurface
+ checkFile first expectSignatureChanged
+ checkFile last expectSignatureChanged
+ updateFile middle updatePublicSurface
+ checkFile last expectOk
+ addFileAbove middle (sourceFile "addedFile" [first])
+ updateFile middle (addDependency "addedFile")
+ checkFile middle expectSignatureChanged
+ checkFile last expectOk
+ }
+
+ []
+ member this.Cleanup() =
+ benchmark.DeleteProjectDir()
From 22b1c9bee775a9bfa3e37015d776561de14aeab2 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Fri, 19 May 2023 19:36:02 +0200
Subject: [PATCH 043/222] f
---
src/Compiler/Service/TransparentCompiler.fs | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 5f32e4325cf..bab6a5a7c7b 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -690,7 +690,6 @@ type internal TransparentCompiler
|> fst
|> Graph.subGraphFor (sourceFiles |> Array.last).Idx
-
let fileIndexes =
graph.Values |> Seq.collect id |> Seq.append graph.Keys |> Seq.distinct |> Set
@@ -835,7 +834,6 @@ type internal TransparentCompiler
let! graph, dependencyFiles = ComputeDependencyGraph priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
-
// layers that can be processed in parallel
let layers = Graph.leafSequence graph |> Seq.toList
From 68df1f6c298ebf5ea3036f2761e3050b889604da Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Mon, 5 Jun 2023 15:44:45 +0200
Subject: [PATCH 044/222] in memory project references
---
src/Compiler/Driver/GraphChecking/Graph.fs | 3 +
src/Compiler/Driver/GraphChecking/Graph.fsi | 2 +
src/Compiler/Service/BackgroundCompiler.fs | 6 +
src/Compiler/Service/FSharpCheckerResults.fs | 1 +
src/Compiler/Service/IncrementalBuild.fs | 1 +
src/Compiler/Service/IncrementalBuild.fsi | 13 +
src/Compiler/Service/TransparentCompiler.fs | 500 ++++++++++++------
.../FSharpChecker/TransparentCompiler.fs | 52 +-
8 files changed, 415 insertions(+), 163 deletions(-)
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fs b/src/Compiler/Driver/GraphChecking/Graph.fs
index 9cbce0b4b9b..41e1ae4a47e 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fs
+++ b/src/Compiler/Driver/GraphChecking/Graph.fs
@@ -27,6 +27,9 @@ module internal Graph =
|> Array.map (fun (KeyValue (k, v)) -> k, v)
|> readOnlyDict
+ let nodes (graph: Graph<'Node>) : Set<'Node> =
+ graph.Values |> Seq.collect id |> Seq.append graph.Keys |> Seq.distinct |> Set
+
/// Find transitive dependencies of a single node.
let transitiveDeps (node: 'Node) (graph: Graph<'Node>) =
let visited = HashSet<'Node>()
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fsi b/src/Compiler/Driver/GraphChecking/Graph.fsi
index 7d885f5c96a..f92a2a58468 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fsi
+++ b/src/Compiler/Driver/GraphChecking/Graph.fsi
@@ -10,6 +10,8 @@ module internal Graph =
/// Build the graph.
val make: nodeDeps: seq<'Node * 'Node array> -> Graph<'Node> when 'Node: equality
val map<'T, 'U when 'U: equality> : f: ('T -> 'U) -> graph: Graph<'T> -> Graph<'U>
+ /// Get all nodes of the graph.
+ val nodes: graph: Graph<'Node> -> Set<'Node>
/// Create a transitive closure of the graph in O(n^2) time (but parallelize it).
/// The resulting graph contains edge A -> C iff the input graph contains a (directed) non-zero length path from A to C.
val transitive<'Node when 'Node: equality> : graph: Graph<'Node> -> Graph<'Node>
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index baad181612a..4de5d8f7972 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -87,6 +87,9 @@ type internal IBackgroundCompiler =
abstract member GetAssemblyData:
options: FSharpProjectOptions * userOpName: string -> NodeCode
+ abstract member GetAssemblyData:
+ projectSnapshot: FSharpProjectSnapshot * userOpName: string -> NodeCode
+
/// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API)
abstract member GetBackgroundCheckResultsForFileInProject:
fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode
@@ -1490,6 +1493,9 @@ type internal BackgroundCompiler
member _.GetAssemblyData(options: FSharpProjectOptions, userOpName: string) : NodeCode =
self.GetAssemblyData(options, userOpName)
+ member _.GetAssemblyData(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : NodeCode =
+ self.GetAssemblyData(projectSnapshot.ToOptions(), userOpName)
+
member _.GetBackgroundCheckResultsForFileInProject
(
fileName: string,
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 408e758427c..5e43544cfe5 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -59,6 +59,7 @@ open Internal.Utilities
open Internal.Utilities.Collections
open FSharp.Compiler.AbstractIL.ILBinaryReader
open System.Threading.Tasks
+open System.Runtime.CompilerServices
type FSharpUnresolvedReferencesSet = FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list
diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs
index 5403a37b86b..bee2e5df0ec 100644
--- a/src/Compiler/Service/IncrementalBuild.fs
+++ b/src/Compiler/Service/IncrementalBuild.fs
@@ -578,6 +578,7 @@ module Utilities =
/// Constructs the build data (IRawFSharpAssemblyData) representing the assembly when used
/// as a cross-assembly reference. Note the assembly has not been generated on disk, so this is
/// a virtualized view of the assembly contents as computed by background checking.
+[]
type RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, generatedCcu: CcuThunk, outfile, topAttrs, assemblyName, ilAssemRef) =
let exportRemapping = MakeExportRemapping generatedCcu generatedCcu.Contents
diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi
index 50c7201195c..d4fe402cce1 100644
--- a/src/Compiler/Service/IncrementalBuild.fsi
+++ b/src/Compiler/Service/IncrementalBuild.fsi
@@ -140,6 +140,19 @@ type internal PartialCheckResults =
member TimeStamp: DateTime
+[]
+type internal RawFSharpAssemblyDataBackedByLanguageService =
+ new:
+ tcConfig: TcConfig *
+ tcGlobals: TcGlobals *
+ generatedCcu: CcuThunk *
+ outfile: string *
+ topAttrs: TopAttribs *
+ assemblyName: string *
+ ilAssemRef: FSharp.Compiler.AbstractIL.IL.ILAssemblyRef ->
+ RawFSharpAssemblyDataBackedByLanguageService
+ interface IRawFSharpAssemblyData
+
/// Manages an incremental build graph for the build of an F# project
[]
type internal IncrementalBuilder =
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 237c32027df..97b264ad663 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -2,6 +2,7 @@ namespace FSharp.Compiler.CodeAnalysis.TransparentCompiler
open System
open System.Collections.Generic
+open System.Runtime.CompilerServices
open System.Diagnostics
open System.IO
@@ -37,6 +38,8 @@ open FSharp.Compiler.TypedTree
open FSharp.Compiler.CheckDeclarations
open FSharp.Compiler.EditorServices
open FSharp.Compiler.CodeAnalysis
+open FSharp.Compiler.CreateILModule
+open FSharp.Compiler.TypedTreeOps
type internal FSharpFile =
{
@@ -49,6 +52,8 @@ type internal FSharpFile =
/// Things we need to start parsing and checking files for a given project snapshot
type internal BootstrapInfo =
{
+ AssemblyName: string
+ OutFile: string
TcConfig: TcConfig
TcImports: TcImports
TcGlobals: TcGlobals
@@ -86,6 +91,19 @@ type internal TcIntermediate =
sink: TcResultsSinkImpl
}
+[]
+type internal DependencyGraphType =
+ /// A dependency graph for a single file - it will be missing files which this file does not depend on
+ | File
+ /// A dependency graph for a project - it will contain all files in the project
+ | Project
+
+[]
+type internal Extensions =
+ []
+ static member Key(fileSnapshots: FSharpFileSnapshot list) =
+ fileSnapshots |> List.map (fun f -> f.Key)
+
type internal TransparentCompiler
(
legacyReferenceResolver,
@@ -102,7 +120,7 @@ type internal TransparentCompiler
getSource: (string -> Async) option,
useChangeNotifications,
useSyntaxTreeCache
- ) =
+ ) as self =
// Is having just one of these ok?
let lexResourceManager = Lexhelp.LexResourceManager()
@@ -115,6 +133,9 @@ type internal TransparentCompiler
let ParseAndCheckFileInProjectCache =
AsyncMemoize(triggerCacheEvent "ParseAndCheckFileInProject")
+ let ParseAndCheckFullProjectCache =
+ AsyncMemoize(triggerCacheEvent "ParseAndCheckFullProject")
+
let FrameworkImportsCache = AsyncMemoize(triggerCacheEvent "FrameworkImports")
let BootstrapInfoStaticCache = AsyncMemoize(triggerCacheEvent "BootstrapInfoStatic")
let BootstrapInfoCache = AsyncMemoize(triggerCacheEvent "BootstrapInfo")
@@ -123,6 +144,8 @@ type internal TransparentCompiler
let DependencyGraphCache = AsyncMemoize(triggerCacheEvent "DependencyGraph")
+ let AssemblyDataCache = AsyncMemoize(triggerCacheEvent "AssemblyData")
+
let SemanticClassificationCache =
AsyncMemoize(triggerCacheEvent "SemanticClassification")
@@ -156,44 +179,6 @@ type internal TransparentCompiler
)
:> IBackgroundCompiler
- let getProjectReferences (project: FSharpProjectSnapshot) userOpName =
- [
- for r in project.ReferencedProjects do
-
- match r with
- | FSharpReferencedProjectSnapshot.FSharpReference (nm, opts) ->
- // Don't use cross-project references for FSharp.Core, since various bits of code
- // require a concrete FSharp.Core to exist on-disk. The only solutions that have
- // these cross-project references to FSharp.Core are VisualFSharp.sln and FSharp.sln. The ramification
- // of this is that you need to build FSharp.Core to get intellisense in those projects.
-
- if
- (try
- Path.GetFileNameWithoutExtension(nm)
- with _ ->
- "")
- <> GetFSharpCoreLibraryName()
- then
- { new IProjectReference with
- member x.EvaluateRawContents() =
- node {
- Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm)
-
- return!
- backgroundCompiler.GetAssemblyData(
- opts.ToOptions(),
- userOpName + ".CheckReferencedProject(" + nm + ")"
- )
- }
-
- member x.TryGetLogicalTimeStamp(cache) =
- // TODO:
- None
-
- member x.FileName = nm
- }
- ]
-
let ComputeFrameworkImports (tcConfig: TcConfig) frameworkDLLs nonFrameworkResolutions =
let frameworkDLLsKey =
frameworkDLLs
@@ -322,6 +307,40 @@ type internal TransparentCompiler
return tcImports, tcInfo
}
+ let getProjectReferences (project: FSharpProjectSnapshot) userOpName =
+ [
+ for r in project.ReferencedProjects do
+
+ match r with
+ | FSharpReferencedProjectSnapshot.FSharpReference (nm, opts) ->
+ // Don't use cross-project references for FSharp.Core, since various bits of code
+ // require a concrete FSharp.Core to exist on-disk. The only solutions that have
+ // these cross-project references to FSharp.Core are VisualFSharp.sln and FSharp.sln. The ramification
+ // of this is that you need to build FSharp.Core to get intellisense in those projects.
+
+ if
+ (try
+ Path.GetFileNameWithoutExtension(nm)
+ with _ ->
+ "")
+ <> GetFSharpCoreLibraryName()
+ then
+ { new IProjectReference with
+ member x.EvaluateRawContents() =
+ node {
+ Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm)
+
+ return! self.GetAssemblyData(opts, userOpName + ".CheckReferencedProject(" + nm + ")")
+ }
+
+ member x.TryGetLogicalTimeStamp(cache) =
+ // TODO:
+ None
+
+ member x.FileName = nm
+ }
+ ]
+
/// Bootstrap info that does not depend on contents of the files
let ComputeBootstrapInfoStatic (projectSnapshot: FSharpProjectSnapshot) =
@@ -457,7 +476,7 @@ type internal TransparentCompiler
setupConfigFromLoadClosure ()
let tcConfig = TcConfig.Create(tcConfigB, validate = true)
- let _outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
+ let outfile, _, assemblyName = tcConfigB.DecideNames sourceFiles
// Resolve assemblies and create the framework TcImports. This caches a level of "system" references. No type providers are
// included in these references.
@@ -548,14 +567,30 @@ type internal TransparentCompiler
importsInvalidatedByTypeProvider
)
- return sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, importsInvalidatedByTypeProvider
+ return
+ assemblyName,
+ outfile,
+ sourceFiles,
+ tcConfig,
+ tcImports,
+ tcGlobals,
+ initialTcInfo,
+ loadClosureOpt,
+ importsInvalidatedByTypeProvider
}
)
let computeBootstrapInfoInner (projectSnapshot: FSharpProjectSnapshot) =
node {
- let! sourceFiles, tcConfig, tcImports, tcGlobals, initialTcInfo, loadClosureOpt, _importsInvalidatedByTypeProvider =
- ComputeBootstrapInfoStatic projectSnapshot
+ let! assemblyName,
+ outFile,
+ sourceFiles,
+ tcConfig,
+ tcImports,
+ tcGlobals,
+ initialTcInfo,
+ loadClosureOpt,
+ _importsInvalidatedByTypeProvider = ComputeBootstrapInfoStatic projectSnapshot
let fileSnapshots = Map [ for f in projectSnapshot.SourceFiles -> f.FileName, f ]
@@ -582,6 +617,8 @@ type internal TransparentCompiler
return
Some
{
+ AssemblyName = assemblyName
+ OutFile = outFile
TcConfig = tcConfig
TcImports = tcImports
TcGlobals = tcGlobals
@@ -667,71 +704,73 @@ type internal TransparentCompiler
}
)
- let ComputeDependencyGraph (priorSnapshot: FSharpProjectSnapshot) parsedInputs (tcConfig: TcConfig) =
- let key = priorSnapshot.SourceFiles |> List.map (fun s -> s.Key)
-
- DependencyGraphCache.Get(
- key,
- node {
+ let computeDependencyGraph parsedInputs (tcConfig: TcConfig) (processGraph: Graph -> Graph) =
+ node {
+ let sourceFiles: FileInProject array =
+ parsedInputs
+ |> Seq.toArray
+ |> Array.mapi (fun idx (input: ParsedInput) ->
+ {
+ Idx = idx
+ FileName = input.FileName
+ ParsedInput = input
+ })
- let sourceFiles: FileInProject array =
- parsedInputs
- |> Seq.toArray
- |> Array.mapi (fun idx (input: ParsedInput) ->
- {
- Idx = idx
- FileName = input.FileName
- ParsedInput = input
- })
+ use _ =
+ Activity.start "ComputeDependencyGraph" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
- use _ =
- Activity.start "ComputeDependencyGraph" [| Activity.Tags.fileName, (sourceFiles |> Array.last).FileName |]
+ let filePairs = FilePairMap(sourceFiles)
- let filePairs = FilePairMap(sourceFiles)
+ // TODO: we will probably want to cache and re-use larger graphs if available
+ let graph =
+ DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
+ |> fst
+ |> processGraph
- // TODO: we will probably want to cache and re-use larger graphs if available
- let graph =
- DependencyResolution.mkGraph tcConfig.compilingFSharpCore filePairs sourceFiles
- |> fst
- |> Graph.subGraphFor (sourceFiles |> Array.last).Idx
+ let nodeGraph = TransformDependencyGraph(graph, filePairs)
- let fileIndexes =
- graph.Values |> Seq.collect id |> Seq.append graph.Keys |> Seq.distinct |> Set
+ let fileNames =
+ parsedInputs
+ |> Seq.mapi (fun idx input -> idx, Path.GetFileName input.FileName)
+ |> Map.ofSeq
- let nodeGraph = TransformDependencyGraph(graph, filePairs)
+ let debugGraph =
+ nodeGraph
+ |> Graph.map (function
+ | NodeToTypeCheck.PhysicalFile i -> i, fileNames[i]
+ | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
+ |> Graph.serialiseToMermaid
- let fileNames =
- parsedInputs
- |> Seq.mapi (fun idx input -> idx, Path.GetFileName input.FileName)
- |> Map.ofSeq
+ Trace.TraceInformation("\n" + debugGraph)
- let debugGraph =
- nodeGraph
- |> Graph.map (function
- | NodeToTypeCheck.PhysicalFile i -> i, fileNames[i]
- | NodeToTypeCheck.ArtificialImplFile i -> -(i + 1), $"AIF : {fileNames[i]}")
- |> Graph.serialiseToMermaid
+ if Activity.Current <> null then
+ Activity.Current.AddTag("graph", debugGraph) |> ignore
- Trace.TraceInformation("\n" + debugGraph)
+ return nodeGraph, graph
+ }
- if Activity.Current <> null then
- Activity.Current.AddTag("graph", debugGraph) |> ignore
+ let ComputeDependencyGraphForFile (priorSnapshot: FSharpProjectSnapshot) parsedInputs (tcConfig: TcConfig) =
+ let key = priorSnapshot.SourceFiles.Key(), DependencyGraphType.File
+ let lastFileIndex = (parsedInputs |> Array.length) - 1
+ DependencyGraphCache.Get(key, computeDependencyGraph parsedInputs tcConfig (Graph.subGraphFor lastFileIndex))
- return nodeGraph, fileIndexes
- }
- )
+ let ComputeDependencyGraphForProject (projectSnapshot: FSharpProjectSnapshot) parsedInputs (tcConfig: TcConfig) =
+ let key = projectSnapshot.SourceFiles.Key(), DependencyGraphType.Project
+ DependencyGraphCache.Get(key, computeDependencyGraph parsedInputs tcConfig id)
let ComputeTcIntermediate
(projectSnapshot: FSharpProjectSnapshot)
- (dependencyFiles: Set)
+ (dependencyGraph: Graph)
(fileIndex: FileIndex)
(parsedInput: ParsedInput, parseErrors)
bootstrapInfo
(prevTcInfo: TcInfo)
=
+ let dependencyFiles = dependencyGraph |> Graph.subGraphFor fileIndex |> Graph.nodes
+
TcIntermediateCache.Get(
- projectSnapshot.UpTo(fileIndex).OnlyWith(dependencyFiles).Key,
+ projectSnapshot.OnlyWith(dependencyFiles).Key,
node {
let input = parsedInput
let fileName = input.FileName
@@ -797,24 +836,79 @@ type internal TransparentCompiler
)
let mergeIntermediateResults =
- Array.fold (fun (tcInfo: TcInfo) (tcIntermediate: TcIntermediate) ->
- let (tcEnv, topAttribs, _checkImplFileOpt, ccuSigForFile), tcState =
- tcInfo.tcState |> tcIntermediate.finisher.Invoke
-
- let tcEnvAtEndOfFile =
- if keepAllBackgroundResolutions then
- tcEnv
- else
- tcState.TcEnvFromImpls
-
- { tcInfo with
- tcState = tcState
- tcEnvAtEndOfFile = tcEnvAtEndOfFile
- topAttribs = Some topAttribs
- tcDiagnosticsRev = tcIntermediate.tcDiagnosticsRev @ tcInfo.tcDiagnosticsRev
- tcDependencyFiles = tcIntermediate.tcDependencyFiles @ tcInfo.tcDependencyFiles
- latestCcuSigForFile = Some ccuSigForFile
- })
+ Array.fold (fun (tcInfos: TcInfo list) (tcIntermediate: TcIntermediate) ->
+ match tcInfos with
+ | [] -> failwith "need initial tcInfo"
+ | tcInfo :: rest ->
+ let (tcEnv, topAttribs, _checkImplFileOpt, ccuSigForFile), tcState =
+ tcInfo.tcState |> tcIntermediate.finisher.Invoke
+
+ let tcEnvAtEndOfFile =
+ if keepAllBackgroundResolutions then
+ tcEnv
+ else
+ tcState.TcEnvFromImpls
+
+ { tcInfo with
+ tcState = tcState
+ tcEnvAtEndOfFile = tcEnvAtEndOfFile
+ topAttribs = Some topAttribs
+ tcDiagnosticsRev = tcIntermediate.tcDiagnosticsRev @ tcInfo.tcDiagnosticsRev
+ tcDependencyFiles = tcIntermediate.tcDependencyFiles @ tcInfo.tcDependencyFiles
+ latestCcuSigForFile = Some ccuSigForFile
+ }
+ :: tcInfo :: rest)
+
+ let typeCheckLayers bootstrapInfo projectSnapshot (parsedInputs: array<_>) graph layers =
+ let rec processLayer (layers: Set list) tcInfos =
+ node {
+ match layers, tcInfos with
+ | [], _ -> return tcInfos
+ | _, [] -> return failwith "need initial tcInfo"
+ | layer :: rest, tcInfo :: _ ->
+ let! results =
+ layer
+ |> Seq.map (fun fileNode ->
+
+ match fileNode with
+ | NodeToTypeCheck.PhysicalFile fileIndex ->
+ let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
+
+ ComputeTcIntermediate projectSnapshot graph fileIndex (parsedInput, parseErrors) bootstrapInfo tcInfo
+ | NodeToTypeCheck.ArtificialImplFile fileIndex ->
+
+ let finisher tcState =
+ let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
+ let prefixPathOpt = None
+ // Retrieve the type-checked signature information and add it to the TcEnvFromImpls.
+ AddSignatureResultToTcImplEnv
+ (bootstrapInfo.TcImports,
+ bootstrapInfo.TcGlobals,
+ prefixPathOpt,
+ TcResultsSink.NoSink,
+ tcState,
+ parsedInput)
+ tcState
+
+ let tcIntermediate =
+ {
+ finisher = finisher
+ moduleNamesDict = tcInfo.moduleNamesDict
+ tcDiagnosticsRev = []
+ tcDependencyFiles = []
+ sink = Unchecked.defaultof<_> // TODO: something nicer
+ }
+
+ node.Return(tcIntermediate))
+ |> NodeCode.Parallel
+
+ return! processLayer rest (mergeIntermediateResults tcInfos results)
+ }
+
+ node {
+ let! tcInfo = processLayer layers [ bootstrapInfo.InitialTcInfo ]
+ return tcInfo, graph
+ }
// Type check everything that is needed to check given file
let ComputeTcPrior (file: FSharpFile) (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) =
@@ -837,7 +931,8 @@ type internal TransparentCompiler
let! parsedInputs = files |> Seq.map (ComputeParseFile bootstrapInfo) |> NodeCode.Parallel
- let! graph, dependencyFiles = ComputeDependencyGraph priorSnapshot (parsedInputs |> Seq.map p13) bootstrapInfo.TcConfig
+ let! graph, dependencyFiles =
+ ComputeDependencyGraphForFile priorSnapshot (parsedInputs |> Array.map p13) bootstrapInfo.TcConfig
// layers that can be processed in parallel
let layers = Graph.leafSequence graph |> Seq.toList
@@ -845,58 +940,9 @@ type internal TransparentCompiler
// remove the final layer, which should be the target file
let layers = layers |> List.take (layers.Length - 1)
- let rec processLayer (layers: Set list) tcInfo =
- node {
- match layers with
- | [] -> return tcInfo
- | layer :: rest ->
- let! results =
- layer
- |> Seq.map (fun fileNode ->
-
- match fileNode with
- | NodeToTypeCheck.PhysicalFile fileIndex ->
- let parsedInput, parseErrors, _ = parsedInputs[fileIndex]
-
- ComputeTcIntermediate
- projectSnapshot
- dependencyFiles
- fileIndex
- (parsedInput, parseErrors)
- bootstrapInfo
- tcInfo
- | NodeToTypeCheck.ArtificialImplFile fileIndex ->
-
- let finisher tcState =
- let parsedInput, _parseErrors, _ = parsedInputs[fileIndex]
- let prefixPathOpt = None
- // Retrieve the type-checked signature information and add it to the TcEnvFromImpls.
- AddSignatureResultToTcImplEnv
- (bootstrapInfo.TcImports,
- bootstrapInfo.TcGlobals,
- prefixPathOpt,
- TcResultsSink.NoSink,
- tcState,
- parsedInput)
- tcState
-
- let tcIntermediate =
- {
- finisher = finisher
- moduleNamesDict = tcInfo.moduleNamesDict
- tcDiagnosticsRev = []
- tcDependencyFiles = []
- sink = Unchecked.defaultof<_>
- }
-
- node.Return(tcIntermediate))
- |> NodeCode.Parallel
-
- return! processLayer rest (mergeIntermediateResults tcInfo results)
- }
+ let! tcInfos, graph = typeCheckLayers bootstrapInfo priorSnapshot parsedInputs dependencyFiles layers
- let! tcInfo = processLayer layers bootstrapInfo.InitialTcInfo
- return tcInfo, dependencyFiles
+ return tcInfos.Head, graph
}
)
@@ -981,24 +1027,46 @@ type internal TransparentCompiler
}
)
+ let ComputeParseAndCheckFullProject (bootstrapInfo: BootstrapInfo) (projectSnapshot: FSharpProjectSnapshot) =
+ ParseAndCheckFullProjectCache.Get(
+ projectSnapshot.Key,
+ node {
+ use _ =
+ Activity.start
+ "ComputeParseAndCheckFullProject"
+ [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |]
+
+ let! parsedInputs =
+ bootstrapInfo.SourceFiles
+ |> Seq.map (ComputeParseFile bootstrapInfo)
+ |> NodeCode.Parallel
+
+ let! graph, dependencyFiles =
+ ComputeDependencyGraphForProject projectSnapshot (parsedInputs |> Array.map p13) bootstrapInfo.TcConfig
+
+ // layers that can be processed in parallel
+ let layers = Graph.leafSequence graph |> Seq.toList
+
+ let! tcInfos, _ = typeCheckLayers bootstrapInfo projectSnapshot parsedInputs dependencyFiles layers
+ return tcInfos |> List.rev
+ }
+ )
+
let tryGetSink fileName (projectSnapshot: FSharpProjectSnapshot) =
node {
- use _ =
- Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
-
match! ComputeBootstrapInfo projectSnapshot with
| None, _ -> return None
| Some bootstrapInfo, _creationDiags ->
let file = bootstrapInfo.GetFile fileName
- let! tcInfo, dependencyFiles = ComputeTcPrior file bootstrapInfo projectSnapshot
+ let! tcInfo, graph = ComputeTcPrior file bootstrapInfo projectSnapshot
let! parseTree, parseDiagnostics, _sourceText = ComputeParseFile bootstrapInfo file
let fileIndex = projectSnapshot.IndexOf fileName
let! { sink = sink } =
- ComputeTcIntermediate projectSnapshot dependencyFiles fileIndex (parseTree, parseDiagnostics) bootstrapInfo tcInfo
+ ComputeTcIntermediate projectSnapshot graph fileIndex (parseTree, parseDiagnostics) bootstrapInfo tcInfo
return Some(sink, bootstrapInfo)
}
@@ -1099,6 +1167,111 @@ type internal TransparentCompiler
| Some itemKeyStore -> return itemKeyStore.FindAll symbol.Item
}
+ member _.GetAssemblyData(projectSnapshot: FSharpProjectSnapshot, _userOpName) =
+ AssemblyDataCache.Get(
+ projectSnapshot.Key,
+ node {
+
+ match! ComputeBootstrapInfo projectSnapshot with
+ | None, _ -> return ProjectAssemblyDataResult.Unavailable true
+ | Some bootstrapInfo, _creationDiags ->
+
+ let! tcInfos = ComputeParseAndCheckFullProject bootstrapInfo projectSnapshot
+
+ let assemblyName = bootstrapInfo.AssemblyName
+ let tcConfig = bootstrapInfo.TcConfig
+ let tcGlobals = bootstrapInfo.TcGlobals
+
+ let results =
+ [
+ for tcInfo in tcInfos ->
+ tcInfo.tcEnvAtEndOfFile, defaultArg tcInfo.topAttribs EmptyTopAttrs, None, tcInfo.latestCcuSigForFile
+ ]
+
+ // Get the state at the end of the type-checking of the last file
+ let finalInfo = List.last tcInfos
+
+ // Finish the checking
+ let (_tcEnvAtEndOfLastFile, topAttrs, _mimpls, _), tcState =
+ CheckMultipleInputsFinish(results, finalInfo.tcState)
+
+ let tcState, _, ccuContents = CheckClosedInputSetFinish([], tcState)
+
+ let generatedCcu = tcState.Ccu.CloneWithFinalizedContents(ccuContents)
+
+ // Compute the identity of the generated assembly based on attributes, options etc.
+ // Some of this is duplicated from fsc.fs
+ let ilAssemRef =
+ let publicKey =
+ try
+ let signingInfo = ValidateKeySigningAttributes(tcConfig, tcGlobals, topAttrs)
+
+ match GetStrongNameSigner signingInfo with
+ | None -> None
+ | Some s -> Some(PublicKey.KeyAsToken(s.PublicKey))
+ with exn ->
+ errorRecoveryNoRange exn
+ None
+
+ let locale =
+ TryFindFSharpStringAttribute
+ tcGlobals
+ (tcGlobals.FindSysAttrib "System.Reflection.AssemblyCultureAttribute")
+ topAttrs.assemblyAttrs
+
+ let assemVerFromAttrib =
+ TryFindFSharpStringAttribute
+ tcGlobals
+ (tcGlobals.FindSysAttrib "System.Reflection.AssemblyVersionAttribute")
+ topAttrs.assemblyAttrs
+ |> Option.bind (fun v ->
+ try
+ Some(parseILVersion v)
+ with _ ->
+ None)
+
+ let ver =
+ match assemVerFromAttrib with
+ | None -> tcConfig.version.GetVersionInfo(tcConfig.implicitIncludeDir)
+ | Some v -> v
+
+ ILAssemblyRef.Create(assemblyName, None, publicKey, false, Some ver, locale)
+
+ let assemblyDataResult =
+ try
+ // Assemblies containing type provider components can not successfully be used via cross-assembly references.
+ // We return 'None' for the assembly portion of the cross-assembly reference
+ let hasTypeProviderAssemblyAttrib =
+ topAttrs.assemblyAttrs
+ |> List.exists (fun (Attrib (tcref, _, _, _, _, _, _)) ->
+ let nm = tcref.CompiledRepresentationForNamedType.BasicQualifiedName
+
+ nm = typeof
+ .FullName)
+
+ if tcState.CreatesGeneratedProvidedTypes || hasTypeProviderAssemblyAttrib then
+ ProjectAssemblyDataResult.Unavailable true
+ else
+ ProjectAssemblyDataResult.Available(
+ RawFSharpAssemblyDataBackedByLanguageService(
+ tcConfig,
+ tcGlobals,
+ generatedCcu,
+ bootstrapInfo.OutFile,
+ topAttrs,
+ assemblyName,
+ ilAssemRef
+ )
+ :> IRawFSharpAssemblyData
+ )
+ with exn ->
+ errorRecoveryNoRange exn
+ ProjectAssemblyDataResult.Unavailable true
+
+ return assemblyDataResult
+ }
+ )
+
interface IBackgroundCompiler with
member _.CacheEvent = cacheEvent.Publish
@@ -1166,6 +1339,9 @@ type internal TransparentCompiler
member _.GetAssemblyData(options: FSharpProjectOptions, userOpName: string) : NodeCode =
backgroundCompiler.GetAssemblyData(options, userOpName)
+ member this.GetAssemblyData(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : NodeCode =
+ this.GetAssemblyData(projectSnapshot, userOpName)
+
member _.GetBackgroundCheckResultsForFileInProject
(
fileName: string,
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 842dcefaf5c..4c626c89221 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -4,6 +4,7 @@ open System.Collections.Concurrent
open System.Diagnostics
open FSharp.Compiler.CodeAnalysis
open Internal.Utilities.Collections
+open FSharp.Compiler.CodeAnalysis.TransparentCompiler
open Xunit
@@ -173,9 +174,14 @@ let ``Changes in a referenced project`` () =
|> updateFile "First" (addDependency "Library")
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+
+ updateFile "First" updatePublicSurface
+ checkFile "Last" expectOk
+
updateFile "Library" updatePublicSurface
saveFile "Library"
checkFile "Last" expectSignatureChanged
+
}
[]
@@ -222,6 +228,7 @@ let ``Files that are not depended on don't invalidate cache`` () =
let cacheEvents = ResizeArray()
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ updateFile "First" updatePublicSurface
checkFile "Last" expectOk
withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
updateFile "Second" updatePublicSurface
@@ -240,7 +247,7 @@ let ``Files that are not depended on don't invalidate cache`` () =
let graphConstructions =
cacheEvents
|> Seq.choose (function
- | ("DependencyGraph", e, k) -> Some ((k :?> FSharpFileKey list) |> List.last |> fst |> Path.GetFileName, e)
+ | ("DependencyGraph", e, k) -> Some ((k :?> (FSharpFileKey list * DependencyGraphType)) |> fst |> List.last |> fst |> Path.GetFileName, e)
| _ -> None)
|> Seq.groupBy fst
|> Seq.map (fun (k, g) -> k, g |> Seq.map snd |> Seq.toList)
@@ -249,3 +256,46 @@ let ``Files that are not depended on don't invalidate cache`` () =
Assert.Equal([Started; Finished], graphConstructions["FileLast.fs"])
Assert.True intermediateTypeChecks.IsEmpty
+
+[]
+let ``Files that are not depended on don't invalidate cache part 2`` () =
+ let project = SyntheticProject.Create(
+ sourceFile "A" [],
+ sourceFile "B" ["A"],
+ sourceFile "C" ["A"],
+ sourceFile "D" ["B"; "C"],
+ sourceFile "E" ["C"])
+
+ let cacheEvents = ResizeArray()
+ let allEvents = ResizeArray()
+
+ ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
+ withChecker (fun checker -> checker.CacheEvent.Add allEvents.Add)
+ updateFile "A" updatePublicSurface
+ checkFile "D" expectOk
+ withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
+ updateFile "B" updatePublicSurface
+ checkFile "E" expectOk
+ } |> ignore
+
+ let intermediateTypeChecks =
+ cacheEvents
+ |> Seq.choose (function
+ | ("TcIntermediate", e, k) -> Some ((k :?> FSharpProjectSnapshotKey).LastFile |> fst |> Path.GetFileName, e)
+ | _ -> None)
+ |> Seq.groupBy fst
+ |> Seq.map (fun (k, g) -> k, g |> Seq.map snd |> Seq.toList)
+ |> Map
+
+ let graphConstructions =
+ cacheEvents
+ |> Seq.choose (function
+ | ("DependencyGraph", e, k) -> Some ((k :?> (FSharpFileKey list * DependencyGraphType)) |> fst |> List.last |> fst |> Path.GetFileName, e)
+ | _ -> None)
+ |> Seq.groupBy fst
+ |> Seq.map (fun (k, g) -> k, g |> Seq.map snd |> Seq.toList)
+ |> Map
+
+ Assert.Equal([Started; Finished], graphConstructions["FileE.fs"])
+
+ Assert.True intermediateTypeChecks.IsEmpty
\ No newline at end of file
From faaf9fa11ce75a2b6321d45650badd8b7111e523 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Mon, 5 Jun 2023 16:58:30 +0200
Subject: [PATCH 045/222] try deflake test
---
src/Compiler/Service/TransparentCompiler.fs | 4 ++--
.../FSharpChecker/TransparentCompiler.fs | 10 ++++++----
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 97b264ad663..d30d38a6a2f 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -312,7 +312,7 @@ type internal TransparentCompiler
for r in project.ReferencedProjects do
match r with
- | FSharpReferencedProjectSnapshot.FSharpReference (nm, opts) ->
+ | FSharpReferencedProjectSnapshot.FSharpReference (nm, projectSnapshot) ->
// Don't use cross-project references for FSharp.Core, since various bits of code
// require a concrete FSharp.Core to exist on-disk. The only solutions that have
// these cross-project references to FSharp.Core are VisualFSharp.sln and FSharp.sln. The ramification
@@ -330,7 +330,7 @@ type internal TransparentCompiler
node {
Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm)
- return! self.GetAssemblyData(opts, userOpName + ".CheckReferencedProject(" + nm + ")")
+ return! self.GetAssemblyData(projectSnapshot, userOpName + ".CheckReferencedProject(" + nm + ")")
}
member x.TryGetLogicalTimeStamp(cache) =
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 4c626c89221..4ded2fb2490 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -267,13 +267,15 @@ let ``Files that are not depended on don't invalidate cache part 2`` () =
sourceFile "E" ["C"])
let cacheEvents = ResizeArray()
- let allEvents = ResizeArray()
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
- withChecker (fun checker -> checker.CacheEvent.Add allEvents.Add)
updateFile "A" updatePublicSurface
checkFile "D" expectOk
- withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
+ withChecker (fun checker ->
+ async {
+ do! Async.Sleep 50 // wait for events from initial project check
+ checker.CacheEvent.Add cacheEvents.Add
+ })
updateFile "B" updatePublicSurface
checkFile "E" expectOk
} |> ignore
@@ -298,4 +300,4 @@ let ``Files that are not depended on don't invalidate cache part 2`` () =
Assert.Equal([Started; Finished], graphConstructions["FileE.fs"])
- Assert.True intermediateTypeChecks.IsEmpty
\ No newline at end of file
+ Assert.Equal([], intermediateTypeChecks |> Map.toList)
\ No newline at end of file
From d244d7337ad26b76e01846c9f38b31dab801dc84 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Mon, 5 Jun 2023 17:32:53 +0200
Subject: [PATCH 046/222] remove distinct
---
src/Compiler/Driver/GraphChecking/Graph.fs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Compiler/Driver/GraphChecking/Graph.fs b/src/Compiler/Driver/GraphChecking/Graph.fs
index 41e1ae4a47e..84d96422811 100644
--- a/src/Compiler/Driver/GraphChecking/Graph.fs
+++ b/src/Compiler/Driver/GraphChecking/Graph.fs
@@ -28,7 +28,7 @@ module internal Graph =
|> readOnlyDict
let nodes (graph: Graph<'Node>) : Set<'Node> =
- graph.Values |> Seq.collect id |> Seq.append graph.Keys |> Seq.distinct |> Set
+ graph.Values |> Seq.collect id |> Seq.append graph.Keys |> Set
/// Find transitive dependencies of a single node.
let transitiveDeps (node: 'Node) (graph: Graph<'Node>) =
From 26c542670f2cbca547c740e27053a3a3f2226152 Mon Sep 17 00:00:00 2001
From: 0101 <0101@innit.cz>
Date: Mon, 5 Jun 2023 17:47:48 +0200
Subject: [PATCH 047/222] try deflake test
---
.../FSharpChecker/TransparentCompiler.fs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
index 4ded2fb2490..1dc0cea36f1 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
+++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs
@@ -230,7 +230,11 @@ let ``Files that are not depended on don't invalidate cache`` () =
ProjectWorkflowBuilder(project, useTransparentCompiler = true) {
updateFile "First" updatePublicSurface
checkFile "Last" expectOk
- withChecker (fun checker -> checker.CacheEvent.Add cacheEvents.Add)
+ withChecker (fun checker ->
+ async {
+ do! Async.Sleep 50 // wait for events from initial project check
+ checker.CacheEvent.Add cacheEvents.Add
+ })
updateFile "Second" updatePublicSurface
checkFile "Last" expectOk
} |> ignore
@@ -255,7 +259,7 @@ let ``Files that are not depended on don't invalidate cache`` () =
Assert.Equal([Started; Finished], graphConstructions["FileLast.fs"])
- Assert.True intermediateTypeChecks.IsEmpty
+ Assert.Equal([], intermediateTypeChecks |> Map.toList)
[]
let ``Files that are not depended on don't invalidate cache part 2`` () =
From 9d4642283094917c6dfff37174033a9e820e27cd Mon Sep 17 00:00:00 2001
From: Petr Pokorny
Date: Thu, 8 Jun 2023 17:36:20 +0200
Subject: [PATCH 048/222] fix cache agent loop
---
src/Compiler/Facilities/AsyncMemoize.fs | 110 ++++++++++--------
src/Compiler/Service/TransparentCompiler.fs | 33 +++---
.../CompilerService/AsyncMemoize.fs | 6 +-
.../FSharp.Editor/Common/CancellableTasks.fs | 60 +++++++++-
.../src/FSharp.Editor/FSharp.Editor.resx | 1 +
.../LanguageService/LanguageService.fs | 2 +-
.../FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 1 +
.../FSharp.Editor/xlf/FSharp.Editor.de.xlf | 2 +
.../FSharp.Editor/xlf/FSharp.Editor.es.xlf | 1 +
.../FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 2 +
.../FSharp.Editor/xlf/FSharp.Editor.it.xlf | 2 +
.../FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 1 +
.../FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 2 +
.../FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 2 +
.../FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 1 +
.../FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 1 +
.../FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 2 +
.../xlf/FSharp.Editor.zh-Hans.xlf | 1 +
.../xlf/FSharp.Editor.zh-Hant.xlf | 2 +
19 files changed, 163 insertions(+), 69 deletions(-)
diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs
index 581e6201193..2b56024fbe0 100644
--- a/src/Compiler/Facilities/AsyncMemoize.fs
+++ b/src/Compiler/Facilities/AsyncMemoize.fs
@@ -1,13 +1,15 @@
namespace Internal.Utilities.Collections
-open FSharp.Compiler.BuildGraph
-open System.Threading
+open System
open System.Collections.Generic
+open System.Threading
+
+open FSharp.Compiler.BuildGraph
type internal Action<'TKey, 'TValue> =
| GetOrCompute of NodeCode<'TValue> * CancellationToken
| CancelRequest
- | JobCompleted
+ | JobCompleted of 'TValue
type MemoizeRequest<'TKey, 'TValue> = 'TKey * Action<'TKey, 'TValue> * AsyncReplyChannel>
@@ -20,12 +22,13 @@ type internal JobEventType =
| Finished
| Canceled
-type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobEventType * 'TKey -> unit)) =
+type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (string -> JobEventType * 'TKey -> unit), ?name: string) =
+ let name = defaultArg name "N/A"
let tok = obj ()
let cache =
- MruCache<_, 'TKey, Job<'TValue>>(keepStrongly = 10, areSame = (fun (x, y) -> x = y))
+ MruCache<_, 'TKey, Job<'TValue>>(keepStrongly = 30, areSame = (fun (x, y) -> x = y))
let requestCounts = Dictionary<'TKey, int>()
@@ -39,7 +42,8 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
let sendAsync (inbox: MailboxProcessor<_>) key msg =
inbox.PostAndAsyncReply(fun rc -> key, msg, rc) |> Async.Ignore |> Async.Start
- let log event = logEvent |> Option.iter ((|>) event)
+ let log event =
+ logEvent |> Option.iter (fun x -> x name event)
let agent =
MailboxProcessor.Start(fun (inbox: MailboxProcessor>) ->
@@ -48,66 +52,72 @@ type internal AsyncMemoize<'TKey, 'TValue when 'TKey: equality>(?logEvent: (JobE
async {
while true do
+ try
+ let _name = name
- let! key, action, replyChannel = inbox.Receive()
-
- match action, cache.TryGet(tok, key) with
- | GetOrCompute _, Some (Completed job) -> replyChannel.Reply job
- | GetOrCompute (_, ct), Some (Running (job, _)) ->
+ let! key, action, replyChannel = inbox.Receive()
- incrRequestCount key
- replyChannel.Reply job
- ct.Register(fun _ -> post key CancelRequest) |> ignore
+ match action, cache.TryGet(tok, key) with
+ | GetOrCompute _, Some (Completed job) -> replyChannel.Reply job
+ | GetOrCompute (_, ct), Some (Running (job, _)) ->
+ incrRequestCount key
+ replyChannel.Reply job
+ ct.Register(fun _ -> post key CancelRequest) |> ignore
- | GetOrCompute (computation, ct), None ->
+ | GetOrCompute (computation, ct), None ->
- let cts = new CancellationTokenSource()
+ let cts = new CancellationTokenSource()
- let startedComputation =
- Async.StartAsTask(
- Async.AwaitNodeCode(
- node {
- log (Started, key)
- let! result = computation
- post key JobCompleted
- return result
- }
- ),
- cancellationToken = cts.Token
- )
+ let startedComputation =
+ Async.StartAsTask(
+ Async.AwaitNodeCode(
+ node {
+ log (Started, key)
+ let! result = computation
+ post key (JobCompleted result)
+ return result
+ }
+ ),
+ cancellationToken = cts.Token
+ )
- let job = NodeCode.AwaitTask startedComputation
+ let job = NodeCode.AwaitTask startedComputation
- cache.Set(tok, key, (Running(job, cts)))
+ cache.Set(tok, key, (Running(job, cts)))
- incrRequestCount key
+ incrRequestCount key
- ct.Register(fun _ -> post key CancelRequest) |> ignore
+ ct.Register(fun _ -> post key CancelRequest) |> ignore
- replyChannel.Reply job
+ replyChannel.Reply job
- | CancelRequest, Some (Running (_, cts)) ->
- let requestCount = requestCounts.TryGetValue key |> snd
+ | CancelRequest, Some (Running (_, cts)) ->
+ let requestCount = requestCounts.TryGetValue key |> snd
- if requestCount > 1 then
- requestCounts.[key] <- requestCount - 1
+ if requestCount > 1 then
+ requestCounts.[key] <- requestCount - 1
- else
- cts.Cancel()
- cache.RemoveAnySimilar(tok, key)
- requestCounts.Remove key |> ignore
- log (Canceled, key)
+ else
+ cts.Cancel()
+ cache.RemoveAnySimilar(tok, key)
+ requestCounts.Remove key |> ignore
+ log (Canceled, key)
- | CancelRequest, None
- | CancelRequest, Some (Completed _) -> ()
+ | CancelRequest, None
+ | CancelRequest, Some (Completed _) -> ()
- | JobCompleted, Some (Running (job, _)) ->
- // TODO: should we re-wrap the result?
- cache.Set(tok, key, (Completed job))
- requestCounts.Remove key |> ignore
- log (Finished, key)
+ | JobCompleted result, Some (Running _)
+ // Job could be evicted from cache while it's running
+ | JobCompleted result, None ->
+ cache.Set(tok, key, (Completed(node.Return result)))
+ requestCounts.Remove key |> ignore
+ log (Finished, key)
- | JobCompleted, _ -> failwith "If this happens there's a bug"
+ | JobCompleted _, _ -> failwith "If this happens there's a bug"
+ with
+ | :? OperationCanceledException as e ->
+ System.Diagnostics.Trace.TraceError($"AsyncMemoize OperationCanceledException: {e.Message}")
+ | ex -> System.Diagnostics.Trace.TraceError($"AsyncMemoize Exception: %A{ex}")
})
member _.Get(key, computation) =
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index d30d38a6a2f..d783c63e359 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -128,28 +128,33 @@ type internal TransparentCompiler
let cacheEvent = new Event()
let triggerCacheEvent name (e, k) = cacheEvent.Trigger(name, e, k)
- let ParseFileCache = AsyncMemoize(triggerCacheEvent "ParseFile")
+ let ParseFileCache = AsyncMemoize(triggerCacheEvent, "ParseFile")
let ParseAndCheckFileInProjectCache =
- AsyncMemoize(triggerCacheEvent "ParseAndCheckFileInProject")
+ AsyncMemoize(triggerCacheEvent, "ParseAndCheckFileInProject")
let ParseAndCheckFullProjectCache =
- AsyncMemoize(triggerCacheEvent "ParseAndCheckFullProject")
+ AsyncMemoize(triggerCacheEvent, "ParseAndCheckFullProject")
- let FrameworkImportsCache = AsyncMemoize(triggerCacheEvent "FrameworkImports")
- let BootstrapInfoStaticCache = AsyncMemoize(triggerCacheEvent "BootstrapInfoStatic")
- let BootstrapInfoCache = AsyncMemoize(triggerCacheEvent "BootstrapInfo")
- let TcPriorCache = AsyncMemoize(triggerCacheEvent "TcPrior")
- let TcIntermediateCache = AsyncMemoize(triggerCacheEvent "TcIntermediate")
+ let FrameworkImportsCache = AsyncMemoize(triggerCacheEvent, "FrameworkImports")
- let DependencyGraphCache = AsyncMemoize(triggerCacheEvent "DependencyGraph")
+ let BootstrapInfoStaticCache =
+ AsyncMemoize(triggerCacheEvent, "BootstrapInfoStatic")
- let AssemblyDataCache = AsyncMemoize(triggerCacheEvent "AssemblyData")
+ let BootstrapInfoCache = AsyncMemoize(triggerCacheEvent, "BootstrapInfo")
+
+ let TcPriorCache = AsyncMemoize(triggerCacheEvent, "TcPrior")
+
+ let TcIntermediateCache = AsyncMemoize(triggerCacheEvent, "TcIntermediate")
+
+ let DependencyGraphCache = AsyncMemoize(triggerCacheEvent, "DependencyGraph")
+
+ let AssemblyDataCache = AsyncMemoize(triggerCacheEvent, "AssemblyData")
let SemanticClassificationCache =
- AsyncMemoize(triggerCacheEvent "SemanticClassification")
+ AsyncMemoize(triggerCacheEvent, "SemanticClassification")
- let ItemKeyStoreCache = AsyncMemoize(triggerCacheEvent "ItemKeyStore")
+ let ItemKeyStoreCache = AsyncMemoize(triggerCacheEvent, "ItemKeyStore")
// We currently share one global dependency provider for all scripts for the FSharpChecker.
// For projects, one is used per project.
@@ -1144,8 +1149,8 @@ type internal TransparentCompiler
member _.ParseFile(fileName, projectSnapshot: FSharpProjectSnapshot, _userOpName) =
node {
- use _ =
- Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
+ //use _ =
+ // Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |]
match! ComputeBootstrapInfo projectSnapshot with
| None, creationDiags -> return emptyParseResult fileName creationDiags
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
index 80c137cc603..61fae5d2af3 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs
@@ -18,7 +18,7 @@ let ``Basics``() =
let eventLog = ResizeArray()
- let memoize = AsyncMemoize(eventLog.Add)
+ let memoize = AsyncMemoize(fun _ -> eventLog.Add)
let task =
NodeCode.Parallel(seq {
@@ -53,7 +53,7 @@ let ``We can cancel a job`` () =
}
let eventLog = ResizeArray()
- let memoize = AsyncMemoize(eventLog.Add)
+ let memoize = AsyncMemoize(fun _ -> eventLog.Add)
use cts1 = new CancellationTokenSource()
use cts2 = new CancellationTokenSource()
@@ -96,7 +96,7 @@ let ``Job keeps running even if first requestor cancels`` () =
}
let eventLog = ResizeArray()
- let memoize = AsyncMemoize(eventLog.Add)
+ let memoize = AsyncMemoize(fun _ -> eventLog.Add)
use cts1 = new CancellationTokenSource()
use cts2 = new CancellationTokenSource()
diff --git a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs
index 11ef1ebe152..6ff78a04d09 100644
--- a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs
+++ b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs
@@ -37,6 +37,14 @@ module CancellableTasks =
open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
open Microsoft.FSharp.Collections
+ []
+ type VolatileBarrier() =
+ [