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.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.

## v0.5.1215 — boxing analysis descends into labeled blocks (#5871)

Five walkers in perry-codegen's `boxed_vars.rs` had no `Stmt::Labeled` arm (while `collect_write_ids_in_stmt` did), so a captured variable reassigned — or captured — inside a labeled block was never boxed: closures kept a creation-time snapshot and never observed later writes. Signature: a captured array read `.length === 0` through the closure while `JSON.stringify` in the same scope printed all four elements — previously seen only inside large minified webpack bundles, which emit labeled early-exit blocks (`e: { … break e; }`) pervasively (#5869). Adds the `Stmt::Labeled { body, .. }` recursion arm to `collect_self_recursive_closure_ids`, `collect_for_init_ids`, `collect_closure_refs_and_writes_in_stmt`, `collect_outer_writes_in_stmt`, and `collect_let_types_in_stmts`. The closure-created-INSIDE-the-label variant remains open on #5869 (perry-hir lowers it with `mutable_captures: []` under the `Labeled{DoWhile(false)}` wrapper); its regression test ships `#[ignore]`d in `crates/perry/tests/issue_5869_labeled_block_capture_boxing.rs`.
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.1215
**Current Version:** 0.5.1216


## TypeScript Parity Status
Expand Down
Loading
Loading