fix: 构造帧 super 状态改显式标志修复多层继承与 return 语义

derived 构造器 super 状态改由 CallFrame.super_called 显式标志承载,
取代依赖 regs[254] 值判定:多层继承中间 derived 帧由 SUPER_CALL 压入
this=构造对象,值判定三重失效(未调 super 不报错 / this-before-super
失效 / 合法 super() 误判 more-than-once)。父构造器正常返回经
construct_result_reg==Some(254) 识别置位调用方帧(该 ABI 不变量仅
SUPER_CALL 压帧满足),抛错走 unwind 不置位。

do_return 检查放宽为非对象返回值(含 undefined/null/原始值)且未调
super 时抛 ReferenceError(规范 §9.2.2.2),调过 super 回退构造 this。

super 构造器改取当前帧 callee 原型而非 newTarget 原型:newTarget 跨
SUPER_CALL 压帧保持为最外层类,取其原型在中间 derived 层解析回同一
父类导致无限压帧。
This commit is contained in:
2026-08-16 01:23:52 +08:00
parent 946c96472f
commit 0c6aa7fbef
7 changed files with 163 additions and 8 deletions
+94
View File
@@ -124,6 +124,100 @@ fn derived_constructor_this_before_super_throws_reference_error() {
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
}
#[test]
fn three_level_inheritance_super_chain_constructs_normally() {
// 多层继承(≥3 层):中间 derived 帧由 SUPER_CALL 压入,合法 super() 不得误报
// more-than-once,构造链须逐层完成。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class A { constructor(){ this.v = 1; } } class B extends A { constructor(){ super(); this.w = 2; } } class C extends B { constructor(){ super(); this.u = 3; } } var c = new C(); c.v + c.w + c.u",
)
.unwrap();
assert_num(result, 6.0);
}
#[test]
fn intermediate_derived_returning_without_super_throws() {
// 中间 derived 构造器未调 super 直接 return:须抛 ReferenceError(此前
// regs[254] 值判定因 this 为外层构造对象而漏检)。
let mut vm = Vm::new();
let err = eval(
&mut vm,
"class A{} class B extends A{ constructor(){ return; } } class C extends B{} new C()",
)
.unwrap_err();
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
}
#[test]
fn derived_returning_without_super_throws_reference_error() {
let mut vm = Vm::new();
let err = eval(&mut vm, "class A{} class B extends A{ constructor(){ return; } } new B()").unwrap_err();
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
}
#[test]
fn intermediate_derived_this_before_super_throws() {
// 中间 derived 帧由 SUPER_CALL 压入后 super() 前读 this:须抛 ReferenceError。
let mut vm = Vm::new();
let err = eval(
&mut vm,
"class A{} class B extends A{ constructor(){ this.x = 1; super(); } } class C extends B{ constructor(){ super(); } } new C()",
)
.unwrap_err();
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
}
#[test]
fn intermediate_derived_double_super_throws() {
// 中间 derived 帧二次调用 super():须抛 more-than-once(字节码父构造器返回后
// 置位 super_called 生效)。
let mut vm = Vm::new();
let err = eval(
&mut vm,
"class A{} class B extends A{ constructor(){ super(); super(); } } class C extends B{} new C()",
)
.unwrap_err();
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
}
#[test]
fn derived_constructor_returning_primitive_without_super_throws() {
// 规范 §9.2.2.2:derived 返回非对象值(42/null)且未调 super → ReferenceError,
// 而非静默回退构造 this。
let mut vm = Vm::new();
let err = eval(&mut vm, "class A{} class B extends A{ constructor(){ return 42; } } new B()").unwrap_err();
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
}
#[test]
fn derived_constructor_returning_null_without_super_throws() {
let mut vm = Vm::new();
let err = eval(&mut vm, "class A{} class B extends A{ constructor(){ return null; } } new B()").unwrap_err();
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
}
#[test]
fn derived_constructor_returning_object_overrides_instance() {
// derived 返回对象值:直接作为构造结果,不校验 super。
let mut vm = Vm::new();
let result = eval(&mut vm, "class A{} class B extends A{ constructor(){ return { x: 1 }; } } new B().x").unwrap();
assert_eq!(result.as_int(), 1);
}
#[test]
fn derived_constructor_primitive_return_after_super_preserves_this() {
// derived 调过 super 后返回原始值:回退构造 this,实例字段保留。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class A{ constructor(){ this.v = 5; } } class B extends A{ constructor(){ super(); return 42; } } new B().v",
)
.unwrap();
assert_num(result, 5.0);
}
#[test]
fn derived_method_super_call_uses_current_receiver() {
let mut vm = Vm::new();