Skip to content

fix(hir): language/expressions/object literal semantics test262 parity#4751

Merged
proggeramlug merged 1 commit into
mainfrom
objlit-parity
Jun 7, 2026
Merged

fix(hir): language/expressions/object literal semantics test262 parity#4751
proggeramlug merged 1 commit into
mainfrom
objlit-parity

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Root cause

Object-literal method definitions ({ m([x, y]) {} }, { m(a = 23) {} }) lowered their parameters in crates/perry-hir/src/lower/expr_object.rs (lower_method_prop) without:

  1. destructuring-extraction statements — a method param like [x, y, z] never produced a Let for x/y/z, so the body threw ReferenceError: identifier is not defined;
  2. default-parameter fill statements — object methods never dispatch through the __perry_wrap_<name> prologue that applies a top-level function's registered defaults, so without the body carrying its own if (p === undefined) p = <default> checks, every defaulted param read as undefined.

Plain functions (lower_fn_decl/expr_function) and class methods (lower_decl/class_members.rs) already do both; the object-literal method path was the one site missing it.

Fix

Mirror lower_decl/class_members.rs exactly:

  • Unwrap Pat::Assign to the inner array/object pattern before the is_destructuring_pattern check — [x] = [1] is a Pat::Assign wrapping the pattern, so checking the raw param.pat missed the defaulted-destructuring form.
  • generate_param_destructuring_stmts before lowering the body, so the destructured bindings are in scope when the body references them.
  • Prepend build_default_param_stmts last, so defaults run before destructuring (m([x] = [1]) {}).

Files touched: crates/perry-hir/src/lower/expr_object.rs (only).

Results — language/expressions/object

453 → 557 pass (+104), zero regressions.

Measured with two isolated runs of both baseline (origin/main @ 25ccfbb) and fix; both pairs were byte-identical (0 flaky), 0 tests that passed before now fail. Default compile path (no env flags).

Fixed families (all the same root cause):

  • dstr/ meth / gen-meth / async-gen-meth (+ -dflt variants) destructuring params — ~90 tests
  • method-definition/ meth-dflt-params / gen-meth-dflt-params / async-meth-dflt-params default-param edge cases
  • scope-{,gen-}meth-param-* var-scope cases

Remaining failures in the directory are unrelated (lone eval(...) of string code, fn.name descriptor edge cases, super-in-object-method, async-generator yield* delegation).

Object-literal method definitions (`{ m([x,y]) {} }`, `{ m(a = 23) {} }`)
lowered their parameters without (1) destructuring-extraction statements or
(2) default-parameter fill statements. Plain functions and class methods both
do this; `lower_method_prop` (the object-literal method path) did not, so:

- bare destructuring params threw `ReferenceError: identifier is not defined`
  (the bound names `x`, `y` never got a `Let`);
- default params read as `undefined` (object methods never dispatch through
  the `__perry_wrap_<name>` prologue that applies a top-level function's
  registered defaults, so the body must carry the `if (p === undefined)`
  checks itself).

Fix mirrors `lower_decl/class_members.rs`: unwrap `Pat::Assign` to the inner
array/object pattern before the destructuring check (so `[x] = [1]` is
recognized), generate extraction `Let`s before lowering the body, then prepend
`build_default_param_stmts` so defaults run before destructuring.

test262 language/expressions/object: 453 -> 557 pass (+104), zero regressions
(two isolated runs each, identical). Fixes the sync `meth`/`gen-meth`/
`meth-dflt`/`gen-meth-dflt` destructuring + default families.
@proggeramlug proggeramlug merged commit 74f5620 into main Jun 7, 2026
13 checks passed
@proggeramlug proggeramlug deleted the objlit-parity branch June 7, 2026 09:29
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.

1 participant