Commit 4697108
Ralph Küpper
fix(async): linearize await inside an async-generator finally (#8715)
An `await` inside a `finally` of an `async function*` compiled to a blocking
busy-wait instead of an async suspend — the finally analog of the #8681
await-in-catch deadlock fixed by #8707.
When a `try` in an async generator has a `finally` that yields or awaits, the
finally is linearized into its own dispatch states. `.next()` and `.throw()`
drive those states through the shared `__agstep` async-step driver, so a
finally `await` suspends on the microtask queue via `AsyncStepChain`. The
`.return()` closure, however, re-drove the SAME states through a separate
`build_dispatch_while_body(states, /*async_step*/ false, …)` continuation loop,
whose `StateExit::Await` lowering emits the busy-wait fallback
`__sent = await value; continue` (fs_await.rs → `js_wait_for_event`). So a
`.return()` that ran the finally — an early `break` in a `for await`, or an
explicit `gen.return(v)` while suspended in the try — block-waited on the
finally's `await`, monopolising the single runtime thread while the driver that
would settle it sits suspended, and deadlocked.
Fix: `.return()` no longer builds or runs an async_step=false loop for async
generators. After `build_abrupt_routing` records the pending return and jumps to
`finally_entry_state`, `.return()` hands off to the shared `__agstep` driver with
a fresh non-error resume (`AsyncGenResume(__agstep, undefined, false)`), exactly
as `.next()`/`.throw()` already do. `__agstep` dispatches from
`finally_entry_state`, runs the finally (its `yield`s settle this `.return()`'s
promise; its `await`s suspend on the microtask queue), and its completion-check
state re-raises the pending return as `{value, done: true}`. Sync generators are
unchanged — they have no `await` states, so their inline busy-wait clone stays
correct, and their `.return()` is a plain (non-driver) closure.
The `async_generator_linearizes_every_await_position` test re-adds the
`await-in-finally` case #8707 had removed (pointing here), plus
await-in-try-and-finally, await-in-try-catch-finally, and
yield-in-finally-with-await; all now leave zero residual `Expr::Await`.
Behaviorally verified byte-identical to Node v26 for explicit `.return()`,
`.throw()`, yield-in-finally, and try/catch/finally shapes, with no deadlock.
Full `cargo test -p perry-transform` is green.
Claude-Session: https://claude.ai/code/session_01TwxRkALrR9HKSF1zKLSTAF1 parent d53f34b commit 4697108
3 files changed
Lines changed: 108 additions & 25 deletions
File tree
- changelog.d
- crates/perry-transform/src
- generator
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
576 | 576 | | |
577 | 577 | | |
578 | 578 | | |
579 | | - | |
580 | | - | |
581 | | - | |
582 | | - | |
583 | | - | |
584 | | - | |
585 | | - | |
586 | | - | |
587 | | - | |
588 | | - | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
589 | 622 | | |
590 | 623 | | |
591 | 624 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
516 | 516 | | |
517 | 517 | | |
518 | 518 | | |
519 | | - | |
520 | | - | |
521 | | - | |
522 | | - | |
523 | | - | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
524 | 530 | | |
525 | | - | |
| 531 | + | |
526 | 532 | | |
527 | 533 | | |
528 | 534 | | |
| |||
577 | 583 | | |
578 | 584 | | |
579 | 585 | | |
580 | | - | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
581 | 590 | | |
582 | 591 | | |
583 | 592 | | |
| |||
977 | 986 | | |
978 | 987 | | |
979 | 988 | | |
980 | | - | |
981 | | - | |
982 | | - | |
983 | | - | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
984 | 993 | | |
985 | 994 | | |
986 | 995 | | |
| |||
994 | 1003 | | |
995 | 1004 | | |
996 | 1005 | | |
997 | | - | |
998 | | - | |
999 | | - | |
1000 | | - | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
1001 | 1036 | | |
1002 | 1037 | | |
1003 | 1038 | | |
| |||
0 commit comments