@@ -1210,16 +1210,30 @@ module AsyncPrimitives =
12101210
12111211 task
12121212
1213+ // Used by Async.Await path to elide egregious AggregateException wrapping
1214+ [<DebuggerHidden>]
1215+ let UnwrapExn ( exn : AggregateException ) =
1216+ if exn.InnerExceptions.Count = 1 then
1217+ exn.InnerExceptions[ 0 ]
1218+ else
1219+ exn
1220+
12131221 // Call the appropriate continuation on completion of a task
12141222 [<DebuggerHidden>]
1215- let OnTaskCompleted ( completedTask : Task < 'T >) ( ctxt : AsyncActivation < 'T >) =
1223+ let OnTaskCompleted unwrap ( completedTask : Task < 'T >) ( ctxt : AsyncActivation < 'T >) =
12161224 assert completedTask.IsCompleted
12171225
12181226 if completedTask.IsCanceled then
12191227 let edi = ExceptionDispatchInfo.Capture( TaskCanceledException completedTask)
12201228 ctxt.econt edi
12211229 elif completedTask.IsFaulted then
1222- let edi = ExceptionDispatchInfo.RestoreOrCapture completedTask.Exception
1230+ let e =
1231+ if unwrap then
1232+ UnwrapExn completedTask.Exception
1233+ else
1234+ completedTask.Exception
1235+
1236+ let edi = ExceptionDispatchInfo.RestoreOrCapture e
12231237 ctxt.econt edi
12241238 else
12251239 ctxt.cont completedTask.Result
@@ -1229,14 +1243,20 @@ module AsyncPrimitives =
12291243 // the overall async (they may be governed by different cancellation tokens, or
12301244 // the task may not have a cancellation token at all).
12311245 [<DebuggerHidden>]
1232- let OnUnitTaskCompleted ( completedTask : Task ) ( ctxt : AsyncActivation < unit >) =
1246+ let OnUnitTaskCompleted unwrap ( completedTask : Task ) ( ctxt : AsyncActivation < unit >) =
12331247 assert completedTask.IsCompleted
12341248
12351249 if completedTask.IsCanceled then
12361250 let edi = ExceptionDispatchInfo.Capture( TaskCanceledException( completedTask))
12371251 ctxt.econt edi
12381252 elif completedTask.IsFaulted then
1239- let edi = ExceptionDispatchInfo.RestoreOrCapture completedTask.Exception
1253+ let e =
1254+ if unwrap then
1255+ UnwrapExn completedTask.Exception
1256+ else
1257+ completedTask.Exception
1258+
1259+ let edi = ExceptionDispatchInfo.RestoreOrCapture e
12401260 ctxt.econt edi
12411261 else
12421262 ctxt.cont ()
@@ -1246,10 +1266,10 @@ module AsyncPrimitives =
12461266 // completing the task. This will install a new trampoline on that thread and continue the
12471267 // execution of the async there.
12481268 [<DebuggerHidden>]
1249- let AttachContinuationToTask ( task : Task < 'T >) ( ctxt : AsyncActivation < 'T >) =
1269+ let AttachContinuationToTask unwrap ( task : Task < 'T >) ( ctxt : AsyncActivation < 'T >) =
12501270 task.ContinueWith(
12511271 Action< Task< 'T>>( fun completedTask ->
1252- ctxt.trampolineHolder.ExecuteWithTrampoline( fun () -> OnTaskCompleted completedTask ctxt)
1272+ ctxt.trampolineHolder.ExecuteWithTrampoline( fun () -> OnTaskCompleted unwrap completedTask ctxt)
12531273 |> unfake),
12541274 TaskContinuationOptions.ExecuteSynchronously
12551275 )
@@ -1261,16 +1281,36 @@ module AsyncPrimitives =
12611281 // completing the task. This will install a new trampoline on that thread and continue the
12621282 // execution of the async there.
12631283 [<DebuggerHidden>]
1264- let AttachContinuationToUnitTask ( task : Task ) ( ctxt : AsyncActivation < unit >) =
1284+ let AttachContinuationToUnitTask unwrap ( task : Task ) ( ctxt : AsyncActivation < unit >) =
12651285 task.ContinueWith(
12661286 Action< Task>( fun completedTask ->
1267- ctxt.trampolineHolder.ExecuteWithTrampoline( fun () -> OnUnitTaskCompleted completedTask ctxt)
1287+ ctxt.trampolineHolder.ExecuteWithTrampoline( fun () -> OnUnitTaskCompleted unwrap completedTask ctxt)
12681288 |> unfake),
12691289 TaskContinuationOptions.ExecuteSynchronously
12701290 )
12711291 |> ignore
12721292 |> fake
12731293
1294+ let AwaitTask unwrap ( task : Task < 'T >) =
1295+ MakeAsyncWithCancelCheck( fun ctxt ->
1296+ if task.IsCompleted then
1297+ // Run synchronously without installing new trampoline
1298+ OnTaskCompleted unwrap task ctxt
1299+ else
1300+ // Continue asynchronously, via syncContext if necessary, installing new trampoline
1301+ let ctxt = DelimitSyncContext ctxt
1302+ ctxt.ProtectCode( fun () -> AttachContinuationToTask unwrap task ctxt))
1303+
1304+ let AwaitUnitTask unwrap ( task : Task ) =
1305+ MakeAsyncWithCancelCheck( fun ctxt ->
1306+ if task.IsCompleted then
1307+ // Continue synchronously without installing new trampoline
1308+ OnUnitTaskCompleted unwrap task ctxt
1309+ else
1310+ // Continue asynchronously, via syncContext if necessary, installing new trampoline
1311+ let ctxt = DelimitSyncContext ctxt
1312+ ctxt.ProtectCode( fun () -> AttachContinuationToUnitTask unwrap task ctxt))
1313+
12741314 /// Removes a registration places on a cancellation token
12751315 let DisposeCancellationRegistration ( registration : byref < CancellationTokenRegistration option >) =
12761316 match registration with
@@ -2203,24 +2243,30 @@ type Async =
22032243 CreateWhenCancelledAsync compensation computation
22042244
22052245 static member AwaitTask ( task : Task < 'T >) : Async < 'T > =
2206- MakeAsyncWithCancelCheck( fun ctxt ->
2207- if task.IsCompleted then
2208- // Run synchronously without installing new trampoline
2209- OnTaskCompleted task ctxt
2210- else
2211- // Continue asynchronously, via syncContext if necessary, installing new trampoline
2212- let ctxt = DelimitSyncContext ctxt
2213- ctxt.ProtectCode( fun () -> AttachContinuationToTask task ctxt))
2246+ AwaitTask false task
22142247
22152248 static member AwaitTask ( task : Task ) : Async < unit > =
2216- MakeAsyncWithCancelCheck( fun ctxt ->
2217- if task.IsCompleted then
2218- // Continue synchronously without installing new trampoline
2219- OnUnitTaskCompleted task ctxt
2220- else
2221- // Continue asynchronously, via syncContext if necessary, installing new trampoline
2222- let ctxt = DelimitSyncContext ctxt
2223- ctxt.ProtectCode( fun () -> AttachContinuationToUnitTask task ctxt))
2249+ AwaitUnitTask false task
2250+
2251+ static member Await ( task : Task < 'T >) : Async < 'T > =
2252+ AwaitTask true task
2253+
2254+ static member Await ( task : Task ) : Async < unit > =
2255+ AwaitUnitTask true task
2256+
2257+ #if NETSTANDARD2_ 1
2258+ static member Await ( task : ValueTask < 'T >) : Async < 'T > =
2259+ if task.IsCompleted then
2260+ async { return task.GetAwaiter() .GetResult() }
2261+ else
2262+ Async.Await( task.AsTask())
2263+
2264+ static member Await ( task : ValueTask ) : Async < unit > =
2265+ if task.IsCompleted then
2266+ async { return task.GetAwaiter() .GetResult() }
2267+ else
2268+ Async.Await( task.AsTask())
2269+ #endif
22242270
22252271module CommonExtensions =
22262272
0 commit comments