Background
PR #754 lowered value-form super.<prop> (introduced for the NestJS smoke fixture's rxjs OperatorSubscriber pattern) by rewriting it to this.<prop> / this[expr] in crates/perry-hir/src/lower/expr_misc.rs. The inline comment is honest about the scope:
The substitution is correct when the child does not override the property (the dominant rxjs / NestJS pattern). When the child does override, this approximation will resolve to the override rather than the parent — a TODO for a future explicit super-vtable path in codegen.
This is a silent semantic regression for any user code that overrides a parent property and reaches up via super.<prop> to read the parent's value. There is no compile error, no runtime warning — the program just returns the wrong value.
Repro shape
class A {
foo = "A";
}
class B extends A {
foo = "B";
parentFoo() {
return super.foo; // strict JS: "A"; perry today: "B"
}
}
console.log(new B().parentFoo());
Expected (node --experimental-strip-types): A
Actual (perry HEAD): B
Why this matters
The PR #754 review accepted the lowering for the merge because the rxjs/NestJS pattern (no override) is the dominant case and the alternative was a hard lower_bail!. That tradeoff is fine, but it leaves user code that does override silently broken.
Suggested fix
Carry an explicit super-vtable lookup through codegen so super.<prop> resolves through the parent's prototype regardless of any child override. The HIR variant probably wants to be an explicit Expr::SuperPropertyGet { property } rather than the current this.<prop> rewrite, so codegen can route it to the parent class's vtable.
Regression net
A parity test that pins the wrong behavior would let a future fix flip it to passing. Suggested location: test-files/test_super_property_override.ts with the snippet above.
Related
Background
PR #754 lowered value-form
super.<prop>(introduced for the NestJS smoke fixture's rxjsOperatorSubscriberpattern) by rewriting it tothis.<prop>/this[expr]incrates/perry-hir/src/lower/expr_misc.rs. The inline comment is honest about the scope:This is a silent semantic regression for any user code that overrides a parent property and reaches up via
super.<prop>to read the parent's value. There is no compile error, no runtime warning — the program just returns the wrong value.Repro shape
Expected (node
--experimental-strip-types):AActual (perry HEAD):
BWhy this matters
The PR #754 review accepted the lowering for the merge because the rxjs/NestJS pattern (no override) is the dominant case and the alternative was a hard
lower_bail!. That tradeoff is fine, but it leaves user code that does override silently broken.Suggested fix
Carry an explicit super-vtable lookup through codegen so
super.<prop>resolves through the parent's prototype regardless of any child override. The HIR variant probably wants to be an explicitExpr::SuperPropertyGet { property }rather than the currentthis.<prop>rewrite, so codegen can route it to the parent class's vtable.Regression net
A parity test that pins the wrong behavior would let a future fix flip it to passing. Suggested location:
test-files/test_super_property_override.tswith the snippet above.Related
crates/perry-hir/src/lower/expr_misc.rs(substitution site + the explanatory comment)