Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## v0.5.1217 — switch inside async/generator state machines miscompiled (#5885, fixes #5868)

Two state-machine defects, one shared fix. (1) A `yield`/`await` inside a switch case was silently lowered to `0`: the linearizer had no `Stmt::Switch` arm, so the switch fell to the catch-all, was emitted unsplit inside one state, and codegen's fallback lowered the residual `Expr::Yield` to `0.0` — `async f(x){ switch(x){ case 1: return await g() } }` resolved to `0` without suspending, and a generator `yield` inside a case vanished. (2) A loop-level `continue` inside a yield-free switch in a CPS'd loop survived as a raw `Stmt::Continue` the dispatch loop ignored, silently running the rest of the iteration. Both live in production paths since #5854 put async class methods through CPS; minifiers turn if-chains into switches routinely. New `desugar_switch_to_ifs` (generator/break_continue.rs): discriminant temp + match-index + guarded-`if` chain preserving JS switch semantics (single-eval discriminant, in-order first-match-wins tests, fallthrough, default-in-the-middle, `break` — incl. from nested if/try — via done-flag with remainder guarding; `continue`/`return`/`throw` pass through). Wired into a new yielding-switch `linearize_body` arm, a splice in `rewrite_break_continue_in_stmts` for continue-bearing yield-free switches (`next_local_id` threaded through), and the labeled arm (`break label` → plain break in a labeled switch). e2e: `crates/perry/tests/issue_5868_switch_state_machine.rs` (9 scenarios vs node). Note: this PR's labeled run showed parity/smokes/doc-tests failing to BUILD with the pre-existing #5466 E0308 feature-combo breakage (#5872) — zero parity tests executed; compiler-output-regression and the full cargo-test suite are green.

## v0.5.1216 — promise reactions must not clobber the single handler slot (#5867)

A promise carries one inline reaction slot (`on_fulfilled`/`on_rejected`/`next`); `js_promise_then` diverted 2nd+ reactions to the overflow table, but two other attach paths stored unconditionally: `js_promise_attach_handlers` (Promise.all/allSettled/race/any via `promise_resolve_for_combinator`, stream adapters) destroyed any earlier reaction — `p.then(cb); Promise.all([p])` lost `cb`, and two combinators sharing one pending input destroyed each other's forwarder so the loser's remaining-count never reached zero (permanent hang; the shared webpack/Turbopack chunk-promise shape, #5437 family) — and `js_promise_finally` on a PENDING promise overwrote the slot and nulled `promise.next`. All three occupancy checks (including `js_promise_then` itself) now treat a non-null `next` as occupied too: a degenerate no-arg `p.then()` parks with both closures null and only `next` set, and the spec combinators attach per-element reactions through `js_promise_then` via `invoke_then`, so `const c = p.then(); Promise.all([p])` stranded `c`'s chain. Also carries the #5437-branch fix: `.finally()` on a SETTLED promise dispatches its own wrapper exactly once via `Task::Inline` (previously N settled finallys ran the last wrapper N times — Turbopack `loadChunkAsync` / Next.js CacheSignal), and settled `.finally` now captures the attach-time async context. e2e: `crates/perry/tests/promise_reaction_slot_overflow.rs` (7 scenarios byte-for-byte vs `node --experimental-strip-types`). `promise/then.rs` (2008 lines) is allowlisted 8-over the file-size gate; the topical split of its #1545 value-read-thunk tail is a tracked follow-up.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation.

**Current Version:** 0.5.1216
**Current Version:** 0.5.1217


## TypeScript Parity Status
Expand Down
Loading
Loading