From b4bd0d3198f372af0bb5b0cdcc91dc2944ef0f3d Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 16 Aug 2026 15:09:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Iterator=20=E6=9E=84=E9=80=A0=E5=99=A8?= =?UTF-8?q?=E6=9C=AC=E4=BD=93=E6=94=AF=E6=8C=81=20subclass=20=E5=9F=BA?= =?UTF-8?q?=E5=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/iterator.rs | 44 +++++++++- .../oxide_vm/tests/builtins_iterator_tests.rs | 86 +++++++++++++++++++ 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/crates/oxide_builtins/src/iterator.rs b/crates/oxide_builtins/src/iterator.rs index ec7d8df7..7b5c2eb2 100644 --- a/crates/oxide_builtins/src/iterator.rs +++ b/crates/oxide_builtins/src/iterator.rs @@ -9,9 +9,47 @@ const INNER_PROP: &str = "__inner__"; const INDEX_PROP: &str = "__index__"; const MODE_PROP: &str = "__mode__"; -/// 占位构造函数:`Iterator` 不是构造函数,任何调用都抛 TypeError。 -pub fn iterator_constructor(vm: &mut H, _args: &[u8]) -> NativeResult { - NativeResult::Err(crate::error::create_type_error(vm, "Iterator is not a constructor")) +/// `Iterator` 构造逻辑:不是构造函数,`new Iterator()` / `Iterator()` 均抛 TypeError; +/// subclass `super()` 路径放行并返回 undefined(原型由调用方按 newTarget 设置)。 +/// +/// 引擎无 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(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 上的 diff --git a/crates/oxide_vm/tests/builtins_iterator_tests.rs b/crates/oxide_vm/tests/builtins_iterator_tests.rs index 9c38a02e..172c9e91 100644 --- a/crates/oxide_vm/tests/builtins_iterator_tests.rs +++ b/crates/oxide_vm/tests/builtins_iterator_tests.rs @@ -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)); } +#[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] fn iterator_prototype_rebound_after_full_reset() { let mut vm = Vm::new();