fix: class 生成器方法补 is_generator 标志,修正方法形态生成器语义

This commit is contained in:
2026-08-16 11:44:20 +08:00
parent 16793d3b36
commit 75f28f6e3e
4 changed files with 156 additions and 29 deletions
+49
View File
@@ -236,3 +236,52 @@ fn for_await_of_return_escape_defers_async_close() {
"\"body\""
);
}
// ── class/object 生成器方法(异步) ──
// class async 生成器方法:yield 顺序与 done 收敛。顶层 then 链驱动
// (普通回调帧内读取类绑定不触发 upvalue cell 误报)。
#[test]
fn class_async_generator_method_yields_in_order() {
assert_eq!(
eval(
"class E { async *ag() { yield 1; yield 2; } }\
var it = new E().ag(); var a, b, c;\
var p = it.next().then(function (r) { a = r.value; return it.next(); })\
.then(function (r) { b = r.value; return it.next(); })\
.then(function (r) { c = r.done; return a + ',' + b + ',' + c; });\
p"
),
"\"1,2,true\""
);
}
// class async 生成器方法 throw:异常进挂起点,被 body 内 catch 拦截后继续 yield。
#[test]
fn class_async_generator_method_throw_reaches_inner_catch() {
assert_eq!(
eval(
"class F { async *t() { try { yield 1; } catch (e) { yield 'caught:' + e; } } }\
var it = new F().t();\
var p = it.next().then(function (r) { return it.throw('boom'); })\
.then(function (r) { return r.value; });\
p"
),
"\"caught:boom\""
);
}
// object async 生成器方法:方法形态的 async generator 语义与函数式一致。
#[test]
fn object_async_generator_method_yields() {
assert_eq!(
eval(
"var o = { async *gen() { yield 5; } };\
var it = o.gen(); var a, d;\
var p = it.next().then(function (r) { a = r.value; return it.next(); })\
.then(function (r) { d = r.done; return a + ':' + d; });\
p"
),
"\"5:true\""
);
}
+70
View File
@@ -567,3 +567,73 @@ fn postfix_increment_on_captured_cell_returns_old_value() {
.unwrap();
assert_num(result, 112.0);
}
// ── class 生成器方法 ──
// 实例生成器方法:yield 顺序与 done 收敛,生成器对象经 next 驱动。
#[test]
fn class_generator_method_yields_in_order() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class C { *g() { yield 10; yield 20; } } var it = new C().g(); [it.next().value, it.next().value, it.next().done].join(',')",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "10,20,true");
}
// 静态生成器方法:挂在构造函数上,调用形态与实例方法一致。
#[test]
fn class_static_generator_method_yields() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class D { static *sg() { yield 30; } } var it = D.sg(); [it.next().value, it.next().done].join(',')",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "30,true");
}
// 生成器方法 throw 传播:throw 进挂起点,异常可被 body 内 catch 拦截。
#[test]
fn class_generator_method_throw_reaches_inner_catch() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class F { *t() { try { yield 1; } catch (e) { yield 'caught'; } } } var it = new F().t(); var r1 = it.next(); var r2 = it.throw(new Error('x')); [r1.value, r2.value].join(',')",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "1,caught");
}
// 生成器方法 next(arg):参数作为 yield 表达式结果传入 body。
#[test]
fn class_generator_method_next_arg_feeds_yield_expression() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class G { *a() { var v = yield 1; yield v * 2; } } var it = new G().a(); var r1 = it.next(); var r2 = it.next(21); [r1.value, r2.value].join(',')",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "1,42");
}
// 生成器方法 yield* 委托:与函数式生成器一致的委托序列。
#[test]
fn class_generator_method_yield_star_delegates() {
let mut vm = Vm::new();
let result = eval(&mut vm, "class H { *ys() { yield* [1, 2, 3]; } } Array.from(new H().ys()).join(',')").unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "1,2,3");
}
// 生成器方法 return():提前关闭生成器并携带返回值。
#[test]
fn class_generator_method_return_closes_with_value() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"class I { *rt() { yield 1; yield 2; } } var it = new I().rt(); var r1 = it.next(); var r2 = it.return(99); [r1.value, r2.value, r2.done].join(',')",
)
.unwrap();
assert_eq!(vm.lookup_str(result).unwrap(), "1,99,true");
}
+20
View File
@@ -358,3 +358,23 @@ fn object_literal_batch_mixed_computed_spread_order() {
);
assert_eq!(eval("var k='k',s={m:3}; ({a:1,[k]:2,...s}).k"), "2");
}
// ── object 生成器方法 ──
// 对象字面量生成器方法:yield 顺序与 done 收敛。
#[test]
fn object_generator_method_yields_in_order() {
assert_eq!(
eval_string("var o = { *gen() { yield 1; yield 2; } }; var it = o.gen(); [it.next().value, it.next().value, it.next().done].join(',')"),
"1,2,true"
);
}
// 对象字面量生成器方法 throw:异常进挂起点,被 body 内 catch 拦截后继续 yield。
#[test]
fn object_generator_method_throw_reaches_inner_catch() {
assert_eq!(
eval_string("var o = { *t() { try { yield 1; } catch (e) { yield 'caught'; } } }; var it = o.t(); var r1 = it.next(); var r2 = it.throw(new Error('x')); [r1.value, r2.value].join(',')"),
"1,caught"
);
}