Skip to content

Await the delegate result in async generator yield* - #4394

Open
Mwrnk wants to merge 1 commit into
google:masterfrom
Mwrnk:fix/async-generator-yield-star-await
Open

Mwrnk wants to merge 1 commit into
google:masterfrom
Mwrnk:fix/async-generator-yield-star-await

Conversation

@Mwrnk

@Mwrnk Mwrnk commented Nov 12, 2026

Copy link
Copy Markdown

AsyncGeneratorWrapper.runDelegateFrame_ calls .then() directly on whatever the delegate's next, throw or return returns. An async iterator may return a plain {value, done} object, and ECMA-262 Yield* awaits innerResult, so native code accepts it, but with --language_out ECMASCRIPT_2017 or lower the outer generator rejects with this.delegate_[a.method](...).then is not a function.

Wrap the result in Promise.resolve(), as the throw-without-throw fallback a few lines below already does for delegate['return'](). Promises and thenables resolve as before, and a synchronous throw from the delegate still reaches the existing catch.

The runtime library's JS tests are not in the GitHub tree, so I tested end to end: built //:compiler_uberjar_deploy.jar from master and from this branch, compiled a script that drives yield* over plain-object next(), throw() and return() results (plus a thenable and an async generator as controls), and ran it in Node 22. On master all seven plain-object cases reject; with this change they all resolve, six of them exactly as native Node does, and the controls are unchanged. The seventh, return(v) during yield*, now finishes with v instead of the delegate's return value; master already does that with Promise-returning delegates, so I left it out of this change. bazelisk test //:all passes (435 tests). If there is a place for a runtime test I can add one there.

Fixes #4385

AsyncGeneratorWrapper.runDelegateFrame_ called .then() directly on the
value returned by the delegate's next/throw/return method. Async
iterators are allowed to return a plain {value, done} object, and
ECMA-262 Yield* awaits innerResult, so transpiled code rejected with
"...then is not a function" where native code works.

Wrap the result in Promise.resolve(), as the throw-without-throw
fallback below already does for delegate.return().

Fixes google#4385
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.

Transpiled async generator yield* throws TypeError when delegate returns a non-Promise

1 participant