for-of 迭代器栈条目化:迭代器与最近 next 结果配对存放

单一 last_for_of_result 槽被嵌套迭代覆盖,CLOSE 判定本迭代器是否
自然 done 时误读他者结果,导致数组解构/spread/嵌套 for-of 提前退出
漏调或误调 return()。改为栈条目 (iterator, last_result) 配对:

- IterState.for_of_iters 元素改 ForOfEntry,删除 last_for_of_result
- INIT 压条目,DONE 写本条目,NEXT/CLOSE 读本条目结果判 done
- GC mark/rewrite、inline save/restore、挂起帧快照同步配对遍历
- for-await-of 数组解构提前 break 现正确触发 return()(任务 40 样例)
This commit is contained in:
2026-08-16 04:00:06 +08:00
parent 19fcdd73d0
commit b885b672b9
9 changed files with 166 additions and 65 deletions
+45
View File
@@ -159,3 +159,48 @@ fn async_gen_yield_then_next_continues() {
"\"1,2,true\""
);
}
#[test]
fn for_await_of_break_closes_iterator() {
// 数组解构的 DONE 结果不得覆盖外层 for-await-of 迭代器的结果:break 提前
// 退出时 CLOSE 按自身条目判 done,须调用 return() 关闭迭代器。
assert_eq!(
eval(
"let closed=false;\
const iter={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){closed=true;return Promise.resolve({done:true})}}}};\
(async()=>{ for await (const [a,b] of iter) { break; } })();\
Promise.resolve().then(()=>closed)"
),
"true"
);
}
#[test]
fn for_await_of_natural_done_skips_return() {
// for-await-of 迭代自然结束(next 返回 done:true)时不调用 return()。
assert_eq!(
eval(
"let closed=false;\
const iter={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:true})},return(){closed=true;return Promise.resolve({done:true})}}}};\
(async()=>{ for await (const x of iter) { } })();\
Promise.resolve().then(()=>closed)"
),
"false"
);
}
#[test]
fn for_await_of_nested_sync_for_of_break_close_respective() {
// for-await-of 内嵌同步 for-of:内层 break 只关内层同步迭代器,外层异步
// 迭代器保持打开(条目配对,互不覆盖结果)。
assert_eq!(
eval(
"let log=[];\
const sync={[Symbol.iterator](){return{next(){return{value:1,done:false}},return(){log.push('s');return{}}}}};\
const asyncIter={[Symbol.asyncIterator](){return{next(){return Promise.resolve({value:1,done:false})},return(){log.push('a');return Promise.resolve({done:true})}}}};\
(async()=>{ for await (const x of asyncIter) { for (const y of sync) { break; } break; } })();\
Promise.resolve().then(()=>log.join(','))"
),
"\"s,a\""
);
}
@@ -124,3 +124,32 @@ fn for_of_array_regression_still_iterates() {
fn for_of_string_regression_still_iterates() {
assert_eq!(eval("var r=0;for(var c of 'abc'){r=r+1;}r===3"), "true");
}
#[test]
fn for_of_destructuring_break_calls_return_on_outer_iterator() {
// 数组解构在循环体内复用 FOR_OF_* 指令:解构自己的 DONE 结果不得覆盖外层
// 迭代器的结果(按迭代器配对),否则 CLOSE 误判外层已自然结束而漏调 return()。
assert_eq!(
eval(
"var closed=0;\
var it={[Symbol.iterator](){return{next(){return{value:[1],done:false}},return(){closed++;return{}}}}};\
for (const [a,b] of it) { break; }closed===1"
),
"true"
);
}
#[test]
fn for_of_nested_iterators_break_close_inner_only() {
// 嵌套 for-of 提前退出:内层 break 只关内层迭代器(各自条目结果配对),
// 外层迭代器保持打开继续下一轮。
assert_eq!(
eval(
"var log=[];\
var inner={[Symbol.iterator](){return{next(){return{value:1,done:false}},return(){log.push('i');return{}}}}};\
var outer={[Symbol.iterator](){return{next(){return{value:1,done:false}},return(){log.push('o');return{}}}}};\
for (var a of outer) { for (var b of inner) { break; } break; }log.join(',')==='i,o'"
),
"true"
);
}