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

This commit is contained in:
2026-08-16 11:44:20 +08:00
parent e54b877f17
commit 00b2f4d8b1
4 changed files with 156 additions and 29 deletions
+17 -29
View File
@@ -99,35 +99,23 @@ impl Emitter {
extra_uv.push((name, c));
}
let method_value = method.value.as_ref();
let mut method_module = if method_value.r#async {
self.compile_function_body_with_field_hooks_gen(
&param_names,
body_stmts,
ctx,
false,
self_binding,
FunctionBodyContext::ClassElement,
None::<fn(&Emitter, &mut CompileCtx) -> Result<(), String>>,
false,
&[],
&extra_uv,
false,
true,
)?
} else {
self.compile_function_body_with_field_hooks(
&param_names,
body_stmts,
ctx,
false,
self_binding,
FunctionBodyContext::ClassElement,
None::<fn(&Emitter, &mut CompileCtx) -> Result<(), String>>,
false,
&[],
&extra_uv,
)?
};
// 生成器/异步/异步生成器方法与普通方法统一走带标志入口:`*m` 置 is_generator,
// `async *m` 同时置 is_generator 与 is_async,VM 据此按生成器协议创建对象并
// 处理 body 内 SUSPEND/YIELD/异常边界。
let mut method_module = self.compile_function_body_with_field_hooks_gen(
&param_names,
body_stmts,
ctx,
false,
self_binding,
FunctionBodyContext::ClassElement,
None::<fn(&Emitter, &mut CompileCtx) -> Result<(), String>>,
false,
&[],
&extra_uv,
method_value.generator,
method_value.r#async,
)?;
ctx.in_instance_method = saved_instance;
ctx.in_static_method = saved_static;
// 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义),普通方法裸属性名。
+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"
);
}