You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
codegen(async): await inside finally of an async generator block-waits (residual raw Await in the linearized finally state) #8715
An await inside a finally block of a real async generator (async function*) is lowered to a raw Expr::Await inside its linearized finally state instead of an async suspend, so codegen (fs_await.rs, !ctx.is_async_fn) emits the blocking busy-wait (js_wait_for_event). This is the same class of deadlock as #8681 (await-in-catch), but in a different path: the #4438 B2-finally lowering in crates/perry-transform/src/generator/lower/abrupt.rs, not the was_plain_async catch path fixed by #8707.
Scope
The was_plain_async closure/function path (build_async_catch_route_body_direct) is not affected — the closure test async_closure_rewrite_leaves_no_residual_await covers in-finally and passes.
Only the real async-generator finally path leaves the residual. Minimal repro (transform-level):
async function*g(){
try {yield0;}
finally { await Promise.resolve();}// <- becomes raw Expr::Await in a finally state}
After transform_async_to_generator + transform_generators, the finally state contains LocalSet(__sent, Await(..)) (2 residual awaits — normal + abrupt completion copies) rather than an async suspend.
Likely fix direction
Analogous to #8707's catch fix: route the finally through its linearized FinallyRoute.finally_entry_state and stop materializing the finally body's suspends as raw awaits (the finally-state emission / build_finally_run_stmts interaction for the async path). This touches the heavily-patched #4438/#4374 abrupt-completion routing, so it wants its own change + behavioral validation (a try { await } finally { await } battery vs Node), separate from the catch fix.
Detection
The regression guard already exists: async_generator_linearizes_every_await_position in async_to_generator.rs had an await-in-finally case (removed from that test in #8707 and pointed here). Re-adding it is the acceptance test for this issue.
Found while landing #8681/#8707 (natively-compiled Claude Code -p streaming deadlock).
Activity
fix(async): linearize `await` inside `catch` for async fns/closures (P…
fix(async): linearize await inside an async-generator finally; fix al…