Repository: babel/babel (TypeScript)

Issue:
[Bug]: (Babel transpilation fail) Empty object destructuring in for-lexical declaration should be allowed
### 💻

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

### How are you using Babel?

Other (Next.js, Gatsby, vue-cli, ...)

### Input code

```js
for ( let { } = 0 ; 0 ; ) ;
```

### Configuration file name

_No response_

### Configuration

_No response_

### Current and expected behavior

The input code has no problem, but Babel throws error while transpiling the code.
```
$ node
Welcome to Node.js v18.11.0.
Type ".help" for more information.
> for ( let { } = 0 ; 0 ; ) ;
undefined
```

### Environment

[Reproduction on Babel's own REPL](https://babeljs.io/repl#?browsers=&build=&builtIns=false&corejs=3.21&spec=false&loose=false&code_lz=GYewTgBAFBA2CmAXCBvCBfCBeCAGCA3HoRAJSFA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=script&lineWrap=true&presets=env%2Creact%2Cstage-2&prettier=true&targets=&version=7.20.0&externalPlugins=&assumptions=%7B%7D)

### Possible solution

_No response_

### Additional context

_No response_


Hints:
Hey @p51lee! 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-destructuring/src/util.ts b/packages/babel-plugin-transform-destructuring/src/util.ts
--- a/packages/babel-plugin-transform-destructuring/src/util.ts
+++ b/packages/babel-plugin-transform-destructuring/src/util.ts
@@ -463,8 +463,6 @@ export class DestructuringTransformer {
       this.nodes.push(this.buildVariableDeclaration(arrayRef, toArray));
     }
 
-    //
-
     for (let i = 0; i < pattern.elements.length; i++) {
       const elem = pattern.elements[i];
 
@@ -641,10 +639,8 @@ export function convertVariableDeclaration(
     }
   }
 
-  const inForInit = t.isForStatement(path.parent, { init: node });
-
   let tail: t.VariableDeclaration | null = null;
-  const nodesOut = [];
+  let nodesOut = [];
   for (const node of nodes) {
     if (t.isVariableDeclaration(node)) {
       if (tail !== null) {
@@ -663,9 +659,38 @@ export function convertVariableDeclaration(
     if (!node.loc) {
       node.loc = nodeLoc;
     }
-    nodesOut.push(
-      inForInit && node.type === "ExpressionStatement" ? node.expression : node,
-    );
+    nodesOut.push(node);
+  }
+
+  if (
+    nodesOut.length === 2 &&
+    t.isVariableDeclaration(nodesOut[0]) &&
+    t.isExpressionStatement(nodesOut[1]) &&
+    t.isCallExpression(nodesOut[1].expression) &&
+    nodesOut[0].declarations.length === 1
+  ) {
+    // This can only happen when we generate this code:
+    //    var _ref = DESTRUCTURED_VALUE;
+    //     babelHelpers.objectDestructuringEmpty(_ref);
+    // Since pushing those two statements to the for loop .init will require an IIFE,
+    // we can optimize them to
+    //     babelHelpers.objectDestructuringEmpty(DESTRUCTURED_VALUE);
+    const expr = nodesOut[1].expression;
+    expr.arguments = [nodesOut[0].declarations[0].init];
+    nodesOut = [expr];
+  } else {
+    // We must keep nodes all are expressions or statements, so `replaceWithMultiple` can work.
+    if (
+      t.isForStatement(path.parent, { init: node }) &&
+      !nodesOut.some(v => t.isVariableDeclaration(v))
+    ) {
+      for (let i = 0; i < nodesOut.length; i++) {
+        const node: t.Node = nodesOut[i];
+        if (t.isExpressionStatement(node)) {
+          nodesOut[i] = node.expression;
+        }
+      }
+    }
   }
 
   if (nodesOut.length === 1) {


Test patch:
diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/input.js
--- a/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/input.js
+++ b/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/input.js
@@ -3,3 +3,5 @@ for ( let x in y ) for ( ; ; ) var { } = x ;
 for ( let x in y ) for ( var { } = x ; ; ) ;
 
 for ( let x in y ) for ( ; { } = x ; {} = x ) var { } = x ;
+
+for ( let { } = 0 ; 0 ; ) ;
diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/output.js
--- a/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/output.js
+++ b/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/destructuring-empty-in-for/output.js
@@ -14,3 +14,6 @@ for (var _x2 in y) {
     babelHelpers.objectDestructuringEmpty(_x2);
   }
 }
+for (babelHelpers.objectDestructuringEmpty(0); 0;) {
+  ;
+}
diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/empty-object-pattern/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/empty-object-pattern/output.js
--- a/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/empty-object-pattern/output.js
+++ b/packages/babel-plugin-transform-destructuring/test/fixtures/destructuring/empty-object-pattern/output.js
@@ -1,2 +1 @@
-var _ref = null;
-babelHelpers.objectDestructuringEmpty(_ref);
+babelHelpers.objectDestructuringEmpty(null);