From e5b3131f3a302abd0325c5d01fe0dfda87e3c97d Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Thu, 25 Jan 2024 16:04:06 +0100 Subject: [PATCH 01/43] Transparent Compiler Tests --- tests/FSharp.Test.Utilities/CompilerAssert.fs | 2 +- tests/FSharp.Test.Utilities/ProjectGeneration.fs | 2 +- tests/service/Common.fs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 7951ba31d5d..8117e5390ce 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -259,7 +259,7 @@ and Compilation = module rec CompilerAssertHelpers = - let useTransparentCompiler = FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically + let useTransparentCompiler = true let checker = FSharpChecker.Create(suggestNamesForErrors=true, useTransparentCompiler=useTransparentCompiler) // Unlike C# whose entrypoint is always string[] F# can make an entrypoint with 0 args, or with an array of string[] diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index 54c00ebe544..37eb2b54a63 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -837,7 +837,7 @@ type ProjectWorkflowBuilder ?autoStart ) = - let useTransparentCompiler = defaultArg useTransparentCompiler FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically + let useTransparentCompiler = defaultArg useTransparentCompiler true let useGetSource = not useTransparentCompiler && defaultArg useGetSource false let useChangeNotifications = not useTransparentCompiler && defaultArg useChangeNotifications false let autoStart = defaultArg autoStart true diff --git a/tests/service/Common.fs b/tests/service/Common.fs index 8516948626a..11723a53a8a 100644 --- a/tests/service/Common.fs +++ b/tests/service/Common.fs @@ -31,7 +31,7 @@ type Async with task.Result // Create one global interactive checker instance -let checker = FSharpChecker.Create(useTransparentCompiler=FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically) +let checker = FSharpChecker.Create(useTransparentCompiler=true) type TempFile(ext, contents: string) = let tmpFile = Path.ChangeExtension(tryCreateTemporaryFileName (), ext) From 44a2f6627d69a6cfc58ed707275ba95776234456 Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Thu, 25 Jan 2024 18:21:23 +0100 Subject: [PATCH 02/43] Fail early with proper error message when no input files are specified --- src/Compiler/Service/TransparentCompiler.fs | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 298c0e6b627..099e49db71e 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -762,20 +762,23 @@ type internal TransparentCompiler |> List.map (fun (m, fileName) -> m, FSharpFileSnapshot.CreateFromFileSystem(fileName)) return - Some - { - Id = bootstrapId - AssemblyName = assemblyName - OutFile = outFile - TcConfig = tcConfig - TcImports = tcImports - TcGlobals = tcGlobals - InitialTcInfo = initialTcInfo - LoadedSources = loadedSources - LoadClosure = loadClosureOpt - LastFileName = sourceFiles |> List.last - //ImportsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider - } + match sourceFiles with + | [] -> None + | _ -> + Some + { + Id = bootstrapId + AssemblyName = assemblyName + OutFile = outFile + TcConfig = tcConfig + TcImports = tcImports + TcGlobals = tcGlobals + InitialTcInfo = initialTcInfo + LoadedSources = loadedSources + LoadClosure = loadClosureOpt + LastFileName = sourceFiles |> List.tryLast |> Option.defaultValue "" + //ImportsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider + } } let ComputeBootstrapInfo (projectSnapshot: ProjectSnapshot) = From e522b129122aebc8aafeefd8ef2f8f93345c35e7 Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Thu, 25 Jan 2024 18:44:12 +0100 Subject: [PATCH 03/43] We don't guarantee the ordering of symbols --- tests/service/ProjectAnalysisTests.fs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/service/ProjectAnalysisTests.fs b/tests/service/ProjectAnalysisTests.fs index a1a58a709b2..134cbfe6098 100644 --- a/tests/service/ProjectAnalysisTests.fs +++ b/tests/service/ProjectAnalysisTests.fs @@ -2510,9 +2510,10 @@ let ``Test Project16 all symbols`` () = wholeProjectResults.GetAllUsesOfAllSymbols() |> Array.map (fun su -> su.Symbol.ToString(), su.Symbol.DisplayName, Project16.cleanFileName su.FileName, tups su.Range, attribsOfSymbolUse su, attribsOfSymbol su.Symbol) + |> Array.sort allUsesOfAllSymbols |> shouldEqual - [|("ClassAttribute", "ClassAttribute", "sig1", ((8, 6), (8, 11)), + ([|("ClassAttribute", "ClassAttribute", "sig1", ((8, 6), (8, 11)), ["attribute"], ["class"]); ("member .ctor", "ClassAttribute", "sig1", ((8, 6), (8, 11)), [], ["member"]); @@ -2591,7 +2592,7 @@ let ``Test Project16 all symbols`` () = ("val x", "x", "file1", ((5, 11), (5, 12)), ["defn"], []); ("val x", "x", "file1", ((8, 11), (8, 12)), ["defn"], []); ("val x", "x", "file1", ((11, 11), (11, 12)), ["defn"], []); - ("Impl", "Impl", "file1", ((2, 7), (2, 11)), ["defn"], ["module"])|] + ("Impl", "Impl", "file1", ((2, 7), (2, 11)), ["defn"], ["module"])|] |> Array.sort) [] let ``Test Project16 sig symbols are equal to impl symbols`` () = From f97683f2ff199912e50f5836410d40d0dbb21ad3 Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Mon, 29 Jan 2024 18:29:42 +0100 Subject: [PATCH 04/43] update --- src/Compiler/Service/TransparentCompiler.fs | 2 +- tests/service/MultiProjectAnalysisTests.fs | 20 ++++++++++++++++---- tests/service/ProjectAnalysisTests.fs | 5 ++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 099e49db71e..b1d506be62b 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1652,7 +1652,7 @@ type internal TransparentCompiler | ProjectAssemblyDataResult.Available data -> Some data | _ -> None - let symbolUses = tcInfo.sink |> Seq.map (fun sink -> sink.GetSymbolUses()) + let symbolUses = tcInfo.sink |> Seq.rev |> Seq.map (fun sink -> sink.GetSymbolUses()) let details = (bootstrapInfo.TcGlobals, diff --git a/tests/service/MultiProjectAnalysisTests.fs b/tests/service/MultiProjectAnalysisTests.fs index a306107eb36..350cf73095e 100644 --- a/tests/service/MultiProjectAnalysisTests.fs +++ b/tests/service/MultiProjectAnalysisTests.fs @@ -133,8 +133,12 @@ let u = Case1 3 let cleanFileName a = if a = fileName1 then "file1" else "??" [] -let ``Test multi project 1 basic`` () = +[] +[] +let ``Test multi project 1 basic`` useTransparentCompiler = + let checker = if useTransparentCompiler then transparentCompilerChecker else checker + let wholeProjectResults = checker.ParseAndCheckProject(MultiProject1.options) |> Async.RunImmediate [ for x in wholeProjectResults.AssemblySignature.Entities -> x.DisplayName ] |> shouldEqual ["MultiProject1"] @@ -704,9 +708,12 @@ let ``Test multi project2 errors`` useTransparentCompiler = wholeProjectResultsC.Diagnostics.Length |> shouldEqual 1 - [] -let ``Test multi project 2 all symbols`` () = +[] +[] +let ``Test multi project 2 all symbols`` useTransparentCompiler = + + let checker = if useTransparentCompiler then transparentCompilerChecker else checker let mpA = checker.ParseAndCheckProject(Project2A.options) |> Async.RunImmediate let mpB = checker.ParseAndCheckProject(Project2B.options) |> Async.RunImmediate @@ -832,7 +839,12 @@ let ``Test active patterns' XmlDocSig declared in referenced projects`` useTrans [] -let ``In-memory cross-project references to projects using generative type provides should fallback to on-disk references`` () = +[] +[] +let ``In-memory cross-project references to projects using generative type provides should fallback to on-disk references`` useTransparentCompiler = + + let checker = if useTransparentCompiler then transparentCompilerChecker else checker + // The type provider and its dependency are compiled as part of the solution build #if DEBUG let csDLL = __SOURCE_DIRECTORY__ + @"/../../artifacts/bin/TestTP/Debug/netstandard2.0/CSharp_Analysis.dll" diff --git a/tests/service/ProjectAnalysisTests.fs b/tests/service/ProjectAnalysisTests.fs index 134cbfe6098..a1a58a709b2 100644 --- a/tests/service/ProjectAnalysisTests.fs +++ b/tests/service/ProjectAnalysisTests.fs @@ -2510,10 +2510,9 @@ let ``Test Project16 all symbols`` () = wholeProjectResults.GetAllUsesOfAllSymbols() |> Array.map (fun su -> su.Symbol.ToString(), su.Symbol.DisplayName, Project16.cleanFileName su.FileName, tups su.Range, attribsOfSymbolUse su, attribsOfSymbol su.Symbol) - |> Array.sort allUsesOfAllSymbols |> shouldEqual - ([|("ClassAttribute", "ClassAttribute", "sig1", ((8, 6), (8, 11)), + [|("ClassAttribute", "ClassAttribute", "sig1", ((8, 6), (8, 11)), ["attribute"], ["class"]); ("member .ctor", "ClassAttribute", "sig1", ((8, 6), (8, 11)), [], ["member"]); @@ -2592,7 +2591,7 @@ let ``Test Project16 all symbols`` () = ("val x", "x", "file1", ((5, 11), (5, 12)), ["defn"], []); ("val x", "x", "file1", ((8, 11), (8, 12)), ["defn"], []); ("val x", "x", "file1", ((11, 11), (11, 12)), ["defn"], []); - ("Impl", "Impl", "file1", ((2, 7), (2, 11)), ["defn"], ["module"])|] |> Array.sort) + ("Impl", "Impl", "file1", ((2, 7), (2, 11)), ["defn"], ["module"])|] [] let ``Test Project16 sig symbols are equal to impl symbols`` () = From 96f5b512ebf616079294b46a67396057776d1720 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Wed, 31 Jan 2024 15:26:46 +0100 Subject: [PATCH 05/43] Fix format specifiers in results --- src/Compiler/Service/TransparentCompiler.fs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index b1d506be62b..9a374f63aba 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1115,7 +1115,7 @@ type internal TransparentCompiler ApplyMetaCommandsFromInputToTcConfig(tcConfig, input, Path.GetDirectoryName fileName, tcImports.DependencyProvider) |> ignore - let sink = TcResultsSinkImpl(tcGlobals) + let sink = TcResultsSinkImpl(tcGlobals, file.SourceText) let hadParseErrors = not (Array.isEmpty file.ParseErrors) @@ -1652,7 +1652,8 @@ type internal TransparentCompiler | ProjectAssemblyDataResult.Available data -> Some data | _ -> None - let symbolUses = tcInfo.sink |> Seq.rev |> Seq.map (fun sink -> sink.GetSymbolUses()) + let symbolUses = + tcInfo.sink |> Seq.rev |> Seq.map (fun sink -> sink.GetSymbolUses()) let details = (bootstrapInfo.TcGlobals, From fb99f362847e96ea5406c777fc607447a688116d Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Wed, 31 Jan 2024 17:04:21 +0100 Subject: [PATCH 06/43] more fixes --- .../.FSharp.Compiler.Service/8.0.300.md | 2 +- .../Driver/GraphChecking/TrieMapping.fs | 2 +- .../TypeChecks/Graph/TrieMappingTests.fs | 23 ++++++++++++++++++- tests/service/CSharpProjectAnalysis.fs | 5 ++-- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 85735d5b430..3678f6a0f3f 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -2,7 +2,7 @@ * Code generated files with > 64K methods and generated symbols crash when loaded. Use infered sequence points for debugging. ([Issue #16399](https://github.com/dotnet/fsharp/issues/16399), [#PR 16514](https://github.com/dotnet/fsharp/pull/16514)) * `nameof Module` expressions and patterns are processed to link files in `--test:GraphBasedChecking`. ([PR #16550](https://github.com/dotnet/fsharp/pull/16550)) -* Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575), [PR #16588](https://github.com/dotnet/fsharp/pull/16588)) +* Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575), [PR #16588](https://github.com/dotnet/fsharp/pull/16588), [PR #16591](https://github.com/dotnet/fsharp/pull/16591)) * Keep parens for problematic exprs (`if`, `match`, etc.) in `$"{(…):N0}"`, `$"{(…),-3}"`, etc. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578)) * Fix crash in DOTNET_SYSTEM_GLOBALIZATION_INVARIANT mode [#PR 16471](https://github.com/dotnet/fsharp/pull/16471)) diff --git a/src/Compiler/Driver/GraphChecking/TrieMapping.fs b/src/Compiler/Driver/GraphChecking/TrieMapping.fs index ff7b32e5640..add261d570c 100644 --- a/src/Compiler/Driver/GraphChecking/TrieMapping.fs +++ b/src/Compiler/Driver/GraphChecking/TrieMapping.fs @@ -123,7 +123,7 @@ let processSynModuleOrNamespace<'Decl> // Only the last node can be a module, depending on the SynModuleOrNamespaceKind. let rec visit continuation (xs: LongIdent) = match xs with - | [] -> failwith "should not be empty" + | [] -> ImmutableDictionary.Empty |> continuation | [ finalPart ] -> let name = finalPart.idText diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TrieMappingTests.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TrieMappingTests.fs index e5bc3ef0299..6ad29818a2a 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TrieMappingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/TrieMappingTests.fs @@ -540,6 +540,27 @@ let ``Tries are built up incrementally`` () = ParsedInput = parseSourceCode ("D.fs", "module D") } |] - + for idx, t in trie do Assert.AreEqual(idx + 1, t.Children.Count) + + +module InvalidSyntax = + + [] + let ``Unnamed module`` () = + let trie = + getLastTrie + [| { Idx = 0 + FileName = "A.fs" + ParsedInput = + parseSourceCode ( + "A.fs", + """ + module + + () + """ + ) } |] + + Assert.True trie.Children.IsEmpty diff --git a/tests/service/CSharpProjectAnalysis.fs b/tests/service/CSharpProjectAnalysis.fs index f23f3038e42..69a13799d7f 100644 --- a/tests/service/CSharpProjectAnalysis.fs +++ b/tests/service/CSharpProjectAnalysis.fs @@ -27,7 +27,7 @@ let internal getProjectReferences (content: string, dllFiles, libDirs, otherFlag let projFileName = Path.ChangeExtension(base1, ".fsproj") FileSystem.OpenFileForWriteShim(fileName1).Write(content) let options = - checker.GetProjectOptionsFromCommandLineArgs(projFileName, + { checker.GetProjectOptionsFromCommandLineArgs(projFileName, [| yield "--debug:full" yield "--define:DEBUG" yield "--optimize-" @@ -41,8 +41,7 @@ let internal getProjectReferences (content: string, dllFiles, libDirs, otherFlag yield "-r:"+dllFile for libDir in libDirs do yield "-I:"+libDir - yield! otherFlags - yield fileName1 |]) + yield! otherFlags |]) with SourceFiles = [| fileName1 |] } let results = checker.ParseAndCheckProject(options) |> Async.RunImmediate if results.HasCriticalErrors then let builder = System.Text.StringBuilder() From 6d7a4f549e2a3b9c1f608f75fd67fb10dc0de483 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Wed, 31 Jan 2024 19:00:32 +0100 Subject: [PATCH 07/43] Remove redundant parsing errors --- src/Compiler/Service/TransparentCompiler.fs | 5 +---- .../FSharpChecker/TransparentCompiler.fs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 9a374f63aba..d0a95e57846 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1144,16 +1144,13 @@ type internal TransparentCompiler //fileChecked.Trigger fileName - let newErrors = - Array.append file.ParseErrors (errHandler.CollectedPhasedDiagnostics) - fileChecked.Trigger(fileName, Unchecked.defaultof<_>) return { finisher = finisher moduleNamesDict = moduleNamesDict - tcDiagnosticsRev = [ newErrors ] + tcDiagnosticsRev = [ errHandler.CollectedPhasedDiagnostics ] tcDependencyFiles = [ fileName ] sink = sink } diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs index 90dc85c4a33..f1b2461476b 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs @@ -626,7 +626,7 @@ let fuzzingTest seed (project: SyntheticProject) = task { () with | e -> - let _log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray + // let _log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray failwith $"Seed: {seed}\nException: %A{e}" } let log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray From e0bedf117ec265b8761fe63a683d4107683200e9 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Wed, 31 Jan 2024 19:36:35 +0100 Subject: [PATCH 08/43] fix fuzzing tests --- .../FSharpChecker/TransparentCompiler.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs index f1b2461476b..859c629d742 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs @@ -479,12 +479,12 @@ type SignatureFiles = Yes = 1 | No = 2 | Some = 3 let fuzzingTest seed (project: SyntheticProject) = task { let rng = System.Random seed - let checkingThreads = 3 - let maxModificationDelayMs = 10 + let checkingThreads = 10 + let maxModificationDelayMs = 50 let maxCheckingDelayMs = 20 //let runTimeMs = 30000 let signatureFileModificationProbability = 0.25 - let modificationLoopIterations = 10 + let modificationLoopIterations = 50 let checkingLoopIterations = 5 let minCheckingTimeoutMs = 0 @@ -622,7 +622,7 @@ let fuzzingTest seed (project: SyntheticProject) = task { } try - let! _x = threads |> Seq.skip 1 |> Task.WhenAll + let! _x = threads |> Task.WhenAll () with | e -> From d7514a0aa426cf551c723604989ad5ceb348af90 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 1 Feb 2024 12:24:51 +0100 Subject: [PATCH 09/43] Added support for other refernce types --- src/Compiler/Service/FSharpProjectSnapshot.fs | 50 ++++++++++++------- src/Compiler/Service/TransparentCompiler.fs | 35 +++++++++++++ .../LanguageService/WorkspaceExtensions.fs | 1 + 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 259948dc706..b9c3e4bb489 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -364,7 +364,10 @@ and internal ProjectCore |> Md5Hasher.addDateTimes (ReferencesOnDisk |> Seq.map (fun r -> r.LastModified)) |> Md5Hasher.addBytes' ( ReferencedProjects - |> Seq.map (fun (FSharpReference(_name, p)) -> p.ProjectSnapshot.SignatureVersion) + |> Seq.map (function + | FSharpReference(_name, p) -> p.ProjectSnapshot.SignatureVersion + | PEReference(getStamp, _) -> Md5Hasher.empty |> Md5Hasher.addDateTime (getStamp ()) + | ILModuleReference(_name, getStamp, _) -> Md5Hasher.empty |> Md5Hasher.addDateTime (getStamp ())) )) let fullHashString = lazy (fullHash.Value |> Md5Hasher.toString) @@ -430,11 +433,11 @@ and internal ProjectCore and [] FSharpReferencedProjectSnapshot = | 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) + | PEReference of getStamp: (unit -> DateTime) * delayedReader: DelayedILModuleReader + | ILModuleReference of + projectOutputFile: string * + getStamp: (unit -> DateTime) * + getReader: (unit -> FSharp.Compiler.AbstractIL.ILBinaryReader.ILModuleReader) /// /// The fully qualified path to the output of the referenced project. This should be the same value as the -r @@ -442,7 +445,9 @@ and [ member this.OutputFile = match this with - | FSharpReference(projectOutputFile, _) -> projectOutputFile + | FSharpReference(projectOutputFile = projectOutputFile) + | ILModuleReference(projectOutputFile = projectOutputFile) -> projectOutputFile + | PEReference(delayedReader = reader) -> reader.OutputFile /// /// Creates a reference for an F# project. The physical data for it is stored/cached inside of the compiler service. @@ -458,6 +463,11 @@ and [ projectOutputFile1 = projectOutputFile2 && options1 = options2 + | PEReference(getStamp1, reader1), PEReference(getStamp2, reader2) -> + reader1.OutputFile = reader2.OutputFile && (getStamp1 ()) = (getStamp2 ()) + | ILModuleReference(projectOutputFile1, getStamp1, _), ILModuleReference(projectOutputFile2, getStamp2, _) -> + projectOutputFile1 = projectOutputFile2 && (getStamp1 ()) = (getStamp2 ()) + | _ -> false | _ -> false @@ -524,17 +534,19 @@ and [] FSha let! referencedProjects = options.ReferencedProjects - |> Seq.choose (function + |> Seq.map (function | FSharpReferencedProject.FSharpReference(outputName, options) -> - Some( - async { - let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot, snapshotAccumulator) - - return FSharpReferencedProjectSnapshot.FSharpReference(outputName, snapshot) - } - ) - // TODO: other types - | _ -> None) + async { + let! snapshot = FSharpProjectSnapshot.FromOptions(options, getFileSnapshot, snapshotAccumulator) + + return FSharpReferencedProjectSnapshot.FSharpReference(outputName, snapshot) + } + | FSharpReferencedProject.PEReference(getStamp, reader) -> + async.Return <| FSharpReferencedProjectSnapshot.PEReference(getStamp, reader) + | FSharpReferencedProject.ILModuleReference(outputName, getStamp, getReader) -> + async.Return + <| FSharpReferencedProjectSnapshot.ILModuleReference(outputName, getStamp, getReader)) + |> Async.Sequential let referencesOnDisk, otherOptions = @@ -601,7 +613,9 @@ let rec internal snapshotToOptions (projectSnapshot: ProjectSnapshotBase<_>) = ReferencedProjects = projectSnapshot.ReferencedProjects |> Seq.map (function - | FSharpReference(name, opts) -> FSharpReferencedProject.FSharpReference(name, opts.ProjectSnapshot |> snapshotToOptions)) + | FSharpReference(name, opts) -> FSharpReferencedProject.FSharpReference(name, opts.ProjectSnapshot |> snapshotToOptions) + | PEReference(getStamp, reader) -> FSharpReferencedProject.PEReference(getStamp, reader) + | ILModuleReference(name, getStamp, getReader) -> FSharpReferencedProject.ILModuleReference(name, getStamp, getReader)) |> Seq.toArray IsIncompleteTypeCheckEnvironment = projectSnapshot.IsIncompleteTypeCheckEnvironment UseScriptResolutionRules = projectSnapshot.UseScriptResolutionRules diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index d0a95e57846..8e5f984d027 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -539,6 +539,41 @@ type internal TransparentCompiler member x.FileName = nm } + | FSharpReferencedProjectSnapshot.PEReference(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 = delayedReader.OutputFile + } + + | FSharpReferencedProjectSnapshot.ILModuleReference(nm, getStamp, getReader) -> + { new IProjectReference with + member x.EvaluateRawContents() = + cancellable { + let ilReader = getReader () + let ilModuleDef, ilAsmRefs = ilReader.ILModuleDef, ilReader.ILAssemblyRefs + let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData + return ProjectAssemblyDataResult.Available data + } + |> NodeCode.FromCancellable + + member x.TryGetLogicalTimeStamp _ = getStamp () |> Some + member x.FileName = nm + } ] let ComputeTcConfigBuilder (projectSnapshot: ProjectSnapshotBase<_>) = diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs index 6e3de8133f1..154517ed6a1 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs @@ -58,6 +58,7 @@ module internal FSharpProjectSnapshotSerialization = | FSharpReference(projectOutputFile, snapshot) -> output.Add("projectOutputFile", projectOutputFile) output.Add("snapshot", serializeSnapshot snapshot) + | _ -> () output From af949ed1d0630a71c332f7917ac413b5c230a84d Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 1 Feb 2024 13:25:49 +0100 Subject: [PATCH 10/43] surfacearea --- ...ervice.SurfaceArea.netstandard20.debug.bsl | 33 ++++++++++++++++--- ...vice.SurfaceArea.netstandard20.release.bsl | 33 ++++++++++++++++--- 2 files changed, 58 insertions(+), 8 deletions(-) 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 b7484492a42..361ff32f3cc 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 @@ -2338,19 +2338,44 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FS FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_Label() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_options() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot options +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String get_projectOutputFile() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String projectOutputFile +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader] getReader +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader] get_getReader() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] getStamp +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] get_getStamp() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: System.String get_projectOutputFile() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: System.String projectOutputFile +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: FSharp.Compiler.CodeAnalysis.DelayedILModuleReader delayedReader +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: FSharp.Compiler.CodeAnalysis.DelayedILModuleReader get_delayedReader() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] getStamp +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] get_getStamp() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags: Int32 FSharpReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags: Int32 ILModuleReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags: Int32 PEReference FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean Equals(System.Object) -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpProjectSnapshot get_options() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpProjectSnapshot options +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean IsFSharpReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean IsILModuleReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean IsPEReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean get_IsFSharpReference() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean get_IsILModuleReference() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean get_IsPEReference() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot CreateFSharp(System.String, FSharpProjectSnapshot) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot NewFSharpReference(System.String, FSharpProjectSnapshot) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot NewILModuleReference(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]) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot NewPEReference(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime], FSharp.Compiler.CodeAnalysis.DelayedILModuleReader) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Int32 GetHashCode() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Int32 Tag FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Int32 get_Tag() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String OutputFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String ToString() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String get_OutputFile() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String get_projectOutputFile() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String projectOutputFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk: Boolean Equals(ReferenceOnDisk) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk: Boolean Equals(System.Object) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk: Boolean Equals(System.Object, System.Collections.IEqualityComparer) 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 b7484492a42..361ff32f3cc 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 @@ -2338,19 +2338,44 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FS FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_Label() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_options() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot options +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String get_projectOutputFile() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String projectOutputFile +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader] getReader +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader] get_getReader() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] getStamp +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] get_getStamp() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: System.String get_projectOutputFile() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: System.String projectOutputFile +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: FSharp.Compiler.CodeAnalysis.DelayedILModuleReader delayedReader +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: FSharp.Compiler.CodeAnalysis.DelayedILModuleReader get_delayedReader() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] getStamp +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime] get_getStamp() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags: Int32 FSharpReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags: Int32 ILModuleReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags: Int32 PEReference FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean Equals(System.Object) -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpProjectSnapshot get_options() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpProjectSnapshot options +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean IsFSharpReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean IsILModuleReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean IsPEReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean get_IsFSharpReference() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean get_IsILModuleReference() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Boolean get_IsPEReference() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+PEReference +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+Tags FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot CreateFSharp(System.String, FSharpProjectSnapshot) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot NewFSharpReference(System.String, FSharpProjectSnapshot) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot NewILModuleReference(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]) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: FSharpReferencedProjectSnapshot NewPEReference(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime], FSharp.Compiler.CodeAnalysis.DelayedILModuleReader) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Int32 GetHashCode() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Int32 Tag FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: Int32 get_Tag() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String OutputFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String ToString() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String get_OutputFile() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String get_projectOutputFile() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot: System.String projectOutputFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk: Boolean Equals(ReferenceOnDisk) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk: Boolean Equals(System.Object) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk: Boolean Equals(System.Object, System.Collections.IEqualityComparer) From 8dcf23c95687968ecf862eb0e5b629b4a422d39c Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 1 Feb 2024 18:55:35 +0100 Subject: [PATCH 11/43] deduplicate diagnostics --- src/Compiler/Service/TransparentCompiler.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 8e5f984d027..b69a10ea10c 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1388,7 +1388,7 @@ type internal TransparentCompiler let! snapshotWithSources = LoadSources bootstrapInfo priorSnapshot let file = snapshotWithSources.SourceFiles |> List.last - let! parseResults = getParseResult projectSnapshot creationDiags file bootstrapInfo.TcConfig + let! parseResults = getParseResult projectSnapshot Seq.empty file bootstrapInfo.TcConfig let! result, tcInfo = ComputeTcLastFile bootstrapInfo snapshotWithSources @@ -1441,7 +1441,7 @@ type internal TransparentCompiler ) let tcDiagnostics = - [| yield! creationDiags; yield! extraDiagnostics; yield! tcDiagnostics |] + [| yield! extraDiagnostics; yield! tcDiagnostics |] let loadClosure = None // TODO: script support From 44320921410d77b7b812ff9909a29981c9f9a57e Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 1 Feb 2024 18:56:29 +0100 Subject: [PATCH 12/43] f --- src/Compiler/Service/TransparentCompiler.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index b69a10ea10c..9f3881ecfd2 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1440,8 +1440,7 @@ type internal TransparentCompiler Some symbolEnv ) - let tcDiagnostics = - [| yield! extraDiagnostics; yield! tcDiagnostics |] + let tcDiagnostics = [| yield! extraDiagnostics; yield! tcDiagnostics |] let loadClosure = None // TODO: script support From 9663c3bc234bc00ef12a3e443141fb874b1b9c74 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 1 Feb 2024 20:29:58 +0100 Subject: [PATCH 13/43] revert test config --- tests/FSharp.Test.Utilities/CompilerAssert.fs | 2 +- tests/FSharp.Test.Utilities/ProjectGeneration.fs | 2 +- tests/service/Common.fs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 8117e5390ce..7951ba31d5d 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -259,7 +259,7 @@ and Compilation = module rec CompilerAssertHelpers = - let useTransparentCompiler = true + let useTransparentCompiler = FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically let checker = FSharpChecker.Create(suggestNamesForErrors=true, useTransparentCompiler=useTransparentCompiler) // Unlike C# whose entrypoint is always string[] F# can make an entrypoint with 0 args, or with an array of string[] diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index 2fdb9c4c49f..144e535bccb 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -926,7 +926,7 @@ type ProjectWorkflowBuilder ?isExistingProject ) = - let useTransparentCompiler = defaultArg useTransparentCompiler true + let useTransparentCompiler = defaultArg useTransparentCompiler FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically let useGetSource = not useTransparentCompiler && defaultArg useGetSource false let useChangeNotifications = not useTransparentCompiler && defaultArg useChangeNotifications false let autoStart = defaultArg autoStart true diff --git a/tests/service/Common.fs b/tests/service/Common.fs index 11723a53a8a..8516948626a 100644 --- a/tests/service/Common.fs +++ b/tests/service/Common.fs @@ -31,7 +31,7 @@ type Async with task.Result // Create one global interactive checker instance -let checker = FSharpChecker.Create(useTransparentCompiler=true) +let checker = FSharpChecker.Create(useTransparentCompiler=FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically) type TempFile(ext, contents: string) = let tmpFile = Path.ChangeExtension(tryCreateTemporaryFileName (), ext) From f509f2d21da05410e4a615975030228533873f9e Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Fri, 2 Feb 2024 11:19:55 +0100 Subject: [PATCH 14/43] docs --- src/Compiler/Service/FSharpProjectSnapshot.fs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index b9c3e4bb489..148d39da787 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -432,8 +432,28 @@ and internal ProjectCore member _.CacheKey = cacheKey.Value and [] FSharpReferencedProjectSnapshot = - | FSharpReference of projectOutputFile: string * options: FSharpProjectSnapshot + /// + /// A reference to 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. + /// Snapshot of the referenced F# project + | FSharpReference of projectOutputFile: string * snapshot: FSharpProjectSnapshot + /// + /// A reference to any portable executable, including F#. The stream is owned by this reference. + /// The stream will be automatically disposed when there are no references to FSharpReferencedProject and is GC collected. + /// Once the stream is evaluated, the function that constructs the stream will no longer be referenced by anything. + /// If the stream evaluation throws an exception, it will be automatically handled. + /// + /// A function that calculates a last-modified timestamp for this reference. This will be used to determine if the reference is up-to-date. + /// A function that opens a Portable Executable data stream for reading. | PEReference of getStamp: (unit -> DateTime) * delayedReader: DelayedILModuleReader + + /// + /// A reference to an 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. + /// A function that calculates a last-modified timestamp for this reference. This will be used to determine if the reference is up-to-date. + /// A function that creates an ILModuleReader for reading module data. | ILModuleReference of projectOutputFile: string * getStamp: (unit -> DateTime) * From 1fe0323a6c718bba8846e54d3dac3f98ec60afb9 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Fri, 2 Feb 2024 13:34:26 +0100 Subject: [PATCH 15/43] surfacearea --- ...Sharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl | 4 ++-- ...arp.Compiler.Service.SurfaceArea.netstandard20.release.bsl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 361ff32f3cc..b6eeea8f992 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 @@ -2338,8 +2338,8 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FS FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_Label() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_options() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot options +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_snapshot() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot snapshot FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String get_projectOutputFile() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String projectOutputFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader] getReader 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 361ff32f3cc..b6eeea8f992 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 @@ -2338,8 +2338,8 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FS FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_Label() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_options() -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot options +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_snapshot() +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot snapshot FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String get_projectOutputFile() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: System.String projectOutputFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+ILModuleReference: Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.AbstractIL.ILBinaryReader+ILModuleReader] getReader From d69f9711df733ed04e02fd3eefb6c1144622215f Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Fri, 2 Feb 2024 13:44:02 +0100 Subject: [PATCH 16/43] fix release notes --- docs/release-notes/.FSharp.Compiler.Service/8.0.300.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 3678f6a0f3f..a090daf5cf3 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -2,7 +2,7 @@ * Code generated files with > 64K methods and generated symbols crash when loaded. Use infered sequence points for debugging. ([Issue #16399](https://github.com/dotnet/fsharp/issues/16399), [#PR 16514](https://github.com/dotnet/fsharp/pull/16514)) * `nameof Module` expressions and patterns are processed to link files in `--test:GraphBasedChecking`. ([PR #16550](https://github.com/dotnet/fsharp/pull/16550)) -* Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575), [PR #16588](https://github.com/dotnet/fsharp/pull/16588), [PR #16591](https://github.com/dotnet/fsharp/pull/16591)) +* Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575), [PR #16588](https://github.com/dotnet/fsharp/pull/16588), [PR #16643](https://github.com/dotnet/fsharp/pull/16643)) * Keep parens for problematic exprs (`if`, `match`, etc.) in `$"{(…):N0}"`, `$"{(…),-3}"`, etc. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578)) * Fix crash in DOTNET_SYSTEM_GLOBALIZATION_INVARIANT mode [#PR 16471](https://github.com/dotnet/fsharp/pull/16471)) From d987d231059524d42b4ba1d4217ceb5eb8026b44 Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Fri, 2 Feb 2024 18:07:41 +0100 Subject: [PATCH 17/43] uncomment --- .../FSharpChecker/TransparentCompiler.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs index 859c629d742..5ff288185c4 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs @@ -626,7 +626,7 @@ let fuzzingTest seed (project: SyntheticProject) = task { () with | e -> - // let _log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray + let _log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray failwith $"Seed: {seed}\nException: %A{e}" } let log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray From ba0e0797565adaccb445826404a2307e47504798 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Wed, 31 Jan 2024 19:40:27 +0100 Subject: [PATCH 18/43] asynclocal --- .../.FSharp.Compiler.Service/8.0.300.md | 1 + src/Compiler/Driver/CompilerImports.fs | 2 + src/Compiler/Facilities/BuildGraph.fs | 69 ++++++++++--------- src/Compiler/Facilities/BuildGraph.fsi | 4 +- src/Compiler/Facilities/DiagnosticsLogger.fs | 30 ++++---- src/Compiler/Facilities/DiagnosticsLogger.fsi | 2 - .../FSharpChecker/TransparentCompiler.fs | 2 +- 7 files changed, 56 insertions(+), 54 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index b8dc1de0de9..710fef1fbc2 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -23,3 +23,4 @@ * Reduce allocations in compiler checking via `ValueOption` usage ([PR #16323](https://github.com/dotnet/fsharp/pull/16323), [PR #16567](https://github.com/dotnet/fsharp/pull/16567)) * Reverted [#16348](https://github.com/dotnet/fsharp/pull/16348) `ThreadStatic` `CancellationToken` changes to improve test stability and prevent potential unwanted cancellations. ([PR #16536](https://github.com/dotnet/fsharp/pull/16536)) * Refactored parenthesization API. ([PR #16461])(https://github.com/dotnet/fsharp/pull/16461)) +* Replaced `ThreadStatic` diagnostics globals with `AsyncLocal` for better stability of Transparent Compiler. ([PR #16602](https://github.com/dotnet/fsharp/pull/16602)) \ No newline at end of file diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index d8d9ccd9866..9bc5ea85516 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2238,6 +2238,7 @@ and [] TcImports | ParallelReferenceResolution.On -> NodeCode.Parallel | ParallelReferenceResolution.Off -> NodeCode.Sequential + let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger let! results = nms |> List.map (fun nm -> @@ -2245,6 +2246,7 @@ and [] TcImports try return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) with e -> + use _ = UseDiagnosticsLogger diagnosticsLogger errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range)) return None }) diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index 71f4d3da991..7d8b0ee410a 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -7,7 +7,7 @@ open System.Threading open System.Threading.Tasks open System.Diagnostics open System.Globalization -open FSharp.Compiler.DiagnosticsLogger +//open FSharp.Compiler.DiagnosticsLogger open Internal.Utilities.Library [] @@ -15,14 +15,15 @@ type NodeCode<'T> = Node of Async<'T> let wrapThreadStaticInfo computation = async { - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + //let phase = DiagnosticsThreadStatics.BuildPhase try return! computation finally - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + //DiagnosticsThreadStatics.BuildPhase <- phase + () } type Async<'T> with @@ -92,19 +93,19 @@ type NodeCodeBuilder() = [] member _.Combine(Node(p1): NodeCode, Node(p2): NodeCode<'T>) : NodeCode<'T> = Node(async.Combine(p1, p2)) - [] - member _.Using(value: CompilationGlobalsScope, binder: CompilationGlobalsScope -> NodeCode<'U>) = - Node( - async { - DiagnosticsThreadStatics.DiagnosticsLogger <- value.DiagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- value.BuildPhase + //[] + //member _.Using(value: CompilationGlobalsScope, binder: CompilationGlobalsScope -> NodeCode<'U>) = + // Node( + // async { + // DiagnosticsThreadStatics.DiagnosticsLogger <- value.DiagnosticsLogger + // DiagnosticsThreadStatics.BuildPhase <- value.BuildPhase - try - return! binder value |> Async.AwaitNodeCode - finally - (value :> IDisposable).Dispose() - } - ) + // try + // return! binder value |> Async.AwaitNodeCode + // finally + // (value :> IDisposable).Dispose() + // } + // ) [] member _.Using(value: IDisposable, binder: IDisposable -> NodeCode<'U>) = @@ -123,22 +124,23 @@ type NodeCode private () = static let cancellationToken = Node(wrapThreadStaticInfo Async.CancellationToken) static member RunImmediate(computation: NodeCode<'T>, ct: CancellationToken) = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + //let phase = DiagnosticsThreadStatics.BuildPhase try try let work = async { - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + //DiagnosticsThreadStatics.BuildPhase <- phase return! computation |> Async.AwaitNodeCode } Async.StartImmediateAsTask(work, cancellationToken = ct).Result finally - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + //DiagnosticsThreadStatics.BuildPhase <- phase + () with :? AggregateException as ex when ex.InnerExceptions.Count = 1 -> raise (ex.InnerExceptions[0]) @@ -146,21 +148,22 @@ type NodeCode private () = NodeCode.RunImmediate(computation, CancellationToken.None) static member StartAsTask_ForTesting(computation: NodeCode<'T>, ?ct: CancellationToken) = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + //let phase = DiagnosticsThreadStatics.BuildPhase try let work = async { - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + //DiagnosticsThreadStatics.BuildPhase <- phase return! computation |> Async.AwaitNodeCode } Async.StartAsTask(work, cancellationToken = defaultArg ct CancellationToken.None) finally - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + //DiagnosticsThreadStatics.BuildPhase <- phase + () static member CancellationToken = cancellationToken @@ -193,14 +196,14 @@ type NodeCode private () = } static member Parallel(computations: NodeCode<'T> seq) = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + //let phase = DiagnosticsThreadStatics.BuildPhase computations |> Seq.map (fun (Node x) -> async { - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + //DiagnosticsThreadStatics.BuildPhase <- phase return! x }) |> Async.Parallel diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index afbf9d2898b..3008e2f283e 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -44,8 +44,8 @@ type NodeCodeBuilder = member Combine: x1: NodeCode * x2: NodeCode<'T> -> NodeCode<'T> - /// A limited form 'use' for establishing the compilation globals. - member Using: CompilationGlobalsScope * (CompilationGlobalsScope -> NodeCode<'T>) -> NodeCode<'T> + ///// A limited form 'use' for establishing the compilation globals. + //member Using: CompilationGlobalsScope * (CompilationGlobalsScope -> NodeCode<'T>) -> NodeCode<'T> /// A generic 'use' that disposes of the IDisposable at the end of the computation. member Using: IDisposable * (IDisposable -> NodeCode<'T>) -> NodeCode<'T> diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 08a46d1a25d..fbf378c3ed4 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -13,6 +13,7 @@ open System.Reflection open System.Threading open Internal.Utilities.Library open Internal.Utilities.Library.Extras +open System.Threading /// Represents the style being used to format errors [] @@ -375,28 +376,25 @@ type CapturingDiagnosticsLogger(nm, ?eagerFormat) = errors |> Array.iter diagnosticsLogger.DiagnosticSink /// Type holds thread-static globals for use by the compiler. -type internal DiagnosticsThreadStatics = - [] - static val mutable private buildPhase: BuildPhase - - [] - static val mutable private diagnosticsLogger: DiagnosticsLogger +type DiagnosticsThreadStatics = + static let buildPhase = new AsyncLocal() + static let diagnosticsLogger = new AsyncLocal() - static member BuildPhaseUnchecked = DiagnosticsThreadStatics.buildPhase + static let EnsureCreated (h: AsyncLocal<_>) d = + if box h.Value |> isNull then + h.Value <- d static member BuildPhase with get () = - match box DiagnosticsThreadStatics.buildPhase with - | Null -> BuildPhase.DefaultPhase - | _ -> DiagnosticsThreadStatics.buildPhase - and set v = DiagnosticsThreadStatics.buildPhase <- v + EnsureCreated buildPhase BuildPhase.DefaultPhase + buildPhase.Value + and set v = buildPhase.Value <- v static member DiagnosticsLogger with get () = - match box DiagnosticsThreadStatics.diagnosticsLogger with - | Null -> AssertFalseDiagnosticsLogger - | _ -> DiagnosticsThreadStatics.diagnosticsLogger - and set v = DiagnosticsThreadStatics.diagnosticsLogger <- v + EnsureCreated diagnosticsLogger AssertFalseDiagnosticsLogger + diagnosticsLogger.Value + and set v = diagnosticsLogger.Value <- v [] module DiagnosticsLoggerExtensions = @@ -498,7 +496,7 @@ module DiagnosticsLoggerExtensions = /// NOTE: The change will be undone when the returned "unwind" object disposes let UseBuildPhase (phase: BuildPhase) = - let oldBuildPhase = DiagnosticsThreadStatics.BuildPhaseUnchecked + let oldBuildPhase = DiagnosticsThreadStatics.BuildPhase DiagnosticsThreadStatics.BuildPhase <- phase { new IDisposable with diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index e9040da36ed..54729756c6b 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -232,8 +232,6 @@ type DiagnosticsThreadStatics = static member BuildPhase: BuildPhase with get, set - static member BuildPhaseUnchecked: BuildPhase - static member DiagnosticsLogger: DiagnosticsLogger with get, set [] diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs index 5ff288185c4..859c629d742 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs @@ -626,7 +626,7 @@ let fuzzingTest seed (project: SyntheticProject) = task { () with | e -> - let _log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray + // let _log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray failwith $"Seed: {seed}\nException: %A{e}" } let log = log.Values |> Seq.collect id |> Seq.sortBy p13 |> Seq.toArray From e85f89398ed584c0dd6ba02f86ce37aeec357a46 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Wed, 31 Jan 2024 22:02:12 +0100 Subject: [PATCH 19/43] remove NodeCode and node CE --- src/Compiler/Driver/CompilerConfig.fs | 2 +- src/Compiler/Driver/CompilerConfig.fsi | 2 +- src/Compiler/Driver/CompilerImports.fs | 26 +- src/Compiler/Driver/CompilerImports.fsi | 6 +- src/Compiler/Driver/fsc.fs | 4 +- src/Compiler/Facilities/AsyncMemoize.fs | 18 +- src/Compiler/Facilities/AsyncMemoize.fsi | 4 +- src/Compiler/Facilities/BuildGraph.fs | 222 ++---------------- src/Compiler/Facilities/BuildGraph.fsi | 77 +----- src/Compiler/Interactive/fsi.fs | 4 +- src/Compiler/Service/BackgroundCompiler.fs | 132 +++++------ src/Compiler/Service/BackgroundCompiler.fsi | 33 ++- src/Compiler/Service/IncrementalBuild.fs | 94 ++++---- src/Compiler/Service/IncrementalBuild.fsi | 32 ++- src/Compiler/Service/TransparentCompiler.fs | 145 ++++++------ src/Compiler/Service/TransparentCompiler.fsi | 8 +- src/Compiler/Service/service.fs | 21 +- .../BuildGraphTests.fs | 66 +++--- .../LanguageService/WorkspaceExtensions.fs | 7 +- 19 files changed, 304 insertions(+), 599 deletions(-) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 32298c0cf05..92ab18ab7d8 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -252,7 +252,7 @@ and IProjectReference = abstract FileName: string /// Evaluate raw contents of the assembly file generated by the project - abstract EvaluateRawContents: unit -> NodeCode + abstract EvaluateRawContents: unit -> Async /// Get the logical timestamp that would be the timestamp of the assembly file generated by the project /// diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index f59950f9e28..282e167bd1f 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -86,7 +86,7 @@ and IProjectReference = /// Evaluate raw contents of the assembly file generated by the project. /// 'None' may be returned if an in-memory view of the contents is, for some reason, /// not available. In this case the on-disk view of the contents will be preferred. - abstract EvaluateRawContents: unit -> NodeCode + abstract EvaluateRawContents: unit -> Async /// Get the logical timestamp that would be the timestamp of the assembly file generated by the project. /// diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 9bc5ea85516..cc32d0bf935 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2158,14 +2158,14 @@ and [] TcImports ( ctok, r: AssemblyResolution - ) : NodeCode<(_ * (unit -> AvailableImportedAssembly list)) option> = - node { + ) : Async<(_ * (unit -> AvailableImportedAssembly list)) option> = + async { CheckDisposed() let m = r.originalReference.Range let fileName = r.resolvedPath let! contentsOpt = - node { + async { match r.ProjectReference with | Some ilb -> return! ilb.EvaluateRawContents() | None -> return ProjectAssemblyDataResult.Unavailable true @@ -2228,21 +2228,21 @@ and [] TcImports // NOTE: When used in the Language Service this can cause the transitive checking of projects. Hence it must be cancellable. member tcImports.RegisterAndImportReferencedAssemblies(ctok, nms: AssemblyResolution list) = - node { + async { CheckDisposed() let tcConfig = tcConfigP.Get ctok let runMethod = match tcConfig.parallelReferenceResolution with - | ParallelReferenceResolution.On -> NodeCode.Parallel - | ParallelReferenceResolution.Off -> NodeCode.Sequential + | ParallelReferenceResolution.On -> Async.Parallel + | ParallelReferenceResolution.Off -> Async.Sequential let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger let! results = nms |> List.map (fun nm -> - node { + async { try return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) with e -> @@ -2284,7 +2284,7 @@ and [] TcImports ReportWarnings warns tcImports.RegisterAndImportReferencedAssemblies(ctok, res) - |> NodeCode.RunImmediateWithoutCancellation + |> Async.RunImmediateWithoutCancellation |> ignore true @@ -2385,7 +2385,7 @@ and [] TcImports // we dispose TcImports is because we need to dispose type providers, and type providers are never included in the framework DLL set. // If a framework set ever includes type providers, you will not have to worry about explicitly calling Dispose as the Finalizer will handle it. static member BuildFrameworkTcImports(tcConfigP: TcConfigProvider, frameworkDLLs, nonFrameworkDLLs) = - node { + async { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2462,7 +2462,7 @@ and [] TcImports resolvedAssemblies |> List.choose tryFindEquivPrimaryAssembly let! fslibCcu, fsharpCoreAssemblyScopeRef = - node { + async { if tcConfig.compilingFSharpCore then // When compiling FSharp.Core.dll, the fslibCcu reference to FSharp.Core.dll is a delayed ccu thunk fixed up during type checking return CcuThunk.CreateDelayed getFSharpCoreLibraryName, ILScopeRef.Local @@ -2555,7 +2555,7 @@ and [] TcImports dependencyProvider ) = - node { + async { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2573,7 +2573,7 @@ and [] TcImports } static member BuildTcImports(tcConfigP: TcConfigProvider, dependencyProvider) = - node { + async { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2605,7 +2605,7 @@ let RequireReferences (ctok, tcImports: TcImports, tcEnv, thisAssemblyName, reso let ccuinfos = tcImports.RegisterAndImportReferencedAssemblies(ctok, resolutions) - |> NodeCode.RunImmediateWithoutCancellation + |> Async.RunImmediateWithoutCancellation let asms = ccuinfos diff --git a/src/Compiler/Driver/CompilerImports.fsi b/src/Compiler/Driver/CompilerImports.fsi index ac06a25c2dc..9697e18968d 100644 --- a/src/Compiler/Driver/CompilerImports.fsi +++ b/src/Compiler/Driver/CompilerImports.fsi @@ -199,14 +199,14 @@ type TcImports = member internal Base: TcImports option static member BuildFrameworkTcImports: - TcConfigProvider * AssemblyResolution list * AssemblyResolution list -> NodeCode + TcConfigProvider * AssemblyResolution list * AssemblyResolution list -> Async static member BuildNonFrameworkTcImports: TcConfigProvider * TcImports * AssemblyResolution list * UnresolvedAssemblyReference list * DependencyProvider -> - NodeCode + Async static member BuildTcImports: - tcConfigP: TcConfigProvider * dependencyProvider: DependencyProvider -> NodeCode + tcConfigP: TcConfigProvider * dependencyProvider: DependencyProvider -> Async /// Process a group of #r in F# Interactive. /// Adds the reference to the tcImports and add the ccu to the type checking environment. diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 014ed840222..a09e748dff8 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -614,7 +614,7 @@ let main1 // Import basic assemblies let tcGlobals, frameworkTcImports = TcImports.BuildFrameworkTcImports(foundationalTcConfigP, sysRes, otherRes) - |> NodeCode.RunImmediateWithoutCancellation + |> Async.RunImmediateWithoutCancellation let ilSourceDocs = [ @@ -663,7 +663,7 @@ let main1 let tcImports = TcImports.BuildNonFrameworkTcImports(tcConfigP, frameworkTcImports, otherRes, knownUnresolved, dependencyProvider) - |> NodeCode.RunImmediateWithoutCancellation + |> Async.RunImmediateWithoutCancellation // register tcImports to be disposed in future disposables.Register tcImports diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs index b780d91ca74..0fa57dcd631 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fs +++ b/src/Compiler/Facilities/AsyncMemoize.fs @@ -50,11 +50,11 @@ type internal MemoizeReply<'TValue> = | New of CancellationToken | Existing of Task<'TValue> -type internal MemoizeRequest<'TValue> = GetOrCompute of NodeCode<'TValue> * CancellationToken +type internal MemoizeRequest<'TValue> = GetOrCompute of Async<'TValue> * CancellationToken [] type internal Job<'TValue> = - | Running of TaskCompletionSource<'TValue> * CancellationTokenSource * NodeCode<'TValue> * DateTime * ResizeArray + | Running of TaskCompletionSource<'TValue> * CancellationTokenSource * Async<'TValue> * DateTime * ResizeArray | Completed of 'TValue * (PhasedDiagnostic * FSharpDiagnosticSeverity) list | Canceled of DateTime | Failed of DateTime * exn // TODO: probably we don't need to keep this @@ -358,7 +358,7 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T DiagnosticsThreadStatics.DiagnosticsLogger <- cachingLogger try - let! result = computation |> Async.AwaitNodeCode + let! result = computation post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) return () finally @@ -481,14 +481,14 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T Version = key.GetVersion() } - node { - let! ct = NodeCode.CancellationToken + async { + let! ct = Async.CancellationToken let callerDiagnosticLogger = DiagnosticsThreadStatics.DiagnosticsLogger match! processRequest post (key, GetOrCompute(computation, ct)) callerDiagnosticLogger - |> NodeCode.AwaitTask + |> Async.AwaitTask with | New internalCt -> @@ -506,7 +506,7 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T log (Started, key) try - let! result = computation |> Async.AwaitNodeCode + let! result = computation post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) return result finally @@ -514,7 +514,7 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T }, cancellationToken = linkedCtSource.Token ) - |> NodeCode.AwaitTask + |> Async.AwaitTask with | TaskCancelled ex -> // TODO: do we need to do anything else here? Presumably it should be done by the registration on @@ -530,7 +530,7 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T post (key, (JobFailed(ex, cachingLogger.CapturedDiagnostics))) return raise ex - | Existing job -> return! job |> NodeCode.AwaitTask + | Existing job -> return! job |> Async.AwaitTask } diff --git a/src/Compiler/Facilities/AsyncMemoize.fsi b/src/Compiler/Facilities/AsyncMemoize.fsi index a34588e7af8..6ffc787d148 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fsi +++ b/src/Compiler/Facilities/AsyncMemoize.fsi @@ -65,9 +65,9 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T member Clear: predicate: ('TKey -> bool) -> unit - member Get: key: ICacheKey<'TKey, 'TVersion> * computation: NodeCode<'TValue> -> NodeCode<'TValue> + member Get: key: ICacheKey<'TKey, 'TVersion> * computation: Async<'TValue> -> Async<'TValue> - member Get': key: 'TKey * computation: NodeCode<'TValue> -> NodeCode<'TValue> + member Get': key: 'TKey * computation: Async<'TValue> -> Async<'TValue> member Event: IEvent diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index 7d8b0ee410a..ea1dbe20047 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -5,210 +5,18 @@ module FSharp.Compiler.BuildGraph open System open System.Threading open System.Threading.Tasks -open System.Diagnostics open System.Globalization -//open FSharp.Compiler.DiagnosticsLogger open Internal.Utilities.Library -[] -type NodeCode<'T> = Node of Async<'T> - -let wrapThreadStaticInfo computation = - async { - //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - //let phase = DiagnosticsThreadStatics.BuildPhase - - try - return! computation - finally - //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - //DiagnosticsThreadStatics.BuildPhase <- phase - () - } - -type Async<'T> with - - static member AwaitNodeCode(node: NodeCode<'T>) = - match node with - | Node(computation) -> wrapThreadStaticInfo computation - -[] -type NodeCodeBuilder() = - - static let zero = Node(async.Zero()) - - [] - member _.Zero() : NodeCode = zero - - [] - member _.Delay(f: unit -> NodeCode<'T>) = - Node( - async.Delay(fun () -> - match f () with - | Node(p) -> p) - ) - - [] - member _.Return value = Node(async.Return(value)) - - [] - member _.ReturnFrom(computation: NodeCode<_>) = computation - - [] - member _.Bind(Node(p): NodeCode<'a>, binder: 'a -> NodeCode<'b>) : NodeCode<'b> = - Node( - async.Bind( - p, - fun x -> - match binder x with - | Node p -> p - ) - ) - - [] - member _.TryWith(Node(p): NodeCode<'T>, binder: exn -> NodeCode<'T>) : NodeCode<'T> = - Node( - async.TryWith( - p, - fun ex -> - match binder ex with - | Node p -> p - ) - ) - - [] - member _.TryFinally(Node(p): NodeCode<'T>, binder: unit -> unit) : NodeCode<'T> = Node(async.TryFinally(p, binder)) - - [] - member _.For(xs: 'T seq, binder: 'T -> NodeCode) : NodeCode = - Node( - async.For( - xs, - fun x -> - match binder x with - | Node p -> p - ) - ) - - [] - member _.Combine(Node(p1): NodeCode, Node(p2): NodeCode<'T>) : NodeCode<'T> = Node(async.Combine(p1, p2)) - - //[] - //member _.Using(value: CompilationGlobalsScope, binder: CompilationGlobalsScope -> NodeCode<'U>) = - // Node( - // async { - // DiagnosticsThreadStatics.DiagnosticsLogger <- value.DiagnosticsLogger - // DiagnosticsThreadStatics.BuildPhase <- value.BuildPhase - - // try - // return! binder value |> Async.AwaitNodeCode - // finally - // (value :> IDisposable).Dispose() - // } - // ) - - [] - member _.Using(value: IDisposable, binder: IDisposable -> NodeCode<'U>) = - Node( - async { - use _ = value - return! binder value |> Async.AwaitNodeCode - } - ) - -let node = NodeCodeBuilder() - [] -type NodeCode private () = - - static let cancellationToken = Node(wrapThreadStaticInfo Async.CancellationToken) - - static member RunImmediate(computation: NodeCode<'T>, ct: CancellationToken) = - //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - //let phase = DiagnosticsThreadStatics.BuildPhase - - try - try - let work = - async { - //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - //DiagnosticsThreadStatics.BuildPhase <- phase - return! computation |> Async.AwaitNodeCode - } - - Async.StartImmediateAsTask(work, cancellationToken = ct).Result - finally - //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - //DiagnosticsThreadStatics.BuildPhase <- phase - () - with :? AggregateException as ex when ex.InnerExceptions.Count = 1 -> - raise (ex.InnerExceptions[0]) - - static member RunImmediateWithoutCancellation(computation: NodeCode<'T>) = - NodeCode.RunImmediate(computation, CancellationToken.None) - - static member StartAsTask_ForTesting(computation: NodeCode<'T>, ?ct: CancellationToken) = - //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - //let phase = DiagnosticsThreadStatics.BuildPhase - - try - let work = - async { - //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - //DiagnosticsThreadStatics.BuildPhase <- phase - return! computation |> Async.AwaitNodeCode - } - - Async.StartAsTask(work, cancellationToken = defaultArg ct CancellationToken.None) - finally - //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - //DiagnosticsThreadStatics.BuildPhase <- phase - () - - static member CancellationToken = cancellationToken - - static member FromCancellable(computation: Cancellable<'T>) = - Node(wrapThreadStaticInfo (Cancellable.toAsync computation)) +type Async = + static member RunImmediateWithoutCancellation(computation) = + Async.RunImmediate(computation, CancellationToken.None) - static member AwaitAsync(computation: Async<'T>) = Node(wrapThreadStaticInfo computation) + static member FromCancellable(computation: Cancellable<'T>) = Cancellable.toAsync computation - static member AwaitTask(task: Task<'T>) = - Node(wrapThreadStaticInfo (Async.AwaitTask task)) - - static member AwaitTask(task: Task) = - Node(wrapThreadStaticInfo (Async.AwaitTask task)) - - static member AwaitWaitHandle_ForTesting(waitHandle: WaitHandle) = - Node(wrapThreadStaticInfo (Async.AwaitWaitHandle(waitHandle))) - - static member Sleep(ms: int) = - Node(wrapThreadStaticInfo (Async.Sleep(ms))) - - static member Sequential(computations: NodeCode<'T> seq) = - node { - let results = ResizeArray() - - for computation in computations do - let! res = computation - results.Add(res) - - return results.ToArray() - } - - static member Parallel(computations: NodeCode<'T> seq) = - //let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - //let phase = DiagnosticsThreadStatics.BuildPhase - - computations - |> Seq.map (fun (Node x) -> - async { - //DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - //DiagnosticsThreadStatics.BuildPhase <- phase - return! x - }) - |> Async.Parallel - |> wrapThreadStaticInfo - |> Node + static member StartAsTask_ForTesting(computation: Async<'T>, ?ct: CancellationToken) = + Async.StartAsTask(computation, cancellationToken = defaultArg ct CancellationToken.None) [] module GraphNode = @@ -229,13 +37,13 @@ module GraphNode = | None -> () [] -type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption<'T>, cachedResultNode: NodeCode<'T>) = +type GraphNode<'T> private (computation: Async<'T>, cachedResult: ValueOption<'T>, cachedResultNode: Async<'T>) = let mutable computation = computation let mutable requestCount = 0 let mutable cachedResult = cachedResult - let mutable cachedResultNode: NodeCode<'T> = cachedResultNode + let mutable cachedResultNode: Async<'T> = cachedResultNode let isCachedResultNodeNotNull () = not (obj.ReferenceEquals(cachedResultNode, null)) @@ -247,11 +55,11 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption if isCachedResultNodeNotNull () then cachedResultNode else - node { + async { Interlocked.Increment(&requestCount) |> ignore try - let! ct = NodeCode.CancellationToken + let! ct = Async.CancellationToken // We must set 'taken' before any implicit cancellation checks // occur, making sure we are under the protection of the 'try'. @@ -270,13 +78,13 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption ||| TaskContinuationOptions.NotOnFaulted ||| TaskContinuationOptions.ExecuteSynchronously) ) - |> NodeCode.AwaitTask + |> Async.AwaitTask match cachedResult with | ValueSome value -> return value | _ -> let tcs = TaskCompletionSource<'T>() - let (Node(p)) = computation + let p = computation Async.StartWithContinuations( async { @@ -285,7 +93,7 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption }, (fun res -> cachedResult <- ValueSome res - cachedResultNode <- node.Return res + cachedResultNode <- async.Return res computation <- Unchecked.defaultof<_> tcs.SetResult(res)), (fun ex -> tcs.SetException(ex)), @@ -293,7 +101,7 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption ct ) - return! tcs.Task |> NodeCode.AwaitTask + return! tcs.Task |> Async.AwaitTask finally if taken then semaphore.Release() |> ignore @@ -308,7 +116,7 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption member _.IsComputing = requestCount > 0 static member FromResult(result: 'T) = - let nodeResult = node.Return result + let nodeResult = async.Return result GraphNode(nodeResult, ValueSome result, nodeResult) new(computation) = GraphNode(computation, ValueNone, Unchecked.defaultof<_>) diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index 3008e2f283e..0265bb54092 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -2,89 +2,24 @@ module internal FSharp.Compiler.BuildGraph -open System -open System.Diagnostics open System.Threading open System.Threading.Tasks -open FSharp.Compiler.DiagnosticsLogger open Internal.Utilities.Library -/// Represents code that can be run as part of the build graph. -/// -/// This is essentially cancellable async code where the only asynchronous waits are on nodes. -/// When a node is evaluated the evaluation is run synchronously on the thread of the -/// first requestor. -[] -type NodeCode<'T> - -type Async<'T> with - - /// Asynchronously await code in the build graph - static member AwaitNodeCode: node: NodeCode<'T> -> Async<'T> - -/// A standard builder for node code. -[] -type NodeCodeBuilder = - - member Bind: NodeCode<'T> * ('T -> NodeCode<'U>) -> NodeCode<'U> - - member Zero: unit -> NodeCode - - member Delay: (unit -> NodeCode<'T>) -> NodeCode<'T> - - member Return: 'T -> NodeCode<'T> - - member ReturnFrom: NodeCode<'T> -> NodeCode<'T> - - member TryWith: NodeCode<'T> * (exn -> NodeCode<'T>) -> NodeCode<'T> - - member TryFinally: NodeCode<'T> * (unit -> unit) -> NodeCode<'T> - - member For: xs: 'T seq * binder: ('T -> NodeCode) -> NodeCode - - member Combine: x1: NodeCode * x2: NodeCode<'T> -> NodeCode<'T> - - ///// A limited form 'use' for establishing the compilation globals. - //member Using: CompilationGlobalsScope * (CompilationGlobalsScope -> NodeCode<'T>) -> NodeCode<'T> - - /// A generic 'use' that disposes of the IDisposable at the end of the computation. - member Using: IDisposable * (IDisposable -> NodeCode<'T>) -> NodeCode<'T> - -/// Specifies code that can be run as part of the build graph. -val node: NodeCodeBuilder - /// Contains helpers to specify code that can be run as part of the build graph. [] -type NodeCode = - - /// Only used for testing, do not use - static member RunImmediate: computation: NodeCode<'T> * ct: CancellationToken -> 'T +type Async = /// Used in places where we don't care about cancellation, e.g. the command line compiler /// and F# Interactive - static member RunImmediateWithoutCancellation: computation: NodeCode<'T> -> 'T - - static member CancellationToken: NodeCode - - static member Sequential: computations: NodeCode<'T> seq -> NodeCode<'T[]> - - 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 + static member RunImmediateWithoutCancellation: computation: Async<'T> -> 'T /// Execute the cancellable computation synchronously using the ambient cancellation token of /// the NodeCode. - static member FromCancellable: computation: Cancellable<'T> -> NodeCode<'T> - - /// Only used for testing, do not use - static member StartAsTask_ForTesting: computation: NodeCode<'T> * ?ct: CancellationToken -> Task<'T> + static member FromCancellable: computation: Cancellable<'T> -> Async<'T> /// Only used for testing, do not use - static member AwaitWaitHandle_ForTesting: waitHandle: WaitHandle -> NodeCode + static member StartAsTask_ForTesting: computation: Async<'T> * ?ct: CancellationToken -> Task<'T> /// Contains helpers related to the build graph [] @@ -102,7 +37,7 @@ module internal GraphNode = type internal GraphNode<'T> = /// - computation - The computation code to run. - new: computation: NodeCode<'T> -> GraphNode<'T> + new: computation: Async<'T> -> GraphNode<'T> /// Creates a GraphNode with given result already cached. static member FromResult: 'T -> GraphNode<'T> @@ -110,7 +45,7 @@ type internal GraphNode<'T> = /// Return NodeCode which, when executed, will get the value of the computation if already computed, or /// await an existing in-progress computation for the node if one exists, or else will synchronously /// start the computation on the current thread. - member GetOrComputeValue: unit -> NodeCode<'T> + member GetOrComputeValue: unit -> Async<'T> /// Return 'Some' if the computation has already been computed, else None if /// the computation is in-progress or has not yet been started. diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index e5ff5b6c754..310c7b07aff 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -4594,7 +4594,7 @@ type FsiEvaluationSession let tcConfig = tcConfigP.Get(ctokStartup) checker.FrameworkImportsCache.Get tcConfig - |> NodeCode.RunImmediateWithoutCancellation + |> Async.RunImmediateWithoutCancellation with e -> stopProcessingRecovery e range0 failwithf "Error creating evaluation session: %A" e @@ -4608,7 +4608,7 @@ type FsiEvaluationSession unresolvedReferences, fsiOptions.DependencyProvider ) - |> NodeCode.RunImmediateWithoutCancellation + |> Async.RunImmediateWithoutCancellation with e -> stopProcessingRecovery e range0 failwithf "Error creating evaluation session: %A" e diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index f9f952dde70..8851adbc885 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -57,7 +57,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async /// Type-check the result obtained by parsing, but only if the antecedent type checking context is available. abstract member CheckFileInProjectAllowingStaleCachedResults: @@ -67,7 +67,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async abstract member ClearCache: options: seq * userOpName: string -> unit @@ -83,31 +83,31 @@ type internal IBackgroundCompiler = symbol: FSharp.Compiler.Symbols.FSharpSymbol * canInvalidateProject: bool * userOpName: string -> - NodeCode> + Async> abstract member FindReferencesInFile: fileName: string * projectSnapshot: FSharpProjectSnapshot * symbol: FSharp.Compiler.Symbols.FSharpSymbol * userOpName: string -> - NodeCode> + Async> abstract member GetAssemblyData: options: FSharpProjectOptions * outputFileName: string * userOpName: string -> - NodeCode + Async abstract member GetAssemblyData: projectSnapshot: FSharpProjectSnapshot * outputFileName: string * userOpName: string -> - NodeCode + Async /// 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 + fileName: string * options: FSharpProjectOptions * userOpName: string -> Async /// 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 + fileName: string * options: FSharpProjectOptions * userOpName: string -> Async abstract member GetCachedCheckFileResult: builder: IncrementalBuilder * fileName: string * sourceText: ISourceText * options: FSharpProjectOptions -> - NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> + Async<(FSharpParseFileResults * FSharpCheckFileResults) option> abstract member GetProjectOptionsFromScript: fileName: string * @@ -125,31 +125,31 @@ type internal IBackgroundCompiler = abstract member GetSemanticClassificationForFile: fileName: string * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async abstract member GetSemanticClassificationForFile: fileName: string * snapshot: FSharpProjectSnapshot * userOpName: string -> - NodeCode + Async abstract member InvalidateConfiguration: options: FSharpProjectOptions * userOpName: string -> unit - abstract member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode + abstract member NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> Async 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 + Async abstract member ParseAndCheckFileInProject: fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> - NodeCode + Async /// Parse and typecheck the whole project. - abstract member ParseAndCheckProject: options: FSharpProjectOptions * userOpName: string -> NodeCode + abstract member ParseAndCheckProject: options: FSharpProjectOptions * userOpName: string -> Async - abstract member ParseAndCheckProject: projectSnapshot: FSharpProjectSnapshot * userOpName: string -> NodeCode + abstract member ParseAndCheckProject: projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async abstract member ParseFile: fileName: string * sourceText: ISourceText * options: FSharpParsingOptions * cache: bool * flatErrors: bool * userOpName: string -> @@ -294,7 +294,7 @@ type internal BackgroundCompiler then { new IProjectReference with member x.EvaluateRawContents() = - node { + async { Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm) return! self.GetAssemblyData(opts, userOpName + ".CheckReferencedProject(" + nm + ")") } @@ -308,8 +308,8 @@ type internal BackgroundCompiler | FSharpReferencedProject.PEReference(getStamp, delayedReader) -> { new IProjectReference with member x.EvaluateRawContents() = - node { - let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> NodeCode.FromCancellable + async { + let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> Async.FromCancellable match ilReaderOpt with | Some ilReader -> @@ -335,7 +335,7 @@ type internal BackgroundCompiler let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> NodeCode.FromCancellable + |> Async.FromCancellable member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm @@ -345,7 +345,7 @@ type internal BackgroundCompiler /// 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 { + async { use _ = Activity.start "BackgroundCompiler.CreateOneIncrementalBuilder" [| Activity.Tags.project, options.ProjectFileName |] @@ -452,14 +452,14 @@ type internal BackgroundCompiler let tryGetBuilderNode options = incrementalBuildersCache.TryGet(AnyCallerThread, options) - let tryGetBuilder options : NodeCode option = + let tryGetBuilder options : Async option = tryGetBuilderNode options |> Option.map (fun x -> x.GetOrComputeValue()) - let tryGetSimilarBuilder options : NodeCode option = + let tryGetSimilarBuilder options : Async option = incrementalBuildersCache.TryGetSimilar(AnyCallerThread, options) |> Option.map (fun x -> x.GetOrComputeValue()) - let tryGetAnyBuilder options : NodeCode option = + let tryGetAnyBuilder options : Async option = incrementalBuildersCache.TryGetAny(AnyCallerThread, options) |> Option.map (fun x -> x.GetOrComputeValue()) @@ -473,16 +473,16 @@ type internal BackgroundCompiler getBuilderNode) let createAndGetBuilder (options, userOpName) = - node { - let! ct = NodeCode.CancellationToken + async { + let! ct = Async.CancellationToken let getBuilderNode = createBuilderNode (options, userOpName, ct) return! getBuilderNode.GetOrComputeValue() } - let getOrCreateBuilder (options, userOpName) : NodeCode = + let getOrCreateBuilder (options, userOpName) : Async = match tryGetBuilder options with | Some getBuilder -> - node { + async { match! getBuilder with | builderOpt, creationDiags when builderOpt.IsNone || not builderOpt.Value.IsReferencesInvalidated -> return builderOpt, creationDiags @@ -534,7 +534,7 @@ type internal BackgroundCompiler | _ -> let res = GraphNode( - node { + async { let! res = self.CheckOneFileImplAux( parseResults, @@ -620,7 +620,7 @@ type internal BackgroundCompiler /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API) member _.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) = - node { + async { use _ = Activity.start "BackgroundCompiler.GetBackgroundParseResultsForFileInProject" @@ -660,7 +660,7 @@ type internal BackgroundCompiler } member _.GetCachedCheckFileResult(builder: IncrementalBuilder, fileName, sourceText: ISourceText, options) = - node { + async { use _ = Activity.start "BackgroundCompiler.GetCachedCheckFileResult" [| Activity.Tags.fileName, fileName |] @@ -697,9 +697,9 @@ type internal BackgroundCompiler tcPrior: PartialCheckResults, tcInfo: TcInfo, creationDiags: FSharpDiagnostic[] - ) : NodeCode = + ) : Async = - node { + async { // Get additional script #load closure information if applicable. // For scripts, this will have been recorded by GetProjectOptionsFromScript. let tcConfig = tcPrior.TcConfig @@ -727,7 +727,7 @@ type internal BackgroundCompiler keepAssemblyContents, suggestNamesForErrors ) - |> NodeCode.FromCancellable + |> Async.FromCancellable GraphNode.SetPreferredUILang tcConfig.preferredUiLang return (parseResults, checkAnswer, sourceText.GetHashCode() |> int64, tcPrior.ProjectTimeStamp) @@ -746,7 +746,7 @@ type internal BackgroundCompiler creationDiags: FSharpDiagnostic[] ) = - node { + async { match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with | Some(_, results) -> return FSharpCheckFileAnswer.Succeeded results | _ -> @@ -767,7 +767,7 @@ type internal BackgroundCompiler options, userOpName ) = - node { + async { use _ = Activity.start "BackgroundCompiler.CheckFileInProjectAllowingStaleCachedResults" @@ -778,7 +778,7 @@ type internal BackgroundCompiler |] let! cachedResults = - node { + async { let! builderOpt, creationDiags = getAnyBuilder (options, userOpName) match builderOpt with @@ -827,7 +827,7 @@ type internal BackgroundCompiler options, userOpName ) = - node { + async { use _ = Activity.start "BackgroundCompiler.CheckFileInProject" @@ -875,7 +875,7 @@ type internal BackgroundCompiler options: FSharpProjectOptions, userOpName ) = - node { + async { use _ = Activity.start "BackgroundCompiler.ParseAndCheckFileInProject" @@ -910,7 +910,7 @@ type internal BackgroundCompiler ) GraphNode.SetPreferredUILang tcPrior.TcConfig.preferredUiLang - let! ct = NodeCode.CancellationToken + let! ct = Async.CancellationToken let parseDiagnostics, parseTree, anyErrors = ParseAndCheckFile.parseFile ( @@ -944,7 +944,7 @@ type internal BackgroundCompiler } member _.NotifyFileChanged(fileName, options, userOpName) = - node { + async { use _ = Activity.start "BackgroundCompiler.NotifyFileChanged" @@ -963,7 +963,7 @@ type internal BackgroundCompiler /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API) member _.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) = - node { + async { use _ = Activity.start "BackgroundCompiler.ParseAndCheckFileInProject" @@ -1075,7 +1075,7 @@ type internal BackgroundCompiler canInvalidateProject: bool, userOpName: string ) = - node { + async { use _ = Activity.start "BackgroundCompiler.FindReferencesInFile" @@ -1103,7 +1103,7 @@ type internal BackgroundCompiler } member _.GetSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, userOpName: string) = - node { + async { use _ = Activity.start "BackgroundCompiler.GetSemanticClassificationForFile" @@ -1160,7 +1160,7 @@ type internal BackgroundCompiler /// Parse and typecheck the whole project (the implementation, called recursively as project graph is evaluated) member private _.ParseAndCheckProjectImpl(options, userOpName) = - node { + async { let! builderOpt, creationDiags = getOrCreateBuilder (options, userOpName) @@ -1233,7 +1233,7 @@ type internal BackgroundCompiler } member _.GetAssemblyData(options, userOpName) = - node { + async { use _ = Activity.start "BackgroundCompiler.GetAssemblyData" @@ -1486,7 +1486,7 @@ type internal BackgroundCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.CheckFileInProject(parseResults, fileName, fileVersion, sourceText, options, userOpName) member _.CheckFileInProjectAllowingStaleCachedResults @@ -1497,7 +1497,7 @@ type internal BackgroundCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.CheckFileInProjectAllowingStaleCachedResults(parseResults, fileName, fileVersion, sourceText, options, userOpName) member _.ClearCache(options: seq, userOpName: string) : unit = self.ClearCache(options, userOpName) @@ -1516,7 +1516,7 @@ type internal BackgroundCompiler symbol: FSharpSymbol, canInvalidateProject: bool, userOpName: string - ) : NodeCode> = + ) : Async> = self.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName) member this.FindReferencesInFile(fileName, projectSnapshot, symbol, userOpName) = @@ -1524,12 +1524,7 @@ type internal BackgroundCompiler member _.FrameworkImportsCache: FrameworkImportsCache = self.FrameworkImportsCache - member _.GetAssemblyData - ( - options: FSharpProjectOptions, - _fileName: string, - userOpName: string - ) : NodeCode = + member _.GetAssemblyData(options: FSharpProjectOptions, _fileName: string, userOpName: string) : Async = self.GetAssemblyData(options, userOpName) member _.GetAssemblyData @@ -1537,7 +1532,7 @@ type internal BackgroundCompiler projectSnapshot: FSharpProjectSnapshot, _fileName: string, userOpName: string - ) : NodeCode = + ) : Async = self.GetAssemblyData(projectSnapshot.ToOptions(), userOpName) member _.GetBackgroundCheckResultsForFileInProject @@ -1545,7 +1540,7 @@ type internal BackgroundCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) member _.GetBackgroundParseResultsForFileInProject @@ -1553,7 +1548,7 @@ type internal BackgroundCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) member _.GetCachedCheckFileResult @@ -1562,7 +1557,7 @@ type internal BackgroundCompiler fileName: string, sourceText: ISourceText, options: FSharpProjectOptions - ) : NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> = + ) : Async<(FSharpParseFileResults * FSharpCheckFileResults) option> = self.GetCachedCheckFileResult(builder, fileName, sourceText, options) member _.GetProjectOptionsFromScript @@ -1598,7 +1593,7 @@ type internal BackgroundCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.GetSemanticClassificationForFile(fileName, options, userOpName) member _.GetSemanticClassificationForFile @@ -1606,13 +1601,13 @@ type internal BackgroundCompiler fileName: string, snapshot: FSharpProjectSnapshot, userOpName: string - ) : NodeCode = + ) : Async = self.GetSemanticClassificationForFile(fileName, snapshot.ToOptions(), userOpName) member _.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string) : unit = self.InvalidateConfiguration(options, userOpName) - member _.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : NodeCode = + member _.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : Async = self.NotifyFileChanged(fileName, options, userOpName) member _.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async = @@ -1625,7 +1620,7 @@ type internal BackgroundCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName) member _.ParseAndCheckFileInProject @@ -1633,22 +1628,22 @@ type internal BackgroundCompiler fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string - ) : NodeCode = - node { + ) : Async = + async { let fileSnapshot = projectSnapshot.ProjectSnapshot.SourceFiles |> Seq.find (fun f -> f.FileName = fileName) - let! sourceText = fileSnapshot.GetSource() |> NodeCode.AwaitTask + let! sourceText = fileSnapshot.GetSource() |> Async.AwaitTask let options = projectSnapshot.ToOptions() return! self.ParseAndCheckFileInProject(fileName, 0, sourceText, options, userOpName) } - member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode = + member _.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : Async = self.ParseAndCheckProject(options, userOpName) - member _.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : NodeCode = + member _.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : Async = self.ParseAndCheckProject(projectSnapshot.ToOptions(), userOpName) member _.ParseFile @@ -1666,7 +1661,6 @@ type internal BackgroundCompiler let options = projectSnapshot.ToOptions() self.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) - |> Async.AwaitNodeCode member _.ProjectChecked: IEvent = self.ProjectChecked diff --git a/src/Compiler/Service/BackgroundCompiler.fsi b/src/Compiler/Service/BackgroundCompiler.fsi index f3bf3c96ccc..4fa73fc3b61 100644 --- a/src/Compiler/Service/BackgroundCompiler.fsi +++ b/src/Compiler/Service/BackgroundCompiler.fsi @@ -32,7 +32,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async /// Type-check the result obtained by parsing, but only if the antecedent type checking context is available. abstract CheckFileInProjectAllowingStaleCachedResults: @@ -42,7 +42,7 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async abstract ClearCache: options: FSharpProjectOptions seq * userOpName: string -> unit @@ -57,7 +57,7 @@ type internal IBackgroundCompiler = projectSnapshot: FSharpProjectSnapshot * symbol: FSharp.Compiler.Symbols.FSharpSymbol * userOpName: string -> - NodeCode + Async abstract FindReferencesInFile: fileName: string * @@ -65,28 +65,27 @@ type internal IBackgroundCompiler = symbol: FSharp.Compiler.Symbols.FSharpSymbol * canInvalidateProject: bool * userOpName: string -> - NodeCode + Async abstract GetAssemblyData: projectSnapshot: FSharpProjectSnapshot * outputFileName: string * userOpName: string -> - NodeCode + Async abstract GetAssemblyData: - options: FSharpProjectOptions * outputFileName: string * userOpName: string -> - NodeCode + options: FSharpProjectOptions * outputFileName: string * userOpName: string -> Async /// Fetch the check information from the background compiler (which checks w.r.t. the FileSystem API) abstract GetBackgroundCheckResultsForFileInProject: fileName: string * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async /// Fetch the parse information from the background compiler (which checks w.r.t. the FileSystem API) abstract GetBackgroundParseResultsForFileInProject: - fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode + fileName: string * options: FSharpProjectOptions * userOpName: string -> Async abstract GetCachedCheckFileResult: builder: IncrementalBuilder * fileName: string * sourceText: ISourceText * options: FSharpProjectOptions -> - NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> + Async<(FSharpParseFileResults * FSharpCheckFileResults) option> abstract GetProjectOptionsFromScript: fileName: string * @@ -104,21 +103,21 @@ type internal IBackgroundCompiler = abstract GetSemanticClassificationForFile: fileName: string * snapshot: FSharpProjectSnapshot * userOpName: string -> - NodeCode + Async abstract GetSemanticClassificationForFile: fileName: string * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async abstract InvalidateConfiguration: options: FSharpProjectOptions * userOpName: string -> unit - abstract NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> NodeCode + abstract NotifyFileChanged: fileName: string * options: FSharpProjectOptions * userOpName: string -> Async abstract NotifyProjectCleaned: options: FSharpProjectOptions * userOpName: string -> Async abstract ParseAndCheckFileInProject: fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> - NodeCode + Async /// Parses and checks the source file and returns untyped AST and check results. abstract ParseAndCheckFileInProject: @@ -127,14 +126,14 @@ type internal IBackgroundCompiler = sourceText: ISourceText * options: FSharpProjectOptions * userOpName: string -> - NodeCode + Async abstract ParseAndCheckProject: - projectSnapshot: FSharpProjectSnapshot * userOpName: string -> NodeCode + projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async /// Parse and typecheck the whole project. abstract ParseAndCheckProject: - options: FSharpProjectOptions * userOpName: string -> NodeCode + options: FSharpProjectOptions * userOpName: string -> Async abstract ParseFile: fileName: string * projectSnapshot: FSharpProjectSnapshot * userOpName: string -> Async diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index f59a1e9b6a5..b6f643158d2 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -136,7 +136,7 @@ module IncrementalBuildSyntaxTree = ), sourceRange, fileName, [||] let parse (source: FSharpSource) = - node { + async { IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBEParsed fileName) use _ = Activity.start "IncrementalBuildSyntaxTree.parse" @@ -149,9 +149,9 @@ module IncrementalBuildSyntaxTree = let diagnosticsLogger = CompilationDiagnosticLogger("Parse", tcConfig.diagnosticsOptions) // Return the disposable object that cleans up use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse) - use! text = source.GetTextContainer() |> NodeCode.AwaitAsync + use! text = source.GetTextContainer() let input = - match text :?> TextContainer with + match text with | TextContainer.Stream(stream) -> ParseOneInputStream(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, false, stream) | TextContainer.SourceText(sourceText) -> @@ -252,8 +252,8 @@ type BoundModel private ( ?tcStateOpt: GraphNode * GraphNode ) = - let getTypeCheck (syntaxTree: SyntaxTree) : NodeCode = - node { + let getTypeCheck (syntaxTree: SyntaxTree) : Async = + async { let! input, _sourceRange, fileName, parseErrors = syntaxTree.ParseNode.GetOrComputeValue() use _ = Activity.start "BoundModel.TypeCheck" [|Activity.Tags.fileName, fileName|] @@ -277,7 +277,7 @@ type BoundModel private ( None, TcResultsSink.WithSink sink, prevTcInfo.tcState, input ) - |> NodeCode.FromCancellable + |> Async.FromCancellable fileChecked.Trigger fileName @@ -322,13 +322,13 @@ type BoundModel private ( | _ -> None let getTcInfo (typeCheck: GraphNode) = - node { + async { let! tcInfo , _, _, _, _ = typeCheck.GetOrComputeValue() return tcInfo } |> GraphNode let getTcInfoExtras (typeCheck: GraphNode) = - node { + async { let! _ , sink, implFile, fileName, _ = typeCheck.GetOrComputeValue() // Build symbol keys let itemKeyStore, semanticClassification = @@ -366,17 +366,17 @@ type BoundModel private ( } } |> GraphNode - let defaultTypeCheck = node { return prevTcInfo, TcResultsSinkImpl(tcGlobals), None, "default typecheck - no syntaxTree", [||] } + let defaultTypeCheck = async { return prevTcInfo, TcResultsSinkImpl(tcGlobals), None, "default typecheck - no syntaxTree", [||] } let typeCheckNode = syntaxTreeOpt |> Option.map getTypeCheck |> Option.defaultValue defaultTypeCheck |> GraphNode let tcInfoExtras = getTcInfoExtras typeCheckNode let diagnostics = - node { + async { let! _, _, _, _, diags = typeCheckNode.GetOrComputeValue() return diags } |> GraphNode let startComputingFullTypeCheck = - node { + async { let! _ = tcInfoExtras.GetOrComputeValue() return! diagnostics.GetOrComputeValue() } @@ -391,7 +391,7 @@ type BoundModel private ( GraphNode.FromResult tcInfo, tcInfoExtras | _ -> // start computing extras, so that typeCheckNode can be GC'd quickly - startComputingFullTypeCheck |> Async.AwaitNodeCode |> Async.Catch |> Async.Ignore |> Async.Start + startComputingFullTypeCheck |> Async.Catch |> Async.Ignore |> Async.Start getTcInfo typeCheckNode, tcInfoExtras member val Diagnostics = diagnostics @@ -417,13 +417,13 @@ type BoundModel private ( member this.GetOrComputeTcInfoExtras = this.TcInfoExtras.GetOrComputeValue - member this.GetOrComputeTcInfoWithExtras() = node { + member this.GetOrComputeTcInfoWithExtras() = async { let! tcInfo = this.TcInfo.GetOrComputeValue() let! tcInfoExtras = this.TcInfoExtras.GetOrComputeValue() return tcInfo, tcInfoExtras } - member this.Next(syntaxTree) = node { + member this.Next(syntaxTree) = async { let! tcInfo = this.TcInfo.GetOrComputeValue() return BoundModel( @@ -442,7 +442,7 @@ type BoundModel private ( } member this.Finish(finalTcDiagnosticsRev, finalTopAttribs) = - node { + async { let! tcInfo = this.TcInfo.GetOrComputeValue() let finishState = { tcInfo with tcDiagnosticsRev = finalTcDiagnosticsRev; topAttribs = finalTopAttribs } return @@ -536,7 +536,7 @@ type FrameworkImportsCache(size) = match frameworkTcImportsCache.TryGet (AnyCallerThread, key) with | Some lazyWork -> lazyWork | None -> - let lazyWork = GraphNode(node { + let lazyWork = GraphNode(async { let tcConfigP = TcConfigProvider.Constant tcConfig return! TcImports.BuildFrameworkTcImports (tcConfigP, frameworkDLLs, nonFrameworkResolutions) }) @@ -548,7 +548,7 @@ type FrameworkImportsCache(size) = /// This function strips the "System" assemblies from the tcConfig and returns a age-cached TcImports for them. member this.Get(tcConfig: TcConfig) = - node { + async { // Split into installed and not installed. let frameworkDLLs, nonFrameworkResolutions, unresolved = TcAssemblyResolutions.SplitNonFoundationalResolutions(tcConfig) let node = this.GetNode(tcConfig, frameworkDLLs, nonFrameworkResolutions) @@ -579,13 +579,13 @@ type PartialCheckResults (boundModel: BoundModel, timeStamp: DateTime, projectTi member _.GetOrComputeTcInfoWithExtras() = boundModel.GetOrComputeTcInfoWithExtras() member _.GetOrComputeItemKeyStoreIfEnabled() = - node { + async { let! info = boundModel.GetOrComputeTcInfoExtras() return info.itemKeyStore } member _.GetOrComputeSemanticClassificationIfEnabled() = - node { + async { let! info = boundModel.GetOrComputeTcInfoExtras() return info.semanticClassificationKeyStore } @@ -658,14 +658,14 @@ module IncrementalBuilderHelpers = #if !NO_TYPEPROVIDERS ,importsInvalidatedByTypeProvider: Event #endif - ) : NodeCode = + ) : Async = - node { + async { let diagnosticsLogger = CompilationDiagnosticLogger("CombineImportedAssembliesTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter) let! tcImports = - node { + async { try let! tcImports = TcImports.BuildNonFrameworkTcImports(tcConfigP, frameworkTcImports, nonFrameworkResolutions, unresolvedReferences, dependencyProvider) #if !NO_TYPEPROVIDERS @@ -736,28 +736,28 @@ module IncrementalBuilderHelpers = /// Finish up the typechecking to produce outputs for the rest of the compilation process let FinalizeTypeCheckTask (tcConfig: TcConfig) tcGlobals partialCheck assemblyName outfile (boundModels: GraphNode seq) = - node { + async { let diagnosticsLogger = CompilationDiagnosticLogger("FinalizeTypeCheckTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck) - let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> NodeCode.Sequential + let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> Async.Sequential let! tcInfos = computedBoundModels - |> Seq.map (fun boundModel -> node { return! boundModel.GetOrComputeTcInfo() }) - |> NodeCode.Sequential + |> Seq.map (fun boundModel -> async { return! boundModel.GetOrComputeTcInfo() }) + |> Async.Sequential // tcInfoExtras can be computed in parallel. This will check any previously skipped implementation files in parallel, too. let! latestImplFiles = computedBoundModels - |> Seq.map (fun boundModel -> node { + |> Seq.map (fun boundModel -> async { if partialCheck then return None else let! tcInfoExtras = boundModel.GetOrComputeTcInfoExtras() return tcInfoExtras.latestImplFile }) - |> NodeCode.Parallel + |> Async.Parallel let results = [ for tcInfo, latestImplFile in Seq.zip tcInfos latestImplFiles -> @@ -826,7 +826,7 @@ module IncrementalBuilderHelpers = let! partialDiagnostics = computedBoundModels |> Seq.map (fun m -> m.Diagnostics.GetOrComputeValue()) - |> NodeCode.Parallel + |> Async.Parallel let diagnostics = [ diagnosticsLogger.GetDiagnostics() yield! partialDiagnostics |> Seq.rev @@ -949,13 +949,13 @@ module IncrementalBuilderStateHelpers = type BuildStatus = Invalidated | Good let createBoundModelGraphNode (prevBoundModel: GraphNode) syntaxTree = - GraphNode(node { + GraphNode(async { let! prevBoundModel = prevBoundModel.GetOrComputeValue() return! prevBoundModel.Next(syntaxTree) }) let createFinalizeBoundModelGraphNode (initialState: IncrementalBuilderInitialState) (boundModels: GraphNode seq) = - GraphNode(node { + GraphNode(async { use _ = Activity.start "GetCheckResultsAndImplementationsForProject" [|Activity.Tags.project, initialState.outfile|] let! result = FinalizeTypeCheckTask @@ -1123,7 +1123,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc tryGetSlot state (slot - 1) let evalUpToTargetSlot (state: IncrementalBuilderState) targetSlot = - node { + async { if targetSlot < 0 then return Some(initialBoundModel, defaultTimeStamp) else @@ -1155,8 +1155,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let mutable currentState = state let setCurrentState state cache (ct: CancellationToken) = - node { - do! semaphore.WaitAsync(ct) |> NodeCode.AwaitTask + async { + do! semaphore.WaitAsync(ct) |> Async.AwaitTask try ct.ThrowIfCancellationRequested() currentState <- computeStampedFileNames initialState state cache @@ -1165,8 +1165,8 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc } let checkFileTimeStamps (cache: TimeStampCache) = - node { - let! ct = NodeCode.CancellationToken + async { + let! ct = Async.CancellationToken do! setCurrentState currentState cache ct } @@ -1196,7 +1196,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc member _.AllDependenciesDeprecated = allDependencies member _.PopulatePartialCheckingResults () = - node { + async { let cache = TimeStampCache defaultTimeStamp // One per step do! checkFileTimeStamps cache let! _ = currentState.finalizedBoundModel.GetOrComputeValue() @@ -1238,7 +1238,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc (builder.TryGetCheckResultsBeforeFileInProject fileName).IsSome member builder.GetCheckResultsBeforeSlotInProject slotOfFile = - node { + async { let cache = TimeStampCache defaultTimeStamp do! checkFileTimeStamps cache let! result = evalUpToTargetSlot currentState (slotOfFile - 1) @@ -1250,7 +1250,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc } member builder.GetFullCheckResultsBeforeSlotInProject slotOfFile = - node { + async { let cache = TimeStampCache defaultTimeStamp do! checkFileTimeStamps cache let! result = evalUpToTargetSlot currentState (slotOfFile - 1) @@ -1275,7 +1275,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc builder.GetFullCheckResultsBeforeSlotInProject slotOfFile member builder.GetFullCheckResultsAfterFileInProject fileName = - node { + async { let slotOfFile = builder.GetSlotOfFileName fileName + 1 let! result = builder.GetFullCheckResultsBeforeSlotInProject(slotOfFile) return result @@ -1285,7 +1285,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc builder.GetCheckResultsBeforeSlotInProject(builder.GetSlotsCount()) member builder.GetCheckResultsAndImplementationsForProject() = - node { + async { let cache = TimeStampCache(defaultTimeStamp) do! checkFileTimeStamps cache let! result = currentState.finalizedBoundModel.GetOrComputeValue() @@ -1297,7 +1297,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc } member builder.GetFullCheckResultsAndImplementationsForProject() = - node { + async { let! result = builder.GetCheckResultsAndImplementationsForProject() let results, _, _, _ = result let! _ = results.GetOrComputeTcInfoWithExtras() // Make sure we forcefully evaluate the info @@ -1342,14 +1342,14 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let slotOfFile = builder.GetSlotOfFileName fileName let syntaxTree = currentState.slots[slotOfFile].SyntaxTree syntaxTree.ParseNode.GetOrComputeValue() - |> Async.AwaitNodeCode + |> Async.RunSynchronously member builder.NotifyFileChanged(fileName, timeStamp) = - node { + async { let slotOfFile = builder.GetSlotOfFileName fileName let cache = TimeStampCache defaultTimeStamp - let! ct = NodeCode.CancellationToken + let! ct = Async.CancellationToken do! setCurrentState { currentState with slots = currentState.slots |> List.updateAt slotOfFile (currentState.slots[slotOfFile].Notify timeStamp) } @@ -1388,14 +1388,14 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let useSimpleResolutionSwitch = "--simpleresolution" - node { + async { // Trap and report diagnostics from creation. let delayedLogger = CapturingDiagnosticsLogger("IncrementalBuilderCreation") use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter) let! builderOpt = - node { + async { try // Create the builder. diff --git a/src/Compiler/Service/IncrementalBuild.fsi b/src/Compiler/Service/IncrementalBuild.fsi index 0dedfb02948..0fd380631e4 100644 --- a/src/Compiler/Service/IncrementalBuild.fsi +++ b/src/Compiler/Service/IncrementalBuild.fsi @@ -38,7 +38,7 @@ type internal FrameworkImportsCacheKey = type internal FrameworkImportsCache = new: size: int -> FrameworkImportsCache - member Get: TcConfig -> NodeCode + member Get: TcConfig -> Async member Clear: unit -> unit @@ -121,25 +121,25 @@ type internal PartialCheckResults = /// Compute the "TcInfo" part of the results. If `enablePartialTypeChecking` is false then /// extras will also be available. - member GetOrComputeTcInfo: unit -> NodeCode + member GetOrComputeTcInfo: unit -> Async /// Compute both the "TcInfo" and "TcInfoExtras" parts of the results. /// Can cause a second type-check if `enablePartialTypeChecking` is true in the checker. /// Only use when it's absolutely necessary to get rich information on a file. - member GetOrComputeTcInfoWithExtras: unit -> NodeCode + member GetOrComputeTcInfoWithExtras: unit -> Async /// Compute the "ItemKeyStore" parts of the results. /// Can cause a second type-check if `enablePartialTypeChecking` is true in the checker. /// Only use when it's absolutely necessary to get rich information on a file. /// /// Will return 'None' for enableBackgroundItemKeyStoreAndSemanticClassification=false. - member GetOrComputeItemKeyStoreIfEnabled: unit -> NodeCode + member GetOrComputeItemKeyStoreIfEnabled: unit -> Async /// Can cause a second type-check if `enablePartialTypeChecking` is true in the checker. /// Only use when it's absolutely necessary to get rich information on a file. /// /// Will return 'None' for enableBackgroundItemKeyStoreAndSemanticClassification=false. - member GetOrComputeSemanticClassificationIfEnabled: unit -> NodeCode + member GetOrComputeSemanticClassificationIfEnabled: unit -> Async member TimeStamp: DateTime @@ -194,7 +194,7 @@ type internal IncrementalBuilder = member AllDependenciesDeprecated: string[] /// The project build. Return true if the background work is finished. - member PopulatePartialCheckingResults: unit -> NodeCode + member PopulatePartialCheckingResults: unit -> Async /// Get the preceding typecheck state of a slot, without checking if it is up-to-date w.r.t. /// the timestamps on files and referenced DLLs prior to this one. Return None if the result is not available. @@ -228,38 +228,36 @@ type internal IncrementalBuilder = /// Get the preceding typecheck state of a slot. Compute the entire type check of the project up /// to the necessary point if the result is not available. This may be a long-running operation. - member GetCheckResultsBeforeFileInProject: fileName: string -> NodeCode + member GetCheckResultsBeforeFileInProject: fileName: string -> Async /// Get the preceding typecheck state of a slot. Compute the entire type check of the project up /// to the necessary point if the result is not available. This may be a long-running operation. /// This will get full type-check info for the file, meaning no partial type-checking. - member GetFullCheckResultsBeforeFileInProject: fileName: string -> NodeCode + member GetFullCheckResultsBeforeFileInProject: fileName: string -> Async /// Get the typecheck state after checking a file. Compute the entire type check of the project up /// to the necessary point if the result is not available. This may be a long-running operation. - member GetCheckResultsAfterFileInProject: fileName: string -> NodeCode + member GetCheckResultsAfterFileInProject: fileName: string -> Async /// Get the typecheck state after checking a file. Compute the entire type check of the project up /// to the necessary point if the result is not available. This may be a long-running operation. /// This will get full type-check info for the file, meaning no partial type-checking. - member GetFullCheckResultsAfterFileInProject: fileName: string -> NodeCode + member GetFullCheckResultsAfterFileInProject: fileName: string -> Async /// Get the typecheck result after the end of the last file. The typecheck of the project is not 'completed'. /// This may be a long-running operation. - member GetCheckResultsAfterLastFileInProject: unit -> NodeCode + member GetCheckResultsAfterLastFileInProject: unit -> Async /// Get the final typecheck result. If 'generateTypedImplFiles' was set on Create then the CheckedAssemblyAfterOptimization will contain implementations. /// This may be a long-running operation. member GetCheckResultsAndImplementationsForProject: - unit -> - NodeCode + unit -> Async /// Get the final typecheck result. If 'generateTypedImplFiles' was set on Create then the CheckedAssemblyAfterOptimization will contain implementations. /// This may be a long-running operation. /// This will get full type-check info for the project, meaning no partial type-checking. member GetFullCheckResultsAndImplementationsForProject: - unit -> - NodeCode + unit -> Async /// Get the logical time stamp that is associated with the output of the project if it were fully built immediately member GetLogicalTimeStampForProject: TimeStampCache -> DateTime @@ -273,7 +271,7 @@ type internal IncrementalBuilder = member GetParseResultsForFile: fileName: string -> ParsedInput * range * string * (PhasedDiagnostic * FSharpDiagnosticSeverity)[] - member NotifyFileChanged: fileName: string * timeStamp: DateTime -> NodeCode + member NotifyFileChanged: fileName: string * timeStamp: DateTime -> Async /// Create the incremental builder static member TryCreateIncrementalBuilderForProjectOptions: @@ -299,7 +297,7 @@ type internal IncrementalBuilder = getSource: (string -> Async) option * useChangeNotifications: bool * useSyntaxTreeCache: bool -> - NodeCode + Async /// Generalized Incremental Builder. This is exposed only for unit testing purposes. module internal IncrementalBuild = diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 9f3881ecfd2..fdb4f6c6083 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -386,7 +386,7 @@ type internal TransparentCompiler caches.FrameworkImports.Get( key, - node { + async { use _ = Activity.start "ComputeFrameworkImports" [] let tcConfigP = TcConfigProvider.Constant tcConfig @@ -410,14 +410,14 @@ type internal TransparentCompiler importsInvalidatedByTypeProvider: Event ) = - node { + async { let diagnosticsLogger = CompilationDiagnosticLogger("CombineImportedAssembliesTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parameter) let! tcImports = - node { + async { try let! tcImports = TcImports.BuildNonFrameworkTcImports( @@ -522,7 +522,7 @@ type internal TransparentCompiler then { new IProjectReference with member x.EvaluateRawContents() = - node { + async { Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm) return! @@ -668,7 +668,7 @@ type internal TransparentCompiler caches.BootstrapInfoStatic.Get( projectSnapshot.CacheKeyWith("BootstrapInfoStatic", assemblyName), - node { + async { use _ = Activity.start "ComputeBootstrapInfoStatic" @@ -744,7 +744,7 @@ type internal TransparentCompiler ) let computeBootstrapInfoInner (projectSnapshot: ProjectSnapshot) = - node { + async { let tcConfigB, sourceFiles, loadClosureOpt = ComputeTcConfigBuilder projectSnapshot @@ -820,7 +820,7 @@ type internal TransparentCompiler caches.BootstrapInfo.Get( projectSnapshot.NoFileVersionsKey, - node { + async { use _ = Activity.start "ComputeBootstrapInfo" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |] @@ -829,7 +829,7 @@ type internal TransparentCompiler use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter) let! bootstrapInfoOpt = - node { + async { try return! computeBootstrapInfoInner projectSnapshot with exn -> @@ -862,8 +862,8 @@ type internal TransparentCompiler // TODO: Not sure if we should cache this. For VS probably not. Maybe it can be configurable by FCS user. let LoadSource (file: FSharpFileSnapshot) isExe isLastCompiland = - node { - let! source = file.GetSource() |> NodeCode.AwaitTask + async { + let! source = file.GetSource() |> Async.AwaitTask return FSharpFileSnapshotWithSource( @@ -876,13 +876,13 @@ type internal TransparentCompiler } let LoadSources (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshot) = - node { + async { let isExe = bootstrapInfo.TcConfig.target.IsExe let! sources = projectSnapshot.SourceFiles |> Seq.map (fun f -> LoadSource f isExe (f.FileName = bootstrapInfo.LastFileName)) - |> NodeCode.Parallel + |> Async.Parallel return ProjectSnapshotWithSources(projectSnapshot.ProjectCore, sources |> Array.toList) @@ -906,7 +906,7 @@ type internal TransparentCompiler caches.ParseFile.Get( key, - node { + async { use _ = Activity.start "ComputeParseFile" @@ -950,7 +950,7 @@ type internal TransparentCompiler |> Graph.make let computeDependencyGraph (tcConfig: TcConfig) parsedInputs (processGraph: Graph -> Graph) = - node { + async { let sourceFiles: FileInProject array = parsedInputs |> Seq.toArray @@ -1084,7 +1084,7 @@ type internal TransparentCompiler caches.TcIntermediate.Get( key, - node { + async { let file = projectSnapshot.SourceFiles[index] @@ -1175,7 +1175,6 @@ type internal TransparentCompiler input, true) |> Cancellable.toAsync - |> NodeCode.AwaitAsync //fileChecked.Trigger fileName @@ -1201,9 +1200,7 @@ type internal TransparentCompiler match fileNode with | NodeToTypeCheck.PhysicalFile index -> - let! tcIntermediate = - ComputeTcIntermediate projectSnapshot dependencyFiles index fileNode bootstrapInfo tcInfo - |> Async.AwaitNodeCode + let! tcIntermediate = ComputeTcIntermediate projectSnapshot dependencyFiles index fileNode bootstrapInfo tcInfo let (Finisher(node = node; finisher = finisher)) = tcIntermediate.finisher @@ -1302,11 +1299,11 @@ type internal TransparentCompiler } let parseSourceFiles (projectSnapshot: ProjectSnapshotWithSources) tcConfig = - node { + async { let! parsedInputs = projectSnapshot.SourceFiles |> Seq.map (ComputeParseFile projectSnapshot tcConfig) - |> NodeCode.Parallel + |> Async.Parallel return ProjectSnapshotBase<_>(projectSnapshot.ProjectCore, parsedInputs |> Array.toList) } @@ -1317,7 +1314,7 @@ type internal TransparentCompiler caches.TcLastFile.Get( projectSnapshot.FileKey fileName, - node { + async { let file = projectSnapshot.SourceFiles |> List.last use _ = @@ -1332,7 +1329,6 @@ type internal TransparentCompiler graph (processGraphNode projectSnapshot bootstrapInfo dependencyFiles false) bootstrapInfo.InitialTcInfo - |> NodeCode.AwaitAsync let lastResult = results |> List.head |> snd @@ -1341,7 +1337,7 @@ type internal TransparentCompiler ) let getParseResult (projectSnapshot: ProjectSnapshot) creationDiags file (tcConfig: TcConfig) = - node { + async { let! parsedFile = ComputeParseFile projectSnapshot tcConfig file let parseDiagnostics = @@ -1374,7 +1370,7 @@ type internal TransparentCompiler let ComputeParseAndCheckFileInProject (fileName: string) (projectSnapshot: ProjectSnapshot) = caches.ParseAndCheckFileInProject.Get( projectSnapshot.FileKey fileName, - node { + async { use _ = Activity.start "ComputeParseAndCheckFileInProject" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] @@ -1477,7 +1473,7 @@ type internal TransparentCompiler let ComputeParseAndCheckAllFilesInProject (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshotWithSources) = caches.ParseAndCheckAllFilesInProject.Get( projectSnapshot.FullKey, - node { + async { use _ = Activity.start "ComputeParseAndCheckAllFilesInProject" @@ -1492,14 +1488,14 @@ type internal TransparentCompiler graph (processGraphNode projectSnapshot bootstrapInfo dependencyFiles true) bootstrapInfo.InitialTcInfo - |> NodeCode.AwaitAsync + } ) let ComputeProjectExtras (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshotWithSources) = caches.ProjectExtras.Get( projectSnapshot.SignatureKey, - node { + async { let! results, finalInfo = ComputeParseAndCheckAllFilesInProject bootstrapInfo projectSnapshot @@ -1592,7 +1588,7 @@ type internal TransparentCompiler let ComputeAssemblyData (projectSnapshot: ProjectSnapshot) fileName = caches.AssemblyData.Get( projectSnapshot.SignatureKey, - node { + async { try @@ -1641,7 +1637,7 @@ type internal TransparentCompiler let ComputeParseAndCheckProject (projectSnapshot: ProjectSnapshot) = caches.ParseAndCheckProject.Get( projectSnapshot.FullKey, - node { + async { match! ComputeBootstrapInfo projectSnapshot with | None, creationDiags -> @@ -1714,7 +1710,7 @@ type internal TransparentCompiler ) let tryGetSink (fileName: string) (projectSnapshot: ProjectSnapshot) = - node { + async { match! ComputeBootstrapInfo projectSnapshot with | None, _ -> return None | Some bootstrapInfo, _creationDiags -> @@ -1729,7 +1725,7 @@ type internal TransparentCompiler let ComputeSemanticClassification (fileName: string, projectSnapshot: ProjectSnapshot) = caches.SemanticClassification.Get( projectSnapshot.FileKey fileName, - node { + async { use _ = Activity.start "ComputeSemanticClassification" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] @@ -1759,7 +1755,7 @@ type internal TransparentCompiler let ComputeItemKeyStore (fileName: string, projectSnapshot: ProjectSnapshot) = caches.ItemKeyStore.Get( projectSnapshot.FileKey fileName, - node { + async { use _ = Activity.start "ComputeItemKeyStore" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] @@ -1794,7 +1790,7 @@ type internal TransparentCompiler ) member _.ParseFile(fileName, projectSnapshot: ProjectSnapshot, _userOpName) = - node { + async { //use _ = // Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] @@ -1824,7 +1820,7 @@ type internal TransparentCompiler member _.FindReferencesInFile(fileName: string, projectSnapshot: ProjectSnapshot, symbol: FSharpSymbol, userOpName: string) = ignore userOpName - node { + async { match! ComputeItemKeyStore(fileName, projectSnapshot) with | None -> return Seq.empty | Some itemKeyStore -> return itemKeyStore.FindAll symbol.Item @@ -1849,11 +1845,9 @@ type internal TransparentCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = - node { - let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) - |> NodeCode.AwaitAsync + ) : Async = + async { + let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) ignore parseResults @@ -1870,11 +1864,9 @@ type internal TransparentCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = - node { - let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) - |> NodeCode.AwaitAsync + ) : Async = + async { + let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) ignore parseResults @@ -1922,10 +1914,10 @@ type internal TransparentCompiler symbol: FSharpSymbol, canInvalidateProject: bool, userOpName: string - ) : NodeCode> = - node { + ) : Async> = + async { ignore canInvalidateProject - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + let! snapshot = FSharpProjectSnapshot.FromOptions options return! this.FindReferencesInFile(fileName, snapshot.ProjectSnapshot, symbol, userOpName) } @@ -1936,9 +1928,9 @@ type internal TransparentCompiler member _.FrameworkImportsCache: FrameworkImportsCache = backgroundCompiler.FrameworkImportsCache - member this.GetAssemblyData(options: FSharpProjectOptions, fileName, userOpName: string) : NodeCode = - node { - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + member this.GetAssemblyData(options: FSharpProjectOptions, fileName, userOpName: string) : Async = + async { + let! snapshot = FSharpProjectSnapshot.FromOptions options return! this.GetAssemblyData(snapshot.ProjectSnapshot, fileName, userOpName) } @@ -1947,7 +1939,7 @@ type internal TransparentCompiler projectSnapshot: FSharpProjectSnapshot, fileName, userOpName: string - ) : NodeCode = + ) : Async = this.GetAssemblyData(projectSnapshot.ProjectSnapshot, fileName, userOpName) member this.GetBackgroundCheckResultsForFileInProject @@ -1955,9 +1947,9 @@ type internal TransparentCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = - node { - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + ) : Async = + async { + let! snapshot = FSharpProjectSnapshot.FromOptions options match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) with | parseResult, FSharpCheckFileAnswer.Succeeded checkResult -> return parseResult, checkResult @@ -1969,9 +1961,9 @@ type internal TransparentCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = - node { - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + ) : Async = + async { + let! snapshot = FSharpProjectSnapshot.FromOptions options return! this.ParseFile(fileName, snapshot.ProjectSnapshot, userOpName) } @@ -1981,13 +1973,11 @@ type internal TransparentCompiler fileName: string, sourceText: ISourceText, options: FSharpProjectOptions - ) : NodeCode<(FSharpParseFileResults * FSharpCheckFileResults) option> = - node { + ) : Async<(FSharpParseFileResults * FSharpCheckFileResults) option> = + async { ignore builder - let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, 1, sourceText) - |> NodeCode.AwaitAsync + let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, 1, sourceText) match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, "GetCachedCheckFileResult") with | parseResult, FSharpCheckFileAnswer.Succeeded checkResult -> return Some(parseResult, checkResult) @@ -2023,7 +2013,7 @@ type internal TransparentCompiler ) member this.GetSemanticClassificationForFile(fileName: string, snapshot: FSharpProjectSnapshot, userOpName: string) = - node { + async { ignore userOpName return! ComputeSemanticClassification(fileName, snapshot.ProjectSnapshot) } @@ -2033,17 +2023,17 @@ type internal TransparentCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = - node { + ) : Async = + async { ignore userOpName - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + let! snapshot = FSharpProjectSnapshot.FromOptions options return! ComputeSemanticClassification(fileName, snapshot.ProjectSnapshot) } member this.InvalidateConfiguration(options: FSharpProjectOptions, userOpName: string) : unit = backgroundCompiler.InvalidateConfiguration(options, userOpName) - member this.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : NodeCode = + member this.NotifyFileChanged(fileName: string, options: FSharpProjectOptions, userOpName: string) : Async = backgroundCompiler.NotifyFileChanged(fileName, options, userOpName) member this.NotifyProjectCleaned(options: FSharpProjectOptions, userOpName: string) : Async = @@ -2056,11 +2046,9 @@ type internal TransparentCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = - node { - let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) - |> NodeCode.AwaitAsync + ) : Async = + async { + let! snapshot = FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) return! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) } @@ -2068,22 +2056,21 @@ type internal TransparentCompiler member this.ParseAndCheckFileInProject(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) = this.ParseAndCheckFileInProject(fileName, projectSnapshot.ProjectSnapshot, userOpName) - member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode = - node { + member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : Async = + async { ignore userOpName - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + let! snapshot = FSharpProjectSnapshot.FromOptions options return! ComputeParseAndCheckProject snapshot.ProjectSnapshot } - member this.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : NodeCode = - node { + member this.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, userOpName: string) : Async = + async { ignore userOpName return! ComputeParseAndCheckProject projectSnapshot.ProjectSnapshot } member this.ParseFile(fileName, projectSnapshot, userOpName) = this.ParseFile(fileName, projectSnapshot.ProjectSnapshot, userOpName) - |> Async.AwaitNodeCode member this.ParseFile ( diff --git a/src/Compiler/Service/TransparentCompiler.fsi b/src/Compiler/Service/TransparentCompiler.fsi index 00167ccc67f..59902bbb404 100644 --- a/src/Compiler/Service/TransparentCompiler.fsi +++ b/src/Compiler/Service/TransparentCompiler.fsi @@ -156,19 +156,19 @@ type internal TransparentCompiler = member FindReferencesInFile: fileName: string * projectSnapshot: ProjectSnapshot.ProjectSnapshot * symbol: FSharpSymbol * userOpName: string -> - NodeCode + Async member GetAssemblyData: projectSnapshot: ProjectSnapshot.ProjectSnapshot * fileName: string * _userOpName: string -> - NodeCode + Async member ParseAndCheckFileInProject: fileName: string * projectSnapshot: ProjectSnapshot.ProjectSnapshot * userOpName: string -> - NodeCode + Async member ParseFile: fileName: string * projectSnapshot: ProjectSnapshot.ProjectSnapshot * _userOpName: 'a -> - NodeCode + Async member SetCacheSizeFactor: sizeFactor: int -> unit diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 492ff2da497..b74fd77527a 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -330,13 +330,11 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) - |> Async.AwaitNodeCode member _.GetBackgroundCheckResultsForFileInProject(fileName, options, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) - |> Async.AwaitNodeCode /// Try to get recent approximate type check results for a file. member _.TryGetRecentCheckResultsForFile(fileName: string, options: FSharpProjectOptions, ?sourceText, ?userOpName: string) = @@ -395,7 +393,6 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.NotifyFileChanged(fileName, options, userOpName) - |> Async.AwaitNodeCode /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. @@ -418,7 +415,6 @@ type FSharpChecker options, userOpName ) - |> Async.AwaitNodeCode /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. @@ -434,7 +430,6 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.CheckFileInProject(parseResults, fileName, fileVersion, sourceText, options, userOpName) - |> Async.AwaitNodeCode /// Typecheck a source code file, returning a handle to the results of the /// parse including the reconstructed types in the file. @@ -449,25 +444,21 @@ type FSharpChecker let userOpName = defaultArg userOpName "Unknown" 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: FSharpProjectOptions, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.ParseAndCheckProject(options, userOpName) - |> Async.AwaitNodeCode member _.ParseAndCheckProject(projectSnapshot: FSharpProjectSnapshot, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.ParseAndCheckProject(projectSnapshot, userOpName) - |> Async.AwaitNodeCode member _.FindBackgroundReferencesInFile ( @@ -481,7 +472,7 @@ type FSharpChecker let canInvalidateProject = defaultArg canInvalidateProject true let userOpName = defaultArg userOpName "Unknown" - node { + async { if fastCheck <> Some true || not captureIdentifiersWhenParsing then return! backgroundCompiler.FindReferencesInFile(fileName, options, symbol, canInvalidateProject, userOpName) else @@ -495,15 +486,12 @@ type FSharpChecker else return Seq.empty } - |> 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) - |> NodeCode.AwaitAsync + async { + let! parseResults = backgroundCompiler.ParseFile(fileName, projectSnapshot, userOpName) if parseResults.ParseTree.Identifiers |> Set.contains symbol.DisplayNameCore @@ -513,19 +501,16 @@ type FSharpChecker else return Seq.empty } - |> Async.AwaitNodeCode member _.GetBackgroundSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, ?userOpName) = let userOpName = defaultArg userOpName "Unknown" 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/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs index 556a9b5bc42..b4b30a91292 100644 --- a/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs +++ b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs @@ -16,14 +16,14 @@ module BuildGraphTests = [] let private createNode () = let o = obj () - GraphNode(node { + GraphNode(async { Assert.shouldBeTrue (o <> null) return 1 }), WeakReference(o) [] let ``Intialization of graph node should not have a computed value``() = - let node = GraphNode(node { return 1 }) + let node = GraphNode(async { return 1 }) Assert.shouldBeTrue(node.TryPeekValue().IsNone) Assert.shouldBeFalse(node.HasValue) @@ -33,23 +33,23 @@ module BuildGraphTests = let resetEventInAsync = new ManualResetEvent(false) let graphNode = - GraphNode(node { + GraphNode(async { resetEventInAsync.Set() |> ignore - let! _ = NodeCode.AwaitWaitHandle_ForTesting(resetEvent) + let! _ = Async.AwaitWaitHandle(resetEvent) return 1 }) let task1 = - node { + async { let! _ = graphNode.GetOrComputeValue() () - } |> NodeCode.StartAsTask_ForTesting + } |> Async.StartAsTask_ForTesting let task2 = - node { + async { let! _ = graphNode.GetOrComputeValue() () - } |> NodeCode.StartAsTask_ForTesting + } |> Async.StartAsTask_ForTesting resetEventInAsync.WaitOne() |> ignore resetEvent.Set() |> ignore @@ -66,12 +66,12 @@ module BuildGraphTests = let mutable computationCount = 0 let graphNode = - GraphNode(node { + GraphNode(async { computationCount <- computationCount + 1 return 1 }) - let work = Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() |> Async.AwaitNodeCode)) + let work = Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() )) Async.RunImmediate(work) |> ignore @@ -82,9 +82,9 @@ module BuildGraphTests = let ``Many requests to get a value asynchronously should get the correct value``() = let requests = 10000 - let graphNode = GraphNode(node { return 1 }) + let graphNode = GraphNode(async { return 1 }) - let work = Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() |> Async.AwaitNodeCode)) + let work = Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() )) let result = Async.RunImmediate(work) @@ -101,7 +101,7 @@ module BuildGraphTests = Assert.shouldBeTrue weak.IsAlive - NodeCode.RunImmediateWithoutCancellation(graphNode.GetOrComputeValue()) + Async.RunImmediateWithoutCancellation(graphNode.GetOrComputeValue()) |> ignore GC.Collect(2, GCCollectionMode.Forced, true) @@ -118,7 +118,7 @@ module BuildGraphTests = Assert.shouldBeTrue weak.IsAlive - Async.RunImmediate(Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() |> Async.AwaitNodeCode))) + Async.RunImmediate(Async.Parallel(Array.init requests (fun _ -> graphNode.GetOrComputeValue() ))) |> ignore GC.Collect(2, GCCollectionMode.Forced, true) @@ -128,21 +128,21 @@ module BuildGraphTests = [] let ``A request can cancel``() = let graphNode = - GraphNode(node { + GraphNode(async { return 1 }) use cts = new CancellationTokenSource() let work = - node { + async { cts.Cancel() return! graphNode.GetOrComputeValue() } let ex = try - NodeCode.RunImmediate(work, ct = cts.Token) + Async.RunImmediate(work, cancellationToken = cts.Token) |> ignore failwith "Should have canceled" with @@ -156,23 +156,23 @@ module BuildGraphTests = let resetEvent = new ManualResetEvent(false) let graphNode = - GraphNode(node { - let! _ = NodeCode.AwaitWaitHandle_ForTesting(resetEvent) + GraphNode(async { + let! _ = Async.AwaitWaitHandle(resetEvent) return 1 }) use cts = new CancellationTokenSource() let task = - node { + async { cts.Cancel() resetEvent.Set() |> ignore } - |> NodeCode.StartAsTask_ForTesting + |> Async.StartAsTask_ForTesting let ex = try - NodeCode.RunImmediate(graphNode.GetOrComputeValue(), ct = cts.Token) + Async.RunImmediate(graphNode.GetOrComputeValue(), cancellationToken = cts.Token) |> ignore failwith "Should have canceled" with @@ -190,9 +190,9 @@ module BuildGraphTests = let mutable computationCount = 0 let graphNode = - GraphNode(node { + GraphNode(async { computationCountBeforeSleep <- computationCountBeforeSleep + 1 - let! _ = NodeCode.AwaitWaitHandle_ForTesting(resetEvent) + let! _ = Async.AwaitWaitHandle(resetEvent) computationCount <- computationCount + 1 return 1 }) @@ -200,7 +200,7 @@ module BuildGraphTests = use cts = new CancellationTokenSource() let work = - node { + async { let! _ = graphNode.GetOrComputeValue() () } @@ -209,15 +209,15 @@ module BuildGraphTests = for i = 0 to requests - 1 do if i % 10 = 0 then - NodeCode.StartAsTask_ForTesting(work, ct = cts.Token) + Async.StartAsTask_ForTesting(work, ct = cts.Token) |> tasks.Add else - NodeCode.StartAsTask_ForTesting(work) + Async.StartAsTask_ForTesting(work) |> tasks.Add cts.Cancel() resetEvent.Set() |> ignore - NodeCode.RunImmediateWithoutCancellation(work) + Async.RunImmediateWithoutCancellation(work) |> ignore Assert.shouldBeTrue cts.IsCancellationRequested @@ -242,15 +242,15 @@ module BuildGraphTests = let rng = Random() fun n -> rng.Next n - let job phase _ = node { - do! random 10 |> Async.Sleep |> NodeCode.AwaitAsync + let job phase _ = async { + do! random 10 |> Async.Sleep Assert.Equal(phase, DiagnosticsThreadStatics.BuildPhase) } let work (phase: BuildPhase) = - node { + async { use _ = new CompilationGlobalsScope(DiscardErrorsLogger, phase) - let! _ = Seq.init 8 (job phase) |> NodeCode.Parallel + let! _ = Seq.init 8 (job phase) |> Async.Parallel Assert.Equal(phase, DiagnosticsThreadStatics.BuildPhase) } @@ -270,6 +270,6 @@ module BuildGraphTests = let pickRandomPhase _ = phases[random phases.Length] Seq.init 100 pickRandomPhase - |> Seq.map (work >> Async.AwaitNodeCode) + |> Seq.map work |> Async.Parallel |> Async.RunSynchronously diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs index 154517ed6a1..6c3b04f1844 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs @@ -317,15 +317,14 @@ module private CheckerExtensions = snapshotCache.Get( key, - node { - let! ct = NodeCode.CancellationToken + async { + let! ct = Async.CancellationToken return! createProjectSnapshot snapshotAccumulatorOpt project options ct - |> NodeCode.AwaitTask + |> Async.AwaitTask } ) - |> Async.AwaitNodeCode let getProjectSnapshotForDocument (document: Document, options: FSharpProjectOptions) = getOrCreateSnapshotForProject document.Project (Some options) None From f69a1d9d6ef3ee61bcf6c13a704c5b27f5418977 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Wed, 31 Jan 2024 22:30:43 +0100 Subject: [PATCH 20/43] fix 2 BuildGraph tests --- .../BuildGraphTests.fs | 35 ++++++------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs index b4b30a91292..4a918c78d14 100644 --- a/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs +++ b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs @@ -3,6 +3,7 @@ namespace FSharp.Compiler.UnitTests open System open System.Threading +open System.Threading.Tasks open System.Runtime.CompilerServices open Xunit open FSharp.Test @@ -134,22 +135,14 @@ module BuildGraphTests = use cts = new CancellationTokenSource() - let work = + let work(): Task = + Async.StartAsTask( async { cts.Cancel() return! graphNode.GetOrComputeValue() - } - - let ex = - try - Async.RunImmediate(work, cancellationToken = cts.Token) - |> ignore - failwith "Should have canceled" - with - | :? OperationCanceledException as ex -> - ex + }, cancellationToken = cts.Token) - Assert.shouldBeTrue(ex <> null) + Assert.ThrowsAnyAsync(work).Wait() [] let ``A request can cancel 2``() = @@ -158,7 +151,7 @@ module BuildGraphTests = let graphNode = GraphNode(async { let! _ = Async.AwaitWaitHandle(resetEvent) - return 1 + failwith "Should have canceled" }) use cts = new CancellationTokenSource() @@ -170,17 +163,11 @@ module BuildGraphTests = } |> Async.StartAsTask_ForTesting - let ex = - try - Async.RunImmediate(graphNode.GetOrComputeValue(), cancellationToken = cts.Token) - |> ignore - failwith "Should have canceled" - with - | :? OperationCanceledException as ex -> - ex - - Assert.shouldBeTrue(ex <> null) - try task.Wait(1000) |> ignore with | :? TimeoutException -> reraise() | _ -> () + Assert.ThrowsAnyAsync(fun () -> + Async.StartImmediateAsTask(graphNode.GetOrComputeValue(), cancellationToken = cts.Token) + ) |> ignore + + if task.Wait(1000) |> not then raise (TimeoutException()) [] let ``Many requests to get a value asynchronously might evaluate the computation more than once even when some requests get canceled``() = From 8e15d57002df3049d1eaee0f406a5627ada92194 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Sat, 3 Feb 2024 15:12:42 +0100 Subject: [PATCH 21/43] release notes --- docs/release-notes/.FSharp.Compiler.Service/8.0.300.md | 2 +- docs/release-notes/.VisualStudio/17.10.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 710fef1fbc2..1ca69243d74 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -23,4 +23,4 @@ * Reduce allocations in compiler checking via `ValueOption` usage ([PR #16323](https://github.com/dotnet/fsharp/pull/16323), [PR #16567](https://github.com/dotnet/fsharp/pull/16567)) * Reverted [#16348](https://github.com/dotnet/fsharp/pull/16348) `ThreadStatic` `CancellationToken` changes to improve test stability and prevent potential unwanted cancellations. ([PR #16536](https://github.com/dotnet/fsharp/pull/16536)) * Refactored parenthesization API. ([PR #16461])(https://github.com/dotnet/fsharp/pull/16461)) -* Replaced `ThreadStatic` diagnostics globals with `AsyncLocal` for better stability of Transparent Compiler. ([PR #16602](https://github.com/dotnet/fsharp/pull/16602)) \ No newline at end of file +* Replaced `ThreadStatic` diagnostics globals with `AsyncLocal` for better stability of Transparent Compiler. Removed `NodeCode` in favor of unflavored Async ([PR #16645](https://github.com/dotnet/fsharp/pull/16645)) \ No newline at end of file diff --git a/docs/release-notes/.VisualStudio/17.10.md b/docs/release-notes/.VisualStudio/17.10.md index 0045b1bd64b..52f1ddabc5d 100644 --- a/docs/release-notes/.VisualStudio/17.10.md +++ b/docs/release-notes/.VisualStudio/17.10.md @@ -5,3 +5,4 @@ ### Changed * Use refactored parenthesization API in unnecessary parentheses code fix. ([PR #16461])(https://github.com/dotnet/fsharp/pull/16461)) +* Removed `NodeCode` in favor of unflavored Async with AsyncLocal state ([PR #16645](https://github.com/dotnet/fsharp/pull/16645)) \ No newline at end of file From e08be3832ee303e153aadb1b94c22b838bf4bc75 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Sat, 3 Feb 2024 15:13:16 +0100 Subject: [PATCH 22/43] concurrent logger --- src/Compiler/Facilities/DiagnosticsLogger.fs | 39 +++++++++++++++++-- src/Compiler/Facilities/DiagnosticsLogger.fsi | 17 ++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index fbf378c3ed4..f3423a64f10 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -375,6 +375,31 @@ type CapturingDiagnosticsLogger(nm, ?eagerFormat) = let errors = diagnostics.ToArray() errors |> Array.iter diagnosticsLogger.DiagnosticSink +type ConcurrentCapturingDiagnosticsLogger(nm, ?eagerFormat) = + inherit DiagnosticsLogger(nm) + let mutable errorCount = 0 + let diagnostics = System.Collections.Concurrent.ConcurrentQueue() + + override _.DiagnosticSink(diagnostic, severity) = + let diagnostic = + match eagerFormat with + | None -> diagnostic + | Some f -> f diagnostic + + if severity = FSharpDiagnosticSeverity.Error then + Interlocked.Increment &errorCount |> ignore + + diagnostics.Enqueue(diagnostic, severity) + + override _.ErrorCount = errorCount + + member _.Diagnostics = diagnostics |> Seq.toList + + member _.CommitDelayedDiagnostics(diagnosticsLogger: DiagnosticsLogger) = + // Eagerly grab all the errors and warnings from the mutable collection + let errors = diagnostics.ToArray() + errors |> Array.iter diagnosticsLogger.DiagnosticSink + /// Type holds thread-static globals for use by the compiler. type DiagnosticsThreadStatics = static let buildPhase = new AsyncLocal() @@ -517,6 +542,17 @@ let UseTransformedDiagnosticsLogger (transformer: DiagnosticsLogger -> #Diagnost let UseDiagnosticsLogger newLogger = UseTransformedDiagnosticsLogger(fun _ -> newLogger) +let CaptureDiagnosticsConcurrently () = + let newLogger = ConcurrentCapturingDiagnosticsLogger("CaptureDiagnosticsConcurrently") + let oldLogger = DiagnosticsThreadStatics.DiagnosticsLogger + DiagnosticsThreadStatics.DiagnosticsLogger <- newLogger + + { new IDisposable with + member _.Dispose() = + newLogger.CommitDelayedDiagnostics oldLogger + DiagnosticsThreadStatics.DiagnosticsLogger <- oldLogger + } + let SetThreadBuildPhaseNoUnwind (phase: BuildPhase) = DiagnosticsThreadStatics.BuildPhase <- phase @@ -855,14 +891,11 @@ type StackGuard(maxDepth: int, name: string) = try if depth % maxDepth = 0 then - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let buildPhase = DiagnosticsThreadStatics.BuildPhase let ct = Cancellable.Token async { do! Async.SwitchToNewThread() Thread.CurrentThread.Name <- $"F# Extra Compilation Thread for {name} (depth {depth})" - use _scope = new CompilationGlobalsScope(diagnosticsLogger, buildPhase) use _token = Cancellable.UsingToken ct return f () } diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index 54729756c6b..0548ba6e4a6 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -226,6 +226,21 @@ type CapturingDiagnosticsLogger = override ErrorCount: int +/// Represents a DiagnosticsLogger that captures all diagnostics, optionally formatting them +/// eagerly. +type ConcurrentCapturingDiagnosticsLogger = + inherit DiagnosticsLogger + + new: nm: string * ?eagerFormat: (PhasedDiagnostic -> PhasedDiagnostic) -> ConcurrentCapturingDiagnosticsLogger + + member CommitDelayedDiagnostics: diagnosticsLogger: DiagnosticsLogger -> unit + + override DiagnosticSink: diagnostic: PhasedDiagnostic * severity: FSharpDiagnosticSeverity -> unit + + member Diagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list + + override ErrorCount: int + /// Thread statics for the installed diagnostic logger [] type DiagnosticsThreadStatics = @@ -280,6 +295,8 @@ val UseTransformedDiagnosticsLogger: transformer: (DiagnosticsLogger -> #Diagnos val UseDiagnosticsLogger: newLogger: DiagnosticsLogger -> IDisposable +val CaptureDiagnosticsConcurrently: unit -> IDisposable + val SetThreadBuildPhaseNoUnwind: phase: BuildPhase -> unit val SetThreadDiagnosticsLoggerNoUnwind: diagnosticsLogger: DiagnosticsLogger -> unit From d84c21c9ce6438c63af3871a136175061bd2d491 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Sat, 3 Feb 2024 15:14:23 +0100 Subject: [PATCH 23/43] use AsyncLocal for Cancellable token --- src/Compiler/Utilities/Cancellable.fs | 33 +++++++-------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index 59e7def4c10..2d99cfa15ae 100644 --- a/src/Compiler/Utilities/Cancellable.fs +++ b/src/Compiler/Utilities/Cancellable.fs @@ -6,37 +6,20 @@ open Internal.Utilities.Library [] type Cancellable = - [] - static val mutable private tokens: CancellationToken list + static let token = AsyncLocal() + + static member UsingToken(ct) = + let previousToken = token.Value + token.Value <- ct - static let disposable = { new IDisposable with - member this.Dispose() = - Cancellable.Tokens <- Cancellable.Tokens |> List.tail + member this.Dispose() = token.Value <- previousToken } - static member Tokens - with private get () = - match box Cancellable.tokens with - | Null -> [] - | _ -> Cancellable.tokens - and private set v = Cancellable.tokens <- v - - static member UsingToken(ct) = - Cancellable.Tokens <- ct :: Cancellable.Tokens - disposable - - static member Token = - match Cancellable.Tokens with - | [] -> CancellationToken.None - | token :: _ -> token + static member Token = token.Value - /// There may be multiple tokens if `UsingToken` is called multiple times, producing scoped structure. - /// We're interested in the current, i.e. the most recent, one. static member CheckAndThrow() = - match Cancellable.Tokens with - | [] -> () - | token :: _ -> token.ThrowIfCancellationRequested() + token.Value.ThrowIfCancellationRequested() namespace Internal.Utilities.Library From 32975e2349918059a60d4a7c207969771efef0fa Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Sat, 3 Feb 2024 15:17:56 +0100 Subject: [PATCH 24/43] restore NodeCode subtly different semantics --- src/Compiler/Driver/CompilerImports.fs | 2 +- src/Compiler/Facilities/BuildGraph.fs | 21 +++++- src/Compiler/Facilities/BuildGraph.fsi | 2 + src/Compiler/Facilities/DiagnosticsLogger.fs | 4 +- src/Compiler/Service/FSharpProjectSnapshot.fs | 3 +- src/Compiler/Service/IncrementalBuild.fs | 4 +- src/Compiler/Service/TransparentCompiler.fs | 6 +- src/Compiler/Utilities/illib.fs | 6 +- .../CompilerService/AsyncMemoize.fs | 74 +++++++++---------- .../ProjectGeneration.fs | 3 +- 10 files changed, 77 insertions(+), 48 deletions(-) diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index cc32d0bf935..33cb248ad77 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2236,7 +2236,7 @@ and [] TcImports let runMethod = match tcConfig.parallelReferenceResolution with | ParallelReferenceResolution.On -> Async.Parallel - | ParallelReferenceResolution.Off -> Async.Sequential + | ParallelReferenceResolution.Off -> Async.SequentialFailFast let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger let! results = diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index ea1dbe20047..deebf21fa58 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -11,13 +11,32 @@ open Internal.Utilities.Library [] type Async = static member RunImmediateWithoutCancellation(computation) = - Async.RunImmediate(computation, CancellationToken.None) + try + let work = async { return! computation } + + Async + .StartImmediateAsTask(work, cancellationToken = CancellationToken.None) + .Result + + with :? AggregateException as ex when ex.InnerExceptions.Count = 1 -> + raise (ex.InnerExceptions[0]) static member FromCancellable(computation: Cancellable<'T>) = Cancellable.toAsync computation static member StartAsTask_ForTesting(computation: Async<'T>, ?ct: CancellationToken) = Async.StartAsTask(computation, cancellationToken = defaultArg ct CancellationToken.None) + static member SequentialFailFast(computations: Async<'T> seq) = + async { + let results = ResizeArray() + + for computation in computations do + let! result = computation + results.Add result + + return results.ToArray() + } + [] module GraphNode = diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index 0265bb54092..c5d44b5b360 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -21,6 +21,8 @@ type Async = /// Only used for testing, do not use static member StartAsTask_ForTesting: computation: Async<'T> * ?ct: CancellationToken -> Task<'T> + static member SequentialFailFast: computations: Async<'T> seq -> Async<'T array> + /// Contains helpers related to the build graph [] module internal GraphNode = diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index f3423a64f10..4855193721b 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -543,7 +543,9 @@ let UseDiagnosticsLogger newLogger = UseTransformedDiagnosticsLogger(fun _ -> newLogger) let CaptureDiagnosticsConcurrently () = - let newLogger = ConcurrentCapturingDiagnosticsLogger("CaptureDiagnosticsConcurrently") + let newLogger = + ConcurrentCapturingDiagnosticsLogger("CaptureDiagnosticsConcurrently") + let oldLogger = DiagnosticsThreadStatics.DiagnosticsLogger DiagnosticsThreadStatics.DiagnosticsLogger <- newLogger diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 148d39da787..6842bc00fcc 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -19,6 +19,7 @@ open System.Runtime.CompilerServices open FSharp.Compiler.Syntax open FSharp.Compiler.Diagnostics open FSharp.Compiler.DiagnosticsLogger +open FSharp.Compiler.BuildGraph type internal ProjectIdentifier = string * string @@ -567,7 +568,7 @@ and [] FSha async.Return <| FSharpReferencedProjectSnapshot.ILModuleReference(outputName, getStamp, getReader)) - |> Async.Sequential + |> Async.SequentialFailFast let referencesOnDisk, otherOptions = options.OtherOptions diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index b6f643158d2..8d0d2d0d94b 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -740,12 +740,12 @@ module IncrementalBuilderHelpers = let diagnosticsLogger = CompilationDiagnosticLogger("FinalizeTypeCheckTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck) - let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> Async.Sequential + let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> Async.SequentialFailFast let! tcInfos = computedBoundModels |> Seq.map (fun boundModel -> async { return! boundModel.GetOrComputeTcInfo() }) - |> Async.Sequential + |> Async.SequentialFailFast // tcInfoExtras can be computed in parallel. This will check any previously skipped implementation files in parallel, too. let! latestImplFiles = diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index fdb4f6c6083..d3989e5ba82 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -542,8 +542,8 @@ type internal TransparentCompiler | FSharpReferencedProjectSnapshot.PEReference(getStamp, delayedReader) -> { new IProjectReference with member x.EvaluateRawContents() = - node { - let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> NodeCode.FromCancellable + async { + let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> Cancellable.toAsync match ilReaderOpt with | Some ilReader -> @@ -569,7 +569,7 @@ type internal TransparentCompiler let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> NodeCode.FromCancellable + |> Async.FromCancellable member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index fca3cd54605..c4ff36263ab 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -160,11 +160,15 @@ module internal PervasiveAutoOpens = static member RunImmediate(computation: Async<'T>, ?cancellationToken) = let cancellationToken = defaultArg cancellationToken Async.DefaultCancellationToken +#if DEBUG let ts = TaskCompletionSource<'T>() - let task = ts.Task Async.StartWithContinuations(computation, (ts.SetResult), (ts.SetException), (fun _ -> ts.SetCanceled()), cancellationToken) + let task = ts.Task +#else + let task = Async.StartAsTask(computation, cancellationToken = cancellationToken) +#endif task.Result [] diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index e442335f940..3aca5ff8479 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs @@ -28,9 +28,9 @@ let waitUntil condition value = } let rec internal spinFor (duration: TimeSpan) = - node { + async { let sw = Stopwatch.StartNew() - do! Async.Sleep 10 |> NodeCode.AwaitAsync + do! Async.Sleep 10 let remaining = duration - sw.Elapsed if remaining > TimeSpan.Zero then return! spinFor remaining @@ -58,8 +58,8 @@ type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality>(mem [] let ``Basics``() = - let computation key = node { - do! Async.Sleep 1 |> NodeCode.AwaitAsync + let computation key = async { + do! Async.Sleep 1 return key * 2 } @@ -77,8 +77,8 @@ let ``Basics``() = memoize.Get'(3, computation 3) memoize.Get'(2, computation 2) } - |> NodeCode.Parallel - |> NodeCode.RunImmediateWithoutCancellation + |> Async.Parallel + |> Async.RunImmediateWithoutCancellation let expected = [| 10; 10; 4; 10; 6; 4|] @@ -95,7 +95,7 @@ let ``We can cancel a job`` () = let jobStarted = new ManualResetEvent(false) - let computation action = node { + let computation action = async { action() |> ignore do! spinFor timeout failwith "Should be canceled before it gets here" @@ -110,13 +110,13 @@ let ``We can cancel a job`` () = let key = 1 - let _task1 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation jobStarted.Set), ct = cts1.Token) + let _task1 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation jobStarted.Set), ct = cts1.Token) waitFor jobStarted jobStarted.Reset() |> ignore - let _task2 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts2.Token) - let _task3 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts3.Token) + let _task2 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts2.Token) + let _task3 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts3.Token) do! waitUntil (events.CountOf Requested) 3 @@ -146,7 +146,7 @@ let ``Job is restarted if first requestor cancels`` () = let jobCanComplete = new ManualResetEvent(false) - let computation key = node { + let computation key = async { jobStarted.Set() |> ignore waitFor jobCanComplete return key * 2 @@ -162,13 +162,13 @@ let ``Job is restarted if first requestor cancels`` () = let key = 1 - let _task1 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token) + let _task1 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token) waitFor jobStarted jobStarted.Reset() |> ignore - let _task2 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token) - let _task3 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token) + let _task2 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token) + let _task3 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token) do! waitUntil (events.CountOf Requested) 3 @@ -197,7 +197,7 @@ let ``Job is restarted if first requestor cancels but keeps running if second re let jobCanComplete = new ManualResetEvent(false) - let computation key = node { + let computation key = async { jobStarted.Set() |> ignore waitFor jobCanComplete return key * 2 @@ -213,13 +213,13 @@ let ``Job is restarted if first requestor cancels but keeps running if second re let key = 1 - let _task1 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token) + let _task1 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token) waitFor jobStarted jobStarted.Reset() |> ignore - let _task2 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token) - let _task3 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token) + let _task2 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token) + let _task3 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token) do! waitUntil (events.CountOf Requested) 3 @@ -275,21 +275,21 @@ let ``Stress test`` () = while (int s.ElapsedMilliseconds) < durationMs do number <- number + 1 % 12345 return [result] - } |> NodeCode.AwaitAsync + } let rec sleepyComputation durationMs result = - node { + async { if rng.NextDouble() < (exceptionProbability / (float durationMs / float stepMs)) then raise (ExpectedException()) if durationMs > 0 then - do! Async.Sleep (min stepMs durationMs) |> NodeCode.AwaitAsync + do! Async.Sleep (min stepMs durationMs) return! sleepyComputation (durationMs - stepMs) result else return [result] } let rec mixedComputation durationMs result = - node { + async { if durationMs > 0 then if rng.NextDouble() < 0.5 then let! _ = intenseComputation (min stepMs durationMs) () @@ -331,7 +331,7 @@ let ``Stress test`` () = let result = key * 2 let job = cache.Get'(key, computation durationMs result) let cts = new CancellationTokenSource() - let runningJob = NodeCode.StartAsTask_ForTesting(job, ct = cts.Token) + let runningJob = Async.StartAsTask_ForTesting(job, ct = cts.Token) cts.CancelAfter timeoutMs Interlocked.Increment &started |> ignore try @@ -385,7 +385,7 @@ let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished = let job2started = new ManualResetEvent(false) let job2finished = new ManualResetEvent(false) - let work onStart onFinish = node { + let work onStart onFinish = async { Interlocked.Increment &started |> ignore onStart() |> ignore waitFor jobCanContinue @@ -400,7 +400,7 @@ let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished = member _.GetVersion() = 1 member _.GetLabel() = "key1" } - cache.Get(key1, work job1started.Set job1finished.Set) |> Async.AwaitNodeCode |> Async.Start + cache.Get(key1, work job1started.Set job1finished.Set) |> Async.Start waitFor job1started @@ -410,7 +410,7 @@ let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished = member _.GetVersion() = key1.GetVersion() + 1 member _.GetLabel() = "key2" } - cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.AwaitNodeCode |> Async.Start + cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.Start waitFor job2started @@ -438,18 +438,18 @@ let ``Preserve thread static diagnostics`` () = let job1Cache = AsyncMemoize() let job2Cache = AsyncMemoize() - let job1 (input: string) = node { - let! _ = Async.Sleep (rng.Next(1, 30)) |> NodeCode.AwaitAsync + let job1 (input: string) = async { + let! _ = Async.Sleep (rng.Next(1, 30)) let ex = DummyException("job1 error") DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex) return Ok input } - let job2 (input: int) = node { + let job2 (input: int) = async { DiagnosticsThreadStatics.DiagnosticsLogger.Warning(DummyException("job2 error 1")) - let! _ = Async.Sleep (rng.Next(1, 30)) |> NodeCode.AwaitAsync + let! _ = Async.Sleep (rng.Next(1, 30)) let key = { new ICacheKey<_, _> with member _.GetKey() = "job1" @@ -481,7 +481,7 @@ let ``Preserve thread static diagnostics`` () = member _.GetVersion() = rng.Next(1, 10) member _.GetLabel() = "job2" } - let! result = job2Cache.Get(key, job2 (i % 10)) |> Async.AwaitNodeCode + let! result = job2Cache.Get(key, job2 (i % 10)) let diagnostics = diagnosticsLogger.GetDiagnostics() @@ -512,7 +512,7 @@ let ``Preserve thread static diagnostics already completed job`` () = member _.GetVersion() = 1 member _.GetLabel() = "job1" } - let job (input: string) = node { + let job (input: string) = async { let ex = DummyException($"job {input} error") DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex) return Ok input @@ -524,8 +524,8 @@ let ``Preserve thread static diagnostics already completed job`` () = use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize) - let! _ = cache.Get(key, job "1" ) |> Async.AwaitNodeCode - let! _ = cache.Get(key, job "2" ) |> Async.AwaitNodeCode + let! _ = cache.Get(key, job "1" ) + let! _ = cache.Get(key, job "2" ) let diagnosticMessages = diagnosticsLogger.GetDiagnostics() |> Array.map (fun (d, _) -> d.Exception.Message) |> Array.toList @@ -545,9 +545,9 @@ let ``We get diagnostics from the job that failed`` () = member _.GetVersion() = 1 member _.GetLabel() = "job1" } - let job (input: int) = node { + let job (input: int) = async { let ex = DummyException($"job {input} error") - do! Async.Sleep 100 |> NodeCode.AwaitAsync + do! Async.Sleep 100 DiagnosticsThreadStatics.DiagnosticsLogger.Error(ex) return 5 } @@ -560,7 +560,7 @@ let ``We get diagnostics from the job that failed`` () = use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize) try - let! _ = cache.Get(key, job i ) |> Async.AwaitNodeCode + let! _ = cache.Get(key, job i ) () with _ -> () diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index 144e535bccb..e32e8ae692e 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -27,6 +27,7 @@ open System.Xml open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.CodeAnalysis.ProjectSnapshot open FSharp.Compiler.Diagnostics +open FSharp.Compiler.BuildGraph open FSharp.Compiler.Text open Xunit @@ -792,7 +793,7 @@ module ProjectOperations = let! projects = p.DependsOn |> Seq.map (absorbAutoGeneratedSignatures checker) - |> Async.Sequential + |> Async.SequentialFailFast return { p with SourceFiles = files From 7101e5b8eaf21efda67bd09cd27646f5a60acda5 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Sun, 4 Feb 2024 11:12:05 +0100 Subject: [PATCH 25/43] not needed --- src/Compiler/Utilities/illib.fs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index c4ff36263ab..fca3cd54605 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -160,15 +160,11 @@ module internal PervasiveAutoOpens = static member RunImmediate(computation: Async<'T>, ?cancellationToken) = let cancellationToken = defaultArg cancellationToken Async.DefaultCancellationToken -#if DEBUG let ts = TaskCompletionSource<'T>() + let task = ts.Task Async.StartWithContinuations(computation, (ts.SetResult), (ts.SetException), (fun _ -> ts.SetCanceled()), cancellationToken) - let task = ts.Task -#else - let task = Async.StartAsTask(computation, cancellationToken = cancellationToken) -#endif task.Result [] From c793bfa4dff6682580fcc36260f2201cafd0d19e Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Sun, 4 Feb 2024 12:29:34 +0100 Subject: [PATCH 26/43] iron things out --- src/Compiler/Driver/CompilerImports.fs | 10 ++- src/Compiler/Driver/ParseAndCheckInputs.fs | 2 +- src/Compiler/Facilities/AsyncMemoize.fs | 14 +-- src/Compiler/Facilities/DiagnosticsLogger.fs | 90 +++++++++---------- src/Compiler/Facilities/DiagnosticsLogger.fsi | 11 ++- .../CompilerService/AsyncMemoize.fs | 12 +-- .../BuildGraphTests.fs | 4 +- .../HashIfExpression.fs | 8 +- 8 files changed, 78 insertions(+), 73 deletions(-) diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 33cb248ad77..44cbe0d03c1 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -1735,7 +1735,7 @@ and [] TcImports m ) = - let startingErrorCount = DiagnosticsThreadStatics.DiagnosticsLogger.ErrorCount + let startingErrorCount = DiagnosticsAsyncState.DiagnosticsLogger.ErrorCount // Find assembly level TypeProviderAssemblyAttributes. These will point to the assemblies that // have class which implement ITypeProvider and which have TypeProviderAttribute on them. @@ -1936,7 +1936,7 @@ and [] TcImports with RecoverableException e -> errorRecovery e m - if startingErrorCount < DiagnosticsThreadStatics.DiagnosticsLogger.ErrorCount then + if startingErrorCount < DiagnosticsAsyncState.DiagnosticsLogger.ErrorCount then error (Error(FSComp.SR.etOneOrMoreErrorsSeenDuringExtensionTypeSetting (), m)) providers @@ -2238,7 +2238,8 @@ and [] TcImports | ParallelReferenceResolution.On -> Async.Parallel | ParallelReferenceResolution.Off -> Async.SequentialFailFast - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + use captureTasks = new CaptureDiagnosticsConcurrently(DiagnosticsAsyncState.DiagnosticsLogger) + let! results = nms |> List.map (fun nm -> @@ -2246,7 +2247,8 @@ and [] TcImports try return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) with e -> - use _ = UseDiagnosticsLogger diagnosticsLogger + use _ = UseDiagnosticsLogger captureTasks.LoggerForTask + errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range)) return None }) diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index 5a23c95ca7b..c6464caa522 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -1828,7 +1828,7 @@ let CheckMultipleInputsUsingGraphMode |> Graph.writeMermaidToFile graphFile) let _ = ctok // TODO Use it - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + let diagnosticsLogger = DiagnosticsAsyncState.DiagnosticsLogger // In the first linear part of parallel checking, we use a 'checkForErrors' that checks either for errors // somewhere in the files processed prior to each one, or in the processing of this particular file. diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs index 0fa57dcd631..e3ad00f891b 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fs +++ b/src/Compiler/Facilities/AsyncMemoize.fs @@ -354,15 +354,15 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T log (Restarted, key) Interlocked.Increment &restarted |> ignore System.Diagnostics.Trace.TraceInformation $"{name} Restarted {key.Label}" - let currentLogger = DiagnosticsThreadStatics.DiagnosticsLogger - DiagnosticsThreadStatics.DiagnosticsLogger <- cachingLogger + let currentLogger = DiagnosticsAsyncState.DiagnosticsLogger + DiagnosticsAsyncState.DiagnosticsLogger <- cachingLogger try let! result = computation post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) return () finally - DiagnosticsThreadStatics.DiagnosticsLogger <- currentLogger + DiagnosticsAsyncState.DiagnosticsLogger <- currentLogger with | TaskCancelled _ -> Interlocked.Increment &cancel_exception_subsequent |> ignore @@ -484,7 +484,7 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T async { let! ct = Async.CancellationToken - let callerDiagnosticLogger = DiagnosticsThreadStatics.DiagnosticsLogger + let callerDiagnosticLogger = DiagnosticsAsyncState.DiagnosticsLogger match! processRequest post (key, GetOrCompute(computation, ct)) callerDiagnosticLogger @@ -500,8 +500,8 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T Async.StartAsTask( async { // TODO: Should unify starting and restarting - let currentLogger = DiagnosticsThreadStatics.DiagnosticsLogger - DiagnosticsThreadStatics.DiagnosticsLogger <- cachingLogger + let currentLogger = DiagnosticsAsyncState.DiagnosticsLogger + DiagnosticsAsyncState.DiagnosticsLogger <- cachingLogger log (Started, key) @@ -510,7 +510,7 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) return result finally - DiagnosticsThreadStatics.DiagnosticsLogger <- currentLogger + DiagnosticsAsyncState.DiagnosticsLogger <- currentLogger }, cancellationToken = linkedCtSource.Token ) diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 4855193721b..a686825cffa 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -401,25 +401,23 @@ type ConcurrentCapturingDiagnosticsLogger(nm, ?eagerFormat) = errors |> Array.iter diagnosticsLogger.DiagnosticSink /// Type holds thread-static globals for use by the compiler. -type DiagnosticsThreadStatics = - static let buildPhase = new AsyncLocal() - static let diagnosticsLogger = new AsyncLocal() +type DiagnosticsAsyncState = + static let buildPhase = new AsyncLocal() + static let diagnosticsLogger = new AsyncLocal() - static let EnsureCreated (h: AsyncLocal<_>) d = - if box h.Value |> isNull then - h.Value <- d + static let getOrCreate (holder: AsyncLocal<_>) defaultValue = + holder.Value + |> ValueOption.defaultWith (fun () -> + holder.Value <- ValueSome defaultValue + defaultValue) static member BuildPhase - with get () = - EnsureCreated buildPhase BuildPhase.DefaultPhase - buildPhase.Value - and set v = buildPhase.Value <- v + with get () = getOrCreate buildPhase BuildPhase.DefaultPhase + and set v = buildPhase.Value <- ValueSome v static member DiagnosticsLogger - with get () = - EnsureCreated diagnosticsLogger AssertFalseDiagnosticsLogger - diagnosticsLogger.Value - and set v = diagnosticsLogger.Value <- v + with get () = getOrCreate diagnosticsLogger AssertFalseDiagnosticsLogger + and set v = diagnosticsLogger.Value <- ValueSome v [] module DiagnosticsLoggerExtensions = @@ -461,7 +459,7 @@ module DiagnosticsLoggerExtensions = | ReportedError _ -> PreserveStackTrace exn raise exn - | _ -> x.DiagnosticSink(PhasedDiagnostic.Create(exn, DiagnosticsThreadStatics.BuildPhase), severity) + | _ -> x.DiagnosticSink(PhasedDiagnostic.Create(exn, DiagnosticsAsyncState.BuildPhase), severity) member x.ErrorR exn = x.EmitDiagnostic(exn, FSharpDiagnosticSeverity.Error) @@ -521,45 +519,32 @@ module DiagnosticsLoggerExtensions = /// NOTE: The change will be undone when the returned "unwind" object disposes let UseBuildPhase (phase: BuildPhase) = - let oldBuildPhase = DiagnosticsThreadStatics.BuildPhase - DiagnosticsThreadStatics.BuildPhase <- phase + let oldBuildPhase = DiagnosticsAsyncState.BuildPhase + DiagnosticsAsyncState.BuildPhase <- phase { new IDisposable with member x.Dispose() = - DiagnosticsThreadStatics.BuildPhase <- oldBuildPhase + DiagnosticsAsyncState.BuildPhase <- oldBuildPhase } /// NOTE: The change will be undone when the returned "unwind" object disposes let UseTransformedDiagnosticsLogger (transformer: DiagnosticsLogger -> #DiagnosticsLogger) = - let oldLogger = DiagnosticsThreadStatics.DiagnosticsLogger - DiagnosticsThreadStatics.DiagnosticsLogger <- transformer oldLogger + let oldLogger = DiagnosticsAsyncState.DiagnosticsLogger + DiagnosticsAsyncState.DiagnosticsLogger <- transformer oldLogger { new IDisposable with member _.Dispose() = - DiagnosticsThreadStatics.DiagnosticsLogger <- oldLogger + DiagnosticsAsyncState.DiagnosticsLogger <- oldLogger } let UseDiagnosticsLogger newLogger = UseTransformedDiagnosticsLogger(fun _ -> newLogger) -let CaptureDiagnosticsConcurrently () = - let newLogger = - ConcurrentCapturingDiagnosticsLogger("CaptureDiagnosticsConcurrently") - - let oldLogger = DiagnosticsThreadStatics.DiagnosticsLogger - DiagnosticsThreadStatics.DiagnosticsLogger <- newLogger - - { new IDisposable with - member _.Dispose() = - newLogger.CommitDelayedDiagnostics oldLogger - DiagnosticsThreadStatics.DiagnosticsLogger <- oldLogger - } - let SetThreadBuildPhaseNoUnwind (phase: BuildPhase) = - DiagnosticsThreadStatics.BuildPhase <- phase + DiagnosticsAsyncState.BuildPhase <- phase let SetThreadDiagnosticsLoggerNoUnwind diagnosticsLogger = - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + DiagnosticsAsyncState.DiagnosticsLogger <- diagnosticsLogger /// This represents the thread-local state established as each task function runs as part of the build. /// @@ -577,30 +562,43 @@ type CompilationGlobalsScope(diagnosticsLogger: DiagnosticsLogger, buildPhase: B unwindBP.Dispose() unwindEL.Dispose() +type CaptureDiagnosticsConcurrently(target) = + let loggers = System.Collections.Concurrent.ConcurrentQueue() + + member _.LoggerForTask: DiagnosticsLogger = + let logger = CapturingDiagnosticsLogger("One of parallel computations") + loggers.Enqueue logger + logger + + interface IDisposable with + member _.Dispose() = + for logger in loggers do + logger.CommitDelayedDiagnostics target + // Global functions are still used by parser and TAST ops. /// Raises an exception with error recovery and returns unit. let errorR exn = - DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR exn + DiagnosticsAsyncState.DiagnosticsLogger.ErrorR exn /// Raises a warning with error recovery and returns unit. let warning exn = - DiagnosticsThreadStatics.DiagnosticsLogger.Warning exn + DiagnosticsAsyncState.DiagnosticsLogger.Warning exn /// Raises a warning with error recovery and returns unit. let informationalWarning exn = - DiagnosticsThreadStatics.DiagnosticsLogger.InformationalWarning exn + DiagnosticsAsyncState.DiagnosticsLogger.InformationalWarning exn /// Raises a special exception and returns 'T - can be caught later at an errorRecovery point. let error exn = - DiagnosticsThreadStatics.DiagnosticsLogger.Error exn + DiagnosticsAsyncState.DiagnosticsLogger.Error exn /// Simulates an error. For test purposes only. let simulateError (diagnostic: PhasedDiagnostic) = - DiagnosticsThreadStatics.DiagnosticsLogger.SimulateError diagnostic + DiagnosticsAsyncState.DiagnosticsLogger.SimulateError diagnostic let diagnosticSink (diagnostic, severity) = - DiagnosticsThreadStatics.DiagnosticsLogger.DiagnosticSink(diagnostic, severity) + DiagnosticsAsyncState.DiagnosticsLogger.DiagnosticSink(diagnostic, severity) let errorSink diagnostic = diagnosticSink (diagnostic, FSharpDiagnosticSeverity.Error) @@ -609,13 +607,13 @@ let warnSink diagnostic = diagnosticSink (diagnostic, FSharpDiagnosticSeverity.Warning) let errorRecovery exn m = - DiagnosticsThreadStatics.DiagnosticsLogger.ErrorRecovery exn m + DiagnosticsAsyncState.DiagnosticsLogger.ErrorRecovery exn m let stopProcessingRecovery exn m = - DiagnosticsThreadStatics.DiagnosticsLogger.StopProcessingRecovery exn m + DiagnosticsAsyncState.DiagnosticsLogger.StopProcessingRecovery exn m let errorRecoveryNoRange exn = - DiagnosticsThreadStatics.DiagnosticsLogger.ErrorRecoveryNoRange exn + DiagnosticsAsyncState.DiagnosticsLogger.ErrorRecoveryNoRange exn let deprecatedWithError s m = errorR (Deprecated(s, m)) @@ -634,7 +632,7 @@ let mlCompatError s m = [] let suppressErrorReporting f = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + let diagnosticsLogger = DiagnosticsAsyncState.DiagnosticsLogger try let diagnosticsLogger = diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index 0548ba6e4a6..4102cce79e7 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -243,7 +243,7 @@ type ConcurrentCapturingDiagnosticsLogger = /// Thread statics for the installed diagnostic logger [] -type DiagnosticsThreadStatics = +type DiagnosticsAsyncState = static member BuildPhase: BuildPhase with get, set @@ -295,12 +295,17 @@ val UseTransformedDiagnosticsLogger: transformer: (DiagnosticsLogger -> #Diagnos val UseDiagnosticsLogger: newLogger: DiagnosticsLogger -> IDisposable -val CaptureDiagnosticsConcurrently: unit -> IDisposable - val SetThreadBuildPhaseNoUnwind: phase: BuildPhase -> unit val SetThreadDiagnosticsLoggerNoUnwind: diagnosticsLogger: DiagnosticsLogger -> unit +type CaptureDiagnosticsConcurrently = + new: target: DiagnosticsLogger -> CaptureDiagnosticsConcurrently + + member LoggerForTask: DiagnosticsLogger + + interface IDisposable + /// Reports an error diagnostic and continues val errorR: exn: exn -> unit diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index 3aca5ff8479..c3d213ab86a 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs @@ -441,13 +441,13 @@ let ``Preserve thread static diagnostics`` () = let job1 (input: string) = async { let! _ = Async.Sleep (rng.Next(1, 30)) let ex = DummyException("job1 error") - DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex) + DiagnosticsAsyncState.DiagnosticsLogger.ErrorR(ex) return Ok input } let job2 (input: int) = async { - DiagnosticsThreadStatics.DiagnosticsLogger.Warning(DummyException("job2 error 1")) + DiagnosticsAsyncState.DiagnosticsLogger.Warning(DummyException("job2 error 1")) let! _ = Async.Sleep (rng.Next(1, 30)) @@ -458,7 +458,7 @@ let ``Preserve thread static diagnostics`` () = let! result = job1Cache.Get(key, job1 "${input}" ) - DiagnosticsThreadStatics.DiagnosticsLogger.Warning(DummyException("job2 error 2")) + DiagnosticsAsyncState.DiagnosticsLogger.Warning(DummyException("job2 error 2")) return input, result @@ -473,7 +473,7 @@ let ``Preserve thread static diagnostics`` () = use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize) - DiagnosticsThreadStatics.DiagnosticsLogger.Warning(DummyException("task error")) + DiagnosticsAsyncState.DiagnosticsLogger.Warning(DummyException("task error")) let key = { new ICacheKey<_, _> with @@ -514,7 +514,7 @@ let ``Preserve thread static diagnostics already completed job`` () = let job (input: string) = async { let ex = DummyException($"job {input} error") - DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex) + DiagnosticsAsyncState.DiagnosticsLogger.ErrorR(ex) return Ok input } @@ -548,7 +548,7 @@ let ``We get diagnostics from the job that failed`` () = let job (input: int) = async { let ex = DummyException($"job {input} error") do! Async.Sleep 100 - DiagnosticsThreadStatics.DiagnosticsLogger.Error(ex) + DiagnosticsAsyncState.DiagnosticsLogger.Error(ex) return 5 } diff --git a/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs index 4a918c78d14..55cfc166f43 100644 --- a/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs +++ b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs @@ -231,14 +231,14 @@ module BuildGraphTests = let job phase _ = async { do! random 10 |> Async.Sleep - Assert.Equal(phase, DiagnosticsThreadStatics.BuildPhase) + Assert.Equal(phase, DiagnosticsAsyncState.BuildPhase) } let work (phase: BuildPhase) = async { use _ = new CompilationGlobalsScope(DiscardErrorsLogger, phase) let! _ = Seq.init 8 (job phase) |> Async.Parallel - Assert.Equal(phase, DiagnosticsThreadStatics.BuildPhase) + Assert.Equal(phase, DiagnosticsAsyncState.BuildPhase) } let phases = [| diff --git a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs index 9f94b7b1c06..d83e379d70c 100644 --- a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs +++ b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs @@ -64,7 +64,7 @@ type public HashIfExpression() = let startPos = Position.Empty let args = mkLexargs (defines, indentationSyntaxStatus, resourceManager, [], diagnosticsLogger, PathMap.empty, applyLineDirectives) - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger + DiagnosticsAsyncState.DiagnosticsLogger <- diagnosticsLogger let parser (s : string) = let lexbuf = LexBuffer.FromChars (true, LanguageVersion.Default, None, s.ToCharArray ()) @@ -77,11 +77,11 @@ type public HashIfExpression() = errors, warnings, parser do // Setup - DiagnosticsThreadStatics.BuildPhase <- BuildPhase.Compile + DiagnosticsAsyncState.BuildPhase <- BuildPhase.Compile interface IDisposable with // Teardown member _.Dispose() = - DiagnosticsThreadStatics.BuildPhase <- BuildPhase.DefaultPhase - DiagnosticsThreadStatics.DiagnosticsLogger <- DiagnosticsThreadStatics.DiagnosticsLogger + DiagnosticsAsyncState.BuildPhase <- BuildPhase.DefaultPhase + DiagnosticsAsyncState.DiagnosticsLogger <- DiagnosticsAsyncState.DiagnosticsLogger [] member _.PositiveParserTestCases()= From e09c5e5eef1be8206ae631b36f801d0dca068246 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Sun, 4 Feb 2024 12:57:15 +0100 Subject: [PATCH 27/43] not needed --- src/Compiler/Facilities/DiagnosticsLogger.fs | 25 ------------------- src/Compiler/Facilities/DiagnosticsLogger.fsi | 15 ----------- 2 files changed, 40 deletions(-) diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index a686825cffa..605c7e87ad7 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -375,31 +375,6 @@ type CapturingDiagnosticsLogger(nm, ?eagerFormat) = let errors = diagnostics.ToArray() errors |> Array.iter diagnosticsLogger.DiagnosticSink -type ConcurrentCapturingDiagnosticsLogger(nm, ?eagerFormat) = - inherit DiagnosticsLogger(nm) - let mutable errorCount = 0 - let diagnostics = System.Collections.Concurrent.ConcurrentQueue() - - override _.DiagnosticSink(diagnostic, severity) = - let diagnostic = - match eagerFormat with - | None -> diagnostic - | Some f -> f diagnostic - - if severity = FSharpDiagnosticSeverity.Error then - Interlocked.Increment &errorCount |> ignore - - diagnostics.Enqueue(diagnostic, severity) - - override _.ErrorCount = errorCount - - member _.Diagnostics = diagnostics |> Seq.toList - - member _.CommitDelayedDiagnostics(diagnosticsLogger: DiagnosticsLogger) = - // Eagerly grab all the errors and warnings from the mutable collection - let errors = diagnostics.ToArray() - errors |> Array.iter diagnosticsLogger.DiagnosticSink - /// Type holds thread-static globals for use by the compiler. type DiagnosticsAsyncState = static let buildPhase = new AsyncLocal() diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index 4102cce79e7..fc05f09b8df 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -226,21 +226,6 @@ type CapturingDiagnosticsLogger = override ErrorCount: int -/// Represents a DiagnosticsLogger that captures all diagnostics, optionally formatting them -/// eagerly. -type ConcurrentCapturingDiagnosticsLogger = - inherit DiagnosticsLogger - - new: nm: string * ?eagerFormat: (PhasedDiagnostic -> PhasedDiagnostic) -> ConcurrentCapturingDiagnosticsLogger - - member CommitDelayedDiagnostics: diagnosticsLogger: DiagnosticsLogger -> unit - - override DiagnosticSink: diagnostic: PhasedDiagnostic * severity: FSharpDiagnosticSeverity -> unit - - member Diagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list - - override ErrorCount: int - /// Thread statics for the installed diagnostic logger [] type DiagnosticsAsyncState = From b98615b8a0f25109176f5398af7a66ce3b0575e4 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Mon, 5 Feb 2024 14:41:01 +0100 Subject: [PATCH 28/43] fail if DiagnosticsLogger not set --- src/Compiler/Facilities/DiagnosticsLogger.fs | 13 +++++++------ src/Compiler/Facilities/DiagnosticsLogger.fsi | 2 +- tests/service/ExprTests.fs | 9 +++++++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 605c7e87ad7..4c15b219a92 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -343,11 +343,12 @@ let DiscardErrorsLogger = member _.ErrorCount = 0 } -let AssertFalseDiagnosticsLogger = - { new DiagnosticsLogger("AssertFalseDiagnosticsLogger") with - // TODO: reenable these asserts in the compiler service - member _.DiagnosticSink(diagnostic, severity) = (* assert false; *) () - member _.ErrorCount = (* assert false; *) 0 +let UninitialzedDiagnosticsLogger = + { new DiagnosticsLogger("UninitialzedDiagnosticsLogger") with + member _.DiagnosticSink(diagnostic, severity) = + failwith "DiagnosticsAsyncState.DiagnosticsLogger not set." + + member _.ErrorCount = failwith "DiagnosticsAsyncState.DiagnosticsLogger not set." } type CapturingDiagnosticsLogger(nm, ?eagerFormat) = @@ -391,7 +392,7 @@ type DiagnosticsAsyncState = and set v = buildPhase.Value <- ValueSome v static member DiagnosticsLogger - with get () = getOrCreate diagnosticsLogger AssertFalseDiagnosticsLogger + with get () = getOrCreate diagnosticsLogger UninitialzedDiagnosticsLogger and set v = diagnosticsLogger.Value <- ValueSome v [] diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index fc05f09b8df..e4c193f3d7f 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -209,7 +209,7 @@ type DiagnosticsLogger = val DiscardErrorsLogger: DiagnosticsLogger /// Represents a DiagnosticsLogger that ignores diagnostics and asserts -val AssertFalseDiagnosticsLogger: DiagnosticsLogger +val UninitialzedDiagnosticsLogger: DiagnosticsLogger /// Represents a DiagnosticsLogger that captures all diagnostics, optionally formatting them /// eagerly. diff --git a/tests/service/ExprTests.fs b/tests/service/ExprTests.fs index 7b35568e38d..d50d2c2eb52 100644 --- a/tests/service/ExprTests.fs +++ b/tests/service/ExprTests.fs @@ -18,6 +18,7 @@ open System.Diagnostics open System.Threading open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Diagnostics +open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.IO open FSharp.Compiler.Service.Tests.Common open FSharp.Compiler.Symbols @@ -736,6 +737,10 @@ let ignoreTestIfStackOverflowExpected () = [] [] let ``Test Unoptimized Declarations Project1`` useTransparentCompiler = + + // TODO: Figure out why Transparent Compiler pushes diagnostics to the outer scope here. + if useTransparentCompiler then DiagnosticsAsyncState.DiagnosticsLogger <- DiscardErrorsLogger + let cleanup, options = Project1.createOptionsWithArgs [ "--langversion:preview" ] use _holder = cleanup let exprChecker = FSharpChecker.Create(keepAssemblyContents=true, useTransparentCompiler=useTransparentCompiler) @@ -877,6 +882,10 @@ let ``Test Unoptimized Declarations Project1`` useTransparentCompiler = [] [] let ``Test Optimized Declarations Project1`` useTransparentCompiler = + + // TODO: Figure out why Transparent Compiler pushes diagnostics to the outer scope here. + if useTransparentCompiler then DiagnosticsAsyncState.DiagnosticsLogger <- DiscardErrorsLogger + let cleanup, options = Project1.createOptionsWithArgs [ "--langversion:preview" ] use _holder = cleanup let exprChecker = FSharpChecker.Create(keepAssemblyContents=true, useTransparentCompiler=useTransparentCompiler) From d4e9031efa65aad891879c6638f5d86195bbf890 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Mon, 5 Feb 2024 17:19:17 +0100 Subject: [PATCH 29/43] typo --- src/Compiler/Facilities/DiagnosticsLogger.fs | 4 ++-- src/Compiler/Facilities/DiagnosticsLogger.fsi | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 4c15b219a92..17b0705ec34 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -343,7 +343,7 @@ let DiscardErrorsLogger = member _.ErrorCount = 0 } -let UninitialzedDiagnosticsLogger = +let UninitializedDiagnosticsLogger = { new DiagnosticsLogger("UninitialzedDiagnosticsLogger") with member _.DiagnosticSink(diagnostic, severity) = failwith "DiagnosticsAsyncState.DiagnosticsLogger not set." @@ -392,7 +392,7 @@ type DiagnosticsAsyncState = and set v = buildPhase.Value <- ValueSome v static member DiagnosticsLogger - with get () = getOrCreate diagnosticsLogger UninitialzedDiagnosticsLogger + with get () = getOrCreate diagnosticsLogger UninitializedDiagnosticsLogger and set v = diagnosticsLogger.Value <- ValueSome v [] diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index e4c193f3d7f..5273baea5fc 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -209,7 +209,7 @@ type DiagnosticsLogger = val DiscardErrorsLogger: DiagnosticsLogger /// Represents a DiagnosticsLogger that ignores diagnostics and asserts -val UninitialzedDiagnosticsLogger: DiagnosticsLogger +val UninitializedDiagnosticsLogger: DiagnosticsLogger /// Represents a DiagnosticsLogger that captures all diagnostics, optionally formatting them /// eagerly. From 2841e87654467d3314d42023eb2217e895ca3000 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Tue, 6 Feb 2024 10:03:23 +0100 Subject: [PATCH 30/43] preserve scope --- src/Compiler/Driver/CompilerImports.fs | 29 +++++++------- src/Compiler/Facilities/AsyncMemoize.fs | 39 ++++++++++--------- src/Compiler/Facilities/BuildGraph.fs | 20 +++++++--- src/Compiler/Facilities/BuildGraph.fsi | 5 ++- src/Compiler/Service/BackgroundCompiler.fs | 8 ++-- src/Compiler/Service/IncrementalBuild.fs | 6 +-- src/Compiler/Service/TransparentCompiler.fs | 6 +-- .../HashIfExpression.fs | 9 ++--- .../LanguageService/WorkspaceExtensions.fs | 1 + 9 files changed, 68 insertions(+), 55 deletions(-) diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 44cbe0d03c1..6f36721b3a5 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2238,21 +2238,22 @@ and [] TcImports | ParallelReferenceResolution.On -> Async.Parallel | ParallelReferenceResolution.Off -> Async.SequentialFailFast - use captureTasks = new CaptureDiagnosticsConcurrently(DiagnosticsAsyncState.DiagnosticsLogger) - - let! results = - nms - |> List.map (fun nm -> - async { - try - return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) - with e -> + let! results = async { + use captureTasks = new CaptureDiagnosticsConcurrently(DiagnosticsAsyncState.DiagnosticsLogger) + return! nms |> List.map (fun nm -> + async { use _ = UseDiagnosticsLogger captureTasks.LoggerForTask - - errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range)) - return None - }) - |> runMethod + try + // Async.CompilationScope because this task tends to replace ambient DiagnosticsLogger. + // TODO: Investigate why this acts defferent now then previously with NodeCode. + return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) |> Async.CompilationScope + with e -> + + errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range)) + return None + }) + |> runMethod + } let _dllinfos, phase2s = results |> Array.choose id |> List.ofArray |> List.unzip fixupOrphanCcus () diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs index e3ad00f891b..e4db56ba663 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fs +++ b/src/Compiler/Facilities/AsyncMemoize.fs @@ -354,15 +354,12 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T log (Restarted, key) Interlocked.Increment &restarted |> ignore System.Diagnostics.Trace.TraceInformation $"{name} Restarted {key.Label}" - let currentLogger = DiagnosticsAsyncState.DiagnosticsLogger - DiagnosticsAsyncState.DiagnosticsLogger <- cachingLogger - - try - let! result = computation - post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) - return () - finally - DiagnosticsAsyncState.DiagnosticsLogger <- currentLogger + use _ = UseDiagnosticsLogger cachingLogger + + let! result = computation + post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) + return () + with | TaskCancelled _ -> Interlocked.Increment &cancel_exception_subsequent |> ignore @@ -481,11 +478,19 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T Version = key.GetVersion() } + let callerDiagnosticLogger = + if DiagnosticsAsyncState.DiagnosticsLogger = UninitializedDiagnosticsLogger then + // TODO: Telemetry? + DiagnosticsAsyncState.DiagnosticsLogger <- DiscardErrorsLogger + + DiagnosticsAsyncState.DiagnosticsLogger + + // Preserve outer diagnostics scope in case the computation doesn't. + let computation = computation |> Async.CompilationScope + async { let! ct = Async.CancellationToken - let callerDiagnosticLogger = DiagnosticsAsyncState.DiagnosticsLogger - match! processRequest post (key, GetOrCompute(computation, ct)) callerDiagnosticLogger |> Async.AwaitTask @@ -500,17 +505,13 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T Async.StartAsTask( async { // TODO: Should unify starting and restarting - let currentLogger = DiagnosticsAsyncState.DiagnosticsLogger - DiagnosticsAsyncState.DiagnosticsLogger <- cachingLogger + use _ = UseDiagnosticsLogger cachingLogger log (Started, key) - try - let! result = computation - post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) - return result - finally - DiagnosticsAsyncState.DiagnosticsLogger <- currentLogger + let! result = computation + post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) + return result }, cancellationToken = linkedCtSource.Token ) diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index deebf21fa58..c2930a2a5c5 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -7,24 +7,32 @@ open System.Threading open System.Threading.Tasks open System.Globalization open Internal.Utilities.Library +open FSharp.Compiler.DiagnosticsLogger [] type Async = + static member CompilationScope(computation: Async<'T>) = + async { + use _ = + new CompilationGlobalsScope(DiagnosticsAsyncState.DiagnosticsLogger, DiagnosticsAsyncState.BuildPhase) + + return! computation + } + static member RunImmediateWithoutCancellation(computation) = try - let work = async { return! computation } - Async - .StartImmediateAsTask(work, cancellationToken = CancellationToken.None) + .StartImmediateAsTask(computation |> Async.CompilationScope, cancellationToken = CancellationToken.None) .Result with :? AggregateException as ex when ex.InnerExceptions.Count = 1 -> raise (ex.InnerExceptions[0]) - static member FromCancellable(computation: Cancellable<'T>) = Cancellable.toAsync computation + static member FromCancellableWithScope(computation: Cancellable<'T>) = + computation |> Cancellable.toAsync |> Async.CompilationScope static member StartAsTask_ForTesting(computation: Async<'T>, ?ct: CancellationToken) = - Async.StartAsTask(computation, cancellationToken = defaultArg ct CancellationToken.None) + Async.StartAsTask(computation |> Async.CompilationScope, cancellationToken = defaultArg ct CancellationToken.None) static member SequentialFailFast(computations: Async<'T> seq) = async { @@ -108,7 +116,7 @@ type GraphNode<'T> private (computation: Async<'T>, cachedResult: ValueOption<'T Async.StartWithContinuations( async { Thread.CurrentThread.CurrentUICulture <- GraphNode.culture - return! p + return! p |> Async.CompilationScope }, (fun res -> cachedResult <- ValueSome res diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index c5d44b5b360..a68cb5d3496 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -16,7 +16,10 @@ type Async = /// Execute the cancellable computation synchronously using the ambient cancellation token of /// the NodeCode. - static member FromCancellable: computation: Cancellable<'T> -> Async<'T> + static member FromCancellableWithScope: computation: Cancellable<'T> -> Async<'T> + + /// Wrap the computation with CompilationGlobalsScope to restore current DiagnosticsAsyncState after it returns. + static member CompilationScope: computation: Async<'T> -> Async<'T> /// Only used for testing, do not use static member StartAsTask_ForTesting: computation: Async<'T> * ?ct: CancellationToken -> Task<'T> diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index 8851adbc885..e95e47c0734 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -309,7 +309,7 @@ type internal BackgroundCompiler { new IProjectReference with member x.EvaluateRawContents() = async { - let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> Async.FromCancellable + let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> Async.FromCancellableWithScope match ilReaderOpt with | Some ilReader -> @@ -335,7 +335,7 @@ type internal BackgroundCompiler let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> Async.FromCancellable + |> Async.FromCancellableWithScope member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm @@ -727,7 +727,7 @@ type internal BackgroundCompiler keepAssemblyContents, suggestNamesForErrors ) - |> Async.FromCancellable + |> Async.FromCancellableWithScope GraphNode.SetPreferredUILang tcConfig.preferredUiLang return (parseResults, checkAnswer, sourceText.GetHashCode() |> int64, tcPrior.ProjectTimeStamp) @@ -1384,7 +1384,7 @@ type internal BackgroundCompiler return options, (diags @ diagnostics.Diagnostics) } - |> Cancellable.toAsync + |> Async.FromCancellableWithScope member bc.InvalidateConfiguration(options: FSharpProjectOptions, userOpName) = use _ = diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 8d0d2d0d94b..b1fd7a76538 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -277,7 +277,7 @@ type BoundModel private ( None, TcResultsSink.WithSink sink, prevTcInfo.tcState, input ) - |> Async.FromCancellable + |> Async.FromCancellableWithScope fileChecked.Trigger fileName @@ -391,7 +391,7 @@ type BoundModel private ( GraphNode.FromResult tcInfo, tcInfoExtras | _ -> // start computing extras, so that typeCheckNode can be GC'd quickly - startComputingFullTypeCheck |> Async.Catch |> Async.Ignore |> Async.Start + startComputingFullTypeCheck |> Async.CompilationScope |> Async.Catch |> Async.Ignore |> Async.Start getTcInfo typeCheckNode, tcInfoExtras member val Diagnostics = diagnostics @@ -1342,7 +1342,7 @@ type IncrementalBuilder(initialState: IncrementalBuilderInitialState, state: Inc let slotOfFile = builder.GetSlotOfFileName fileName let syntaxTree = currentState.slots[slotOfFile].SyntaxTree syntaxTree.ParseNode.GetOrComputeValue() - + |> Async.CompilationScope |> Async.RunSynchronously member builder.NotifyFileChanged(fileName, timeStamp) = diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index d3989e5ba82..dd4418ef30e 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -543,7 +543,7 @@ type internal TransparentCompiler { new IProjectReference with member x.EvaluateRawContents() = async { - let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> Cancellable.toAsync + let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> Async.FromCancellableWithScope match ilReaderOpt with | Some ilReader -> @@ -569,7 +569,7 @@ type internal TransparentCompiler let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> Async.FromCancellable + |> Async.FromCancellableWithScope member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm @@ -1174,7 +1174,7 @@ type internal TransparentCompiler prevTcInfo.tcState, input, true) - |> Cancellable.toAsync + |> Async.FromCancellableWithScope //fileChecked.Trigger fileName diff --git a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs index d83e379d70c..0cb607603e7 100644 --- a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs +++ b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs @@ -76,12 +76,11 @@ type public HashIfExpression() = errors, warnings, parser - do // Setup - DiagnosticsAsyncState.BuildPhase <- BuildPhase.Compile + // Setup + let globalScope = new CompilationGlobalsScope(DiagnosticsAsyncState.DiagnosticsLogger, BuildPhase.Compile) + interface IDisposable with // Teardown - member _.Dispose() = - DiagnosticsAsyncState.BuildPhase <- BuildPhase.DefaultPhase - DiagnosticsAsyncState.DiagnosticsLogger <- DiagnosticsAsyncState.DiagnosticsLogger + member _.Dispose() = (globalScope :> IDisposable).Dispose() [] member _.PositiveParserTestCases()= diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs index 6c3b04f1844..c729ad1342f 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs @@ -323,6 +323,7 @@ module private CheckerExtensions = return! createProjectSnapshot snapshotAccumulatorOpt project options ct |> Async.AwaitTask + |> Async.CompilationScope } ) From 37b6e1e0e25fc6d50c6821857e6e7b8d25fa1bab Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Tue, 6 Feb 2024 12:08:07 +0100 Subject: [PATCH 31/43] wrap EvaluateRawContents in scope --- src/Compiler/Driver/CompilerImports.fs | 5 +---- src/Compiler/Service/BackgroundCompiler.fs | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 6f36721b3a5..914f4bf4964 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2244,11 +2244,8 @@ and [] TcImports async { use _ = UseDiagnosticsLogger captureTasks.LoggerForTask try - // Async.CompilationScope because this task tends to replace ambient DiagnosticsLogger. - // TODO: Investigate why this acts defferent now then previously with NodeCode. - return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) |> Async.CompilationScope + return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) with e -> - errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range)) return None }) diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index e95e47c0734..c7657b54ad9 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -321,6 +321,7 @@ type internal BackgroundCompiler // continue to try to use an on-disk DLL return ProjectAssemblyDataResult.Unavailable false } + |> Async.CompilationScope member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = delayedReader.OutputFile From 4206ced5564c5d85cec73ae4d41dbf1b6dbbac8f Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Tue, 6 Feb 2024 13:04:56 +0100 Subject: [PATCH 32/43] wrap, too --- src/Compiler/Service/BackgroundCompiler.fs | 1 + src/Compiler/Service/StandardError.txt | 0 2 files changed, 1 insertion(+) create mode 100644 src/Compiler/Service/StandardError.txt diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index c7657b54ad9..e20e1a61426 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -298,6 +298,7 @@ type internal BackgroundCompiler Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm) return! self.GetAssemblyData(opts, userOpName + ".CheckReferencedProject(" + nm + ")") } + |> Async.CompilationScope member x.TryGetLogicalTimeStamp(cache) = self.TryGetLogicalTimeStampForProject(cache, opts) diff --git a/src/Compiler/Service/StandardError.txt b/src/Compiler/Service/StandardError.txt new file mode 100644 index 00000000000..e69de29bb2d From 2e8362921a5fe4bf7c058e6fc68403e685c465bb Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Tue, 6 Feb 2024 17:44:03 +0100 Subject: [PATCH 33/43] provisional fix to unblock transparent compiler --- src/Compiler/Service/TransparentCompiler.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index dd4418ef30e..7f33daef0ce 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1795,7 +1795,8 @@ type internal TransparentCompiler // Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] // TODO: might need to deal with exceptions here: - let tcConfigB, sourceFileNames, _ = ComputeTcConfigBuilder projectSnapshot + let tcConfigB, sourceFileNames, _ = + DiagnosticsLogger.suppressErrorReporting (fun () -> ComputeTcConfigBuilder projectSnapshot) let tcConfig = TcConfig.Create(tcConfigB, validate = true) From 96376d39d0a37db83e809fa94b463703057bf226 Mon Sep 17 00:00:00 2001 From: Jakub Majocha Date: Wed, 7 Feb 2024 10:18:44 +0100 Subject: [PATCH 34/43] naming --- src/Compiler/Driver/CompilerImports.fs | 2 +- src/Compiler/Facilities/BuildGraph.fs | 2 +- src/Compiler/Facilities/BuildGraph.fsi | 2 +- src/Compiler/Service/FSharpProjectSnapshot.fs | 2 +- src/Compiler/Service/IncrementalBuild.fs | 4 ++-- tests/FSharp.Test.Utilities/ProjectGeneration.fs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index 914f4bf4964..77c957f1cee 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -2236,7 +2236,7 @@ and [] TcImports let runMethod = match tcConfig.parallelReferenceResolution with | ParallelReferenceResolution.On -> Async.Parallel - | ParallelReferenceResolution.Off -> Async.SequentialFailFast + | ParallelReferenceResolution.Off -> Async.SequentialImmediate let! results = async { use captureTasks = new CaptureDiagnosticsConcurrently(DiagnosticsAsyncState.DiagnosticsLogger) diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index c2930a2a5c5..abb2fd0c52e 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -34,7 +34,7 @@ type Async = static member StartAsTask_ForTesting(computation: Async<'T>, ?ct: CancellationToken) = Async.StartAsTask(computation |> Async.CompilationScope, cancellationToken = defaultArg ct CancellationToken.None) - static member SequentialFailFast(computations: Async<'T> seq) = + static member SequentialImmediate(computations: Async<'T> seq) = async { let results = ResizeArray() diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index a68cb5d3496..ef05b61c122 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -24,7 +24,7 @@ type Async = /// Only used for testing, do not use static member StartAsTask_ForTesting: computation: Async<'T> * ?ct: CancellationToken -> Task<'T> - static member SequentialFailFast: computations: Async<'T> seq -> Async<'T array> + static member SequentialImmediate: computations: Async<'T> seq -> Async<'T array> /// Contains helpers related to the build graph [] diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 6842bc00fcc..3a1698bb5b5 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -568,7 +568,7 @@ and [] FSha async.Return <| FSharpReferencedProjectSnapshot.ILModuleReference(outputName, getStamp, getReader)) - |> Async.SequentialFailFast + |> Async.SequentialImmediate let referencesOnDisk, otherOptions = options.OtherOptions diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index b1fd7a76538..a81d1d167d5 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -740,12 +740,12 @@ module IncrementalBuilderHelpers = let diagnosticsLogger = CompilationDiagnosticLogger("FinalizeTypeCheckTask", tcConfig.diagnosticsOptions) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck) - let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> Async.SequentialFailFast + let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> Async.SequentialImmediate let! tcInfos = computedBoundModels |> Seq.map (fun boundModel -> async { return! boundModel.GetOrComputeTcInfo() }) - |> Async.SequentialFailFast + |> Async.SequentialImmediate // tcInfoExtras can be computed in parallel. This will check any previously skipped implementation files in parallel, too. let! latestImplFiles = diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index e32e8ae692e..c187f10e269 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -793,7 +793,7 @@ module ProjectOperations = let! projects = p.DependsOn |> Seq.map (absorbAutoGeneratedSignatures checker) - |> Async.SequentialFailFast + |> Async.SequentialImmediate return { p with SourceFiles = files From ff358b91757903bb4b525cf66fad8d6af54860e2 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 14:28:23 +0100 Subject: [PATCH 35/43] Plug in dependency files --- src/Compiler/Service/TransparentCompiler.fs | 4 +--- tests/service/ProjectAnalysisTests.fs | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 0795cb6c17a..df2d1c602c1 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1474,8 +1474,6 @@ type internal TransparentCompiler let tcSymbolUses = sink.GetSymbolUses() let tcOpenDeclarations = sink.GetOpenDeclarations() - let tcDependencyFiles = [] // TODO add as a set to TcIntermediate - // TODO: Apparently creating diagnostics can produce further diagnostics. So let's capture those too. Hopefully there is a more elegant solution... // Probably diagnostics need to be evaluated during typecheck anyway for proper formatting, which might take care of this too. let extraLogger = CapturingDiagnosticsLogger("DiagnosticsWhileCreatingDiagnostics") @@ -1535,7 +1533,7 @@ type internal TransparentCompiler projectSnapshot.IsIncompleteTypeCheckEnvironment, None, projectSnapshot.ToOptions(), - Array.ofList tcDependencyFiles, + Array.ofList tcInfo.tcDependencyFiles, creationDiags, parseResults.Diagnostics, tcDiagnostics, diff --git a/tests/service/ProjectAnalysisTests.fs b/tests/service/ProjectAnalysisTests.fs index a1a58a709b2..8a643c9a7bc 100644 --- a/tests/service/ProjectAnalysisTests.fs +++ b/tests/service/ProjectAnalysisTests.fs @@ -4593,8 +4593,13 @@ let ``Test project35b Dependency files for ParseAndCheckFileInProject`` () = for d in checkFileResults.DependencyFiles do printfn "ParseAndCheckFileInProject dependency: %s" d checkFileResults.DependencyFiles |> Array.exists (fun s -> s.Contains "notexist.dll") |> shouldEqual true - // The file itself is not a dependency since it is never read from the file system when using ParseAndCheckFileInProject - checkFileResults.DependencyFiles |> Array.exists (fun s -> s.Contains Project35b.fileName1) |> shouldEqual false + + if not checker.UsesTransparentCompiler then + // The file itself is not a dependency since it is never read from the file system when using ParseAndCheckFileInProject + checkFileResults.DependencyFiles |> Array.exists (fun s -> s.Contains Project35b.fileName1) |> shouldEqual false + else + // Transparent compiler doesn't differentiate between foreground and background requests. All files have to be present in the input snapshot so the filesystem doesn't have to be watched for those. Maybe source files shouldn't be included in the dependency list at all. But they show the dependencies gathered from graph-based checking which could be useful? + () [] let ``Test project35b Dependency files for GetBackgroundCheckResultsForFileInProject`` () = @@ -4602,8 +4607,13 @@ let ``Test project35b Dependency files for GetBackgroundCheckResultsForFileInPro for d in checkFileResults.DependencyFiles do printfn "GetBackgroundCheckResultsForFileInProject dependency: %s" d checkFileResults.DependencyFiles |> Array.exists (fun s -> s.Contains "notexist.dll") |> shouldEqual true - // The file is a dependency since it is read from the file system when using GetBackgroundCheckResultsForFileInProject - checkFileResults.DependencyFiles |> Array.exists (fun s -> s.Contains Project35b.fileName1) |> shouldEqual true + + if not checker.UsesTransparentCompiler then + // The file is a dependency since it is read from the file system when using GetBackgroundCheckResultsForFileInProject + checkFileResults.DependencyFiles |> Array.exists (fun s -> s.Contains Project35b.fileName1) |> shouldEqual true + else + // Transparent compiler doesn't differentiate between foreground and background requests. All files have to be present in the input snapshot so the filesystem doesn't have to be watched for those. Maybe source files shouldn't be included in the dependency list at all. But they show the dependencies gathered from graph-based checking which could be useful? + () [] let ``Test project35b Dependency files for check of project`` () = From f176a0d4025e7a7e8d8d0b173d90bdf817509b70 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 15:55:23 +0100 Subject: [PATCH 36/43] pipeline update --- azure-pipelines.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index df00f0bc2c2..919ac948f47 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,4 +1,4 @@ -# CI and PR triggers +# CI and PR triggers trigger: branches: include: @@ -433,6 +433,10 @@ stages: vs_release: _configuration: Release _testKind: testVs + experimental_features: + _configuration: Release + _testKind: testCoreclr + ${{ if eq(variables['Build.Reason'], 'Flaky, disabled, was PullRequest') }}: inttests_release: _configuration: Release @@ -450,7 +454,15 @@ stages: env: NativeToolsOnMachine: true displayName: Build / Test - condition: ne(variables['_testKind'], 'testIntegration') + condition: and( ne(variables['_testKind'], 'testIntegration'), ne(variables['System.JobName'], 'experimental_features') ) + + - script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind) + env: + FSHARP_EXPERIMENTAL_FEATURES: 1 + NativeToolsOnMachine: true + displayName: Build / Test Experimental Features + condition: and( eq(variables['System.JobName'], 'experimental_features'), ne(variables['_testKind'], 'testIntegration') ) + - script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind) env: NativeToolsOnMachine: true From deac66c526af1d092dbcb1c0c93afc2efc40fd78 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 17:27:25 +0100 Subject: [PATCH 37/43] more tests, separating pipeline from experimental features --- azure-pipelines.yml | 10 +++++----- .../TypeChecks/TyparNameTests.fs | 2 +- .../FSharpExprPatternsTests.fs | 4 +++- tests/FSharp.Compiler.Service.Tests/TooltipTests.fs | 8 ++++++-- tests/FSharp.Test.Utilities/CompilerAssert.fs | 7 +++++-- .../FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj | 2 +- tests/FSharp.Test.Utilities/ProjectGeneration.fs | 2 +- tests/service/AssemblyContentProviderTests.fs | 3 ++- tests/service/PerfTests.fs | 3 ++- .../FSharp.Editor.Tests/BraceMatchingServiceTests.fs | 3 ++- .../EditorFormattingServiceTests.fs | 8 ++++---- .../FSharp.Editor.Tests/IndentationServiceTests.fs | 2 +- .../FSharp.Editor.Tests/SignatureHelpProviderTests.fs | 3 ++- 13 files changed, 35 insertions(+), 22 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 919ac948f47..24984bc3a30 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -433,7 +433,7 @@ stages: vs_release: _configuration: Release _testKind: testVs - experimental_features: + transparent_compiler: _configuration: Release _testKind: testCoreclr @@ -454,14 +454,14 @@ stages: env: NativeToolsOnMachine: true displayName: Build / Test - condition: and( ne(variables['_testKind'], 'testIntegration'), ne(variables['System.JobName'], 'experimental_features') ) + condition: and( ne(variables['_testKind'], 'testIntegration'), ne(variables['System.JobName'], 'transparent_compiler') ) - script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind) env: - FSHARP_EXPERIMENTAL_FEATURES: 1 + TEST_TRANSPARENT_COMPILER: 1 NativeToolsOnMachine: true - displayName: Build / Test Experimental Features - condition: and( eq(variables['System.JobName'], 'experimental_features'), ne(variables['_testKind'], 'testIntegration') ) + displayName: Build / Test Transparent Compiler + condition: and( eq(variables['System.JobName'], 'transparent_compiler'), ne(variables['_testKind'], 'testIntegration') ) - script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind) env: diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/TyparNameTests.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/TyparNameTests.fs index 339fa1e2629..d8316d365e7 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/TyparNameTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/TyparNameTests.fs @@ -14,7 +14,7 @@ module TyparNameTests = (additionalFile: SourceCodeFileKind) : string array = let typeCheckResult = - cUnit |> withAdditionalSourceFile additionalFile |> typecheckProject false false + cUnit |> withAdditionalSourceFile additionalFile |> typecheckProject false CompilerAssertHelpers.UseTransparentCompiler assert (Array.isEmpty typeCheckResult.Diagnostics) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharpExprPatternsTests.fs b/tests/FSharp.Compiler.Service.Tests/FSharpExprPatternsTests.fs index 5d31b6f74fc..a50010f6f86 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharpExprPatternsTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/FSharpExprPatternsTests.fs @@ -1,5 +1,7 @@ module FSharp.Compiler.Service.Tests.FSharpExprPatternsTests +open FSharp.Test + #nowarn "57" open FSharp.Compiler.CodeAnalysis @@ -137,7 +139,7 @@ let testPatterns handler source = } let checker = - FSharpChecker.Create(documentSource = DocumentSource.Custom documentSource, keepAssemblyContents = true) + FSharpChecker.Create(documentSource = DocumentSource.Custom documentSource, keepAssemblyContents = true, useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let checkResult = checker.ParseAndCheckFileInProject("A.fs", 0, Map.find "A.fs" files, projectOptions) diff --git a/tests/FSharp.Compiler.Service.Tests/TooltipTests.fs b/tests/FSharp.Compiler.Service.Tests/TooltipTests.fs index 92993a62a61..d3e08461809 100644 --- a/tests/FSharp.Compiler.Service.Tests/TooltipTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/TooltipTests.fs @@ -1,5 +1,6 @@ module FSharp.Compiler.Service.Tests.TooltipTests + #nowarn "57" open FSharp.Compiler.CodeAnalysis @@ -8,6 +9,7 @@ open FSharp.Compiler.Text open FSharp.Compiler.Tokenization open FSharp.Compiler.EditorServices open FSharp.Compiler.Symbols +open FSharp.Test open NUnit.Framework let testXmlDocFallbackToSigFileWhileInImplFile sigSource implSource line colAtEndOfNames lineText names (expectedContent: string) = @@ -29,7 +31,8 @@ let testXmlDocFallbackToSigFileWhileInImplFile sigSource implSource line colAtEn SourceFiles = [| "A.fsi"; "A.fs" |] } let checker = - FSharpChecker.Create(documentSource = DocumentSource.Custom documentSource) + FSharpChecker.Create(documentSource = DocumentSource.Custom documentSource, + useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let checkResult = checker.ParseAndCheckFileInProject("A.fs", 0, Map.find "A.fs" files, projectOptions) @@ -276,7 +279,8 @@ let testToolTipSquashing source line colAtEndOfNames lineText names tokenTag = SourceFiles = [| "A.fs" |] } let checker = - FSharpChecker.Create(documentSource = DocumentSource.Custom documentSource) + FSharpChecker.Create(documentSource = DocumentSource.Custom documentSource, + useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let checkResult = checker.ParseAndCheckFileInProject("A.fs", 0, Map.find "A.fs" files, projectOptions) diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 7951ba31d5d..b22e0b2d020 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -259,8 +259,11 @@ and Compilation = module rec CompilerAssertHelpers = - let useTransparentCompiler = FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically - let checker = FSharpChecker.Create(suggestNamesForErrors=true, useTransparentCompiler=useTransparentCompiler) + let UseTransparentCompiler = + FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically || + not (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TEST_TRANSPARENT_COMPILER"))) + + let checker = FSharpChecker.Create(suggestNamesForErrors=true, useTransparentCompiler=UseTransparentCompiler) // Unlike C# whose entrypoint is always string[] F# can make an entrypoint with 0 args, or with an array of string[] let mkDefaultArgs (entryPoint:MethodBase) : obj[] = [| diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj index 5cfcba98ca7..d3307295480 100644 --- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj +++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj @@ -28,11 +28,11 @@ scriptlib.fsx - + diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index 2236eee988d..2157d8fb7fe 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -931,7 +931,7 @@ type ProjectWorkflowBuilder ?isExistingProject ) = - let useTransparentCompiler = defaultArg useTransparentCompiler FSharp.Compiler.CompilerConfig.FSharpExperimentalFeaturesEnabledAutomatically + let useTransparentCompiler = defaultArg useTransparentCompiler CompilerAssertHelpers.UseTransparentCompiler let useGetSource = not useTransparentCompiler && defaultArg useGetSource false let useChangeNotifications = not useTransparentCompiler && defaultArg useChangeNotifications false let autoStart = defaultArg autoStart true diff --git a/tests/service/AssemblyContentProviderTests.fs b/tests/service/AssemblyContentProviderTests.fs index 41d6a8c660f..03deb321c24 100644 --- a/tests/service/AssemblyContentProviderTests.fs +++ b/tests/service/AssemblyContentProviderTests.fs @@ -12,6 +12,7 @@ open NUnit.Framework open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.EditorServices open FSharp.Compiler.Service.Tests.Common +open FSharp.Test let private filePath = "C:\\test.fs" @@ -28,7 +29,7 @@ let private projectOptions : FSharpProjectOptions = UnresolvedReferences = None Stamp = None } -let private checker = FSharpChecker.Create() +let private checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let private assertAreEqual (expected, actual) = if actual <> expected then diff --git a/tests/service/PerfTests.fs b/tests/service/PerfTests.fs index b3c47903283..86619d57e78 100644 --- a/tests/service/PerfTests.fs +++ b/tests/service/PerfTests.fs @@ -16,9 +16,10 @@ open FSharp.Compiler.IO open FSharp.Compiler.Text open FSharp.Compiler.Service.Tests.Common open TestFramework +open FSharp.Test // Create an interactive checker instance -let internal checker = FSharpChecker.Create() +let internal checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) module internal Project1 = diff --git a/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs index 135d5d31f2f..60bd773b6b4 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs @@ -8,9 +8,10 @@ open Microsoft.CodeAnalysis.Text open FSharp.Compiler.CodeAnalysis open Microsoft.VisualStudio.FSharp.Editor open FSharp.Editor.Tests.Helpers +open FSharp.Test type BraceMatchingServiceTests() = - let checker = FSharpChecker.Create() + let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let fileName = "C:\\test.fs" diff --git a/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs index 9442957325f..75f9469a6b2 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs @@ -57,7 +57,7 @@ marker4""" [] [] member this.TestIndentation(marker: string, expectedLine: string) = - let checker = FSharpChecker.Create() + let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let position = indentTemplate.IndexOf(marker) Assert.True(position >= 0, "Precondition failed: unable to find marker in template") @@ -94,7 +94,7 @@ marker4""" [] [] member this.TestPasteChanges_PastingOntoIndentedLine(enabled: bool, prefix: string) = - let checker = FSharpChecker.Create() + let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions RoslynTestHelpers.DefaultProjectOptions @@ -160,7 +160,7 @@ somethingElseHere [] [] member this.TestPasteChanges_PastingOntoEmptyLine(prefix: string) = - let checker = FSharpChecker.Create() + let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions RoslynTestHelpers.DefaultProjectOptions @@ -220,7 +220,7 @@ somethingElseHere [] member this.TestPasteChanges_PastingWithAutoIndentationInPasteSpan() = - let checker = FSharpChecker.Create() + let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions RoslynTestHelpers.DefaultProjectOptions diff --git a/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs index 81f2bfc7f09..723e535ac5d 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs @@ -12,7 +12,7 @@ open FSharp.Editor.Tests.Helpers open FSharp.Test type IndentationServiceTests() = - let checker = FSharpChecker.Create() + let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let filePath = "C:\\test.fs" diff --git a/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs b/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs index af66c01ed69..232764cdc37 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs @@ -12,6 +12,7 @@ open FSharp.Editor.Tests.Helpers open Microsoft.CodeAnalysis open Microsoft.IO open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks +open FSharp.Test module SignatureHelpProvider = let private DefaultDocumentationProvider = @@ -20,7 +21,7 @@ module SignatureHelpProvider = override doc.AppendDocumentation(_, _, _, _, _, _, _, _) = () } - let checker = FSharpChecker.Create() + let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let filePath = "C:\\test.fs" From 0664ffe4b2218cc9e5671c1baf8f1d4d46dd741b Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 19:01:34 +0100 Subject: [PATCH 38/43] Use DocumentSource when creating snapshot from options --- src/Compiler/Service/FSharpCheckerResults.fs | 5 +++ src/Compiler/Service/FSharpCheckerResults.fsi | 6 +++ src/Compiler/Service/FSharpProjectSnapshot.fs | 42 +++++++++++++++--- src/Compiler/Service/TransparentCompiler.fs | 44 ++++++++++++++----- src/Compiler/Service/service.fs | 5 --- src/Compiler/Service/service.fsi | 6 --- 6 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index f55010a9025..045e0aae7a0 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -60,6 +60,11 @@ open Internal.Utilities.Hashing type FSharpUnresolvedReferencesSet = FSharpUnresolvedReferencesSet of UnresolvedAssemblyReference list +[] +type DocumentSource = + | FileSystem + | Custom of (string -> Async) + [] type DelayedILModuleReader = val private name: string diff --git a/src/Compiler/Service/FSharpCheckerResults.fsi b/src/Compiler/Service/FSharpCheckerResults.fsi index 26781c4356e..0ae8b3039d9 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fsi +++ b/src/Compiler/Service/FSharpCheckerResults.fsi @@ -30,6 +30,12 @@ open FSharp.Compiler.Text open Internal.Utilities.Collections +[] +[] +type DocumentSource = + | FileSystem + | Custom of (string -> Async) + /// Delays the creation of an ILModuleReader [] type DelayedILModuleReader = diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index 148d39da787..cdc7ffe9252 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -81,6 +81,25 @@ type FSharpFileSnapshot(FileName: string, Version: string, GetSource: unit -> Ta |> Task.FromResult ) + static member CreateFromDocumentSource(fileName: string, documentSource: DocumentSource) = + + match documentSource with + | DocumentSource.Custom f -> + let version = DateTime.Now.Ticks.ToString() + + FSharpFileSnapshot( + fileName, + version, + fun () -> + task { + match! f fileName |> Async.StartAsTask with + | Some source -> return SourceTextNew.ofISourceText source + | None -> return failwith $"Couldn't get source for file {f}" + } + ) + + | DocumentSource.FileSystem -> FSharpFileSnapshot.CreateFromFileSystem fileName + member public _.FileName = FileName member _.Version = Version member _.GetSource() = GetSource() @@ -603,13 +622,22 @@ and [] FSha return snapshotAccumulator[options] } - static member internal GetFileSnapshotFromDisk _ fileName = - FSharpFileSnapshot.CreateFromFileSystem fileName |> async.Return - - static member FromOptions(options: FSharpProjectOptions) = - FSharpProjectSnapshot.FromOptions(options, FSharpProjectSnapshot.GetFileSnapshotFromDisk) + static member FromOptions(options: FSharpProjectOptions, documentSource: DocumentSource) = + FSharpProjectSnapshot.FromOptions( + options, + fun _ fileName -> + FSharpFileSnapshot.CreateFromDocumentSource(fileName, documentSource) + |> async.Return + ) - static member FromOptions(options: FSharpProjectOptions, fileName: string, fileVersion: int, sourceText: ISourceText) = + static member FromOptions + ( + options: FSharpProjectOptions, + fileName: string, + fileVersion: int, + sourceText: ISourceText, + documentSource: DocumentSource + ) = let getFileSnapshot _ fName = if fName = fileName then @@ -619,7 +647,7 @@ and [] FSha fun () -> Task.FromResult(SourceTextNew.ofISourceText sourceText) ) else - FSharpFileSnapshot.CreateFromFileSystem fName + FSharpFileSnapshot.CreateFromDocumentSource(fName, documentSource) |> async.Return FSharpProjectSnapshot.FromOptions(options, getFileSnapshot) diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index df2d1c602c1..124be183fd9 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -325,6 +325,11 @@ type internal TransparentCompiler useSyntaxTreeCache ) as self = + let documentSource = + match getSource with + | Some getSource -> DocumentSource.Custom getSource + | None -> DocumentSource.FileSystem + // Is having just one of these ok? let lexResourceManager = Lexhelp.LexResourceManager() @@ -1932,7 +1937,7 @@ type internal TransparentCompiler ) : NodeCode = node { let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) + FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText, documentSource) |> NodeCode.AwaitAsync ignore parseResults @@ -1953,7 +1958,7 @@ type internal TransparentCompiler ) : NodeCode = node { let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) + FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText, documentSource) |> NodeCode.AwaitAsync ignore parseResults @@ -2005,7 +2010,10 @@ type internal TransparentCompiler ) : NodeCode> = node { ignore canInvalidateProject - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + + let! snapshot = + FSharpProjectSnapshot.FromOptions(options, documentSource) + |> NodeCode.AwaitAsync return! this.FindReferencesInFile(fileName, snapshot.ProjectSnapshot, symbol, userOpName) } @@ -2018,7 +2026,10 @@ type internal TransparentCompiler member this.GetAssemblyData(options: FSharpProjectOptions, fileName, userOpName: string) : NodeCode = node { - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + let! snapshot = + FSharpProjectSnapshot.FromOptions(options, documentSource) + |> NodeCode.AwaitAsync + return! this.GetAssemblyData(snapshot.ProjectSnapshot, fileName, userOpName) } @@ -2037,7 +2048,9 @@ type internal TransparentCompiler userOpName: string ) : NodeCode = node { - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + let! snapshot = + FSharpProjectSnapshot.FromOptions(options, documentSource) + |> NodeCode.AwaitAsync match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) with | parseResult, FSharpCheckFileAnswer.Succeeded checkResult -> return parseResult, checkResult @@ -2051,7 +2064,10 @@ type internal TransparentCompiler userOpName: string ) : NodeCode = node { - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + let! snapshot = + FSharpProjectSnapshot.FromOptions(options, documentSource) + |> NodeCode.AwaitAsync + return! this.ParseFile(fileName, snapshot.ProjectSnapshot, userOpName) } @@ -2066,7 +2082,7 @@ type internal TransparentCompiler ignore builder let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, 1, sourceText) + FSharpProjectSnapshot.FromOptions(options, fileName, 1, sourceText, documentSource) |> NodeCode.AwaitAsync match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, "GetCachedCheckFileResult") with @@ -2116,7 +2132,11 @@ type internal TransparentCompiler ) : NodeCode = node { ignore userOpName - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + + let! snapshot = + FSharpProjectSnapshot.FromOptions(options, documentSource) + |> NodeCode.AwaitAsync + return! ComputeSemanticClassification(fileName, snapshot.ProjectSnapshot) } @@ -2139,7 +2159,7 @@ type internal TransparentCompiler ) : NodeCode = node { let! snapshot = - FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText) + FSharpProjectSnapshot.FromOptions(options, fileName, fileVersion, sourceText, documentSource) |> NodeCode.AwaitAsync return! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) @@ -2151,7 +2171,11 @@ type internal TransparentCompiler member this.ParseAndCheckProject(options: FSharpProjectOptions, userOpName: string) : NodeCode = node { ignore userOpName - let! snapshot = FSharpProjectSnapshot.FromOptions options |> NodeCode.AwaitAsync + + let! snapshot = + FSharpProjectSnapshot.FromOptions(options, documentSource) + |> NodeCode.AwaitAsync + return! ComputeParseAndCheckProject snapshot.ProjectSnapshot } diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 492ff2da497..803755ab13f 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -37,11 +37,6 @@ open FSharp.Compiler.Text.Range open FSharp.Compiler.TcGlobals open FSharp.Compiler.BuildGraph -[] -type DocumentSource = - | FileSystem - | Custom of (string -> Async) - /// Callback that indicates whether a requested result has become obsolete. [] type IsResultObsolete = IsResultObsolete of (unit -> bool) diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi index 14124fbda6b..e74249cd604 100644 --- a/src/Compiler/Service/service.fsi +++ b/src/Compiler/Service/service.fsi @@ -19,12 +19,6 @@ open FSharp.Compiler.Syntax open FSharp.Compiler.Text open FSharp.Compiler.Tokenization -[] -[] -type DocumentSource = - | FileSystem - | Custom of (string -> Async) - /// Used to parse and check F# source code. [] type public FSharpChecker = From 665b9093f676858bf4526b54526fd8bfe5f63260 Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 20:29:53 +0100 Subject: [PATCH 39/43] stabilize AsyncMemoize.Basics test --- .../CompilerService/AsyncMemoize.fs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index e442335f940..7c252019e2d 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs @@ -54,6 +54,8 @@ type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality>(mem let actual = events |> Seq.toArray Assert.Equal<_ array>(expected, actual) + member _.Sequence = events |> Seq.map id + [] let ``Basics``() = @@ -63,10 +65,8 @@ let ``Basics``() = return key * 2 } - let eventLog = ConcurrentBag() - let memoize = AsyncMemoize() - memoize.OnEvent(fun (e, (_label, k, _version)) -> eventLog.Add (e, k)) + let events = EventRecorder(memoize) let result = seq { @@ -84,7 +84,9 @@ let ``Basics``() = Assert.Equal(expected, result) - let groups = eventLog |> Seq.groupBy snd |> Seq.toList + (waitUntil (events.CountOf Finished) 3).Wait() + + let groups = events.Sequence |> Seq.groupBy snd |> Seq.toList Assert.Equal(3, groups.Length) for key, events in groups do Assert.Equal>(Set [ Requested, key; Started, key; Finished, key ], Set events) From 3656a737d56b7ee078a9ed93255e17c93757922e Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 20:30:03 +0100 Subject: [PATCH 40/43] surfacearea --- ...harp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl | 5 +++-- ...rp.Compiler.Service.SurfaceArea.netstandard20.release.bsl | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) 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 e53606d2de3..da61adbe19b 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 @@ -2304,6 +2304,7 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Boolean Equals( FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Boolean IsSignatureFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Boolean get_IsSignatureFile() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: FSharpFileSnapshot Create(System.String, System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceTextNew]]) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: FSharpFileSnapshot CreateFromDocumentSource(System.String, FSharp.Compiler.CodeAnalysis.DocumentSource) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: FSharpFileSnapshot CreateFromFileSystem(System.String) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Int32 GetHashCode() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: System.String FileName @@ -2333,9 +2334,9 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjec FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectIdentifier get_Identifier() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Create(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+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.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Replace(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot]) -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.CodeAnalysis.DocumentSource) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+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.ProjectSnapshot+FSharpFileSnapshot]]], Microsoft.FSharp.Core.FSharpOption`1[System.Collections.Generic.Dictionary`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot]]) -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.DocumentSource) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_Label() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_snapshot() 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 e53606d2de3..da61adbe19b 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 @@ -2304,6 +2304,7 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Boolean Equals( FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Boolean IsSignatureFile FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Boolean get_IsSignatureFile() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: FSharpFileSnapshot Create(System.String, System.String, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Threading.Tasks.Task`1[FSharp.Compiler.Text.ISourceTextNew]]) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: FSharpFileSnapshot CreateFromDocumentSource(System.String, FSharp.Compiler.CodeAnalysis.DocumentSource) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: FSharpFileSnapshot CreateFromFileSystem(System.String) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: Int32 GetHashCode() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot: System.String FileName @@ -2333,9 +2334,9 @@ FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjec FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectIdentifier get_Identifier() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Create(System.String, Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+ReferenceOnDisk], Microsoft.FSharp.Collections.FSharpList`1[System.String], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+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.ProjectSnapshot+FSharpProjectSnapshot: FSharpProjectSnapshot Replace(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpFileSnapshot]) -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.CodeAnalysis.DocumentSource) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+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.ProjectSnapshot+FSharpFileSnapshot]]], Microsoft.FSharp.Core.FSharpOption`1[System.Collections.Generic.Dictionary`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot]]) -FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText) +FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: Microsoft.FSharp.Control.FSharpAsync`1[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot] FromOptions(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.DocumentSource) FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String Label FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot: System.String get_Label() FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpReferencedProjectSnapshot+FSharpReference: FSharpProjectSnapshot get_snapshot() From 57d13b5c0cd2ebd8281d1eb24a384f248ab48bba Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 20:57:07 +0100 Subject: [PATCH 41/43] revert test --- tests/service/PerfTests.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/service/PerfTests.fs b/tests/service/PerfTests.fs index 86619d57e78..b3c47903283 100644 --- a/tests/service/PerfTests.fs +++ b/tests/service/PerfTests.fs @@ -16,10 +16,9 @@ open FSharp.Compiler.IO open FSharp.Compiler.Text open FSharp.Compiler.Service.Tests.Common open TestFramework -open FSharp.Test // Create an interactive checker instance -let internal checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) +let internal checker = FSharpChecker.Create() module internal Project1 = From a9191939916365671ac719583138dca517ec5e0a Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Thu, 8 Feb 2024 23:33:08 +0100 Subject: [PATCH 42/43] f --- .../BraceMatchingServiceTests.fs | 3 ++- .../EditorFormattingServiceTests.fs | 13 +++++++++---- .../FSharp.Editor.Tests/IndentationServiceTests.fs | 3 ++- .../SignatureHelpProviderTests.fs | 3 ++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs index 60bd773b6b4..8027a06e85f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs @@ -11,7 +11,8 @@ open FSharp.Editor.Tests.Helpers open FSharp.Test type BraceMatchingServiceTests() = - let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let fileName = "C:\\test.fs" diff --git a/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs index 75f9469a6b2..985abc67e31 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/EditorFormattingServiceTests.fs @@ -57,7 +57,9 @@ marker4""" [] [] member this.TestIndentation(marker: string, expectedLine: string) = - let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) + let position = indentTemplate.IndexOf(marker) Assert.True(position >= 0, "Precondition failed: unable to find marker in template") @@ -94,7 +96,8 @@ marker4""" [] [] member this.TestPasteChanges_PastingOntoIndentedLine(enabled: bool, prefix: string) = - let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions RoslynTestHelpers.DefaultProjectOptions @@ -160,7 +163,8 @@ somethingElseHere [] [] member this.TestPasteChanges_PastingOntoEmptyLine(prefix: string) = - let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions RoslynTestHelpers.DefaultProjectOptions @@ -220,7 +224,8 @@ somethingElseHere [] member this.TestPasteChanges_PastingWithAutoIndentationInPasteSpan() = - let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let parsingOptions, _ = checker.GetParsingOptionsFromProjectOptions RoslynTestHelpers.DefaultProjectOptions diff --git a/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs index 723e535ac5d..6b70bb07c8c 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/IndentationServiceTests.fs @@ -12,7 +12,8 @@ open FSharp.Editor.Tests.Helpers open FSharp.Test type IndentationServiceTests() = - let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let filePath = "C:\\test.fs" diff --git a/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs b/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs index 232764cdc37..f85ee51a6c8 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/SignatureHelpProviderTests.fs @@ -21,7 +21,8 @@ module SignatureHelpProvider = override doc.AppendDocumentation(_, _, _, _, _, _, _, _) = () } - let checker = FSharpChecker.Create(useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let filePath = "C:\\test.fs" From 4223425501af61e69e4384d9e294255f6e3646fa Mon Sep 17 00:00:00 2001 From: 0101 <0101@innit.cz> Date: Fri, 9 Feb 2024 11:06:40 +0100 Subject: [PATCH 43/43] un-hardcode seed --- .../FSharpChecker/TransparentCompiler.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs index 664b79d4e0e..cbc8e7690fe 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs @@ -651,7 +651,7 @@ let fuzzingTest seed (project: SyntheticProject) = task { [] let Fuzzing signatureFiles = - let seed = 1106087513 + let seed = System.Random().Next() let rng = System.Random(int seed) let fileCount = 30 @@ -711,7 +711,6 @@ type GiraffeTheoryAttribute() = [] let GiraffeFuzzing signatureFiles = let seed = System.Random().Next() - //let seed = 1044159179 let giraffeDir = if signatureFiles then giraffeSignaturesDir else giraffeDir let giraffeTestsDir = if signatureFiles then giraffeSignaturesTestsDir else giraffeTestsDir