Repository navigation
Conversation
…suspending handlers A try/with handler or try/finally compensation that suspends is moved out of its exception-handling region. The rewrite recorded the body's outcome in a Choice<'T, exn>, allocated on every run including success, and rethrew a pending exception with a plain throw, which reset its stack trace. This affected a suspending finally (including use of an IAsyncDisposable), reraise () after a suspension, and an unmatched handler pattern. * Record the body's result and the pending exception in two locals; the exception stays null when the body succeeds, so nothing is allocated. * Rethrow with ExceptionDispatchInfo.Capture(exn).Throw(). The helper moves from LowerAsyncSeq into RuntimeAsyncExceptionRewrite and is shared; the rewrite now receives the import map. * Tests for stack traces and success-path allocation; update the IL fragments of the composed CE test and pin the rethrow. * Docs and release notes.
✅ Release notes checked
|
| let resultVal, bodyResult = | ||
| if isUnitTy g resultTy then | ||
| None, mkUnit g m | ||
| else | ||
| let resultVal, result = mkMutableCompGenLocal m "__runtimeAsyncResult" resultTy | ||
| Some resultVal, result |
There was a problem hiding this comment.
For a byref-like try result like the one below, FS3919 now names this generated local, which the user never wrote. Could the message refer to the try result instead of the generated local, or say that the result can't be held across the suspension?
let f (arr: int[]) : Task<int> =
StateMachineHelpers.__runtimeAsyncReturn (
let s = (try Span<int>(arr) finally AsyncHelpers.Await(Task.Delay 1))
s.Length)With this PR's build and --langversion:preview, this gives error FS3919: A byref, byref-like, or pinned local '__runtimeAsyncResult' cannot be used after a runtime async suspension. at the try, with optimization off and on. Rejecting it is right: the merge-base build compiles it, and on runtime 11.0.0-rc.1 f(...).Result throws an AggregateException wrapping a TypeLoadException, because Span<int> can't be the first type argument of the old Choice. None of the runtime-async tests has a byref-like try result, so a test would also keep this case rejected.
There was a problem hiding this comment.
Yes, good catch. C# in such case gives just
“Instance of type ‘System.Span‘ cannot be preserved across ‘await’ or ‘yield’ boundary.”
A try/with handler or try/finally compensation that suspends is moved out of its exception-handling region. The rewrite recorded the body's outcome in a Choice<'T, exn>, allocated on every run including success, and rethrew a pending exception with a plain throw, which reset its stack trace. This affected a suspending finally (including use of an IAsyncDisposable), reraise () after a suspension, and an unmatched handler pattern.
Fix:
Fixes #20869