fix: class 生成器方法补 is_generator 标志,修正方法形态生成器语义
This commit is contained in:
@@ -99,8 +99,10 @@ 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(
|
||||
// 生成器/异步/异步生成器方法与普通方法统一走带标志入口:`*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(
|
||||
¶m_names,
|
||||
body_stmts,
|
||||
ctx,
|
||||
@@ -111,23 +113,9 @@ impl Emitter {
|
||||
false,
|
||||
&[],
|
||||
&extra_uv,
|
||||
false,
|
||||
true,
|
||||
)?
|
||||
} else {
|
||||
self.compile_function_body_with_field_hooks(
|
||||
¶m_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 语义),普通方法裸属性名。
|
||||
|
||||
@@ -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\""
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user