💻
How are you using Babel?
babel-loader (webpack)
Input code
Minimal example that shows the compilation issue:
async function f() {
for await (const x of [].push()) {}
}
More elaborate example that crashes at runtime if f is invoked:
async function f() {
for await (const { foo: { bar } } of [1].map(async x => ({ foo: { bar: x } }))) {}
}
Configuration file name
babel.config.js
Configuration
https://babeljs.io/repl defaults with not ie 11 in "targets" changed to ie 11
Current and expected behavior
(This section was a red herring as the codegen change was intended, the actual issue is that the AsyncFromSyncIterator behavior was not updated to match the new codegen; see #13811 (comment))
Babel is miscompiling the sample for await loop in such a way that it's effectively building a regular for of loop on top of regenerator. While the iterator.next() call is being awaited, the yielded value is not itself getting awaited as it's supposed to, so the looped over values are Promise instances instead of their values.
This is a regression from (at least) 7.13. The REPL doesn't seem to have 7.14 so I couldn't check that.
Relevant annotated output in 7.13.17:
case 4:
_context.next = 6;
// await iterator.next()
return regeneratorRuntime.awrap(_iterator.next());
case 6:
_step = _context.sent;
// store whether iterator is complete but don't check yet to not leak the potential Promise
_iteratorNormalCompletion = _step.done;
_context.next = 10;
// await step.value (what was yielded from iterator.next())
return regeneratorRuntime.awrap(_step.value);
case 10:
// read the result of await step.value
_value = _context.sent;
// check now for iterator completion
if (_iteratorNormalCompletion) {
_context.next = 16;
break;
}
// set the loop variable to the awaited iterator.value
x = _value;
Relevant annotated output in 7.15.7:
case 4:
_context.next = 6;
// await iterator.next()
return regeneratorRuntime.awrap(_iterator.next());
case 6:
// directly check if iterator is done before awaiting for value
if (!(_iteratorAbruptCompletion = !(_step = _context.sent).done)) {
_context.next = 11;
break;
}
// directly uses step.value, which at this point is a Promise instead of the yielded value
x = _step.value;
// Promise is leaked if user doesn't redundantly await the value inside the loop
Environment
System:
OS: Linux 5.10 Ubuntu 20.04.3 LTS (Focal Fossa)
Binaries:
Node: 16.5.0 - ~/.nodenv/versions/16.5.0/bin/node
Yarn: 3.0.0 - ~/.nodenv/versions/16.5.0/bin/yarn
npm: 7.19.1 - ~/.nodenv/versions/16.5.0/bin/npm
Monorepos:
Yarn Workspaces: 3.0.0
npmPackages:
@babel/core: ^7.15.5 => 7.15.5
@babel/runtime: ^7.15.4 => 7.15.4
jest: ^27.0.6 => 27.0.6
Possible solution
No response
Additional context
No response
💻
How are you using Babel?
babel-loader (webpack)
Input code
Minimal example that shows the compilation issue:
More elaborate example that crashes at runtime if
fis invoked:Configuration file name
babel.config.js
Configuration
https://babeljs.io/repl defaults with
not ie 11in "targets" changed toie 11Current and expected behavior
(This section was a red herring as the codegen change was intended, the actual issue is that the AsyncFromSyncIterator behavior was not updated to match the new codegen; see #13811 (comment))
Babel is miscompiling the sample
for awaitloop in such a way that it's effectively building a regularfor ofloop on top of regenerator. While theiterator.next()call is beingawaited, the yielded value is not itself gettingawaited as it's supposed to, so the looped over values arePromiseinstances instead of their values.This is a regression from (at least) 7.13. The REPL doesn't seem to have 7.14 so I couldn't check that.
Relevant annotated output in 7.13.17:
Relevant annotated output in 7.15.7:
Environment
Possible solution
No response
Additional context
No response