Skip to content

fix(reflect): correct return values for set/get/define/delete/extensibility - #3402

Merged
proggeramlug merged 4 commits into
mainfrom
fix-reflect-semantics-2756-2762
May 30, 2026
Merged

fix(reflect): correct return values for set/get/define/delete/extensibility#3402
proggeramlug merged 4 commits into
mainfrom
fix-reflect-semantics-2756-2762

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Closes #2756
Closes #2757
Closes #2758
Closes #2760
Closes #2762

Implementation

Perry's Reflect.* helpers reported success unconditionally and Reflect.getPrototypeOf returned the target object itself. This corrects the observable return values to match Node v25, covering the ordinary (non-proxy) [[Set]]/[[Delete]]/[[DefineOwnProperty]]/extensibility semantics plus the proxy-trap return-value coercion that already had the dispatch wired.

New reflect-support predicates (extensibility flag, own-key presence, writable/configurable attrs) were extracted into crates/perry-runtime/src/object/reflect_support.rs to keep object_ops.rs under the 2000-line lint cap. The two new #[no_mangle] entry points (js_reflect_is_extensible, js_reflect_prevent_extensions) are declared in runtime_decls/objects.rs and pinned with #[used] keepalive anchors so the auto-optimize whole-program bitcode rebuild does not dead-strip them. New HIR variants use unique stable-hash tags 12043/12044.

Validation

test-files/test_gap_reflect_2756_2762.ts is byte-identical to node --experimental-strip-types under the default auto-optimize compile:

{"protoObj":true,"protoNull":null,"def1":true,"defNonExt":false,"defNonConfig":false,"del1":true,"delNonConfig":false,"delNonConfigRemains":1,"isExtBefore":true,"prevRet":true,"isExtAfter":false,"setNonWritable":false,"setNonExt":false,"setOk":true,"setOkVal":3}
prevThrow TypeError
isExtThrow TypeError
prevThrow TypeError
isExtThrow TypeError
prevThrow TypeError
isExtThrow TypeError
  • check_file_size.sh — OK (object_ops.rs back to 1987 lines)
  • cargo fmt --all -- --check — clean
  • cargo test --release -p perry-hir — pass (incl. expr_variant_stable_hash_tags_are_unique)
  • Existing test_gap_proxy_reflect.ts — still byte-identical to Node (no regression)

Note on scope

The proxy-trap return paths above are implemented because the trap-dispatch plumbing already existed. The Object-prototype-chain identity case from #2757's example (Reflect.getPrototypeOf(Object.create(proto)) === proto) is a pre-existing Object.getPrototypeOf limitation (it returns the object for plain object-literal chains) and is out of scope here — the issue explicitly scopes itself to the Reflect.getPrototypeOf helper sharing Object.getPrototypeOf semantics, which it now does. The gap test covers getPrototypeOf({}) === Object.prototype and the null-prototype case, both of which match Node.

Ralph Küpper added 4 commits May 30, 2026 18:44
…-2756-2762

# Conflicts:
#	crates/perry-codegen/src/collectors/i32_locals.rs
#	crates/perry-codegen/src/collectors/refs.rs
#	crates/perry-runtime/src/object/object_ops.rs
…Escape) + extract object/mod.rs tests to tests.rs (under 2000-cap)
@proggeramlug
proggeramlug merged commit 32a7d4b into main May 30, 2026
11 checks passed
@proggeramlug
proggeramlug deleted the fix-reflect-semantics-2756-2762 branch May 30, 2026 17:58
proggeramlug pushed a commit that referenced this pull request May 30, 2026
RegExpEscape (#3414) and ReflectIsExtensible (#3402) both landed on
main with stable-hash tag 12045, tripping
stable_hash::tests::expr_variant_stable_hash_tags_are_unique once this
branch merged main. Reassign RegExpEscape (the newer variant) to the
next free tag 12061 so every Expr variant has a distinct tag without
renumbering any other variant.
proggeramlug added a commit that referenced this pull request May 30, 2026
#3409 (RegExpEscape) and #3402 (ReflectIsExtensible) both merged via a
tag race, each assigning stable-hash tag 12045 — making
expr_variant_stable_hash_tags_are_unique fail on main and blocking all
PR CI. Reassign ReflectIsExtensible to the free tag 12048 (matches the
fix already on PR #3445's branch, so no future conflict).

Co-authored-by: Ralph Küpper <ralph2@skelpo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment