Skip to content

Preserve outer rethrows in nested runtime async try/with #20575

Description

@T-Gro

Runtime async leaves an outer-owned reraise() unchanged when it is inside a nested try/with protected body. Moving the suspending outer handler out of its catch region then leaves an orphan IL rethrow.

Repro steps

Save as Reraise.fs and compile as a library using the compiler and matching net10.0 FSharp.Core built from main e61631709fadcb83a90d336852c650e8c86b0189.

module Reraise

open System
open System.IO
open System.Threading.Tasks
open System.Runtime.CompilerServices
open Microsoft.FSharp.Core.CompilerServices.StateMachineHelpers

let recover (original: exn) (audit: Task) : Task<int> =
    __runtimeAsyncReturn (
        try
            raise original
        with _ ->
            AsyncHelpers.Await audit
            try
                reraise ()
            with :? IOException ->
                7)
dotnet artifacts/bin/fsc/Release/net11.0/fsc.dll \
  --targetprofile:netcore --langversion:preview --optimize+ --target:library \
  -r:artifacts/bin/FSharp.Core/Release/net10.0/FSharp.Core.dll \
  -o:Reraise.dll Reraise.fs

Compile and inspect only; do not execute the invalid output.

Expected behavior

After audit completes, the nested handler returns 7 for an IOException. Other exceptions propagate as the original exception object. The protected-body rethrow must refer to the outer catch; the inner handler keeps its own exception scope.

Actual behavior

Compilation succeeds, but recover contains rethrow at IL_0040, outside every catch/filter handler. The handler ranges are [0015,0024) and [0063,0086). The separate rethrow at IL_007B is inside the inner handler and is legal.

A region-aware component assertion fails with:

recover: orphan rethrow at IL_0040

Known workarounds

Match the caught exception directly. For an unhandled exception, ExceptionDispatchInfo.Capture(error).Throw() avoids the orphan rethrow. The pending-audit, exception-identity and IOException fallback controls pass.

Related information

Reproduced after #20235 on main e6163170, with a freshly built compiler/Core and .NET 11.0.0-rc.1.26420.103 on macOS ARM64. This is accepted low-level intrinsic code. It is separate from #20405, which adds support for currently rejected CE-handler reraise forms; no FS0413 language change is requested here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions