An await inside a switch nested in a labeled for…of loop compiles, then hangs forever at runtime.
async function f(xs: number[]) {
const out: string[] = [];
outer: for (const x of xs) {
switch (x % 4) {
case 0: out.push("z" + x); break;
case 1: await Promise.resolve(); out.push("a" + x); break;
case 2: if (x > 5) break outer; out.push("b" + x); break;
default: await Promise.resolve(); if (x > 10) continue outer; out.push("d" + x);
}
out.push("|");
}
return out.join("");
}
(async () => { console.log(await f([0,1,2,3,4,5,6,7,11,12])); })();
|
result |
| node 26.5.1 |
z0|a1|b2|d3|z4|a5| |
| perry |
hangs; killed at 20 s, process in state R at ~14% CPU (spinning, not blocked) |
The loop label is doing the work here: the same body without outer: and without break outer/continue outer terminates. Both abrupt completions target the enclosing labeled loop from inside a switch that also contains an await, so the case bodies are split across generator states.
Confirmed pre-existing on main, by rebuilding the compiler with crates/perry-transform/src/generator/linearize.rs reverted to main and re-running: identical hang, exit 124 both ways. Found while auditing #9189, which is adjacent (it routes labeled breaks through yielding switches, #9186) but does not address this — its own case is a labeled switch, not a labeled for…of containing one.
Sibling: the async-generator form fails differently and is filed separately.
An
awaitinside aswitchnested in a labeledfor…ofloop compiles, then hangs forever at runtime.z0|a1|b2|d3|z4|a5|Rat ~14% CPU (spinning, not blocked)The loop label is doing the work here: the same body without
outer:and withoutbreak outer/continue outerterminates. Both abrupt completions target the enclosing labeled loop from inside a switch that also contains anawait, so the case bodies are split across generator states.Confirmed pre-existing on
main, by rebuilding the compiler withcrates/perry-transform/src/generator/linearize.rsreverted tomainand re-running: identical hang, exit 124 both ways. Found while auditing #9189, which is adjacent (it routes labeled breaks through yielding switches, #9186) but does not address this — its own case is a labeledswitch, not a labeledfor…ofcontaining one.Sibling: the async-generator form fails differently and is filed separately.