Skip to content

transform-block-scoping: closure created in a for-loop initializer captures the wrong binding#18191

Description

@ko-success

馃捇

  • Would you like to work on a fix?

How are you using Babel?

babel-loader (webpack)

Input code

REPL reproduction

for (let i = 0, f = () => i; i < 1;) {
  i = 42;
  console.log(f());
}

Configuration file name

No response

Configuration

{
  "plugins": ["@babel/plugin-transform-block-scoping"]
}

Current and expected behavior

Babel changes the observable runtime behavior of this program.
The original JavaScript prints 0.
However, @babel/plugin-transform-block-scoping transforms it into:

for (var i = 0, f = () => i; i < 1;) {
  i = 42;
  console.log(f());
}

The transformed program prints 42.

The closure f is created while evaluating the lexical for initializer and captures the initial i binding.
Before executing the first iteration, the ECMAScript for semantics create a new per-iteration binding for i. Therefore, the assignment i = 42 in the loop body updates the per-iteration binding, while f must continue to observe the initial binding whose value is 0.
Lowering both bindings to the same var i loses this distinction. As a result, the transform silently changes valid JavaScript semantics.

Environment

  • Babel version(s): 8.0.4; also reproduces with 7.29.1
  • Plugin: @babel/plugin-transform-block-scoping
  • Node: 24.14.0
  • npm: 11.11.0
  • OS: macOS
  • Monorepo: no

Possible solution

The loop-binding capture analysis should also account for closures created in a ForStatement initializer.

Currently, references outside the loop body appear to be discarded even when they occur inside a closure. Consequently, the reference to i in f = () => i is not treated as requiring preservation of the lexical environment.

The transform needs to preserve the initializer environment separately from the per-iteration environment when lowering the lexical declaration to var.

Additional context

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions