Repository: babel/babel (TypeScript)

Issue:
[Bug]: Endless loop found in code transformed by plugin @babel/plugin-transform-block-scoping 
### 💻

- [X] Would you like to work on a fix?

### How are you using Babel?

babel-loader (webpack)

### Input code

```js
var i;
for (let i = 0; i < 1; ) {
  i++
  () => i;
}
```

### Configuration file name

babel.config.json

### Configuration

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

### Current and expected behavior

Current:
```js
"use strict";

var i;
var _loop = function (_i) {
  _i++;
  () => _i;
  i = _i;
};
for (var _i2 = 0; _i2 < 1;) {
  _loop(_i2);
}
```

Expect:
```js
"use strict";

var i;
var _loop = function (_i) {
  _i++;
  () => _i;
  _i2 = _i;
};
for (var _i2 = 0; _i2 < 1;) {
  _loop(_i2);
}
```

### Environment

System:
    OS: macOS 13.0
  Binaries:
    Node: 14.16.0 - ~/.nvm/versions/node/v14.16.0/bin/node
    Yarn: 1.22.4 - ~/.nvm/versions/node/v14.16.0/bin/yarn
    npm: 6.14.11 - ~/.nvm/versions/node/v14.16.0/bin/npm
  npmPackages:
    @babel/core: 7.14.8 => 7.14.8 
    @babel/eslint-parser: 7.14.7 => 7.14.7 
    @babel/plugin-proposal-json-strings: 7.2.0 => 7.2.0 
    @babel/plugin-proposal-nullish-coalescing-operator: 7.2.0 => 7.2.0 
    @babel/plugin-proposal-numeric-separator: 7.2.0 => 7.2.0 
    @babel/plugin-proposal-object-rest-spread: 7.7.4 => 7.7.4 
    @babel/plugin-proposal-optional-chaining: 7.12.7 => 7.12.7 
    @babel/plugin-transform-runtime: 7.14.5 => 7.14.5 
    @babel/preset-env: 7.14.8 => 7.14.8 
    @babel/preset-react: 7.14.5 => 7.14.5 
    @babel/runtime: 7.14.8 => 7.14.8 
    babel-jest: 27.0.6 => 27.0.6 
    babel-loader: 8.2.2 => 8.2.2 
    babel-plugin-dynamic-import-node: 2.3.3 => 2.3.3 
    babel-plugin-import: 1.13.3 => 1.13.3 
    babel-plugin-syntax-jsx: 6.18.0 => 6.18.0 
    babel-plugin-transform-object-rest-spread: 6.26.0 => 6.26.0 
    babel-plugin-transform-react-remove-prop-types: 0.4.24 => 0.4.24 
    babel-template: 6.26.0 => 6.26.0 
    eslint: 7.31.0 => 7.31.0 
    jest: 27.0.6 => 27.0.6 
    karma-babel-preprocessor: 6.0.1 => 6.0.1 
    webpack: 5.64.1 => 5.64.1

### Possible solution

_No response_

### Additional context

_No response_


Hints:
Hey @a130888599! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant [Slack community](https://babeljs.slack.com) that typically always has someone willing to help. You can sign-up [here](https://slack.babeljs.io/) for an invite.

Patch:
diff --git a/packages/babel-plugin-transform-block-scoping/src/index.ts b/packages/babel-plugin-transform-block-scoping/src/index.ts
--- a/packages/babel-plugin-transform-block-scoping/src/index.ts
+++ b/packages/babel-plugin-transform-block-scoping/src/index.ts
@@ -84,10 +84,7 @@ export default declare((api, opts: Options) => {
               const { usages, capturedInClosure, hasConstantViolations } =
                 getUsageInBody(binding, path);
 
-              if (capturedInClosure) {
-                markNeedsBodyWrap();
-                captured.push(name);
-              } else if (
+              if (
                 headScope.parent.hasBinding(name) ||
                 headScope.parent.hasGlobal(name)
               ) {
@@ -100,6 +97,11 @@ export default declare((api, opts: Options) => {
                 name = newName;
               }
 
+              if (capturedInClosure) {
+                markNeedsBodyWrap();
+                captured.push(name);
+              }
+
               if (isForStatement && hasConstantViolations) {
                 updatedBindingsUsages.set(name, usages);
               }


Test patch:
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-15308-for-variable-shadow-and-capture/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-15308-for-variable-shadow-and-capture/output.js
--- a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-15308-for-variable-shadow-and-capture/output.js
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-15308-for-variable-shadow-and-capture/output.js
@@ -1,7 +1,7 @@
 var i;
-var _loop = function (i) {
+var _loop = function (_i) {
   (function () {
-    return i;
+    return _i;
   });
 };
 for (var _i = 4; _i < 6; _i++) {
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-973/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-973/output.js
--- a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-973/output.js
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/issue-973/output.js
@@ -1,8 +1,8 @@
 var arr = [];
 for (var i = 0; i < 10; i++) {
-  var _loop = function (i) {
+  var _loop = function (_i) {
     arr.push(function () {
-      return i;
+      return _i;
     });
   };
   for (var _i = 0; _i < 10; _i++) {
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/wrap-closure-shadow-variables/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/wrap-closure-shadow-variables/output.js
--- a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/wrap-closure-shadow-variables/output.js
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/wrap-closure-shadow-variables/output.js
@@ -1,7 +1,7 @@
 var a = 1;
-var _loop = function (a) {
+var _loop = function (_a) {
   items.forEach(function (item) {
-    return a;
+    return _a;
   });
 };
 for (var _a = 1; _a < 100; _a++) {
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/input.ts b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/input.ts
similarity index 100%
rename from packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/input.ts
rename to packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/input.ts
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/options.json b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/options.json
@@ -0,0 +1,3 @@
+{
+  "plugins": ["./plugin.cjs", "transform-block-scoping"]
+}
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/output.js
similarity index 100%
rename from packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/output.js
rename to packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/output.js
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/plugin.cjs b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/plugin.cjs
similarity index 100%
rename from packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/plugin.cjs
rename to packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-global-ids/plugin.cjs
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/options.json b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/options.json
deleted file mode 100644
--- a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/rename-with-other-plugins/options.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "plugins": ["./plugin.cjs", "transform-typescript", "transform-block-scoping"]
-}
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/input.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/input.js
@@ -0,0 +1,7 @@
+// https://github.com/babel/babel/issues/15397
+
+var i;
+for (let i = 0; i < 1; ) {
+  i++
+  () => i;
+}
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/options.json b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/options.json
@@ -0,0 +1,3 @@
+{
+  "plugins": ["transform-block-scoping"]
+}
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/output.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/regression/wrap-closure-updated-shadow-variables/output.js
@@ -0,0 +1,11 @@
+// https://github.com/babel/babel/issues/15397
+
+var i;
+var _loop = function (_i2) {
+  _i2++;
+  () => _i2;
+  _i = _i2;
+};
+for (var _i = 0; _i < 1;) {
+  _loop(_i);
+}