Skip to content

fix(runtime): #5834 — WeakMap/WeakSet constructor + instance-identity test262 fixes - #5851

Merged
proggeramlug merged 2 commits into
mainfrom
worktree-5834-test262-weakmap-weakset
Jul 1, 2026
Merged

fix(runtime): #5834 — WeakMap/WeakSet constructor + instance-identity test262 fixes#5851
proggeramlug merged 2 commits into
mainfrom
worktree-5834-test262-weakmap-weakset

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the built-ins/WeakMap (11) and built-ins/WeakSet (7) test262 failures from the #5834 worklist — a coherent single-root subcluster: WeakMap/WeakSet constructor semantics and instance identity.

  • Constructor iterable handling: js_weakmap_init_iterable/js_weakset_init_iterable previously drained the whole iterable eagerly via a native helper and never actually read/called the set/add adder through a real property Get. Rewrote both to mirror js_map_from_iterable/js_set_from_iterable: fetch the adder only when iterable is non-null/undefined (matching spec step order, so a poisoned WeakMap.prototype.set accessor getter must not fire for new WeakMap()/new WeakMap(null)), honor an accessor descriptor on set/add via a new collection_iter::builtin_prototype_adder helper, and drive the iterable with lazy per-item stepping (iterator_next_value) so an abrupt Get/adder-call closes the iterator (IteratorClose) before rethrowing.
  • Arity-gated dispatch bug: try_weak_method_dispatch's "add"/"set"/etc. arms were gated on args.len(), so an under-arity call like s.add() fell through to a no-op instead of running WeakSet.prototype.add's CanBeHeldWeakly check (which must throw TypeError for undefined). Now always dispatches, padding missing positions with undefined.
  • Instance identity: Object.getPrototypeOf(new WeakMap()) and (new WeakMap()).constructor had no arm for WeakMap/WeakSet instances (a reserved, non-declared-class class_id), so both fell through to the receiver itself / undefined. Added arms in prototype.rs's collection_prototype closure and get_field_by_name_tail.rs's constructor special case.
  • instanceof: x instanceof WeakMap/WeakSet had no runtime probe for real instances — this was a documented, deliberate gap in perry-codegen/src/expr/instance_misc1.rs ("no runtime probe for real instances yet"). Added a probe in js_instanceof (compile-time-literal path) plus the global_builtin_constructor_class_id counterpart for the dynamic x instanceof ctorVar form.

Test plan

  • scripts/test262_subset.py --dir built-ins/WeakMap built-ins/WeakSet: 18/18 originally-failing cases now pass; 100% parity (158/158 judged), 0 regressions.
  • cargo fmt --all -- --check clean.
  • bash scripts/check_file_size.sh clean.
  • cargo test --release -p perry-runtime -p perry-codegen: 1107 passed / 1 failed. The 1 failure (object::tests::builtin_prototype_methods_reject_dynamic_new, asserting Date.prototype.toJSON) is unrelated to this change (no Date/global_this code touched) and matches a known pre-existing test-isolation flake in this suite (shared global builtin-population state races under parallel test threads).

No version bump / CHANGELOG update, per the #5834 worklist's code-only-PR instructions.

Refs #5834.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved WeakMap/WeakSet handling for constructor, prototype, and instanceof checks, including correct resolution for internally-reserved class-id cases.
    • Corrected getPrototypeOf behavior so getPrototypeOf(new WeakMap())/getPrototypeOf(new WeakSet()) no longer falls back to returning the receiver itself.
    • Fixed WeakMap/WeakSet method dispatch and iterable initialization for missing arguments, lazy consumption, and proper iterator cleanup on abrupt failures.

… test262 fixes

Fixes the built-ins/WeakMap (11) and built-ins/WeakSet (7) test262 failures
from the #5834 worklist:

- WeakMap/WeakSet constructors never read/called the `set`/`add` adder
  through a real property Get, and drained the whole iterable eagerly
  instead of stepping it lazily. Rewrote both to mirror
  `js_map_from_iterable`/`js_set_from_iterable`: fetch the adder only when
  `iterable` is non-null/undefined (matching the spec's step order so a
  poisoned accessor doesn't fire for `new WeakMap()`), honor an accessor
  descriptor on `set`/`add` via a new `builtin_prototype_adder` helper, and
  drive the iterable with lazy per-item stepping so an abrupt Get/adder
  call closes the iterator before rethrowing.
- `try_weak_method_dispatch`'s arity-gated arms skipped validation for
  under-arity calls (e.g. `s.add()`), so `WeakSet.prototype.add` never ran
  its CanBeHeldWeakly check on a missing argument. Now always dispatches,
  padding missing args with `undefined`.
- `Object.getPrototypeOf`/`.constructor` had no arm for WeakMap/WeakSet
  instances (a reserved, non-declared-class `class_id`), so both fell
  through to the receiver itself / `undefined`.
- `x instanceof WeakMap`/`WeakSet` had no runtime probe for real instances
  (documented as a known gap) — added one, plus the dynamic
  `x instanceof ctorVar` counterpart.

Verified via scripts/test262_subset.py: built-ins/WeakMap and
built-ins/WeakSet now both at 100% parity (0 regressions). No version
bump/CHANGELOG per the #5834 worklist's code-only-PR instructions.

Refs #5834.
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d8589464-7e5b-451b-80a9-632a955f23f7

📥 Commits

Reviewing files that changed from the base of the PR and between de67ad5 and 5de1979.

📒 Files selected for processing (1)
  • crates/perry-runtime/src/weakref.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/perry-runtime/src/weakref.rs

📝 Walkthrough

Walkthrough

Runtime changes add reserved class-id handling for WeakMap/WeakSet across instanceof checks, constructor property resolution, prototype lookup, method dispatch, and iterable initialization. A new builtin_prototype_adder helper resolves accessor properties, and codegen comments are clarified.

Changes

WeakMap/WeakSet reserved-id handling

Layer / File(s) Summary
Codegen comment clarification
crates/perry-codegen/src/expr/instance_misc1.rs
Comments updated to state WeakMap/WeakSet use runtime probing for real instances, while DataView still relies on class-chain matching.
instanceof and constructor class-id mapping
crates/perry-runtime/src/object/instanceof.rs, crates/perry-runtime/src/object/field_get_set/get_field_by_name_tail.rs, crates/perry-runtime/src/object/object_ops/prototype.rs
Adds reserved class-id handling for WeakMap/WeakSet in constructor-id lookup, instanceof probing, constructor property reads, and prototype resolution.
Builtin prototype adder and weak method dispatch
crates/perry-runtime/src/collection_iter.rs, crates/perry-runtime/src/weakref.rs
Adds builtin_prototype_adder and updates weak method dispatch to pad missing arguments, constrain dispatch by receiver class id, and fall through for unsupported method names.
WeakMap and WeakSet iterable initialization
crates/perry-runtime/src/weakref.rs
Rewrites WeakMap and WeakSet iterable initialization to use lazy constructor_iter consumption with iterator closing on abrupt completion.
Estimated code review effort: 4 (Complex) ~50 minutes

Possibly related PRs

  • PerryTS/perry#5468: Also changes crates/perry-runtime/src/weakref.rs around WeakMap/WeakSet reserved ids and weak-collection behavior.
  • PerryTS/perry#5667: Also modifies crates/perry-runtime/src/object/instanceof.rs and related instanceof resolution behavior.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the PR's main theme: WeakMap/WeakSet constructor and instance-identity fixes for runtime behavior and test262.
Description check ✅ Passed The summary and test plan are detailed and relevant, but the template's separate Changes/Checklist sections aren't filled out explicitly.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-5834-test262-weakmap-weakset

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/perry-runtime/src/weakref.rs (1)

802-834: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Gate weak-method dispatch by receiver class crates/perry-runtime/src/weakref.rs:802-833try_weak_method_dispatch still routes only on method_name, so a WeakMap receiver can hit "add"/a WeakSet receiver can hit "set" etc. and call the wrong helper instead of throwing the incompatible-receiver TypeError. Add a class/method pairing check before dispatching.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-runtime/src/weakref.rs` around lines 802 - 834,
`try_weak_method_dispatch` is dispatching solely by `method_name`, which can let
a WeakMap receiver reach WeakSet helpers (and vice versa) instead of rejecting
incompatible calls. Update the dispatch logic in `try_weak_method_dispatch` to
verify the receiver’s `class_id` matches the requested weak method before
calling `js_weakmap_set`, `js_weakset_add`, `js_weakmap_get`, `js_weakmap_has`,
or `js_weakmap_delete`, and return `None` for mismatched class/method pairs so
the normal incompatible-receiver `TypeError` path is preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/perry-runtime/src/weakref.rs`:
- Around line 802-834: `try_weak_method_dispatch` is dispatching solely by
`method_name`, which can let a WeakMap receiver reach WeakSet helpers (and vice
versa) instead of rejecting incompatible calls. Update the dispatch logic in
`try_weak_method_dispatch` to verify the receiver’s `class_id` matches the
requested weak method before calling `js_weakmap_set`, `js_weakset_add`,
`js_weakmap_get`, `js_weakmap_has`, or `js_weakmap_delete`, and return `None`
for mismatched class/method pairs so the normal incompatible-receiver
`TypeError` path is preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c1fb4d93-1f66-453a-9acb-51a6078616f5

📥 Commits

Reviewing files that changed from the base of the PR and between 9b6993b and de67ad5.

📒 Files selected for processing (6)
  • crates/perry-codegen/src/expr/instance_misc1.rs
  • crates/perry-runtime/src/collection_iter.rs
  • crates/perry-runtime/src/object/field_get_set/get_field_by_name_tail.rs
  • crates/perry-runtime/src/object/instanceof.rs
  • crates/perry-runtime/src/object/object_ops/prototype.rs
  • crates/perry-runtime/src/weakref.rs

Per CodeRabbit review on PR #5851: try_weak_method_dispatch routed purely
on method_name, so a WeakMap receiver could reach "add" (WeakSet-only) and
vice versa, instead of falling through to the ordinary property lookup
that correctly resolves the missing method and throws
TypeError: ... is not a function. Match on (method_name, class_id) so
"set"/"get" require CLASS_ID_WEAKMAP and "add" requires CLASS_ID_WEAKSET;
"has"/"delete" stay shared. Any other pairing (including unknown method
names) now returns None instead of a silent undefined, letting the caller
fall through to normal dispatch.

Refs #5834.
@proggeramlug
proggeramlug merged commit 7d9ee87 into main Jul 1, 2026
15 checks passed
@proggeramlug
proggeramlug deleted the worktree-5834-test262-weakmap-weakset branch July 1, 2026 12:12
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