Skip to content

Fix for-await-of inside async generators permanently suspending#2353

Merged
lahma merged 5 commits into
mainfrom
copilot/fix-async-test-failures-repl
Mar 23, 2026
Merged

Fix for-await-of inside async generators permanently suspending#2353
lahma merged 5 commits into
mainfrom
copilot/fix-async-test-failures-repl

Conversation

Copilot AI commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

for await inside async function* bodies never resumed after the iterator's .next() Promise resolved, leaving the outer .next() Promise permanently pending.

async function* gen() {
  for await ([,] of [[]]) console.log("iteration"); // never ran
}
gen().next().then(() => console.log("OK")); // never ran

Root cause

SuspendForAsyncIteration registered onFulfilled/onRejected handlers that called AsyncGeneratorResumeNext(). That method exits early when _asyncGeneratorQueue is empty — which it always is at this point, because the current request was already dequeued before execution started. The generator body was left permanently suspended.

Changes

  • AsyncGeneratorInstance: Add AsyncGeneratorContinueForAwait(PromiseCapability) — resumes the current request's execution directly (_asyncGeneratorState = Executing, _isResuming = true, ResumeExecution(capability)) without requiring a queued request.

  • SuspendData: Add RejectedValue to ForAwaitSuspendData so rejected iterator Promises can be propagated as throws on resume.

  • JintForInForOfStatement.SuspendForAsyncIteration (async generator branch):

    • Capture _currentPromiseCapability before suspension
    • Wrap handlers in engine.AddToEventLoop (matching async function pattern for correct microtask ordering)
    • Call AsyncGeneratorContinueForAwait instead of AsyncGeneratorResumeNext
    • Store RejectedValue in the rejection handler
  • JintForInForOfStatement.ExecuteInternal: On for-await-of resumption inside an async generator, check ForAwaitSuspendData.RejectedValue and throw it into the generator context.

Original prompt

This section details on the original issue you should resolve

<issue_title>Async test failures in REPL</issue_title>
<issue_description>Version/platform/runtime used

.NET 10.0.201 Linux aarch64

Describe the bug

I tried compared results from Jint.Tests.Test262 vs my own test262 harness that runs Jint.Repl and noticed that quite a lot of async tests are failing when running against Jint.Repl binary. Especially most of test/language/statements/for-await-of/ tests.

To Reproduce

Couple representative examples, stripped down to bare minimum:

$ cat min1.js
// test/language/statements/for-await-of/async-gen-decl-dstr-array-elision-val-array.js
async function* gen() {
  for await ([,] of [[]]) console.log("iteration");
}
gen().next().then(() => console.log("OK"));
$ node min1.js
iteration
OK
$ ./Jint.Repl min1.js
[object Promise]

$ cat min2.js 
// test/language/statements/async-generator/yield-star-async-next.js
const obj = {
  [Symbol.asyncIterator]() {
    return {
      get next() {
        console.log("get next");
        return function () {
          console.log("call next");
          return {
            then(resolve) {
              resolve({
                get value() {
                  console.log("get value");
                  return "OK";
                },
                get done() {
                  console.log("get done");
                  return false;
                }
              });
            }
          };
        };
      }
    };
  }
};
async function* gen() {
  yield* obj;
}
gen().next().then(x => console.log(x.value));
$ node min2.js
get next
call next
get done
get value
OK
$ ./Jint.Repl min2.js
get next
get next
call next
null
[object Promise]

Additional context

I attached full list of errors I'm getting: jint-diffs.json

This is a subset of tests that Jint.Tests.Test262 is configured to run and passes, extracted from an instrumented Jint.Tests.Test262 binary, and for which I can't reproduce success with Jint.Repl. Most of them are async related.</issue_description>

Comments on the Issue (you are @copilot in this section)


⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

Copilot AI and others added 2 commits March 23, 2026 21:13
Copilot AI changed the title [WIP] Fix async test failures in Jint.Repl Fix for-await-of inside async generators permanently suspending Mar 23, 2026
Copilot AI requested a review from lahma March 23, 2026 21:18
@lahma
lahma requested a review from Copilot March 23, 2026 21:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a deadlock where for await...of inside async function* would suspend the generator body and never resume, leaving the outer .next() promise permanently pending.

Changes:

  • Add an async-generator-specific continuation path (AsyncGeneratorContinueForAwait) to resume the current dequeued request after a for-await-of suspension.
  • Track for-await-of iterator .next() rejections via ForAwaitSuspendData.RejectedValue and rethrow on resume within async generators.
  • Add regression tests covering for await inside async generators (including destructuring and multiple suspensions).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
Jint/Runtime/SuspendData.cs Extends ForAwaitSuspendData with RejectedValue to propagate iterator .next() promise rejections on resume.
Jint/Runtime/Interpreter/Statements/JintForInForOfStatement.cs Switches async-generator for-await-of resumption to AsyncGeneratorContinueForAwait, queues resumption via event loop, and throws stored rejection on resume.
Jint/Native/AsyncGenerator/AsyncGeneratorInstance.cs Introduces AsyncGeneratorContinueForAwait to resume execution without relying on the request queue.
Jint.Tests/Runtime/AsyncTests.cs Adds regression tests for for await inside async function* bodies (including destructuring and repeated suspensions).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Jint/Runtime/Interpreter/Statements/JintForInForOfStatement.cs
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.

Async test failures in REPL

3 participants