diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index 5a23c95ca7b..875cd7b7cc3 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -42,6 +42,7 @@ open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TypedTreeBasics open FSharp.Compiler.TcGlobals +open FSharp.Compiler.BuildGraph let CanonicalizeFilename fileName = let basic = FileSystemUtils.fileNameOfPath fileName @@ -811,23 +812,40 @@ let UseMultipleDiagnosticLoggers (inputs, diagnosticsLogger, eagerFormat) f = logger.CommitDelayedDiagnostics diagnosticsLogger let ParseInputFilesInParallel (tcConfig: TcConfig, lexResourceManager, sourceFiles, delayLogger: DiagnosticsLogger, retryLocked) = + node { + use _ = UseDiagnosticsLogger delayLogger - let isLastCompiland, isExe = sourceFiles |> tcConfig.ComputeCanContainEntryPoint + let isLastCompiland, isExe = sourceFiles |> tcConfig.ComputeCanContainEntryPoint - for fileName in sourceFiles do - checkInputFile tcConfig fileName + for fileName in sourceFiles do + checkInputFile tcConfig fileName - let sourceFiles = List.zip sourceFiles isLastCompiland + let sourceFiles = List.zip sourceFiles isLastCompiland - UseMultipleDiagnosticLoggers (sourceFiles, delayLogger, None) (fun sourceFilesWithDelayLoggers -> - sourceFilesWithDelayLoggers - |> ListParallel.map (fun ((fileName, isLastCompiland), delayLogger) -> - let directoryName = Path.GetDirectoryName fileName + let! result = + sourceFiles + |> Seq.map (fun (fileName, isLastCompiland) -> + node { + let directoryName = Path.GetDirectoryName fileName - let input = - parseInputFileAux (tcConfig, lexResourceManager, fileName, (isLastCompiland, isExe), delayLogger, retryLocked) + let input = + parseInputFileAux ( + tcConfig, + lexResourceManager, + fileName, + (isLastCompiland, isExe), + DiagnosticsThreadStatics.DiagnosticsLogger, + retryLocked + ) - (input, directoryName))) + return (input, directoryName) + }) + |> NodeCode.Parallel + + return result |> Array.toList + } + |> Async.AwaitNodeCode + |> Async.RunImmediate let ParseInputFilesSequential (tcConfig: TcConfig, lexResourceManager, sourceFiles, diagnosticsLogger: DiagnosticsLogger, retryLocked) = let isLastCompiland, isExe = sourceFiles |> tcConfig.ComputeCanContainEntryPoint diff --git a/src/Compiler/Facilities/AsyncMemoize.fs b/src/Compiler/Facilities/AsyncMemoize.fs index b780d91ca74..4edee5fbc45 100644 --- a/src/Compiler/Facilities/AsyncMemoize.fs +++ b/src/Compiler/Facilities/AsyncMemoize.fs @@ -354,15 +354,11 @@ 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 |> Async.AwaitNodeCode + post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) + return () with | TaskCancelled _ -> Interlocked.Increment &cancel_exception_subsequent |> ignore @@ -500,17 +496,12 @@ 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 - log (Started, key) - try - let! result = computation |> Async.AwaitNodeCode - post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) - return result - finally - DiagnosticsThreadStatics.DiagnosticsLogger <- currentLogger + use _ = UseDiagnosticsLogger cachingLogger + let! result = computation |> Async.AwaitNodeCode + post (key, (JobCompleted(result, cachingLogger.CapturedDiagnostics))) + return result }, cancellationToken = linkedCtSource.Token ) diff --git a/src/Compiler/Facilities/BuildGraph.fs b/src/Compiler/Facilities/BuildGraph.fs index b4abe3ad1ed..b7e32ed156c 100644 --- a/src/Compiler/Facilities/BuildGraph.fs +++ b/src/Compiler/Facilities/BuildGraph.fs @@ -9,29 +9,28 @@ open System.Diagnostics open System.Globalization open FSharp.Compiler.DiagnosticsLogger open Internal.Utilities.Library +open Internal.Utilities.Library.Cancellable [] type NodeCode<'T> = Node of Async<'T> let wrapThreadStaticInfo computation = async { - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLoggerNC + let phase = DiagnosticsThreadStatics.BuildPhaseNC try return! computation finally - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger + DiagnosticsThreadStatics.BuildPhaseNC <- phase } let unwrapNode (Node(computation)) = computation type Async<'T> with - static member AwaitNodeCode(node: NodeCode<'T>) = - match node with - | Node(computation) -> wrapThreadStaticInfo computation + static member AwaitNodeCode(node: NodeCode<'T>) = unwrapNode node [] type NodeCodeBuilder() = @@ -95,27 +94,8 @@ type NodeCodeBuilder() = member _.Combine(Node(p1): NodeCode, Node(p2): NodeCode<'T>) : NodeCode<'T> = Node(async.Combine(p1, p2)) [] - member _.Using(value: CompilationGlobalsScope, binder: CompilationGlobalsScope -> NodeCode<'U>) = - Node( - async { - DiagnosticsThreadStatics.DiagnosticsLogger <- value.DiagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- value.BuildPhase - - 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 - } - ) + member this.Using(resource: ('T :> IDisposable), binder: ('T :> IDisposable) -> NodeCode<'U>) = + async.Using(resource, binder >> unwrapNode) |> Node let node = NodeCodeBuilder() @@ -125,22 +105,22 @@ type NodeCode private () = static let cancellationToken = Node(wrapThreadStaticInfo Async.CancellationToken) static member RunImmediate(computation: NodeCode<'T>, ct: CancellationToken) = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLoggerNC + let phase = DiagnosticsThreadStatics.BuildPhaseNC try try let work = async { - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase - return! computation |> Async.AwaitNodeCode + DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger + DiagnosticsThreadStatics.BuildPhaseNC <- phase + return! unwrapNode computation } Async.StartImmediateAsTask(work, cancellationToken = ct).Result finally - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger + DiagnosticsThreadStatics.BuildPhaseNC <- phase with :? AggregateException as ex when ex.InnerExceptions.Count = 1 -> raise (ex.InnerExceptions[0]) @@ -148,26 +128,26 @@ type NodeCode private () = NodeCode.RunImmediate(computation, CancellationToken.None) static member StartAsTask_ForTesting(computation: NodeCode<'T>, ?ct: CancellationToken) = - let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger - let phase = DiagnosticsThreadStatics.BuildPhase + let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLoggerNC + let phase = DiagnosticsThreadStatics.BuildPhaseNC try let work = async { - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase - return! computation |> Async.AwaitNodeCode + DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger + DiagnosticsThreadStatics.BuildPhaseNC <- phase + return! unwrapNode computation } Async.StartAsTask(work, cancellationToken = defaultArg ct CancellationToken.None) finally - DiagnosticsThreadStatics.DiagnosticsLogger <- diagnosticsLogger - DiagnosticsThreadStatics.BuildPhase <- phase + DiagnosticsThreadStatics.DiagnosticsLoggerNC <- diagnosticsLogger + DiagnosticsThreadStatics.BuildPhaseNC <- phase static member CancellationToken = cancellationToken static member FromCancellable(computation: Cancellable<'T>) = - Node(wrapThreadStaticInfo (Cancellable.toAsync computation)) + Node(Cancellable.toAsync computation) static member AwaitAsync(computation: Async<'T>) = Node(wrapThreadStaticInfo computation) @@ -176,6 +156,12 @@ type NodeCode private () = static member AwaitTask(task: Task) = Node(wrapThreadStaticInfo (Async.AwaitTask task)) + + static member AwaitTaskWithoutWrapping(task: Task<'T>) = + Node((Async.AwaitTask task)) + + static member AwaitTaskWithoutWrapping(task: Task) = + Node((Async.AwaitTask task)) static member AwaitWaitHandle_ForTesting(waitHandle: WaitHandle) = Node(wrapThreadStaticInfo (Async.AwaitWaitHandle(waitHandle))) @@ -196,26 +182,21 @@ type NodeCode private () = static member Parallel(computations: NodeCode<'T> seq) = node { - let concurrentLogging = new CaptureDiagnosticsConcurrently() let phase = DiagnosticsThreadStatics.BuildPhase - // Why does it return just IDisposable? - use _ = concurrentLogging + use concurrentLogging = new CaptureDiagnosticsConcurrently() let injectLogger i computation = let logger = concurrentLogging.GetLoggerForTask($"NodeCode.Parallel {i}") async { - DiagnosticsThreadStatics.DiagnosticsLogger <- logger - DiagnosticsThreadStatics.BuildPhase <- phase - return! unwrapNode computation + SetThreadDiagnosticsLoggerNoUnwind logger + SetThreadBuildPhaseNoUnwind phase + + return! computation |> unwrapNode } - return! - computations - |> Seq.mapi injectLogger - |> Async.Parallel - |> wrapThreadStaticInfo - |> Node + return! computations |> Seq.mapi injectLogger |> Async.Parallel |> wrapThreadStaticInfo |> Node + } [] @@ -256,6 +237,7 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption cachedResultNode else node { + Interlocked.Increment(&requestCount) |> ignore try @@ -278,18 +260,17 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption ||| TaskContinuationOptions.NotOnFaulted ||| TaskContinuationOptions.ExecuteSynchronously) ) - |> NodeCode.AwaitTask + |> NodeCode.AwaitTaskWithoutWrapping match cachedResult with | ValueSome value -> return value | _ -> let tcs = TaskCompletionSource<'T>() - let (Node(p)) = computation Async.StartWithContinuations( async { Thread.CurrentThread.CurrentUICulture <- GraphNode.culture - return! p + return! computation |> unwrapNode |> wrapThreadStaticInfo }, (fun res -> cachedResult <- ValueSome res @@ -301,7 +282,7 @@ type GraphNode<'T> private (computation: NodeCode<'T>, cachedResult: ValueOption ct ) - return! tcs.Task |> NodeCode.AwaitTask + return! tcs.Task |> NodeCode.AwaitTaskWithoutWrapping finally if taken then semaphore.Release() |> ignore diff --git a/src/Compiler/Facilities/BuildGraph.fsi b/src/Compiler/Facilities/BuildGraph.fsi index afbf9d2898b..a340b8c5b1d 100644 --- a/src/Compiler/Facilities/BuildGraph.fsi +++ b/src/Compiler/Facilities/BuildGraph.fsi @@ -44,11 +44,8 @@ type NodeCodeBuilder = member Combine: x1: NodeCode * x2: NodeCode<'T> -> NodeCode<'T> - /// A limited form 'use' for establishing the compilation globals. - member Using: CompilationGlobalsScope * (CompilationGlobalsScope -> NodeCode<'T>) -> NodeCode<'T> + member Using: ('T :> IDisposable) * (('T :> IDisposable) -> NodeCode<'U>) -> NodeCode<'U> - /// 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 diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fs b/src/Compiler/Facilities/DiagnosticsLogger.fs index 75dfaaef39e..c4b03287879 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fs +++ b/src/Compiler/Facilities/DiagnosticsLogger.fs @@ -13,7 +13,6 @@ open System.Reflection open System.Threading open Internal.Utilities.Library open Internal.Utilities.Library.Extras -open System.Collections.Concurrent /// Represents the style being used to format errors [] @@ -346,8 +345,9 @@ let DiscardErrorsLogger = 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 + member _.DiagnosticSink(diagnostic, severity) = () //assert false + + member _.ErrorCount = 0 //assert false } type CapturingDiagnosticsLogger(nm, ?eagerFormat) = @@ -375,8 +375,58 @@ type CapturingDiagnosticsLogger(nm, ?eagerFormat) = let errors = diagnostics.ToArray() errors |> Array.iter diagnosticsLogger.DiagnosticSink +[] +module Tracing = + let dlName (dl: DiagnosticsLogger) = + if box dl |> isNull then "NULL" else dl.DebugDisplay() + + let tid () = Thread.CurrentThread.ManagedThreadId + /// Type holds thread-static globals for use by the compiler. type internal DiagnosticsThreadStatics = + + static let buildPhaseAsync = new AsyncLocal() + + static let diagnosticsLoggerAsync = + new AsyncLocal() + //fun args -> + // if args.ThreadContextChanged then + // Trace.WriteLine( + // "" //$"\nt:{Thread.CurrentThread.ManagedThreadId} ASYNCLOCAL context change\n\t\tprev: {dlName args.PreviousValue}\n\t\tcurrent: {dlName args.CurrentValue}\n" + // )) + + static let check () = + let al = diagnosticsLoggerAsync.Value + let ts = DiagnosticsThreadStatics.diagnosticsLogger + + match box al, box ts with + | a, t when a = t -> () + | Null, _ -> () // New context. + | _ when ts = AssertFalseDiagnosticsLogger -> () // Threadstatic not yet initialized. + | _ when al.DebugDisplay().Contains("Caching") || ts.DebugDisplay().Contains("Caching") -> () // AsyncMemoize, disregard until fixed. + | _ when al.DebugDisplay().Contains("NodeCode") || ts.DebugDisplay().Contains("NodeCode") -> () // Threadstatic needs to catch up. + | _ when al.DebugDisplay() <> ts.DebugDisplay() -> // Not good. +#if DEBUG + Trace.WriteLine $"t:{tid()}, AL: {dlName al} TS: {dlName ts}" + Debugger.Break() +#else + failwith $"DiagnosticsLogger diverged. AsyncLocal: <{dlName al}>, ThreadStatic: <{dlName ts}>, tid: {Thread.CurrentThread.ManagedThreadId}." +#endif + | _ -> () +#if DEBUG + static let log prefix = + //let al = diagnosticsLoggerAsync.Value + let ts = DiagnosticsThreadStatics.diagnosticsLogger + + //let dls = + // if box al = box ts then + // dlName al + // else + // $"\nDIVERGED \n\tAsyncLocal: {dlName al}\n\tThreadStatic: {dlName ts}\n" + + Trace.WriteLine($"t:{tid()} {prefix} {dlName ts}") +#endif + [] static val mutable private buildPhase: BuildPhase @@ -394,14 +444,48 @@ type internal DiagnosticsThreadStatics = static member DiagnosticsLogger with get () = + + match box DiagnosticsThreadStatics.diagnosticsLogger with + | Null -> AssertFalseDiagnosticsLogger + | _ -> + + check() + DiagnosticsThreadStatics.diagnosticsLogger + and set v = + diagnosticsLoggerAsync.Value <- v + DiagnosticsThreadStatics.diagnosticsLogger <- v + + static member BuildPhaseNC + with get () = + match box DiagnosticsThreadStatics.buildPhase with + | Null -> BuildPhase.DefaultPhase + | _ -> DiagnosticsThreadStatics.buildPhase + and set v = DiagnosticsThreadStatics.buildPhase <- v + + static member DiagnosticsLoggerNC + with get () = + #if DEBUG + log "NC ->" + #endif match box DiagnosticsThreadStatics.diagnosticsLogger with | Null -> AssertFalseDiagnosticsLogger | _ -> DiagnosticsThreadStatics.diagnosticsLogger - and set v = DiagnosticsThreadStatics.diagnosticsLogger <- v + and set v = + DiagnosticsThreadStatics.diagnosticsLogger <- v + #if DEBUG + log "NC <-" + #endif + + + static member InitGlobals() = + Trace.WriteLine($"t:{Thread.CurrentThread.ManagedThreadId} INIT GLOBAL DIAGNOSTICS") + buildPhaseAsync.Value <- BuildPhase.DefaultPhase + diagnosticsLoggerAsync.Value <- AssertFalseDiagnosticsLogger + DiagnosticsThreadStatics.buildPhase <- BuildPhase.DefaultPhase + DiagnosticsThreadStatics.diagnosticsLogger <- AssertFalseDiagnosticsLogger [] module DiagnosticsLoggerExtensions = - // Dev15.0 shipped with a bug in diasymreader in the portable pdb symbol reader which causes an AV // This uses a simple heuristic to detect it (the vsversion is < 16.0) let tryAndDetectDev15 = @@ -425,6 +509,8 @@ module DiagnosticsLoggerExtensions = Debug.Assert(false, "Could not preserve stack trace for watson exception.") () + do DiagnosticsThreadStatics.InitGlobals() + type DiagnosticsLogger with member x.EmitDiagnostic(exn, severity) = @@ -499,7 +585,10 @@ module DiagnosticsLoggerExtensions = /// NOTE: The change will be undone when the returned "unwind" object disposes let UseBuildPhase (phase: BuildPhase) = - let oldBuildPhase = DiagnosticsThreadStatics.BuildPhaseUnchecked + + // TODO: possibly restore this optimization. BuildPhaseUnchecked can be null so it complicates things for us. + // let oldBuildPhase = DiagnosticsThreadStatics.BuildPhaseUnchecked + let oldBuildPhase = DiagnosticsThreadStatics.BuildPhase DiagnosticsThreadStatics.BuildPhase <- phase { new IDisposable with @@ -510,11 +599,16 @@ let UseBuildPhase (phase: BuildPhase) = /// 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 newLogger = transformer oldLogger + DiagnosticsThreadStatics.DiagnosticsLogger <- newLogger + Trace.IndentLevel <- Trace.IndentLevel + 1 + Trace.WriteLine $"t:{tid()} use : {dlName DiagnosticsThreadStatics.DiagnosticsLogger}" { new IDisposable with member _.Dispose() = DiagnosticsThreadStatics.DiagnosticsLogger <- oldLogger + Trace.WriteLine $"t:{tid()} disp: {newLogger.DebugDisplay()}, restored: {oldLogger.DebugDisplay()}" + Trace.IndentLevel <- Trace.IndentLevel - 1 } let UseDiagnosticsLogger newLogger = @@ -546,6 +640,7 @@ type CompilationGlobalsScope(diagnosticsLogger: DiagnosticsLogger, buildPhase: B /// Raises an exception with error recovery and returns unit. let errorR exn = + Trace.WriteLine $"t:{Thread.CurrentThread.ManagedThreadId} pushing ERROR to {DiagnosticsThreadStatics.DiagnosticsLogger.DebugDisplay()}" DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR exn /// Raises a warning with error recovery and returns unit. diff --git a/src/Compiler/Facilities/DiagnosticsLogger.fsi b/src/Compiler/Facilities/DiagnosticsLogger.fsi index bcbdd197b73..399b94d69c0 100644 --- a/src/Compiler/Facilities/DiagnosticsLogger.fsi +++ b/src/Compiler/Facilities/DiagnosticsLogger.fsi @@ -236,6 +236,10 @@ type DiagnosticsThreadStatics = static member DiagnosticsLogger: DiagnosticsLogger with get, set + static member BuildPhaseNC: BuildPhase with get, set + + static member DiagnosticsLoggerNC: DiagnosticsLogger with get, set + [] module DiagnosticsLoggerExtensions = diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs index 54bea5584ad..dd718a308c6 100644 --- a/src/Compiler/Service/BackgroundCompiler.fs +++ b/src/Compiler/Service/BackgroundCompiler.fs @@ -566,7 +566,7 @@ type internal BackgroundCompiler flatErrors: bool, userOpName: string ) = - async { + node { use _ = Activity.start "BackgroundCompiler.ParseFile" @@ -583,7 +583,7 @@ type internal BackgroundCompiler | Some res -> return res | None -> Interlocked.Increment(&actualParseFileCount) |> ignore - let! ct = Async.CancellationToken + let! ct = NodeCode.CancellationToken let parseDiagnostics, parseTree, anyErrors = ParseAndCheckFile.parseFile ( @@ -603,7 +603,7 @@ type internal BackgroundCompiler parseCacheLock.AcquireLock(fun ltok -> parseFileCache.Set(ltok, (fileName, hash, options), res)) return res else - let! ct = Async.CancellationToken + let! ct = NodeCode.CancellationToken let parseDiagnostics, parseTree, anyErrors = ParseAndCheckFile.parseFile ( @@ -1667,6 +1667,7 @@ type internal BackgroundCompiler userOpName: string ) = self.ParseFile(fileName, sourceText, options, cache, flatErrors, userOpName) + |> Async.AwaitNodeCode member _.ParseFile(fileName: string, projectSnapshot: FSharpProjectSnapshot, userOpName: string) = let options = projectSnapshot.ToOptions() diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index f59a1e9b6a5..0861d79817e 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -151,7 +151,7 @@ module IncrementalBuildSyntaxTree = use _holder = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Parse) use! text = source.GetTextContainer() |> NodeCode.AwaitAsync let input = - match text :?> TextContainer with + match text with | TextContainer.Stream(stream) -> ParseOneInputStream(tcConfig, lexResourceManager, fileName, isLastCompiland, diagnosticsLogger, false, stream) | TextContainer.SourceText(sourceText) -> diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index 7c252019e2d..f9a0450f7d3 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs @@ -56,7 +56,6 @@ type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality>(mem member _.Sequence = events |> Seq.map id - [] let ``Basics``() = @@ -431,7 +430,7 @@ type DummyException(msg) = inherit Exception(msg) [] -let ``Preserve thread static diagnostics`` () = +let ``Preserve thread static diagnostics`` () = let seed = System.Random().Next() @@ -469,7 +468,7 @@ let ``Preserve thread static diagnostics`` () = let tasks = seq { for i in 1 .. 100 do - task { + node { let diagnosticsLogger = CompilationDiagnosticLogger($"Testing task {i}", FSharpDiagnosticOptions.Default) @@ -483,7 +482,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() @@ -493,7 +492,7 @@ let ``Preserve thread static diagnostics`` () = } } - let results = (Task.WhenAll tasks).Result + let results = tasks |> NodeCode.Parallel |> Async.AwaitNodeCode |> Async.RunSynchronously let _diagnosticCounts = results |> Seq.map snd |> Seq.map Array.length |> Seq.groupBy id |> Seq.map (fun (k, v) -> k, v |> Seq.length) |> Seq.sortBy fst |> Seq.toList @@ -520,21 +519,21 @@ let ``Preserve thread static diagnostics already completed job`` () = return Ok input } - async { + node { let diagnosticsLogger = CompilationDiagnosticLogger($"Testing", FSharpDiagnosticOptions.Default) 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 Assert.Equal>(["job 1 error"; "job 1 error"], diagnosticMessages) } - |> Async.StartAsTask + |> NodeCode.StartAsTask_ForTesting [] @@ -557,12 +556,12 @@ let ``We get diagnostics from the job that failed`` () = let result = [1; 2] |> Seq.map (fun i -> - async { + node { let diagnosticsLogger = CompilationDiagnosticLogger($"Testing", FSharpDiagnosticOptions.Default) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize) try - let! _ = cache.Get(key, job i ) |> Async.AwaitNodeCode + let! _ = cache.Get(key, job i ) () with _ -> () @@ -570,8 +569,8 @@ let ``We get diagnostics from the job that failed`` () = return diagnosticMessages }) - |> Async.Parallel - |> Async.StartAsTask + |> NodeCode.Parallel + |> NodeCode.StartAsTask_ForTesting |> (fun t -> t.Result) |> Array.toList diff --git a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs index 9f94b7b1c06..5821a3c162e 100644 --- a/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs +++ b/tests/FSharp.Compiler.UnitTests/HashIfExpression.fs @@ -46,6 +46,13 @@ type public HashIfExpression() = sb.ToString () + let restoreScope = + let logger = DiagnosticsThreadStatics.DiagnosticsLogger + let phase = DiagnosticsThreadStatics.BuildPhase + fun () -> + DiagnosticsThreadStatics.DiagnosticsLogger <- logger + DiagnosticsThreadStatics.BuildPhase <- phase + let createParser () = let errors = ResizeArray() let warnings = ResizeArray() @@ -79,9 +86,7 @@ type public HashIfExpression() = do // Setup DiagnosticsThreadStatics.BuildPhase <- BuildPhase.Compile interface IDisposable with // Teardown - member _.Dispose() = - DiagnosticsThreadStatics.BuildPhase <- BuildPhase.DefaultPhase - DiagnosticsThreadStatics.DiagnosticsLogger <- DiagnosticsThreadStatics.DiagnosticsLogger + member _.Dispose() = restoreScope() [] member _.PositiveParserTestCases()= diff --git a/tests/FSharp.Compiler.UnitTests/xunit.runner.json b/tests/FSharp.Compiler.UnitTests/xunit.runner.json index 743febb7028..de930b44321 100644 --- a/tests/FSharp.Compiler.UnitTests/xunit.runner.json +++ b/tests/FSharp.Compiler.UnitTests/xunit.runner.json @@ -1,5 +1,5 @@ { - "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", - "appDomain": "ifAvailable", - "shadowCopy": false + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "appDomain": "ifAvailable", + "shadowCopy": false }