fix: for-of/for-in 提前退出时按规范顺序完成 IteratorClose

return/break/continue 逃出 for-of 时此前完全不执行 IteratorClose:
BREAK/CONTINUE/RETURN 指令现在经 ext 字携带词法逃出的迭代器层数
(for-of + for-in 各 16 位),运行时在全部 finally 穿越之后、真正
跳转/返回之前按 LIFO 关闭——与规范 §13.7.5.4(循环体完成值已含
内部 try-finally 处理,IteratorClose 在后)顺序一致。

- emit 词法:LabelCtx 增加 for-of/for-in 深度计数,loop/switch/label
  打开时快照,break/continue/return 按当前深度减目标深度计算逃出层数
  (switch 内 break 以 switch 打开点为基准,目标循环自身不计入)
- 指令编码:brk/cont/ret 三参构造,lower 跳转路径补发 ext 字
- 运行时:dispatch_break/continue/return 读取逃出计数,无 finally 时
  直接关闭后跳转/返回,有 finally 时随 Completion 悬挂由 TRY_FINALLY_END
  在穿越完成后消费;生成器 .return()/.throw() 注入经 complete_generator_return
  全关快照栈迭代器;return() 抛错经 unwind 替代完成值并关闭剩余迭代器
- 顺带:for-in 逃出残留(无 return() 语义,仅弹栈);for-await-of 的
  异步迭代器不做同步关闭(return() promise 须 await,走异步机制)
- 新增 15 项回归测试:return/labeled break/continue/switch/while/finally
  顺序/抛错优先/生成器注入/for-in/for-await-of 嵌套
This commit is contained in:
2026-08-16 09:31:39 +08:00
parent b885b672b9
commit a8378694be
23 changed files with 893 additions and 204 deletions
+34 -2
View File
@@ -104,7 +104,10 @@ fn async_throw_rejects_promise() {
#[test]
fn async_is_not_constructor() {
assert!(eval("new (async function(){})").starts_with("vm error") || eval("new (async function(){})").contains("not a constructor"));
assert!(
eval("new (async function(){})").starts_with("vm error")
|| eval("new (async function(){})").contains("not a constructor")
);
}
#[test]
@@ -201,6 +204,35 @@ fn for_await_of_nested_sync_for_of_break_close_respective() {
(async()=>{ for await (const x of asyncIter) { for (const y of sync) { break; } break; } })();\
Promise.resolve().then(()=>log.join(','))"
),
"\"s,a\""
"\"s,a\""
);
}
#[test]
fn for_await_of_body_throw_closes_and_original_error_wins() {
// for-await-of 循环体抛错:先调 return() 关闭迭代器,原错误优先传播给 catch。
assert_eq!(
eval(
"let log=[];\
const it={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){log.push('r');return Promise.resolve({done:true})}}}};\
(async()=>{ try { for await (const x of it) { throw 'orig'; } } catch(e) { log.push('c:'+e); } return log.join(','); })()"
),
"\"r,c:orig\""
);
}
#[test]
fn for_await_of_return_escape_defers_async_close() {
// return 逃出 for-await-of:异步迭代器 return() 的 promise 须 await 后结算,
// 走异步关闭机制(后续阶段);阶段 1 同步逃出路径不得同步调用异步 return()。
// 断言循环体已执行且没有同步副作用泄露。
assert_eq!(
eval(
"let log=[];\
const it={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){log.push('close');return Promise.resolve({done:true})}}}};\
(async()=>{ for await (const x of it) { log.push('body'); return 1; } })();\
Promise.resolve().then(()=>log.join(','))"
),
"\"body\""
);
}