diff --git a/azure-pipelines.yml b/azure-pipelines.yml index df00f0bc2c..24984bc3a3 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 + transparent_compiler: + _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'], 'transparent_compiler') ) + + - script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind) + env: + TEST_TRANSPARENT_COMPILER: 1 + NativeToolsOnMachine: true + 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: NativeToolsOnMachine: true 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 6a4d44d2ae..aba40cf03b 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -27,3 +27,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. 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 a4b0a8a9f0..05bcf91879 100644 --- a/docs/release-notes/.VisualStudio/17.10.md +++ b/docs/release-notes/.VisualStudio/17.10.md @@ -6,3 +6,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 diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 32298c0cf0..92ab18ab7d 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 f59950f9e2..282e167bd1 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 d8d9ccd986..77c957f1ce 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 @@ -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,27 +2228,29 @@ 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 - - let! results = - nms - |> List.map (fun nm -> - node { - try - return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) - with e -> - errorR (Error(FSComp.SR.buildProblemReadingAssembly (nm.resolvedPath, e.Message), nm.originalReference.Range)) - return None - }) - |> runMethod + | ParallelReferenceResolution.On -> Async.Parallel + | ParallelReferenceResolution.Off -> Async.SequentialImmediate + + let! results = async { + use captureTasks = new CaptureDiagnosticsConcurrently(DiagnosticsAsyncState.DiagnosticsLogger) + return! nms |> List.map (fun nm -> + async { + use _ = UseDiagnosticsLogger captureTasks.LoggerForTask + try + return! tcImports.TryRegisterAndPrepareToImportReferencedDll(ctok, nm) + 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 () @@ -2282,7 +2284,7 @@ and [] TcImports ReportWarnings warns tcImports.RegisterAndImportReferencedAssemblies(ctok, res) - |> NodeCode.RunImmediateWithoutCancellation + |> Async.RunImmediateWithoutCancellation |> ignore true @@ -2383,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 @@ -2460,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 @@ -2553,7 +2555,7 @@ and [] TcImports dependencyProvider ) = - node { + async { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2571,7 +2573,7 @@ and [] TcImports } static member BuildTcImports(tcConfigP: TcConfigProvider, dependencyProvider) = - node { + async { let ctok = CompilationThreadToken() let tcConfig = tcConfigP.Get ctok @@ -2603,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 ac06a25c2d..9697e18968 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/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index 5a23c95ca7..c6464caa52 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/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 014ed84022..a09e748dff 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 b780d91ca7..e4db56ba66 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 @@ -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 = DiagnosticsThreadStatics.DiagnosticsLogger - DiagnosticsThreadStatics.DiagnosticsLogger <- cachingLogger - - try - let! result = computation |> Async.AwaitNodeCode - post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) - return () - finally - DiagnosticsThreadStatics.DiagnosticsLogger <- currentLogger + use _ = UseDiagnosticsLogger cachingLogger + + let! result = computation + post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) + return () + with | TaskCancelled _ -> Interlocked.Increment &cancel_exception_subsequent |> ignore @@ -481,14 +478,22 @@ type internal AsyncMemoize<'TKey, 'TVersion, 'TValue when 'TKey: equality and 'T Version = key.GetVersion() } - node { - let! ct = NodeCode.CancellationToken + 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 - let callerDiagnosticLogger = DiagnosticsThreadStatics.DiagnosticsLogger + async { + let! ct = Async.CancellationToken match! processRequest post (key, GetOrCompute(computation, ct)) callerDiagnosticLogger - |> NodeCode.AwaitTask + |> Async.AwaitTask with | New internalCt -> @@ -500,21 +505,17 @@ 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 + use _ = UseDiagnosticsLogger cachingLogger log (Started, key) - try - let! result = computation |> Async.AwaitNodeCode - post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) - return result - finally - DiagnosticsThreadStatics.DiagnosticsLogger <- currentLogger + let! result = computation + post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) + return result }, 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 +531,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 a34588e7af..6ffc787d14 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 71f4d3da99..abb2fd0c52 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -5,208 +5,46 @@ 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() +open FSharp.Compiler.DiagnosticsLogger [] -type NodeCode private () = - - static let cancellationToken = Node(wrapThreadStaticInfo Async.CancellationToken) +type Async = + static member CompilationScope(computation: Async<'T>) = + async { + use _ = + new CompilationGlobalsScope(DiagnosticsAsyncState.DiagnosticsLogger, DiagnosticsAsyncState.BuildPhase) - static member RunImmediate(computation: NodeCode<'T>, ct: CancellationToken) = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + return! computation + } + static member RunImmediateWithoutCancellation(computation) = try - try - let work = - async { - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase - return! computation |> Async.AwaitNodeCode - } + Async + .StartImmediateAsTask(computation |> Async.CompilationScope, cancellationToken = CancellationToken.None) + .Result - 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)) - - static member AwaitAsync(computation: Async<'T>) = Node(wrapThreadStaticInfo computation) - - static member AwaitTask(task: Task<'T>) = - Node(wrapThreadStaticInfo (Async.AwaitTask task)) + static member FromCancellableWithScope(computation: Cancellable<'T>) = + computation |> Cancellable.toAsync |> Async.CompilationScope - static member AwaitTask(task: Task) = - Node(wrapThreadStaticInfo (Async.AwaitTask task)) + static member StartAsTask_ForTesting(computation: Async<'T>, ?ct: CancellationToken) = + Async.StartAsTask(computation |> Async.CompilationScope, cancellationToken = defaultArg ct CancellationToken.None) - 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 { + static member SequentialImmediate(computations: Async<'T> seq) = + async { let results = ResizeArray() for computation in computations do - let! res = computation - results.Add(res) + let! result = computation + results.Add result 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 - [] module GraphNode = @@ -226,13 +64,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)) @@ -244,11 +82,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'. @@ -267,22 +105,22 @@ 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 { Thread.CurrentThread.CurrentUICulture <- GraphNode.culture - return! p + return! p |> Async.CompilationScope }, (fun res -> cachedResult <- ValueSome res - cachedResultNode <- node.Return res + cachedResultNode <- async.Return res computation <- Unchecked.defaultof<_> tcs.SetResult(res)), (fun ex -> tcs.SetException(ex)), @@ -290,7 +128,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 @@ -305,7 +143,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 afbf9d2898..ef05b61c12 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -2,89 +2,29 @@ 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> + static member FromCancellableWithScope: computation: Cancellable<'T> -> Async<'T> - /// Only used for testing, do not use - static member StartAsTask_ForTesting: computation: NodeCode<'T> * ?ct: CancellationToken -> Task<'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 AwaitWaitHandle_ForTesting: waitHandle: WaitHandle -> NodeCode + static member StartAsTask_ForTesting: computation: Async<'T> * ?ct: CancellationToken -> Task<'T> + + static member SequentialImmediate: computations: Async<'T> seq -> Async<'T array> /// Contains helpers related to the build graph [] @@ -102,7 +42,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 +50,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/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 08a46d1a25..17b0705ec3 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 [] @@ -342,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 UninitializedDiagnosticsLogger = + { new DiagnosticsLogger("UninitialzedDiagnosticsLogger") with + member _.DiagnosticSink(diagnostic, severity) = + failwith "DiagnosticsAsyncState.DiagnosticsLogger not set." + + member _.ErrorCount = failwith "DiagnosticsAsyncState.DiagnosticsLogger not set." } type CapturingDiagnosticsLogger(nm, ?eagerFormat) = @@ -375,28 +377,23 @@ 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 +type DiagnosticsAsyncState = + static let buildPhase = new AsyncLocal() + static let diagnosticsLogger = new AsyncLocal() - [] - static val mutable private diagnosticsLogger: DiagnosticsLogger - - static member BuildPhaseUnchecked = DiagnosticsThreadStatics.buildPhase + static let getOrCreate (holder: AsyncLocal<_>) defaultValue = + holder.Value + |> ValueOption.defaultWith (fun () -> + holder.Value <- ValueSome defaultValue + defaultValue) static member BuildPhase - with get () = - match box DiagnosticsThreadStatics.buildPhase with - | Null -> BuildPhase.DefaultPhase - | _ -> DiagnosticsThreadStatics.buildPhase - and set v = DiagnosticsThreadStatics.buildPhase <- v + with get () = getOrCreate buildPhase BuildPhase.DefaultPhase + and set v = buildPhase.Value <- ValueSome v static member DiagnosticsLogger - with get () = - match box DiagnosticsThreadStatics.diagnosticsLogger with - | Null -> AssertFalseDiagnosticsLogger - | _ -> DiagnosticsThreadStatics.diagnosticsLogger - and set v = DiagnosticsThreadStatics.diagnosticsLogger <- v + with get () = getOrCreate diagnosticsLogger UninitializedDiagnosticsLogger + and set v = diagnosticsLogger.Value <- ValueSome v [] module DiagnosticsLoggerExtensions = @@ -438,7 +435,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) @@ -498,32 +495,32 @@ module DiagnosticsLoggerExtensions = /// NOTE: The change will be undone when the returned "unwind" object disposes let UseBuildPhase (phase: BuildPhase) = - let oldBuildPhase = DiagnosticsThreadStatics.BuildPhaseUnchecked - 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 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. /// @@ -541,30 +538,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) @@ -573,13 +583,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)) @@ -598,7 +608,7 @@ let mlCompatError s m = [] let suppressErrorReporting f = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger + let diagnosticsLogger = DiagnosticsAsyncState.DiagnosticsLogger try let diagnosticsLogger = @@ -857,14 +867,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 e9040da36e..5273baea5f 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 UninitializedDiagnosticsLogger: DiagnosticsLogger /// Represents a DiagnosticsLogger that captures all diagnostics, optionally formatting them /// eagerly. @@ -228,12 +228,10 @@ type CapturingDiagnosticsLogger = /// Thread statics for the installed diagnostic logger [] -type DiagnosticsThreadStatics = +type DiagnosticsAsyncState = static member BuildPhase: BuildPhase with get, set - static member BuildPhaseUnchecked: BuildPhase - static member DiagnosticsLogger: DiagnosticsLogger with get, set [] @@ -286,6 +284,13 @@ 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/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index e5ff5b6c75..310c7b07af 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 f9f952dde7..e20e1a6142 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,10 +294,11 @@ 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 + ")") } + |> Async.CompilationScope member x.TryGetLogicalTimeStamp(cache) = self.TryGetLogicalTimeStampForProject(cache, opts) @@ -308,8 +309,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.FromCancellableWithScope match ilReaderOpt with | Some ilReader -> @@ -321,6 +322,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 @@ -335,7 +337,7 @@ type internal BackgroundCompiler let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> NodeCode.FromCancellable + |> Async.FromCancellableWithScope member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm @@ -345,7 +347,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 +454,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 +475,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 +536,7 @@ type internal BackgroundCompiler | _ -> let res = GraphNode( - node { + async { let! res = self.CheckOneFileImplAux( parseResults, @@ -620,7 +622,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 +662,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 +699,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 +729,7 @@ type internal BackgroundCompiler keepAssemblyContents, suggestNamesForErrors ) - |> NodeCode.FromCancellable + |> Async.FromCancellableWithScope GraphNode.SetPreferredUILang tcConfig.preferredUiLang return (parseResults, checkAnswer, sourceText.GetHashCode() |> int64, tcPrior.ProjectTimeStamp) @@ -746,7 +748,7 @@ type internal BackgroundCompiler creationDiags: FSharpDiagnostic[] ) = - node { + async { match! bc.GetCachedCheckFileResult(builder, fileName, sourceText, options) with | Some(_, results) -> return FSharpCheckFileAnswer.Succeeded results | _ -> @@ -767,7 +769,7 @@ type internal BackgroundCompiler options, userOpName ) = - node { + async { use _ = Activity.start "BackgroundCompiler.CheckFileInProjectAllowingStaleCachedResults" @@ -778,7 +780,7 @@ type internal BackgroundCompiler |] let! cachedResults = - node { + async { let! builderOpt, creationDiags = getAnyBuilder (options, userOpName) match builderOpt with @@ -827,7 +829,7 @@ type internal BackgroundCompiler options, userOpName ) = - node { + async { use _ = Activity.start "BackgroundCompiler.CheckFileInProject" @@ -875,7 +877,7 @@ type internal BackgroundCompiler options: FSharpProjectOptions, userOpName ) = - node { + async { use _ = Activity.start "BackgroundCompiler.ParseAndCheckFileInProject" @@ -910,7 +912,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 +946,7 @@ type internal BackgroundCompiler } member _.NotifyFileChanged(fileName, options, userOpName) = - node { + async { use _ = Activity.start "BackgroundCompiler.NotifyFileChanged" @@ -963,7 +965,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 +1077,7 @@ type internal BackgroundCompiler canInvalidateProject: bool, userOpName: string ) = - node { + async { use _ = Activity.start "BackgroundCompiler.FindReferencesInFile" @@ -1103,7 +1105,7 @@ type internal BackgroundCompiler } member _.GetSemanticClassificationForFile(fileName: string, options: FSharpProjectOptions, userOpName: string) = - node { + async { use _ = Activity.start "BackgroundCompiler.GetSemanticClassificationForFile" @@ -1160,7 +1162,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 +1235,7 @@ type internal BackgroundCompiler } member _.GetAssemblyData(options, userOpName) = - node { + async { use _ = Activity.start "BackgroundCompiler.GetAssemblyData" @@ -1384,7 +1386,7 @@ type internal BackgroundCompiler return options, (diags @ diagnostics.Diagnostics) } - |> Cancellable.toAsync + |> Async.FromCancellableWithScope member bc.InvalidateConfiguration(options: FSharpProjectOptions, userOpName) = use _ = @@ -1486,7 +1488,7 @@ type internal BackgroundCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.CheckFileInProject(parseResults, fileName, fileVersion, sourceText, options, userOpName) member _.CheckFileInProjectAllowingStaleCachedResults @@ -1497,7 +1499,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 +1518,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 +1526,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 +1534,7 @@ type internal BackgroundCompiler projectSnapshot: FSharpProjectSnapshot, _fileName: string, userOpName: string - ) : NodeCode = + ) : Async = self.GetAssemblyData(projectSnapshot.ToOptions(), userOpName) member _.GetBackgroundCheckResultsForFileInProject @@ -1545,7 +1542,7 @@ type internal BackgroundCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.GetBackgroundCheckResultsForFileInProject(fileName, options, userOpName) member _.GetBackgroundParseResultsForFileInProject @@ -1553,7 +1550,7 @@ type internal BackgroundCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.GetBackgroundParseResultsForFileInProject(fileName, options, userOpName) member _.GetCachedCheckFileResult @@ -1562,7 +1559,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 +1595,7 @@ type internal BackgroundCompiler fileName: string, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.GetSemanticClassificationForFile(fileName, options, userOpName) member _.GetSemanticClassificationForFile @@ -1606,13 +1603,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 +1622,7 @@ type internal BackgroundCompiler sourceText: ISourceText, options: FSharpProjectOptions, userOpName: string - ) : NodeCode = + ) : Async = self.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName) member _.ParseAndCheckFileInProject @@ -1633,22 +1630,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 +1663,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 f3bf3c96cc..4fa73fc3b6 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/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index f55010a902..045e0aae7a 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 26781c4356..0ae8b3039d 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 148d39da78..07b730bd16 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 @@ -81,6 +82,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() @@ -567,7 +587,7 @@ and [] FSha async.Return <| FSharpReferencedProjectSnapshot.ILModuleReference(outputName, getStamp, getReader)) - |> Async.Sequential + |> Async.SequentialImmediate let referencesOnDisk, otherOptions = options.OtherOptions @@ -603,13 +623,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 +648,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/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index f59a1e9b6a..a81d1d167d 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.FromCancellableWithScope 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.CompilationScope |> 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.SequentialImmediate let! tcInfos = computedBoundModels - |> Seq.map (fun boundModel -> node { return! boundModel.GetOrComputeTcInfo() }) - |> NodeCode.Sequential + |> Seq.map (fun boundModel -> async { return! boundModel.GetOrComputeTcInfo() }) + |> Async.SequentialImmediate // 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.CompilationScope |> 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 0dedfb0294..0fd380631e 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/StandardError.txt b/src/Compiler/Service/StandardError.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 0795cb6c17..cda177dbdd 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() @@ -382,7 +387,7 @@ type internal TransparentCompiler = caches.ScriptClosure.Get( projectSnapshot.FileKey fileName, - node { + async { let useFsiAuxLib = defaultArg useFsiAuxLib true let useSdkRefs = defaultArg useSdkRefs true let reduceMemoryUsage = ReduceMemoryFlag.Yes @@ -435,7 +440,7 @@ type internal TransparentCompiler caches.FrameworkImports.Get( key, - node { + async { use _ = Activity.start "ComputeFrameworkImports" [] let tcConfigP = TcConfigProvider.Constant tcConfig @@ -459,14 +464,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( @@ -571,7 +576,7 @@ type internal TransparentCompiler then { new IProjectReference with member x.EvaluateRawContents() = - node { + async { Trace.TraceInformation("FCS: {0}.{1} ({2})", userOpName, "GetAssemblyData", nm) return! @@ -591,8 +596,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() |> Async.FromCancellableWithScope match ilReaderOpt with | Some ilReader -> @@ -618,7 +623,7 @@ type internal TransparentCompiler let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData return ProjectAssemblyDataResult.Available data } - |> NodeCode.FromCancellable + |> Async.FromCancellableWithScope member x.TryGetLogicalTimeStamp _ = getStamp () |> Some member x.FileName = nm @@ -626,7 +631,7 @@ type internal TransparentCompiler ] let ComputeTcConfigBuilder (projectSnapshot: ProjectSnapshot) = - node { + async { let useSimpleResolutionSwitch = "--simpleresolution" let commandLineArgs = projectSnapshot.CommandLineOptions let defaultFSharpBinariesDir = FSharpCheckerResultsSettings.defaultFSharpBinariesDir @@ -646,8 +651,8 @@ type internal TransparentCompiler let! (loadClosureOpt: LoadClosure option) = match projectSnapshot.SourceFiles, projectSnapshot.UseScriptResolutionRules with | [ fsxFile ], true -> // assuming UseScriptResolutionRules and a single source file means we are doing this for a script - node { - let! source = fsxFile.GetSource() |> NodeCode.AwaitTask + async { + let! source = fsxFile.GetSource() |> Async.AwaitTask let! closure = ComputeScriptClosure @@ -663,7 +668,7 @@ type internal TransparentCompiler return (Some closure) } - | _ -> node { return None } + | _ -> async { return None } let sdkDirOverride = match loadClosureOpt with @@ -740,7 +745,7 @@ type internal TransparentCompiler caches.BootstrapInfoStatic.Get( projectSnapshot.CacheKeyWith("BootstrapInfoStatic", assemblyName), - node { + async { use _ = Activity.start "ComputeBootstrapInfoStatic" @@ -816,7 +821,7 @@ type internal TransparentCompiler ) let computeBootstrapInfoInner (projectSnapshot: ProjectSnapshot) = - node { + async { let! tcConfigB, sourceFiles, loadClosureOpt = ComputeTcConfigBuilder projectSnapshot @@ -892,7 +897,7 @@ type internal TransparentCompiler caches.BootstrapInfo.Get( projectSnapshot.NoFileVersionsKey, - node { + async { use _ = Activity.start "ComputeBootstrapInfo" [| Activity.Tags.project, projectSnapshot.ProjectFileName |> Path.GetFileName |] @@ -901,7 +906,7 @@ type internal TransparentCompiler use _ = new CompilationGlobalsScope(delayedLogger, BuildPhase.Parameter) let! bootstrapInfoOpt = - node { + async { try return! computeBootstrapInfoInner projectSnapshot with exn -> @@ -934,8 +939,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( @@ -948,13 +953,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) @@ -978,7 +983,7 @@ type internal TransparentCompiler caches.ParseFile.Get( key, - node { + async { use _ = Activity.start "ComputeParseFile" @@ -1022,7 +1027,7 @@ type internal TransparentCompiler |> Graph.make let computeDependencyGraph (tcConfig: TcConfig) parsedInputs (processGraph: Graph -> Graph) = - node { + async { let sourceFiles: FileInProject array = parsedInputs |> Seq.toArray @@ -1156,7 +1161,7 @@ type internal TransparentCompiler caches.TcIntermediate.Get( key, - node { + async { let file = projectSnapshot.SourceFiles[index] @@ -1246,8 +1251,7 @@ type internal TransparentCompiler prevTcInfo.tcState, input, true) - |> Cancellable.toAsync - |> NodeCode.AwaitAsync + |> Async.FromCancellableWithScope //fileChecked.Trigger fileName @@ -1273,9 +1277,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 @@ -1374,11 +1376,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) } @@ -1389,7 +1391,7 @@ type internal TransparentCompiler caches.TcLastFile.Get( projectSnapshot.FileKey fileName, - node { + async { let file = projectSnapshot.SourceFiles |> List.last use _ = @@ -1404,7 +1406,6 @@ type internal TransparentCompiler graph (processGraphNode projectSnapshot bootstrapInfo dependencyFiles false) bootstrapInfo.InitialTcInfo - |> NodeCode.AwaitAsync let lastResult = results |> List.head |> snd @@ -1413,7 +1414,7 @@ type internal TransparentCompiler ) let getParseResult (projectSnapshot: ProjectSnapshot) creationDiags file (tcConfig: TcConfig) = - node { + async { let! parsedFile = ComputeParseFile projectSnapshot tcConfig file let parseDiagnostics = @@ -1446,7 +1447,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 |] @@ -1474,8 +1475,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 +1534,7 @@ type internal TransparentCompiler projectSnapshot.IsIncompleteTypeCheckEnvironment, None, projectSnapshot.ToOptions(), - Array.ofList tcDependencyFiles, + Array.ofList tcInfo.tcDependencyFiles, creationDiags, parseResults.Diagnostics, tcDiagnostics, @@ -1559,7 +1558,7 @@ type internal TransparentCompiler let ComputeParseAndCheckAllFilesInProject (bootstrapInfo: BootstrapInfo) (projectSnapshot: ProjectSnapshotWithSources) = caches.ParseAndCheckAllFilesInProject.Get( projectSnapshot.FullKey, - node { + async { use _ = Activity.start "ComputeParseAndCheckAllFilesInProject" @@ -1574,14 +1573,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 @@ -1674,7 +1673,7 @@ type internal TransparentCompiler let ComputeAssemblyData (projectSnapshot: ProjectSnapshot) fileName = caches.AssemblyData.Get( projectSnapshot.SignatureKey, - node { + async { try @@ -1723,7 +1722,7 @@ type internal TransparentCompiler let ComputeParseAndCheckProject (projectSnapshot: ProjectSnapshot) = caches.ParseAndCheckProject.Get( projectSnapshot.FullKey, - node { + async { match! ComputeBootstrapInfo projectSnapshot with | None, creationDiags -> @@ -1796,7 +1795,7 @@ type internal TransparentCompiler ) let tryGetSink (fileName: string) (projectSnapshot: ProjectSnapshot) = - node { + async { match! ComputeBootstrapInfo projectSnapshot with | None, _ -> return None | Some bootstrapInfo, _creationDiags -> @@ -1811,7 +1810,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 |] @@ -1841,7 +1840,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 |] @@ -1876,10 +1875,12 @@ type internal TransparentCompiler ) member _.ParseFile(fileName, projectSnapshot: ProjectSnapshot, _userOpName) = - node { + async { //use _ = // Activity.start "ParseFile" [| Activity.Tags.fileName, fileName |> Path.GetFileName |] + // TODO: We don't do anything with the resulting diagnostics. This is here to not fail in case there is no global logger. + use _ = new DiagnosticsScope(false) // TODO: might need to deal with exceptions here: let! tcConfigB, sourceFileNames, _ = ComputeTcConfigBuilder projectSnapshot @@ -1906,7 +1907,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 @@ -1931,11 +1932,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, documentSource) ignore parseResults @@ -1952,11 +1951,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, documentSource) ignore parseResults @@ -2004,10 +2001,11 @@ 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, documentSource) return! this.FindReferencesInFile(fileName, snapshot.ProjectSnapshot, symbol, userOpName) } @@ -2018,9 +2016,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, documentSource) return! this.GetAssemblyData(snapshot.ProjectSnapshot, fileName, userOpName) } @@ -2029,7 +2027,7 @@ type internal TransparentCompiler projectSnapshot: FSharpProjectSnapshot, fileName, userOpName: string - ) : NodeCode = + ) : Async = this.GetAssemblyData(projectSnapshot.ProjectSnapshot, fileName, userOpName) member this.GetBackgroundCheckResultsForFileInProject @@ -2037,9 +2035,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, documentSource) match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) with | parseResult, FSharpCheckFileAnswer.Succeeded checkResult -> return parseResult, checkResult @@ -2051,9 +2049,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, documentSource) return! this.ParseFile(fileName, snapshot.ProjectSnapshot, userOpName) } @@ -2063,13 +2061,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, documentSource) match! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, "GetCachedCheckFileResult") with | parseResult, FSharpCheckFileAnswer.Succeeded checkResult -> return Some(parseResult, checkResult) @@ -2105,7 +2101,7 @@ type internal TransparentCompiler ) member this.GetSemanticClassificationForFile(fileName: string, snapshot: FSharpProjectSnapshot, userOpName: string) = - node { + async { ignore userOpName return! ComputeSemanticClassification(fileName, snapshot.ProjectSnapshot) } @@ -2115,17 +2111,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, documentSource) 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 = @@ -2138,11 +2134,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, documentSource) return! this.ParseAndCheckFileInProject(fileName, snapshot.ProjectSnapshot, userOpName) } @@ -2150,22 +2144,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, documentSource) 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 14562f34f1..e021ffd602 100644 --- a/src/Compiler/Service/TransparentCompiler.fsi +++ b/src/Compiler/Service/TransparentCompiler.fsi @@ -158,19 +158,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 492ff2da49..b17f374624 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) @@ -330,13 +325,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 +388,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 +410,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 +425,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 +439,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 +467,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 +481,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 +496,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/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi index 14124fbda6..e74249cd60 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 = diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs index 59e7def4c1..2d99cfa15a 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 diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index e442335f94..9385758fae 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 @@ -54,19 +54,19 @@ 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``() = - let computation key = node { - do! Async.Sleep 1 |> NodeCode.AwaitAsync + let computation key = async { + do! Async.Sleep 1 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 { @@ -77,14 +77,16 @@ 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|] 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) @@ -95,7 +97,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 +112,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 +148,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 +164,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 +199,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 +215,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 +277,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 +333,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 +387,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 +402,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 +412,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 +440,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) + DiagnosticsAsyncState.DiagnosticsLogger.ErrorR(ex) return Ok input } - let job2 (input: int) = node { + 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)) |> NodeCode.AwaitAsync + let! _ = Async.Sleep (rng.Next(1, 30)) let key = { new ICacheKey<_, _> with member _.GetKey() = "job1" @@ -458,7 +460,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 +475,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 @@ -481,7 +483,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,9 +514,9 @@ 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) + DiagnosticsAsyncState.DiagnosticsLogger.ErrorR(ex) return Ok input } @@ -524,8 +526,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,10 +547,10 @@ 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 - DiagnosticsThreadStatics.DiagnosticsLogger.Error(ex) + do! Async.Sleep 100 + DiagnosticsAsyncState.DiagnosticsLogger.Error(ex) return 5 } @@ -560,7 +562,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.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/TransparentCompiler.fs index 664b79d4e0..fde34642ff 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 @@ -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 diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/TyparNameTests.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/TyparNameTests.fs index 339fa1e262..d8316d365e 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/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index e53606d2de..da61adbe19 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 e53606d2de..da61adbe19 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() diff --git a/tests/FSharp.Compiler.Service.Tests/FSharpExprPatternsTests.fs b/tests/FSharp.Compiler.Service.Tests/FSharpExprPatternsTests.fs index 5d31b6f74f..a50010f6f8 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 92993a62a6..d3e0846180 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.Compiler.UnitTests/BuildGraphTests.fs b/tests/FSharp.Compiler.UnitTests/BuildGraphTests.fs index 556a9b5bc4..55cfc166f4 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 @@ -16,14 +17,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 +34,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 +67,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 +83,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 +102,7 @@ module BuildGraphTests = Assert.shouldBeTrue weak.IsAlive - NodeCode.RunImmediateWithoutCancellation(graphNode.GetOrComputeValue()) + Async.RunImmediateWithoutCancellation(graphNode.GetOrComputeValue()) |> ignore GC.Collect(2, GCCollectionMode.Forced, true) @@ -118,7 +119,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,59 +129,45 @@ module BuildGraphTests = [] let ``A request can cancel``() = let graphNode = - GraphNode(node { + GraphNode(async { return 1 }) use cts = new CancellationTokenSource() - let work = - node { + let work(): Task = + Async.StartAsTask( + async { cts.Cancel() return! graphNode.GetOrComputeValue() - } - - let ex = - try - NodeCode.RunImmediate(work, ct = 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``() = let resetEvent = new ManualResetEvent(false) let graphNode = - GraphNode(node { - let! _ = NodeCode.AwaitWaitHandle_ForTesting(resetEvent) - return 1 + GraphNode(async { + let! _ = Async.AwaitWaitHandle(resetEvent) + failwith "Should have canceled" }) 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) - |> ignore - failwith "Should have canceled" - with - | :? OperationCanceledException as ex -> - ex + Assert.ThrowsAnyAsync(fun () -> + Async.StartImmediateAsTask(graphNode.GetOrComputeValue(), cancellationToken = cts.Token) + ) |> ignore - Assert.shouldBeTrue(ex <> null) - try task.Wait(1000) |> ignore with | :? TimeoutException -> reraise() | _ -> () + 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``() = @@ -190,9 +177,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 +187,7 @@ module BuildGraphTests = use cts = new CancellationTokenSource() let work = - node { + async { let! _ = graphNode.GetOrComputeValue() () } @@ -209,15 +196,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,16 +229,16 @@ module BuildGraphTests = let rng = Random() fun n -> rng.Next n - let job phase _ = node { - do! random 10 |> Async.Sleep |> NodeCode.AwaitAsync - Assert.Equal(phase, DiagnosticsThreadStatics.BuildPhase) + let job phase _ = async { + do! random 10 |> Async.Sleep + Assert.Equal(phase, DiagnosticsAsyncState.BuildPhase) } let work (phase: BuildPhase) = - node { + async { use _ = new CompilationGlobalsScope(DiscardErrorsLogger, phase) - let! _ = Seq.init 8 (job phase) |> NodeCode.Parallel - Assert.Equal(phase, DiagnosticsThreadStatics.BuildPhase) + let! _ = Seq.init 8 (job phase) |> Async.Parallel + Assert.Equal(phase, DiagnosticsAsyncState.BuildPhase) } let phases = [| @@ -270,6 +257,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/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs index 9f94b7b1c0..0cb607603e 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 ()) @@ -76,12 +76,11 @@ type public HashIfExpression() = errors, warnings, parser - do // Setup - DiagnosticsThreadStatics.BuildPhase <- BuildPhase.Compile + // Setup + let globalScope = new CompilationGlobalsScope(DiagnosticsAsyncState.DiagnosticsLogger, BuildPhase.Compile) + interface IDisposable with // Teardown - member _.Dispose() = - DiagnosticsThreadStatics.BuildPhase <- BuildPhase.DefaultPhase - DiagnosticsThreadStatics.DiagnosticsLogger <- DiagnosticsThreadStatics.DiagnosticsLogger + member _.Dispose() = (globalScope :> IDisposable).Dispose() [] member _.PositiveParserTestCases()= diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 7951ba31d5..b22e0b2d02 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 5cfcba98ca..d330729548 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 2236eee988..000b700258 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 @@ -797,7 +798,7 @@ module ProjectOperations = let! projects = p.DependsOn |> Seq.map (absorbAutoGeneratedSignatures checker) - |> Async.Sequential + |> Async.SequentialImmediate return { p with SourceFiles = files @@ -931,7 +932,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 41d6a8c660..03deb321c2 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/ExprTests.fs b/tests/service/ExprTests.fs index 7b35568e38..d50d2c2eb5 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) diff --git a/tests/service/ProjectAnalysisTests.fs b/tests/service/ProjectAnalysisTests.fs index a1a58a709b..8a643c9a7b 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`` () = diff --git a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs index 154517ed6a..c729ad1342 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs @@ -317,15 +317,15 @@ 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.CompilationScope } ) - |> Async.AwaitNodeCode let getProjectSnapshotForDocument (document: Document, options: FSharpProjectOptions) = getOrCreateSnapshotForProject document.Project (Some options) None diff --git a/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs index 135d5d31f2..8027a06e85 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/BraceMatchingServiceTests.fs @@ -8,9 +8,11 @@ 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 9442957325..985abc67e3 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() + 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() + 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() + 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() + 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 81f2bfc7f0..6b70bb07c8 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() + 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 af66c01ed6..f85ee51a6c 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,8 @@ module SignatureHelpProvider = override doc.AppendDocumentation(_, _, _, _, _, _, _, _) = () } - let checker = FSharpChecker.Create() + let checker = + FSharpChecker.Create(useTransparentCompiler = CompilerAssertHelpers.UseTransparentCompiler) let filePath = "C:\\test.fs"