Repository: swc-project/swc (rust)

Issue:
Scope analysis fails for parameter with type identifier with same name
### Describe the bug

Given the following code:

```ts
import type { Foo } from "./foo.ts";

function _bar(...Foo: Foo) {
  console.log(Foo);
}
```

### Expected behavior

```ts
import { Foo__1 } from "./foo.ts";
function _bar__1(...Foo__2: Foo__1) {
    console.log(Foo__2);
}
```

### Actual behavior

Started doing this in the most recent upgrade for us:

```ts
import { Foo__1 } from "./foo.ts";
function _bar__1(...Foo__2: Foo__2) {
    console.log(Foo__2);
}
```

### Version

swc_ecma_transforms_base 0.82.5 (main)

I looked through the code a bit in resolver/mod.rs, but on first glance I'm not sure what's going wrong.

Pull request:
fix: ensure parameter type is resolved to parent when name is same
**Description:**

Fixes some usages of parameter types. swc does not still properly handle some other scenarios, but not a big deal because it's super edge case and I will open an issue later.

**Related issue (if exists):**

Closes #4610


Patch:
diff --git a/crates/swc_ecma_transforms_base/src/resolver/mod.rs b/crates/swc_ecma_transforms_base/src/resolver/mod.rs
index ad2bf3f278..556b213529 100644
--- a/crates/swc_ecma_transforms_base/src/resolver/mod.rs
+++ b/crates/swc_ecma_transforms_base/src/resolver/mod.rs
@@ -440,7 +440,9 @@ macro_rules! typed_ref {
     ($name:ident, $T:ty) => {
         fn $name(&mut self, node: &mut $T) {
             if self.config.handle_types {
+                let ident_type = self.ident_type;
                 node.visit_mut_children_with(self);
+                self.ident_type = ident_type;
             }
         }
     };
@@ -451,9 +453,11 @@ macro_rules! typed_ref_init {
         fn $name(&mut self, node: &mut $T) {
             if self.config.handle_types {
                 let in_type = self.in_type;
+                let ident_type = self.ident_type;
                 self.ident_type = IdentType::Ref;
                 self.in_type = true;
                 node.visit_mut_children_with(self);
+                self.ident_type = ident_type;
                 self.in_type = in_type;
             }
         }
@@ -1058,6 +1062,21 @@ impl<'a> VisitMut for Resolver<'a> {
         p.visit_mut_children_with(self);
     }
 
+    fn visit_mut_assign_pat(&mut self, node: &mut AssignPat) {
+        // visit the type first so that it doesn't resolve any
+        // identifiers from the others
+        node.type_ann.visit_mut_with(self);
+        node.left.visit_mut_with(self);
+        node.right.visit_mut_with(self);
+    }
+
+    fn visit_mut_rest_pat(&mut self, node: &mut RestPat) {
+        // visit the type first so that it doesn't resolve any
+        // identifiers from the arg
+        node.type_ann.visit_mut_with(self);
+        node.arg.visit_mut_with(self);
+    }
+
     fn visit_mut_private_method(&mut self, m: &mut PrivateMethod) {
         m.key.visit_mut_with(self);
 


Test patch:
diff --git a/crates/swc_ecma_transforms_base/tests/resolver/for_of_hoisting/input.js b/crates/swc_ecma_transforms_base/tests/resolver/for_of_hoisting/input.js
new file mode 100644
index 0000000000..8edde4383f
--- /dev/null
+++ b/crates/swc_ecma_transforms_base/tests/resolver/for_of_hoisting/input.js
@@ -0,0 +1,6 @@
+var k, v;
+var map = new Map([["", true]]);
+for ([k, ...[v]] of map) {
+    k;
+    v;
+}
diff --git a/crates/swc_ecma_transforms_base/tests/resolver/for_of_hoisting/output.js b/crates/swc_ecma_transforms_base/tests/resolver/for_of_hoisting/output.js
new file mode 100644
index 0000000000..257d9489f2
--- /dev/null
+++ b/crates/swc_ecma_transforms_base/tests/resolver/for_of_hoisting/output.js
@@ -0,0 +1,11 @@
+var k__1, v__1;
+var map__1 = new Map([
+    [
+        "",
+        true
+    ]
+]);
+for ([k__1, ...[v__1]] of map__1){
+    k__1;
+    v__1;
+}
diff --git a/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/input.ts b/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/input.ts
index 9a522d465b..a6ab87b0e1 100644
--- a/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/input.ts
+++ b/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/input.ts
@@ -1,6 +1,9 @@
 import type { Foo } from "./foo.ts";
-//            ^^^ <---- (a)
+
 function _bar(...Foo: Foo) {
-    //                    ^^^ <---- (b)
     console.log(Foo);
 }
+
+function _bar2(Foo: Foo, other = Foo) {
+    Foo;
+}
diff --git a/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/output.ts b/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/output.ts
index 5e5d83f842..a50ddcdc1c 100644
--- a/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/output.ts
+++ b/crates/swc_ecma_transforms_base/tests/ts-resolver/deno/lint/705/output.ts
@@ -1,4 +1,7 @@
 import { Foo__1 } from "./foo.ts";
-function _bar__1(...Foo__2: Foo__2) {
+function _bar__1(...Foo__2: Foo__1) {
     console.log(Foo__2);
 }
+function _bar2__1(Foo__4: Foo__1, other__4 = Foo__4) {
+    Foo__4;
+}