Skip to content

Commit 32975e2

Browse files
committed
restore NodeCode subtly different semantics
1 parent d84c21c commit 32975e2

File tree

10 files changed

+77
-48
lines changed

10 files changed

+77
-48
lines changed

src/Compiler/Driver/CompilerImports.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2236,7 +2236,7 @@ and [<Sealed>] TcImports
22362236
let runMethod =
22372237
match tcConfig.parallelReferenceResolution with
22382238
| ParallelReferenceResolution.On -> Async.Parallel
2239-
| ParallelReferenceResolution.Off -> Async.Sequential
2239+
| ParallelReferenceResolution.Off -> Async.SequentialFailFast
22402240

22412241
let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger
22422242
let! results =

src/Compiler/Facilities/BuildGraph.fs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,32 @@ open Internal.Utilities.Library
1111
[<AbstractClass; Sealed>]
1212
type Async =
1313
static member RunImmediateWithoutCancellation(computation) =
14-
Async.RunImmediate(computation, CancellationToken.None)
14+
try
15+
let work = async { return! computation }
16+
17+
Async
18+
.StartImmediateAsTask(work, cancellationToken = CancellationToken.None)
19+
.Result
20+
21+
with :? AggregateException as ex when ex.InnerExceptions.Count = 1 ->
22+
raise (ex.InnerExceptions[0])
1523

1624
static member FromCancellable(computation: Cancellable<'T>) = Cancellable.toAsync computation
1725

1826
static member StartAsTask_ForTesting(computation: Async<'T>, ?ct: CancellationToken) =
1927
Async.StartAsTask(computation, cancellationToken = defaultArg ct CancellationToken.None)
2028

29+
static member SequentialFailFast(computations: Async<'T> seq) =
30+
async {
31+
let results = ResizeArray()
32+
33+
for computation in computations do
34+
let! result = computation
35+
results.Add result
36+
37+
return results.ToArray()
38+
}
39+
2140
[<RequireQualifiedAccess>]
2241
module GraphNode =
2342

src/Compiler/Facilities/BuildGraph.fsi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ type Async =
2121
/// Only used for testing, do not use
2222
static member StartAsTask_ForTesting: computation: Async<'T> * ?ct: CancellationToken -> Task<'T>
2323

24+
static member SequentialFailFast: computations: Async<'T> seq -> Async<'T array>
25+
2426
/// Contains helpers related to the build graph
2527
[<RequireQualifiedAccess>]
2628
module internal GraphNode =

src/Compiler/Facilities/DiagnosticsLogger.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,9 @@ let UseDiagnosticsLogger newLogger =
543543
UseTransformedDiagnosticsLogger(fun _ -> newLogger)
544544

545545
let CaptureDiagnosticsConcurrently () =
546-
let newLogger = ConcurrentCapturingDiagnosticsLogger("CaptureDiagnosticsConcurrently")
546+
let newLogger =
547+
ConcurrentCapturingDiagnosticsLogger("CaptureDiagnosticsConcurrently")
548+
547549
let oldLogger = DiagnosticsThreadStatics.DiagnosticsLogger
548550
DiagnosticsThreadStatics.DiagnosticsLogger <- newLogger
549551

src/Compiler/Service/FSharpProjectSnapshot.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ open System.Runtime.CompilerServices
1919
open FSharp.Compiler.Syntax
2020
open FSharp.Compiler.Diagnostics
2121
open FSharp.Compiler.DiagnosticsLogger
22+
open FSharp.Compiler.BuildGraph
2223

2324
type internal ProjectIdentifier = string * string
2425

@@ -567,7 +568,7 @@ and [<Experimental("This FCS API is experimental and subject to change.")>] FSha
567568
async.Return
568569
<| FSharpReferencedProjectSnapshot.ILModuleReference(outputName, getStamp, getReader))
569570

570-
|> Async.Sequential
571+
|> Async.SequentialFailFast
571572

572573
let referencesOnDisk, otherOptions =
573574
options.OtherOptions

src/Compiler/Service/IncrementalBuild.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,12 +740,12 @@ module IncrementalBuilderHelpers =
740740
let diagnosticsLogger = CompilationDiagnosticLogger("FinalizeTypeCheckTask", tcConfig.diagnosticsOptions)
741741
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
742742

743-
let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> Async.Sequential
743+
let! computedBoundModels = boundModels |> Seq.map (fun g -> g.GetOrComputeValue()) |> Async.SequentialFailFast
744744

745745
let! tcInfos =
746746
computedBoundModels
747747
|> Seq.map (fun boundModel -> async { return! boundModel.GetOrComputeTcInfo() })
748-
|> Async.Sequential
748+
|> Async.SequentialFailFast
749749

750750
// tcInfoExtras can be computed in parallel. This will check any previously skipped implementation files in parallel, too.
751751
let! latestImplFiles =

src/Compiler/Service/TransparentCompiler.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,8 @@ type internal TransparentCompiler
542542
| FSharpReferencedProjectSnapshot.PEReference(getStamp, delayedReader) ->
543543
{ new IProjectReference with
544544
member x.EvaluateRawContents() =
545-
node {
546-
let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> NodeCode.FromCancellable
545+
async {
546+
let! ilReaderOpt = delayedReader.TryGetILModuleReader() |> Cancellable.toAsync
547547

548548
match ilReaderOpt with
549549
| Some ilReader ->
@@ -569,7 +569,7 @@ type internal TransparentCompiler
569569
let data = RawFSharpAssemblyData(ilModuleDef, ilAsmRefs) :> IRawFSharpAssemblyData
570570
return ProjectAssemblyDataResult.Available data
571571
}
572-
|> NodeCode.FromCancellable
572+
|> Async.FromCancellable
573573

574574
member x.TryGetLogicalTimeStamp _ = getStamp () |> Some
575575
member x.FileName = nm

src/Compiler/Utilities/illib.fs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,15 @@ module internal PervasiveAutoOpens =
160160

161161
static member RunImmediate(computation: Async<'T>, ?cancellationToken) =
162162
let cancellationToken = defaultArg cancellationToken Async.DefaultCancellationToken
163+
#if DEBUG
163164
let ts = TaskCompletionSource<'T>()
164-
let task = ts.Task
165165

166166
Async.StartWithContinuations(computation, (ts.SetResult), (ts.SetException), (fun _ -> ts.SetCanceled()), cancellationToken)
167167

168+
let task = ts.Task
169+
#else
170+
let task = Async.StartAsTask(computation, cancellationToken = cancellationToken)
171+
#endif
168172
task.Result
169173

170174
[<AbstractClass>]

tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ let waitUntil condition value =
2828
}
2929

3030
let rec internal spinFor (duration: TimeSpan) =
31-
node {
31+
async {
3232
let sw = Stopwatch.StartNew()
33-
do! Async.Sleep 10 |> NodeCode.AwaitAsync
33+
do! Async.Sleep 10
3434
let remaining = duration - sw.Elapsed
3535
if remaining > TimeSpan.Zero then
3636
return! spinFor remaining
@@ -58,8 +58,8 @@ type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality>(mem
5858
[<Fact>]
5959
let ``Basics``() =
6060

61-
let computation key = node {
62-
do! Async.Sleep 1 |> NodeCode.AwaitAsync
61+
let computation key = async {
62+
do! Async.Sleep 1
6363
return key * 2
6464
}
6565

@@ -77,8 +77,8 @@ let ``Basics``() =
7777
memoize.Get'(3, computation 3)
7878
memoize.Get'(2, computation 2)
7979
}
80-
|> NodeCode.Parallel
81-
|> NodeCode.RunImmediateWithoutCancellation
80+
|> Async.Parallel
81+
|> Async.RunImmediateWithoutCancellation
8282

8383
let expected = [| 10; 10; 4; 10; 6; 4|]
8484

@@ -95,7 +95,7 @@ let ``We can cancel a job`` () =
9595

9696
let jobStarted = new ManualResetEvent(false)
9797

98-
let computation action = node {
98+
let computation action = async {
9999
action() |> ignore
100100
do! spinFor timeout
101101
failwith "Should be canceled before it gets here"
@@ -110,13 +110,13 @@ let ``We can cancel a job`` () =
110110

111111
let key = 1
112112

113-
let _task1 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation jobStarted.Set), ct = cts1.Token)
113+
let _task1 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation jobStarted.Set), ct = cts1.Token)
114114

115115
waitFor jobStarted
116116
jobStarted.Reset() |> ignore
117117

118-
let _task2 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts2.Token)
119-
let _task3 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts3.Token)
118+
let _task2 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts2.Token)
119+
let _task3 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation ignore), ct = cts3.Token)
120120

121121
do! waitUntil (events.CountOf Requested) 3
122122

@@ -146,7 +146,7 @@ let ``Job is restarted if first requestor cancels`` () =
146146

147147
let jobCanComplete = new ManualResetEvent(false)
148148

149-
let computation key = node {
149+
let computation key = async {
150150
jobStarted.Set() |> ignore
151151
waitFor jobCanComplete
152152
return key * 2
@@ -162,13 +162,13 @@ let ``Job is restarted if first requestor cancels`` () =
162162

163163
let key = 1
164164

165-
let _task1 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token)
165+
let _task1 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token)
166166

167167
waitFor jobStarted
168168
jobStarted.Reset() |> ignore
169169

170-
let _task2 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token)
171-
let _task3 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token)
170+
let _task2 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token)
171+
let _task3 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token)
172172

173173
do! waitUntil (events.CountOf Requested) 3
174174

@@ -197,7 +197,7 @@ let ``Job is restarted if first requestor cancels but keeps running if second re
197197

198198
let jobCanComplete = new ManualResetEvent(false)
199199

200-
let computation key = node {
200+
let computation key = async {
201201
jobStarted.Set() |> ignore
202202
waitFor jobCanComplete
203203
return key * 2
@@ -213,13 +213,13 @@ let ``Job is restarted if first requestor cancels but keeps running if second re
213213

214214
let key = 1
215215

216-
let _task1 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token)
216+
let _task1 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts1.Token)
217217

218218
waitFor jobStarted
219219
jobStarted.Reset() |> ignore
220220

221-
let _task2 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token)
222-
let _task3 = NodeCode.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token)
221+
let _task2 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts2.Token)
222+
let _task3 = Async.StartAsTask_ForTesting( memoize.Get'(key, computation key), ct = cts3.Token)
223223

224224
do! waitUntil (events.CountOf Requested) 3
225225

@@ -275,21 +275,21 @@ let ``Stress test`` () =
275275
while (int s.ElapsedMilliseconds) < durationMs do
276276
number <- number + 1 % 12345
277277
return [result]
278-
} |> NodeCode.AwaitAsync
278+
}
279279

280280
let rec sleepyComputation durationMs result =
281-
node {
281+
async {
282282
if rng.NextDouble() < (exceptionProbability / (float durationMs / float stepMs)) then
283283
raise (ExpectedException())
284284
if durationMs > 0 then
285-
do! Async.Sleep (min stepMs durationMs) |> NodeCode.AwaitAsync
285+
do! Async.Sleep (min stepMs durationMs)
286286
return! sleepyComputation (durationMs - stepMs) result
287287
else
288288
return [result]
289289
}
290290

291291
let rec mixedComputation durationMs result =
292-
node {
292+
async {
293293
if durationMs > 0 then
294294
if rng.NextDouble() < 0.5 then
295295
let! _ = intenseComputation (min stepMs durationMs) ()
@@ -331,7 +331,7 @@ let ``Stress test`` () =
331331
let result = key * 2
332332
let job = cache.Get'(key, computation durationMs result)
333333
let cts = new CancellationTokenSource()
334-
let runningJob = NodeCode.StartAsTask_ForTesting(job, ct = cts.Token)
334+
let runningJob = Async.StartAsTask_ForTesting(job, ct = cts.Token)
335335
cts.CancelAfter timeoutMs
336336
Interlocked.Increment &started |> ignore
337337
try
@@ -385,7 +385,7 @@ let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished =
385385
let job2started = new ManualResetEvent(false)
386386
let job2finished = new ManualResetEvent(false)
387387

388-
let work onStart onFinish = node {
388+
let work onStart onFinish = async {
389389
Interlocked.Increment &started |> ignore
390390
onStart() |> ignore
391391
waitFor jobCanContinue
@@ -400,7 +400,7 @@ let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished =
400400
member _.GetVersion() = 1
401401
member _.GetLabel() = "key1" }
402402

403-
cache.Get(key1, work job1started.Set job1finished.Set) |> Async.AwaitNodeCode |> Async.Start
403+
cache.Get(key1, work job1started.Set job1finished.Set) |> Async.Start
404404

405405
waitFor job1started
406406

@@ -410,7 +410,7 @@ let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished =
410410
member _.GetVersion() = key1.GetVersion() + 1
411411
member _.GetLabel() = "key2" }
412412

413-
cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.AwaitNodeCode |> Async.Start
413+
cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.Start
414414

415415
waitFor job2started
416416

@@ -438,18 +438,18 @@ let ``Preserve thread static diagnostics`` () =
438438
let job1Cache = AsyncMemoize()
439439
let job2Cache = AsyncMemoize()
440440

441-
let job1 (input: string) = node {
442-
let! _ = Async.Sleep (rng.Next(1, 30)) |> NodeCode.AwaitAsync
441+
let job1 (input: string) = async {
442+
let! _ = Async.Sleep (rng.Next(1, 30))
443443
let ex = DummyException("job1 error")
444444
DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex)
445445
return Ok input
446446
}
447447

448-
let job2 (input: int) = node {
448+
let job2 (input: int) = async {
449449

450450
DiagnosticsThreadStatics.DiagnosticsLogger.Warning(DummyException("job2 error 1"))
451451

452-
let! _ = Async.Sleep (rng.Next(1, 30)) |> NodeCode.AwaitAsync
452+
let! _ = Async.Sleep (rng.Next(1, 30))
453453

454454
let key = { new ICacheKey<_, _> with
455455
member _.GetKey() = "job1"
@@ -481,7 +481,7 @@ let ``Preserve thread static diagnostics`` () =
481481
member _.GetVersion() = rng.Next(1, 10)
482482
member _.GetLabel() = "job2" }
483483

484-
let! result = job2Cache.Get(key, job2 (i % 10)) |> Async.AwaitNodeCode
484+
let! result = job2Cache.Get(key, job2 (i % 10))
485485

486486
let diagnostics = diagnosticsLogger.GetDiagnostics()
487487

@@ -512,7 +512,7 @@ let ``Preserve thread static diagnostics already completed job`` () =
512512
member _.GetVersion() = 1
513513
member _.GetLabel() = "job1" }
514514

515-
let job (input: string) = node {
515+
let job (input: string) = async {
516516
let ex = DummyException($"job {input} error")
517517
DiagnosticsThreadStatics.DiagnosticsLogger.ErrorR(ex)
518518
return Ok input
@@ -524,8 +524,8 @@ let ``Preserve thread static diagnostics already completed job`` () =
524524

525525
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize)
526526

527-
let! _ = cache.Get(key, job "1" ) |> Async.AwaitNodeCode
528-
let! _ = cache.Get(key, job "2" ) |> Async.AwaitNodeCode
527+
let! _ = cache.Get(key, job "1" )
528+
let! _ = cache.Get(key, job "2" )
529529

530530
let diagnosticMessages = diagnosticsLogger.GetDiagnostics() |> Array.map (fun (d, _) -> d.Exception.Message) |> Array.toList
531531

@@ -545,9 +545,9 @@ let ``We get diagnostics from the job that failed`` () =
545545
member _.GetVersion() = 1
546546
member _.GetLabel() = "job1" }
547547

548-
let job (input: int) = node {
548+
let job (input: int) = async {
549549
let ex = DummyException($"job {input} error")
550-
do! Async.Sleep 100 |> NodeCode.AwaitAsync
550+
do! Async.Sleep 100
551551
DiagnosticsThreadStatics.DiagnosticsLogger.Error(ex)
552552
return 5
553553
}
@@ -560,7 +560,7 @@ let ``We get diagnostics from the job that failed`` () =
560560

561561
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize)
562562
try
563-
let! _ = cache.Get(key, job i ) |> Async.AwaitNodeCode
563+
let! _ = cache.Get(key, job i )
564564
()
565565
with _ ->
566566
()

tests/FSharp.Test.Utilities/ProjectGeneration.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ open System.Xml
2727
open FSharp.Compiler.CodeAnalysis
2828
open FSharp.Compiler.CodeAnalysis.ProjectSnapshot
2929
open FSharp.Compiler.Diagnostics
30+
open FSharp.Compiler.BuildGraph
3031
open FSharp.Compiler.Text
3132

3233
open Xunit
@@ -792,7 +793,7 @@ module ProjectOperations =
792793
let! projects =
793794
p.DependsOn
794795
|> Seq.map (absorbAutoGeneratedSignatures checker)
795-
|> Async.Sequential
796+
|> Async.SequentialFailFast
796797
return
797798
{ p with
798799
SourceFiles = files

0 commit comments

Comments
 (0)