Repository: swc-project/swc (rust)

Issue:
Wrong loop variable scope when destructuring is used
### Describe the bug

With ES2017 target (when object destructuring requires a helper function), loop variables get emitted with `var` instead of `const`, breaking their scoping within callbacks.

### Input code

```typescript
for (const a of [1,2,3]) {
    const { ...rest } = {};
    setTimeout(() => { console.log(a) });
}
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": true
    },
    "target": "es2017",
    "loose": false,
    "minify": {
      "compress": false,
      "mangle": false
    }
  },
  "module": {
    "type": "es6"
  },
  "minify": false,
  "isModule": true
}
```


### Playground link

https://play.swc.rs/?version=1.3.36&code=H4sIAAAAAAAAA0vLL1LQSM7PKy5RSFTIT1OINtQx0jGO1VSo5uVSAAKIVLWCnp5eUSqQVatgq1Bdaw2RLE4tCcnMTc0vLdHQ0FSwtQOqA6nPz0nVy8lP10jUVKjVBCqt5eUCAARxsoRnAAAA&config=H4sIAAAAAAAAA0WOSwrDMAxE76J1Fm0XLfgOPYRwleDgH5ICNcZ3r21SshtmRk9TYRcLpkJGFuKhpETFLxjQkkksu6ywgEq3lA9qXSNvpL1B8rjdXz31KQmBWdELLRBcdGsZLJtCZhK5Ioyb%2FzdbZ4X0OYZR57vJfEK7GOedk%2FdZnBt%2BFe0Yj7cAAAA%3D

### Expected behavior

```
for (const a of [1, 2, 3]){
    const rest = _extends({}, _objectDestructuringEmpty({}));
    setTimeout(()=>{
        console.log(a);
    });
}
```

### Actual behavior

```
for (const _ref of [1, 2, 3]){
    var a = _ref;
    const rest = _extends({}, _objectDestructuringEmpty({}));
    setTimeout(()=>{
        console.log(a);
    });
}
```

### Version

1.3.36

### Additional context

Really nasty bug :(

Pull request:
fix(es/compat): Fix variable scoping of object rest pass.
**Description:**


**Related issue:**

 - Closes #6988.

Patch:
diff --git a/crates/swc_ecma_transforms_compat/src/es2018/object_rest_spread.rs b/crates/swc_ecma_transforms_compat/src/es2018/object_rest_spread.rs
index 9dab742cf8..c7f1371233 100644
--- a/crates/swc_ecma_transforms_compat/src/es2018/object_rest_spread.rs
+++ b/crates/swc_ecma_transforms_compat/src/es2018/object_rest_spread.rs
@@ -87,7 +87,7 @@ macro_rules! impl_for_for_stmt {
                     stmt = Some(Stmt::Decl(
                         VarDecl {
                             span: DUMMY_SP,
-                            kind: VarDeclKind::Var,
+                            kind: VarDeclKind::Let,
                             decls,
                             declare: false,
                         }


Test patch:
diff --git a/crates/swc/tests/fixture/issues-2xxx/2531/2/output/index.js b/crates/swc/tests/fixture/issues-2xxx/2531/2/output/index.js
index 05686a71b3..d01012946e 100644
--- a/crates/swc/tests/fixture/issues-2xxx/2531/2/output/index.js
+++ b/crates/swc/tests/fixture/issues-2xxx/2531/2/output/index.js
@@ -1,7 +1,7 @@
 import { _ as _object_without_properties } from "@swc/helpers/_/_object_without_properties";
 const items = [];
 for (const _ref of items){
-    var item = _ref;
+    let item = _ref;
     const { name  } = item, rest = _object_without_properties(item, [
         "name"
     ]);
diff --git a/crates/swc/tests/tsc-references/objectRestForOf.1.normal.js b/crates/swc/tests/tsc-references/objectRestForOf.1.normal.js
index 21de3918b5..3c972760f3 100644
--- a/crates/swc/tests/tsc-references/objectRestForOf.1.normal.js
+++ b/crates/swc/tests/tsc-references/objectRestForOf.1.normal.js
@@ -4,7 +4,7 @@ import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props";
 import { _ as _object_without_properties } from "@swc/helpers/_/_object_without_properties";
 let array;
 for (let _ref of array){
-    var { x  } = _ref, restOf = _object_without_properties(_ref, [
+    let { x  } = _ref, restOf = _object_without_properties(_ref, [
         "x"
     ]);
     [
diff --git a/crates/swc/tests/tsc-references/objectRestForOf.2.minified.js b/crates/swc/tests/tsc-references/objectRestForOf.2.minified.js
index 7fb67cf05b..6c40e47c84 100644
--- a/crates/swc/tests/tsc-references/objectRestForOf.2.minified.js
+++ b/crates/swc/tests/tsc-references/objectRestForOf.2.minified.js
@@ -4,14 +4,17 @@ import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
 import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props";
 import { _ as _object_without_properties } from "@swc/helpers/_/_object_without_properties";
 for (let _ref of array){
-    var _ref1, { x  } = _ref;
+    let { x  } = _ref;
     _object_without_properties(_ref, [
         "x"
     ]);
 }
-for (var _ref of array)_object_without_properties(_ref1 = _ref, [
-    "x"
-]), { x: xx  } = _ref1;
+for (var _ref of array){
+    var _ref1;
+    _object_without_properties(_ref1 = _ref, [
+        "x"
+    ]), { x: xx  } = _ref1;
+}
 for (let norest of array.map((a)=>_object_spread_props(_object_spread({}, a), {
         x: 'a string'
     })))norest.x, norest.y;
diff --git a/crates/swc_ecma_transforms_compat/tests/es2018_object_rest_spread.rs b/crates/swc_ecma_transforms_compat/tests/es2018_object_rest_spread.rs
index 2b9b3ad77b..6d275e73df 100644
--- a/crates/swc_ecma_transforms_compat/tests/es2018_object_rest_spread.rs
+++ b/crates/swc_ecma_transforms_compat/tests/es2018_object_rest_spread.rs
@@ -5,7 +5,7 @@ use swc_ecma_transforms_compat::{
     es2015::{self, spread},
     es2018::{object_rest_spread, object_rest_spread::Config},
 };
-use swc_ecma_transforms_testing::{test, test_exec};
+use swc_ecma_transforms_testing::{compare_stdout, test, test_exec};
 use swc_ecma_visit::Fold;
 
 fn syntax() -> Syntax {
@@ -269,7 +269,7 @@ async function a() {
     r#"
 // ForXStatement
 for (var _ref of []) {
-  var {
+  let {
     a
   } = _ref,
       b = _object_without_properties(_ref, ["a"]);
@@ -3134,3 +3134,23 @@ test_exec!(
     thing({ queryKey: [{ url: 'https://www.google.com', id: '1' }] })
     "#
 );
+
+compare_stdout!(
+    syntax(),
+    |_| {
+        //
+        let unresolved_mark = Mark::new();
+        let top_level_mark = Mark::new();
+        chain!(
+            resolver(unresolved_mark, top_level_mark, false),
+            tr(Default::default()),
+        )
+    },
+    issue_6988_1,
+    r###"
+    for (const a of [1,2,3]) {
+      const { ...rest } = {};
+      setTimeout(() => { console.log(a) });
+    }
+    "###
+);