Skip to content

for await runs its body one iteration at a time (#498) - #503

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-for-await-sequential
Oct 5, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-for-await-sequential

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

The body of a for await loop ran as concurrent tasks. mlirGen(ForStatement) wrapped each iteration's body in an async.execute and added its token to an async.group created before the loop. It then waited for the whole group only once, with async.await_all after the loop. So the bodies ran together on the async runtime's threads:

  • iterations interleaved (<7<8><9>);
  • writes from one iteration were lost to another (keep.push, log += ...), under gc, rc and none;
  • one run printed nothing at all.

Each iteration now awaits its body's token before going on, as await does since #440. The next value is requested only once the body is done, as in TypeScript. The group and the await_all are gone. The body stays an async.execute, because an await inside it needs one.

New test 00for_await_sequential.ts checks, over eight iterations, that the bodies' writes happen in order, every push is kept, and awaits inside the body run in order. On main it failed in all 6 ctest variants, three runs out of three. With the fix it passes every time, and under own too.

Gate Result
Windows full suite (Release) 3840/3840
Linux (WSL) full suite 3825/3825
DefaultLib build + its own tests.ps1 -Model, release + debug, compile + JIT gc 159/159; rc, none 158 passed + weakref_basic skipped (gc only); all "All tests passed"
own corpus no flips, no first-error changes (461/619; the new test passes under own)

Not part of this change: break / continue in a for await body, and a nested for await, crash the compiler on main as well. Filed as #502.

Closes #498

🤖 Generated with Claude Code

The body of a `for await` loop ran as concurrent tasks: mlirGen
(ForStatement) wrapped each iteration's body in an async.execute, added
its token to an async.group made before the loop, and waited for the
whole group once, with async.await_all, after the loop. The bodies ran
together on the async runtime's threads: iterations interleaved
(`<7<8><9>`), and writes were lost (`keep.push` from one iteration,
`log += ...` from another), under gc, rc and none; one run printed
nothing at all.

Each iteration now awaits its body's token before going on, as
`await` does since #440, so the next value is asked for only once the
body is done, as in TypeScript. The group and the await_all are gone.
The body stays an async.execute: an `await` in it needs one.

00for_await_sequential.ts checks the bodies' writes and awaits run in
order over eight iterations; on main it failed in every variant, three
runs out of three.

Closes #498

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit f499095 into main Oct 5, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-for-await-sequential branch October 5, 2026 00:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

for await runs its body as concurrent tasks: iterations interleave and lose writes

1 participant