mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 18:51:13 +08:00
feat: Iterator 构造器本体支持 subclass 基座
This commit is contained in:
@@ -9,9 +9,47 @@ const INNER_PROP: &str = "__inner__";
|
|||||||
const INDEX_PROP: &str = "__index__";
|
const INDEX_PROP: &str = "__index__";
|
||||||
const MODE_PROP: &str = "__mode__";
|
const MODE_PROP: &str = "__mode__";
|
||||||
|
|
||||||
/// 占位构造函数:`Iterator` 不是构造函数,任何调用都抛 TypeError。
|
/// `Iterator` 构造逻辑:不是构造函数,`new Iterator()` / `Iterator()` 均抛 TypeError;
|
||||||
pub fn iterator_constructor<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
|
/// subclass `super()` 路径放行并返回 undefined(原型由调用方按 newTarget 设置)。
|
||||||
NativeResult::Err(crate::error::create_type_error(vm, "Iterator is not a constructor"))
|
///
|
||||||
|
/// 引擎无 native [[Construct]]/newTarget 通道,用与 `Symbol` 构造器同款的启发式
|
||||||
|
/// 判别调用形态:
|
||||||
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. `this` 非对象 → TypeError(普通调用 `Iterator()`:emit 以 undefined 作 this)。
|
||||||
|
/// 2. `this.proto === %IteratorPrototype%` → TypeError(`new Iterator()`:调用方以
|
||||||
|
/// ctor.prototype 为原型建新对象传入)。
|
||||||
|
/// 3. newTarget 槽(regs[255])非对象 → TypeError(`Iterator.call(x)` 顶层调用,
|
||||||
|
/// 顶层 newTarget 初始化为 undefined)。
|
||||||
|
/// 4. 否则返回 undefined(subclass `super()`:调用方随后按 new.target.prototype
|
||||||
|
/// 设置实例原型)。
|
||||||
|
///
|
||||||
|
/// # 注意事项
|
||||||
|
/// 类构造器内调用 `Iterator.call(x)` 时 regs[255] 为类对象会被放行(规范外罕见
|
||||||
|
/// 场景,与 `Symbol` 构造器同款已知边界)。
|
||||||
|
pub fn iterator_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
if !this_val.is_object() {
|
||||||
|
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator is not a constructor"));
|
||||||
|
}
|
||||||
|
let ptr = this_val.as_js_object_ptr();
|
||||||
|
if !ptr.is_null() {
|
||||||
|
let obj = unsafe { &*ptr };
|
||||||
|
let proto = obj.proto();
|
||||||
|
if proto.is_object() {
|
||||||
|
let proto_ptr = proto.as_js_object_ptr();
|
||||||
|
if !proto_ptr.is_null() {
|
||||||
|
let home = vm.session().builtin_world().iterator_proto.as_ptr() as *mut JsObject;
|
||||||
|
if std::ptr::eq(proto_ptr, home) {
|
||||||
|
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator is not a constructor"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !vm.reg(255).is_object() {
|
||||||
|
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator is not a constructor"));
|
||||||
|
}
|
||||||
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `%IteratorPrototype%` 上 `constructor` 访问器的 getter:返回当前 global 上的
|
/// `%IteratorPrototype%` 上 `constructor` 访问器的 getter:返回当前 global 上的
|
||||||
|
|||||||
@@ -514,6 +514,92 @@ fn iterator_helper_prototype_links_to_iterator_proto() {
|
|||||||
assert!(std::ptr::eq(helper_proto_val.as_js_object_ptr(), iter_ptr));
|
assert!(std::ptr::eq(helper_proto_val.as_js_object_ptr(), iter_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iterator_constructor_plain_call_throws() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
// 普通调用 `Iterator()` 抛 TypeError(emit 以 undefined 作 this)。
|
||||||
|
let bool_cases = [
|
||||||
|
("try { Iterator(); false } catch (e) { e instanceof TypeError }", true),
|
||||||
|
// call/apply 显式传对象 this 顶层调用同样抛(newTarget 槽为 undefined)。
|
||||||
|
("try { Iterator.call({}); false } catch (e) { e instanceof TypeError }", true),
|
||||||
|
("try { Iterator.apply({}, []); false } catch (e) { e instanceof TypeError }", true),
|
||||||
|
// 以 %IteratorPrototype% 为原型的对象顶层调用也抛(home 形态误判保护)。
|
||||||
|
(
|
||||||
|
"try { Iterator.call(Object.create(Iterator.prototype)); false } \
|
||||||
|
catch (e) { e instanceof TypeError }",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (src, expected) in bool_cases {
|
||||||
|
let result = eval(&mut vm, src).unwrap();
|
||||||
|
assert_eq!(result.as_bool(), expected, "for {}", src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iterator_constructor_subclassable() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
// `class X extends Iterator {}` 的 super() 经放行路径返回 undefined,
|
||||||
|
// 实例原型按 newTarget 设为 X.prototype。
|
||||||
|
let bool_cases = [
|
||||||
|
(
|
||||||
|
"class TestIterator extends Iterator {} \
|
||||||
|
var it = new TestIterator(); \
|
||||||
|
it instanceof TestIterator && it instanceof Iterator",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"class TestIterator extends Iterator {} \
|
||||||
|
Object.getPrototypeOf(new TestIterator()) === TestIterator.prototype",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"class TestIterator extends Iterator {} \
|
||||||
|
Object.getPrototypeOf(TestIterator.prototype) === Iterator.prototype",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
// 显式 constructor 内 super() 与隐式等价。
|
||||||
|
(
|
||||||
|
"class TestIterator extends Iterator { constructor() { super(); } } \
|
||||||
|
new TestIterator() instanceof Iterator",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
// 多层继承:newTarget 跨层保持为最外层类。
|
||||||
|
(
|
||||||
|
"class A extends Iterator {} class B extends A {} \
|
||||||
|
var b = new B(); \
|
||||||
|
b instanceof B && b instanceof A && b instanceof Iterator",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
// 构造器 name 不受影响。
|
||||||
|
("class TestIterator extends Iterator {} TestIterator.name === 'TestIterator'", true),
|
||||||
|
];
|
||||||
|
for (src, expected) in bool_cases {
|
||||||
|
let result = eval(&mut vm, src).unwrap();
|
||||||
|
assert_eq!(result.as_bool(), expected, "for {}", src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iterator_constructor_subclass_still_rejects_new_after_reset() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
// dirty reset 后构造器经 bind_iterator_global 重绑,本体与 subclass 路径不变。
|
||||||
|
unsafe { &mut *(vm.session().builtin_world().iterator_proto.as_ptr() as *mut JsObject) }.bump_generation();
|
||||||
|
vm.full_reset();
|
||||||
|
let bool_cases = [
|
||||||
|
("try { new Iterator(); false } catch (e) { e instanceof TypeError }", true),
|
||||||
|
(
|
||||||
|
"class TestIterator extends Iterator {} \
|
||||||
|
new TestIterator() instanceof Iterator",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (src, expected) in bool_cases {
|
||||||
|
let result = eval(&mut vm, src).unwrap();
|
||||||
|
assert_eq!(result.as_bool(), expected, "for {}", src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iterator_prototype_rebound_after_full_reset() {
|
fn iterator_prototype_rebound_after_full_reset() {
|
||||||
let mut vm = Vm::new();
|
let mut vm = Vm::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user