fix(transformer/es2018/for-await): hoist for-await generated bindings (#22355)

`for await` lowering emits several temporary bindings as `var`, but the transformer was registering those generated symbols in the current block scope instead of the nearest hoist scope.

For example, this input:

```js
async function* f(iter) {
  {
    for await (const value of iter) {
      value;
    }
  }
}
```

is lowered into code shaped like this:

```js
async function* f(iter) {
  {
    var _iteratorAbruptCompletion = false;
    var _didIteratorError = false;
    var _iteratorError;

    try {
      for (
        var _iterator = _asyncIterator(iter), _step;
        //  ^^^^^^^^^                         ^^^^^
        //  These are `var` declarations, so semantically they belong to
        //  the function/hoist scope, not the inner block scope.
        _iteratorAbruptCompletion = !(_step = await _iterator.next()).done;
        _iteratorAbruptCompletion = false
      ) {
        const value = _step.value;
        value;
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    }
  }
}
```

Before this PR, the AST transform generated the right JavaScript, but its semantic metadata recorded `_iterator`, `_step`, `_didIteratorError`, `_iteratorError`, and `_iteratorAbruptCompletion` in the current block scope:

That made the transformed semantic data disagree with semantic data rebuilt from the emitted AST.
This commit is contained in:
camc314 committed 2026-05-12 17:37:47 +00:00
1 parent ba2a1d39c6
commit 67ab1c9288
3 files changed
+8 -74

No files matched your search

@@ -102,8 +102,11 @@ impl<'a> AsyncGeneratorFunctions<'a> {
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> ArenaVec<'a, Statement<'a>> {
let step_key =
ctx.generate_uid("step", ctx.current_scope_id(), SymbolFlags::FunctionScopedVariable);
let step_key = ctx.generate_uid(
"step",
ctx.current_hoist_scope_id(),
SymbolFlags::FunctionScopedVariable,
);
// step.value
let step_value = Expression::from(ctx.ast.member_expression_static(
SPAN,
@@ -205,7 +208,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> ArenaVec<'a, Statement<'a>> {
let var_scope_id = ctx.current_scope_id();
let var_scope_id = ctx.current_hoist_scope_id();
let iterator_had_error_key =
ctx.generate_uid("didIteratorError", var_scope_id, SymbolFlags::FunctionScopedVariable);
+1 -24
View File
@@ -2,7 +2,7 @@ commit: 6402dbbf
semantic_babel Summary:
AST Parsed : 2236/2236 (100.00%)
Positive Passed: 2030/2236 (90.79%)
Positive Passed: 2031/2236 (90.83%)
semantic Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/comments/decorators/decorators-after-export/input.js
Symbol span mismatch for "C":
after transform: SymbolId(0): Span { start: 65, end: 66 }
@@ -87,29 +87,6 @@ Symbol scope ID mismatch for "_await":
after transform: SymbolId(3): ScopeId(2)
rebuilt : SymbolId(2): ScopeId(0)
semantic Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/valid-await-using-comments/input.js
Bindings mismatch:
after transform: ScopeId(1): ["_usingCtx", "_usingCtx3", "_usingCtx4"]
rebuilt : ScopeId(3): ["_didIteratorError", "_iterator", "_iteratorAbruptCompletion", "_iteratorError", "_step", "_usingCtx", "_usingCtx3", "_usingCtx4"]
Bindings mismatch:
after transform: ScopeId(7): ["_didIteratorError", "_iterator", "_iteratorAbruptCompletion", "_iteratorError", "_step"]
rebuilt : ScopeId(16): []
Symbol scope ID mismatch for "_iteratorAbruptCompletion":
after transform: SymbolId(14): ScopeId(7)
rebuilt : SymbolId(13): ScopeId(3)
Symbol scope ID mismatch for "_didIteratorError":
after transform: SymbolId(13): ScopeId(7)
rebuilt : SymbolId(14): ScopeId(3)
Symbol scope ID mismatch for "_iteratorError":
after transform: SymbolId(15): ScopeId(7)
rebuilt : SymbolId(15): ScopeId(3)
Symbol scope ID mismatch for "_iterator":
after transform: SymbolId(16): ScopeId(7)
rebuilt : SymbolId(16): ScopeId(3)
Symbol scope ID mismatch for "_step":
after transform: SymbolId(11): ScopeId(7)
rebuilt : SymbolId(17): ScopeId(3)
semantic Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/valid-for-using-binding-of-of/input.js
Symbol reference IDs mismatch for "of":
after transform: SymbolId(1): [ReferenceId(0)]
+1 -47
View File
@@ -2,53 +2,7 @@ commit: d0c1b455
semantic_test262 Summary:
AST Parsed : 47095/47095 (100.00%)
Positive Passed: 45450/47095 (96.51%)
semantic Error: tasks/coverage/test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js
Bindings mismatch:
after transform: ScopeId(4): []
rebuilt : ScopeId(4): ["_didIteratorError", "_iterator", "_iteratorAbruptCompletion", "_iteratorError", "_step"]
Bindings mismatch:
after transform: ScopeId(5): ["_didIteratorError", "_iterator", "_iteratorAbruptCompletion", "_iteratorError", "_step"]
rebuilt : ScopeId(5): []
Symbol scope ID mismatch for "_iteratorAbruptCompletion":
after transform: SymbolId(8): ScopeId(5)
rebuilt : SymbolId(5): ScopeId(4)
Symbol scope ID mismatch for "_didIteratorError":
after transform: SymbolId(7): ScopeId(5)
rebuilt : SymbolId(6): ScopeId(4)
Symbol scope ID mismatch for "_iteratorError":
after transform: SymbolId(9): ScopeId(5)
rebuilt : SymbolId(7): ScopeId(4)
Symbol scope ID mismatch for "_iterator":
after transform: SymbolId(10): ScopeId(5)
rebuilt : SymbolId(8): ScopeId(4)
Symbol scope ID mismatch for "_step":
after transform: SymbolId(5): ScopeId(5)
rebuilt : SymbolId(9): ScopeId(4)
semantic Error: tasks/coverage/test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js
Bindings mismatch:
after transform: ScopeId(4): []
rebuilt : ScopeId(4): ["_didIteratorError", "_iterator", "_iteratorAbruptCompletion", "_iteratorError", "_step"]
Bindings mismatch:
after transform: ScopeId(5): ["_didIteratorError", "_iterator", "_iteratorAbruptCompletion", "_iteratorError", "_step"]
rebuilt : ScopeId(5): []
Symbol scope ID mismatch for "_iteratorAbruptCompletion":
after transform: SymbolId(8): ScopeId(5)
rebuilt : SymbolId(5): ScopeId(4)
Symbol scope ID mismatch for "_didIteratorError":
after transform: SymbolId(7): ScopeId(5)
rebuilt : SymbolId(6): ScopeId(4)
Symbol scope ID mismatch for "_iteratorError":
after transform: SymbolId(9): ScopeId(5)
rebuilt : SymbolId(7): ScopeId(4)
Symbol scope ID mismatch for "_iterator":
after transform: SymbolId(10): ScopeId(5)
rebuilt : SymbolId(8): ScopeId(4)
Symbol scope ID mismatch for "_step":
after transform: SymbolId(5): ScopeId(5)
rebuilt : SymbolId(9): ScopeId(4)
Positive Passed: 45452/47095 (96.51%)
semantic Error: tasks/coverage/test262/test/language/arguments-object/cls-decl-async-private-gen-meth-args-trailing-comma-multiple.js
Scope flags mismatch:
after transform: ScopeId(2): ScopeFlags(StrictMode | Function)