feat(Async): Add exception-unwrapping Await#19785
Conversation
❗ Release notes required
|
b2b2b6a to
b710cc1
Compare
|
@T-Gro if you and/or others can give this a quick scan please, I'd like to confirm:
TL;DR the overall proposition
CC @TheAngryByrd @gusty @njlr who have provided useful feedback/review on stuff in this space in recent times |
There was a problem hiding this comment.
Pull request overview
Adds a new Async.Await API to FSharp.Core for Task/Task<'T> (and ValueTask/ValueTask<'T> on netstandard2.1) that unwraps “egregious” single-inner AggregateExceptions so exception matching works as expected, while aiming to preserve existing AwaitTask stacktrace behavior.
Changes:
- Implement
Async.Awaitinasync.fsby sharing the existingAwaitTaskcontinuation machinery and selectively unwrapping single-innerAggregateExceptions. - Expand unit tests to exercise both
AwaitTaskandAwaitbehavior (including AggregateException cases) and add ValueTask coverage under#if NETSTANDARD2_1. - Update FSharp.Core surface area baseline (partially) and add a release-notes entry.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs | Converts many tests to run against both AwaitTask and new Await; adds new behavior-focused tests for AggregateException unwrapping and ValueTask. |
| tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl | Adds Async.Await entries for netstandard2.1 Debug surface area baseline. |
| src/FSharp.Core/async.fsi | Updates AwaitTask XML docs and adds new Async.Await API docs (including ValueTask overloads under netstandard2.1). |
| src/FSharp.Core/async.fs | Implements Async.Await and refactors task-await internals to optionally unwrap single-inner AggregateExceptions. |
| docs/release-notes/.FSharp.Core/11.0.100.md | Adds release note entry for new Async.Await. |
7aec92d to
9ab202c
Compare
|
I'm thinking about naming. |
@majocha Yes, this was already part of the brief as per the comment from @dsyme. I'd personally need to research what it would entail, so if you or anyone wants to contribute an impl, feel free to hang a PR off this one. But bottom line I agree it would be good for the support for tasklike things to be done either as part of this PR or as a very fast follow so the world only needs to validate the overloading works out cleanly once. |
Implements
Async.AwaitforTask,Task<'T>,ValueTaskandValueTask<'T>(aka the communityAwaitTaskCorrectimplemention)Key differentiation from
Async.AwaitTaskis thatAggregateExceptions are unwrapped such that atry ... with <ExceptionType> ->will type-match correctly.Key distinction from the canonical implementation (which derives from https://www.fssnip.net/7Rc/title/AsyncAwaitTaskCorrect) is that the implementation is intended to have 1:1 matching of all stacktrace preservation properties borne by
AwaitTask(and continue to track that over time).NOTE one key implementation decision is that this PR does NOT attempt to resolve #2127 so:
Awaitis invoked, normal cancellation semantics as perAwaitTaskapply:OperationCanceledExceptionTaskin question'sResultwill go unobservedAwait, it will (likeAwaitTask):Taskawaitwould] until such time as theTaskcompletes (either successfully, with a fault, or via cancellation)Checklist
AwaitTaskwill always yield anAggregateExceptionAwaitshould be the used in preference for new codeAwaitcan technically still propagate anAggregateException