Skip to content

fix(runtime): computed object keys on class proto and ClassRef (#6945) - #7134

Merged
proggeramlug merged 3 commits into
mainfrom
fix/6945-computed-key-class-proto
Jul 31, 2026
Merged

fix(runtime): computed object keys on class proto and ClassRef (#6945)#7134
proggeramlug merged 3 commits into
mainfrom
fix/6945-computed-key-class-proto

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #6945 — computed / dynamic object-key property access on class prototypes and class constructors.

Three cooperating gaps (none GC-related):

  1. js_dyn_index_get treated non-string, non-numeric keys as floats (format!("{}", f64)), so obj[{toString(){return "k"}}] never ran ToPropertyKey. Object / boolean / null / undefined / bigint keys now go through js_to_property_key (with receiver rooting) before the by-name get.

  2. Class-instance field get walked the reflective decl-proto object only for accessors (to avoid class-id re-entry). Runtime C.prototype[k] = v stores an own data field there, so (new C()).name missed it while C.prototype.name saw it. Own data is now read via own_data_field_by_name.

  3. Codegen IndexGet last-resort routes non-string keys on a known ClassRef through js_object_get_index_polymorphic, which rejected every INT32-tagged receiver as a primitive. Registered class-ids now forward to js_dyn_index_get's class-ref arm so C[objectKey] resolves statics / CLASS_DYNAMIC_PROPS.

Test plan

  • test-files/test_gap_computed_key_class_proto_6945.ts — byte-for-byte vs Node 26.5 (prototype instance inheritance, computed key read/write, static ClassRef computed key, boolean/null keys, observable toString on absent key)
  • cargo check -p perry-runtime
  • Release rebuild of perry-runtime-static + compiled gap binary parity

Notes

No version bump (maintainer bumps at merge). Changelog fragment provisionally named on the issue number; can be renamed to the PR number if needed.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed computed-key property access on class prototypes and constructors.
    • Improved support for object, boolean, null, and symbol keys through consistent property-key conversion.
    • Corrected inherited instance fields, accessors, static properties, and missing-property lookups.
    • Improved dynamic access for registered class references and symbol-backed properties.
  • Tests

    • Added regression coverage for computed keys, prototype inheritance, static properties, symbol access, and key-coercion side effects.

Ralph Küpper added 2 commits July 31, 2026 11:33
Make object-key and dynamic-key property access match Node on class
prototypes and class constructors:

- js_dyn_index_get: ToPropertyKey for non-numeric keys (was format!("{}", f64))
- class-instance get: own data fields on the reflective decl-proto
- js_object_get_index_polymorphic: registered ClassRef receivers forward
  to js_dyn_index_get instead of returning undefined

Regression: test_gap_computed_key_class_proto_6945.ts
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The runtime now applies ToPropertyKey to computed reads and writes, preserves symbol keys, routes class references through dynamic lookup, and exposes declaration-prototype data fields to instances. Regression tests cover prototypes, constructors, plain objects, inherited properties, primitive keys, and symbols.

Changes

Computed key access

Layer / File(s) Summary
Key coercion and class-reference dispatch
crates/perry-runtime/src/value/dyn_index.rs, crates/perry-runtime/src/object/polymorphic_index.rs
Dynamic reads and writes apply ToPropertyKey, preserve symbols, root values across coercion, and route registered class references through dynamic lookup.
Class prototype data lookup
crates/perry-runtime/src/object/class_registry/prototype_objects.rs
Prototype resolution reads declaration-prototype accessors and own data fields without recursive class-id lookup.
Regression coverage and changelog
test-files/test_gap_computed_key_class_proto_6945.ts, changelog.d/7134-computed-key-class-proto.md
Tests cover computed keys on prototypes, constructors, plain objects, absent properties, primitive keys, inherited properties, and symbols. The changelog records the runtime changes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant js_dyn_index_get
  participant js_to_property_key
  participant js_object_get_index_polymorphic
  participant resolve_proto_chain_field_inner
  Caller->>js_dyn_index_get: read computed property
  js_dyn_index_get->>js_to_property_key: coerce object or primitive key
  js_to_property_key-->>js_dyn_index_get: string or symbol key
  js_dyn_index_get->>js_object_get_index_polymorphic: dispatch receiver and key
  js_object_get_index_polymorphic->>resolve_proto_chain_field_inner: resolve class instance property
  resolve_proto_chain_field_inner-->>Caller: property value
Loading

Possibly related PRs

  • PerryTS/perry#6685: Both changes use js_dyn_index_get and computed-symbol handling.
  • PerryTS/perry#6941: Both changes modify ToPropertyKey, dynamic indexing, and class-reference handling.
  • PerryTS/perry#7127: Both changes update runtime ToPropertyKey handling for object-key operations.

Suggested reviewers: thehypnoo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the runtime fix for computed object keys on class prototypes and ClassRef constructors.
Description check ✅ Passed The description explains the changes, links issue #6945, and documents the test plan, although it omits some template headings and checklist items.
Linked Issues check ✅ Passed The changes address issue #6945 by fixing prototype, instance, plain-object, and ClassRef computed-key access with ToPropertyKey coercion.
Out of Scope Changes check ✅ Passed The runtime changes, regression test, and changelog fragment are related to the linked issue and stated pull request objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 fix/6945-computed-key-class-proto

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.

Actionable comments posted: 1

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

Inline comments:
In `@crates/perry-runtime/src/value/dyn_index.rs`:
- Around line 272-310: The set-side dynamic index fallback should match
js_dyn_index_get by using js_to_property_key instead of js_jsvalue_to_string for
non-native keys. Update js_dyn_index_set so Symbol results are preserved and
routed through the symbol-property path, allowing the required assignment
behavior to occur rather than stringifying the Symbol.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8af455c6-28d5-490e-a0d1-0cb04be0042d

📥 Commits

Reviewing files that changed from the base of the PR and between 0044b1c and 8377c34.

📒 Files selected for processing (5)
  • changelog.d/7134-computed-key-class-proto.md
  • crates/perry-runtime/src/object/class_registry/prototype_objects.rs
  • crates/perry-runtime/src/object/polymorphic_index.rs
  • crates/perry-runtime/src/value/dyn_index.rs
  • test-files/test_gap_computed_key_class_proto_6945.ts

Comment thread crates/perry-runtime/src/value/dyn_index.rs
Address CodeRabbit: align set-side key coercion with the get-side
js_to_property_key path, and fix rooted_property_key_{get,set} so a
Symbol-yielding @@toPrimitive is not dropped as a null string key.
@proggeramlug
proggeramlug merged commit 217e962 into main Jul 31, 2026
6 of 7 checks passed
@proggeramlug
proggeramlug deleted the fix/6945-computed-key-class-proto branch July 31, 2026 10:19

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

Actionable comments posted: 1

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

Inline comments:
In `@crates/perry-runtime/src/value/dyn_index.rs`:
- Around line 632-653: Update the ClassRef assignment branch around its existing
js_string_coerce handling to use js_to_property_key, preserving Symbol results
instead of converting them to strings. When the coerced key is a Symbol, route
the write through the existing js_object_set_symbol_property path before the
string-property logic. Add a regression covering ClassRef[viaSym] assignment and
retrieval, including a Symbol returned by Symbol.toPrimitive.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f303a4f2-269a-468b-95b4-4c742cb53e55

📥 Commits

Reviewing files that changed from the base of the PR and between 8377c34 and 5b91a04.

📒 Files selected for processing (4)
  • changelog.d/7134-computed-key-class-proto.md
  • crates/perry-runtime/src/object/polymorphic_index.rs
  • crates/perry-runtime/src/value/dyn_index.rs
  • test-files/test_gap_computed_key_class_proto_6945.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • changelog.d/7134-computed-key-class-proto.md
  • crates/perry-runtime/src/object/polymorphic_index.rs

Comment on lines +632 to +653
// #6945 / CodeRabbit: use `js_to_property_key` (not `js_jsvalue_to_string`)
// so an `@@toPrimitive` that returns a Symbol is preserved and routed to
// the symbol store — matching the get-side fallback. Stringifying that
// Symbol would miss the target property (and Spec ToPropertyKey must not
// turn a Symbol result into a string).
let scope = crate::gc::RuntimeHandleScope::new();
let recv = scope.root_raw_mut_ptr(raw_ptr as *mut crate::object::ObjectHeader);
let value_handle = scope.root_nanbox_f64(value);
let key_ptr = crate::value::js_jsvalue_to_string(index);
let key = unsafe { crate::object::js_to_property_key(index) };
let key_h = scope.root_nanbox_f64(key);
let key = key_h.get_nanbox_f64();
let value = value_handle.get_nanbox_f64();
if unsafe { crate::symbol::js_is_symbol(key) } != 0 {
let recv_bits = crate::value::js_nanbox_pointer(
recv.get_raw_const_ptr::<crate::object::ObjectHeader>() as i64,
);
unsafe {
crate::symbol::js_object_set_symbol_property(recv_bits, key, value);
}
return value;
}
let key_ptr = crate::value::js_get_string_pointer_unified(key) as *const crate::StringHeader;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve symbol keys in the ClassRef write branch.

Line 640 fixes only the non-array object fallback. ClassRef receivers return through lines 480-509 first. That branch still uses js_string_coerce for a non-string key.

If key[Symbol.toPrimitive]() returns a Symbol, C[key] = value cannot reach js_object_set_symbol_property. Route the ClassRef coercion through js_to_property_key, then dispatch Symbol results through the existing symbol setter.

Add a regression for ClassRef[viaSym] assignment and retrieval. As per PR objectives, computed class constructor writes must use the same property-key semantics as other computed writes.

🤖 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/value/dyn_index.rs` around lines 632 - 653, Update
the ClassRef assignment branch around its existing js_string_coerce handling to
use js_to_property_key, preserving Symbol results instead of converting them to
strings. When the coerced key is a Symbol, route the write through the existing
js_object_set_symbol_property path before the string-property logic. Add a
regression covering ClassRef[viaSym] assignment and retrieval, including a
Symbol returned by Symbol.toPrimitive.

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.

runtime: computed object-key write on a class prototype is invisible to instances and to the computed read

1 participant