fix: Reflect.construct 换真构造帧并支持 newTarget 覆写

This commit is contained in:
2026-09-20 15:13:18 +00:00
parent 299708e729
commit 3fb3ebc3cc
5 changed files with 269 additions and 41 deletions
@@ -133,3 +133,191 @@ fn reflect_non_object_target_throws_type_error() {
let result = eval(&mut vm, "try { Reflect.get(1, 'x') } catch (e) { e instanceof TypeError }").unwrap();
assert!(result.as_bool());
}
// 派生类(extends Array)经 Reflect.construct 产出真实例:isArray 与 length 就位。
#[test]
fn reflect_construct_derived_class_instance() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class B extends Array { constructor(x) { super(x); } } \
var inst = Reflect.construct(B, [2]); \
inst instanceof B && Array.isArray(inst) && inst.length === 2",
)
.unwrap();
assert!(result.as_bool());
}
// 派生类经 Reflect.construct 正常走 super 链构造,实例值判别。
#[test]
fn reflect_construct_derived_extends_base_class() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class Base { constructor(x) { this.x = x; } } \
class D extends Base { constructor(x) { super(x); } } \
var inst = Reflect.construct(D, [9]); \
inst instanceof D && inst.x === 9",
)
.unwrap();
assert!(result.as_bool());
}
// 无 newTarget 时构造帧内 new.target = target。
#[test]
fn reflect_construct_new_target_defaults_to_target() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var newTarget = null; function f() { newTarget = new.target; } \
Reflect.construct(f, []); newTarget === f",
)
.unwrap();
assert!(result.as_bool());
}
// newTarget 覆写臂:构造帧内 new.target = newTarget,实例 proto 取 newTarget.prototype。
#[test]
fn reflect_construct_new_target_override() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var newTarget = null; function f() { newTarget = new.target; } \
var NT = function() {}; \
Reflect.construct(f, [], NT); \
newTarget === NT && Object.getPrototypeOf(Reflect.construct(f, [], NT)) === NT.prototype",
)
.unwrap();
assert!(result.as_bool());
}
// 派生类 + newTarget 覆写全形:super 实参逐位、new.target = NT、this = 实例。
#[test]
fn reflect_construct_derived_with_new_target() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var expectedNewTarget = function() {}; \
var thisValue, instance, args, actualNewTarget; \
function Parent() { thisValue = this; args = arguments; actualNewTarget = new.target; } \
class Child extends Parent { constructor() { super(1, 2, 3); } } \
instance = Reflect.construct(Child, [4, 5, 6], expectedNewTarget); \
thisValue === instance && args.length === 3 && args[0] === 1 && args[1] === 2 && args[2] === 3 \
&& actualNewTarget === expectedNewTarget \
&& Object.getPrototypeOf(instance) === expectedNewTarget.prototype",
)
.unwrap();
assert!(result.as_bool());
}
// 基类 + newTarget 覆写:实例 proto 取 NT.prototype,new.target = NT。
#[test]
fn reflect_construct_base_class_with_new_target() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class CBase { constructor(x) { this.x = x; this.nt = new.target; } } \
var NT = function() {}; \
var inst = Reflect.construct(CBase, [5], NT); \
Object.getPrototypeOf(inst) === NT.prototype && inst.nt === NT && inst.x === 5",
)
.unwrap();
assert!(result.as_bool());
}
// 入参面:target 非构造器(Date.now / 箭头 / 基元)均 TypeError。
#[test]
fn reflect_construct_non_constructor_target_throws() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var t1 = false, t2 = false, t3 = false; \
try { Reflect.construct(Date.now, [], Array); } catch (e) { t1 = e instanceof TypeError; } \
try { Reflect.construct((a) => a, []); } catch (e) { t2 = e instanceof TypeError; } \
try { Reflect.construct(1, []); } catch (e) { t3 = e instanceof TypeError; } \
t1 && t2 && t3",
)
.unwrap();
assert!(result.as_bool());
}
// 入参面:newTarget 非构造器与 argumentsList 非对象均 TypeError。
#[test]
fn reflect_construct_invalid_new_target_or_arguments_list_throws() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var t1 = false, t2 = false; \
try { Reflect.construct(function(){}, [], 1); } catch (e) { t1 = e instanceof TypeError; } \
try { Reflect.construct(function(){}, 1); } catch (e) { t2 = e instanceof TypeError; } \
t1 && t2",
)
.unwrap();
assert!(result.as_bool());
}
// length 访问器抛出的异常原值传播(不降级、不吞没)。
#[test]
fn reflect_construct_length_getter_exception_propagates() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var o = {}; \
Object.defineProperty(o, 'length', { get: function() { throw new RangeError('len'); } }); \
try { Reflect.construct(function(a){ return a; }, o); false } catch (e) { e instanceof RangeError }",
)
.unwrap();
assert!(result.as_bool());
}
// array-like 对象按规范 Get 逐位取值(非位序直读),值与实参个数就位。
#[test]
fn reflect_construct_array_like_elements_read_by_get() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var captured; \
function C(a, b) { captured = [typeof a, arguments.length]; } \
Reflect.construct(C, { length: 2, 0: 'a', 1: 'b' }); \
captured[0] === 'string' && captured[1] === 2",
)
.unwrap();
assert!(result.as_bool());
}
// 守卫面:native 构造器(Array 填槽)、构造帧 arguments 完整、显式返回对象
// 优先、绑定元数据(isConstructor(Reflect.construct) === false)。
#[test]
fn reflect_construct_guard_face() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var arr = Reflect.construct(Array, [3]); \
function fn() { this.args = arguments; } \
var result = Reflect.construct(fn, [42, 'Mike', 'Leo']); \
var retObj = Reflect.construct(function() { return { z: 9 }; }, []); \
var meta = false; \
try { Reflect.construct(Reflect.construct, []); } catch (e) { meta = e instanceof TypeError; } \
arr instanceof Array && arr.length === 3 \
&& result.args.length === 3 && result.args[0] === 42 && result.args[1] === 'Mike' && result.args[2] === 'Leo' \
&& retObj.z === 9 && !(retObj instanceof Function) && meta",
)
.unwrap();
assert!(result.as_bool());
}
// 227.1 回归守卫:隐式 super 面经 `new` 直接构造不回归。
#[test]
fn construct_direct_new_derived_array_guard() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class B extends Array { constructor(x) { super(x); } } \
var sub = new B(2); \
class Sub extends Array { constructor(x) { super(x); } } \
var s7 = new Sub(7); \
sub instanceof B && sub.length === 2 && s7.length === 7",
)
.unwrap();
assert!(result.as_bool());
}