Skip to content

fix: closes #655 — Array methods on Map.get(...).field chained access - #657

Merged
proggeramlug merged 1 commit into
mainfrom
fix/issue-655
May 10, 2026
Merged

fix: closes #655 — Array methods on Map.get(...).field chained access#657
proggeramlug merged 1 commit into
mainfrom
fix/issue-655

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Closes #655. Under perry compile, calling Array.prototype methods on an array reached through Map.get(k)!.field returned garbage and never mutated for shift / splice / pop / slice / unshift, and field.length = N writes were silently ignored. Aliasing to a single-identifier local first dispatched correctly.

Root cause

crates/perry-codegen/src/type_analysis.rs::static_type_of's PropertyGet arm only consulted ctx.classes. TS interfaces live in hir.interfaces, not hir.classes, so a receiver typed s: State (where State is an interface with pending: number[]) failed the is_array_expr gate. The call fell into generic property+call dispatch, which has no idea how to invoke Array.prototype on a NaN-boxed array handle. push was special-cased elsewhere and accidentally worked; everything else didn't.

Changes

  • Thread interfaces: HashMap<String, perry_hir::Interface> through CrossModuleCtx and FnCtx (six instantiation sites).
  • static_type_of falls back to ctx.interfaces.get(...) after a class miss, walks the extends chain.
  • Add a splice arm to lower_array_method.rs so chained .splice() doesn't hit the silent return-receiver fallback when the new array fast-path engages.

Test plan

  • Issue AOT: Array methods are undefined when accessed via Map.get(...).field #655's exact repro byte-identical to Node for shift / pop / slice / splice / length= (test-files/issue_655_repro.ts).
  • Gap-suite: 27/28 pass — same baseline (the 1 failure, test_gap_console_methods, is the pre-existing timing-sensitive divergence).
  • cargo test --release -p perry-runtime --lib: 225/225 pass.

Out of scope (filed separately)

…ss (v0.5.782)

`m.get(k)!.pending.shift()` returned garbage and never mutated; `field.length =
N` was silently ignored. Codegen's `static_type_of` for `PropertyGet` only
consulted `ctx.classes`, so interface-typed receivers (`s: State` where
`State` is a TS `interface`) failed the array-fast-path gate and fell into
generic property dispatch.

- Thread `interfaces: HashMap<String, perry_hir::Interface>` through
  `CrossModuleCtx` and `FnCtx` (six instantiation sites).
- `static_type_of` falls back to `ctx.interfaces.get(...)` after a class miss
  and walks the `extends` chain.
- Add `splice` arm to `lower_array_method.rs` so chained `.splice()` doesn't
  hit the silent return-receiver fallback.

Repro byte-identical to Node for `shift` / `pop` / `slice` / `splice` /
`length=`. 27/28 gap-suite tests pass (same baseline; 1 pre-existing failure
unrelated). 225/225 perry-runtime unit tests pass.

(Originally committed as v0.5.775 [ea921e02] but lost in a parallel-session
hard-reset to origin/main; cherry-picked here with version bumped to v0.5.782
since v0.5.775..v0.5.781 are now occupied on origin.)
@proggeramlug
proggeramlug merged commit 29fe10d into main May 10, 2026
2 of 10 checks passed
@TheHypnoo
TheHypnoo deleted the fix/issue-655 branch May 16, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AOT: Array methods are undefined when accessed via Map.get(...).field

1 participant