fix(async): linearize await inside catch; complete the RegExp test262 worklist - #8716
Merged
Conversation
… worklist Lands #8707 and #8667. #8707 (fixes #8681) stops an `await` inside a `catch` compiling to a blocking busy-wait. `build_async_catch_route_body_direct` ignored `catch_entry_state` and re-inlined the catch body through `rewrite_yield_to_await_in_stmts`, turning every catch suspend back into a raw `Expr::Await` that codegen lowers as `js_wait_for_event`. Reached re-entrantly from the async-step cascade -- a rejected awaited promise in a `try` routing to a `catch` that itself awaits, the ordinary stream retry/backoff shape -- that blocking wait monopolises the single runtime thread while the driver that would resolve it sits suspended above it, and the program deadlocks. This is the natively-compiled Claude Code `-p` streaming hang. The revision also closes the `await`-in-`finally` gap its own test caught: a linearized catch now takes the state-based upper bound (`protected_end_state`, which excludes the catch's own states), so an error raised inside the catch routes correctly. The legacy inline path (`catch_entry_state == None`) keeps the bound it always used. #8667 completes the RegExp test262 worklist. Its `Cargo.toml` change is additive -- `regress` gains `features = ["utf16"]`, nothing dropped -- and `cargo check --locked` still succeeds, so the lockfile is current. One fix on top: #8707's new coverage pushed `async_to_generator.rs` to 2722 lines, past the file-size gate. `computed_and_field_async_tests` moved to a sibling file declared with `#[path]`, so the module path and every test name are unchanged (verified by running them). 2722 -> 1806. No version bump.
This was referenced Aug 24, 2026
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughThe PR updates regex matcher selection and WTF-8 replacement handling. It also records async generator methods and routes errors through linearized async catch states. Regression tests cover both runtime and transformation changes. ChangesRegex matching and replacement
Async generator transformation
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant js_string_replace_regex
participant replace_wtf8_subject
participant regress
js_string_replace_regex->>replace_wtf8_subject: pass WTF-8 subject and replacement
replace_wtf8_subject->>regress: match UTF-16 or UCS-2 units
regress-->>replace_wtf8_subject: return match captures
replace_wtf8_subject-->>js_string_replace_regex: return WTF-8 replacement output
sequenceDiagram
participant async_step
participant catch_dispatch
participant async_step_loop
async_step->>catch_dispatch: deliver error to linearized catch
catch_dispatch->>async_step_loop: set catch_entry_state
async_step_loop->>catch_dispatch: execute catch states
catch_dispatch-->>async_step: propagate catch-raised throw
Suggested reviewers: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lands #8707 and #8667.
#8707 —
awaitinsidecatchcompiled to a blocking busy-wait (fixes #8681)build_async_catch_route_body_directignoredcatch_entry_stateand re-inlined the catch body throughrewrite_yield_to_await_in_stmts, turning every catch suspend back into a rawExpr::Awaitthat codegen lowers asjs_wait_for_event. Reached re-entrantly from the async-step cascade — a rejected awaited promise in atryrouting to acatchthat itself awaits, i.e. the ordinary stream retry/backoff shape — that blocking wait monopolises the single runtime thread while the driver that would resolve it sits suspended above it on the stack. The program deadlocks. This is the natively-compiled Claude Code-pstreaming hang.The revision also closes the
await-in-finallygap that its own test caught. When I first validated this againstmain,async_generator_linearizes_every_await_positionreportedawait-in-finally: 2 raw await(s) survived; it passed on the PR's own head, so it was an interaction with newermain, not a defect in the PR as written. The fix is that a linearized catch now takes the state-based upper bound (protected_end_state, which excludes the catch's own states), so an error raised inside the catch routes correctly. The legacy inline path (catch_entry_state == None) keeps the bound it always used. That test now passes on the merged result.#8667 — complete the RegExp test262 worklist
Now rebases cleanly. I checked the
Cargo.tomlconflict I'd flagged as risky to union-resolve: the change is purely additive —regressgainsfeatures = ["utf16"], nothing dropped — andcargo check --lockedstill succeeds, so the lockfile is current and CI's locked build won't break.One fix on top
#8707's new coverage pushed
async_to_generator.rsto 2722 lines, past the file-size gate.computed_and_field_async_testsmoved to a sibling file declared with#[path = "async_to_generator_tests.rs"], so the module path — and therefore every test name — is unchanged. Verified by running them: they still report asasync_to_generator::computed_and_field_async_tests::*, 8/8. 2722 → 1806.Validation (on the merged result)
lint-job checkers passperry-transform --lib: 92 passed, 0 failed (count unchanged across the split, so no test was lost)perry-runtime --lib(RUST_TEST_THREADS=1): 2657 passed, 0 failed (+2 from fix(runtime): complete RegExp test262 worklist #8667)perry-codegen --lib: 1214 passed, 0 failedcargo check --locked -p perry-runtime: cleanNo version bump.
Summary by CodeRabbit
Bug Fixes
awaitinsidecatchblocks in async functions and generators.Tests