You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A dynamic-heritage class with an explicit constructor loses this.<field> written after super() (static extends Object is fine) #9503
node : ok 1
perry: TypeError: Cannot read properties of undefined (reading 't') rc=1
this.def is written immediately after super(def) and reads back undefined. One evaluation of the factory; no chaining.
What narrows it
variant
perry
class D extends Object { constructor(def) { super(def); this.def = def } } — static heritage
ok, node-identical
class D extends (P ?? Object) { … } inside a factory — dynamic heritage
this.def is undefined
dynamic heritage, no explicit constructor
ok
So the trigger is a dynamic (runtime-value) heritage that resolves to an
uncallable builtin, combined with an explicit constructor that calls super(...) and then assigns to this. The identical class with a static extends Object works, which is why this is not simply "extends Object is
broken".
Suspected site
js_fetch_or_value_super in crates/perry-runtime/src/object/global_this/fetch_globals.rs. A dynamic
heritage that resolves to a builtin in is_uncallable_builtin_super_parent's
list (Object is in it) takes this arm:
let new_target = crate::object::class_constructor_ref_value(cid);returncrate::object::js_new_function_construct_with_new_target(
parent_val, args_ptr, args_len, new_target,);
which returns a fresh object. The caller
(crates/perry-codegen/src/expr/this_super_call.rs) then feeds that return
through js_ctor_return_override(current_this, parent_result, 0) and stores the
result back into the this slot. The subsequent this.def = def therefore
appears to land somewhere other than the object new hands back. The static extends Object path does not go through this arm, which matches the table
above.
This is a suspicion from reading the two sites, not a bisected root cause — the
observable is the table.
Found while validating #9406. The chained form of this program used to
SIGSEGV; #9406 fixed the crash, and the program now reaches this pre-existing
wrong value instead:
Fixed by #9749, which landed on main via merge train #9798. The train was merged as its own branch, so the Fixes #9503 keyword in #9749 never fired — closing manually. Verified the fix is on main by patch-id (git cherry), not just by the PR being closed.
Activity
proggeramlug commentedon Sep 5, 2026
Fixed by #9749, which landed on
mainvia merge train #9798. The train was merged as its own branch, so theFixes #9503keyword in #9749 never fired — closing manually. Verified the fix is onmainby patch-id (git cherry), not just by the PR being closed.