Repository: swc-project/swc (rust)

Issue:
`this` in class method default parameter transpiles to `(void 0)`
### Describe the bug

Since `1.2.206`, when `module` is not set to `es6`, if a class with a method that has a default parameter references a class field with `this`, that reference will be transpiled to `(void 0)`, yielding an error when the code is run.

`this` is correctly retained when `module` is set to `es6` but is transpiled to `(void 0)` for all other values of `module`. Prior to `1.2.206`, `this` is retained regardless of the value of `module`.

### Input code

```typescript
class Foo {
    bar = 5
    getThing(a, b = this.bar) {
        return a + b;
    }
}
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false
    },
    "target": "es2022",
    "loose": false,
    "minify": {
      "compress": false,
      "mangle": false
    }
  },
  "module": {
    "type": "commonjs"
  },
  "minify": false,
  "isModule": true
}
```


### Playground link

https://play.swc.rs/?version=1.2.207&code=H4sIAAAAAAAAA0vOSSwuVnDLz1eo5lIAgqTEIgVbBVMwOz21JCQjMy9dI1FHIQkoWpKRWawHVKAJVQsCRaklpUV5CokK2gpJ1mDRWq5aLgCgdCWCVgAAAA%3D%3D&config=H4sIAAAAAAAAA0WMTQrEIAyF75K1i8Fl79BDBCctFv9IUqiIdx8Fh64S3vve1%2BASB1uDgizE85OaFB%2FYgFxEceyLghnYiA4MQt2AIp%2BkExH7sXbUIWehBRiIPvmjTpnLsTCJvBWmM%2FzJPlwxf%2B8ZNNBaxp2TmNMl0F%2FRGnvZF618U%2F8BElOxt70AAAA%3D

### Expected behavior

The transpiled version of the above input code should retain the reference to `this`:

```js
"use strict";
class Foo {
    bar = 5;
    getThing(a, b = this.bar) {
        return a + b;
    }
}
```

### Actual behavior

The reference to `this` is transpiled to `(void 0)`, such that an error is yielded if the method is called:

```js
"use strict";
class Foo {
    bar = 5;
    getThing(a, b = (void 0).bar) {
        return a + b;
    }
}
```

### Version

1.2.207

### Additional context

On the [the MDN page for default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters), one of the examples uses `this` in a default parameter position -- I don't think it's rare to do this.

Pull request:
fix(es/module): handle this in class method
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
- fix #5063 

Patch:
diff --git a/crates/swc_ecma_transforms_module/src/amd.rs b/crates/swc_ecma_transforms_module/src/amd.rs
index 697d674cff..41593e084c 100644
--- a/crates/swc_ecma_transforms_module/src/amd.rs
+++ b/crates/swc_ecma_transforms_module/src/amd.rs
@@ -160,7 +160,7 @@ impl VisitMut for Amd {
         stmts.visit_mut_children_with(&mut ModuleRefRewriter {
             import_map,
             lazy_record: Default::default(),
-            top_level: true,
+            is_global_this: true,
         });
 
         // ====================
diff --git a/crates/swc_ecma_transforms_module/src/common_js.rs b/crates/swc_ecma_transforms_module/src/common_js.rs
index c698784f98..a384ecaf53 100644
--- a/crates/swc_ecma_transforms_module/src/common_js.rs
+++ b/crates/swc_ecma_transforms_module/src/common_js.rs
@@ -136,7 +136,7 @@ impl VisitMut for Cjs {
         stmts.visit_mut_children_with(&mut ModuleRefRewriter {
             import_map,
             lazy_record,
-            top_level: true,
+            is_global_this: true,
         });
 
         *n = stmts;
diff --git a/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs b/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs
index e43c83749a..8f3d4853cc 100644
--- a/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs
+++ b/crates/swc_ecma_transforms_module/src/module_ref_rewriter.rs
@@ -35,7 +35,7 @@ pub(crate) struct ModuleRefRewriter {
 
     pub lazy_record: AHashSet<Id>,
 
-    pub top_level: bool,
+    pub is_global_this: bool,
 }
 
 impl VisitMut for ModuleRefRewriter {
@@ -67,7 +67,7 @@ impl VisitMut for ModuleRefRewriter {
             }
 
             Expr::This(ThisExpr { span }) => {
-                if self.top_level {
+                if self.is_global_this {
                     *n = *undefined(*span);
                 }
             }
@@ -99,38 +99,34 @@ impl VisitMut for ModuleRefRewriter {
     }
 
     fn visit_mut_function(&mut self, n: &mut Function) {
-        n.params.visit_mut_with(self);
-
-        self.visit_mut_with_non_top_level(&mut n.body);
+        self.visit_mut_with_non_global_this(n);
     }
 
     fn visit_mut_constructor(&mut self, n: &mut Constructor) {
-        n.params.visit_mut_with(self);
-
-        self.visit_mut_with_non_top_level(&mut n.body);
+        self.visit_mut_with_non_global_this(n);
     }
 
     fn visit_mut_class_prop(&mut self, n: &mut ClassProp) {
         n.key.visit_mut_with(self);
 
-        self.visit_mut_with_non_top_level(&mut n.value);
+        self.visit_mut_with_non_global_this(&mut n.value);
     }
 
     fn visit_mut_static_block(&mut self, n: &mut StaticBlock) {
-        self.visit_mut_with_non_top_level(&mut n.body);
+        self.visit_mut_with_non_global_this(n);
     }
 }
 
 impl ModuleRefRewriter {
-    fn visit_mut_with_non_top_level<T>(&mut self, n: &mut T)
+    fn visit_mut_with_non_global_this<T>(&mut self, n: &mut T)
     where
         T: VisitMutWith<Self>,
     {
-        let top_level = self.top_level;
+        let top_level = self.is_global_this;
 
-        self.top_level = false;
-        n.visit_mut_with(self);
-        self.top_level = top_level;
+        self.is_global_this = false;
+        n.visit_mut_children_with(self);
+        self.is_global_this = top_level;
     }
 
     fn map_module_ref_ident(&mut self, ref_ident: &Ident) -> Option<Expr> {
diff --git a/crates/swc_ecma_transforms_module/src/umd.rs b/crates/swc_ecma_transforms_module/src/umd.rs
index f3aada5dc2..cb2d904dbc 100644
--- a/crates/swc_ecma_transforms_module/src/umd.rs
+++ b/crates/swc_ecma_transforms_module/src/umd.rs
@@ -140,7 +140,7 @@ impl VisitMut for Umd {
         stmts.visit_mut_children_with(&mut ModuleRefRewriter {
             import_map,
             lazy_record: Default::default(),
-            top_level: true,
+            is_global_this: true,
         });
 
         // ====================


Test patch:
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/input.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/input.js
new file mode 100644
index 0000000000..022472890b
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/input.js
@@ -0,0 +1,6 @@
+class Foo {
+    bar = 5;
+    getThing(a, b = this.bar) {
+        return a + b;
+    }
+}
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.amd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.amd.js
new file mode 100644
index 0000000000..2893f0ca70
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.amd.js
@@ -0,0 +1,11 @@
+define([
+    "require"
+], function(require) {
+    "use strict";
+    class Foo {
+        bar = 5;
+        getThing(a, b = this.bar) {
+            return a + b;
+        }
+    }
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.cjs b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.cjs
new file mode 100644
index 0000000000..b3368f5147
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.cjs
@@ -0,0 +1,7 @@
+"use strict";
+class Foo {
+    bar = 5;
+    getThing(a, b = this.bar) {
+        return a + b;
+    }
+}
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.umd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.umd.js
new file mode 100644
index 0000000000..626386383e
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/1/output.umd.js
@@ -0,0 +1,13 @@
+(function(global, factory) {
+    if (typeof module === "object" && typeof module.exports === "object") factory();
+    else if (typeof define === "function" && define.amd) define([], factory);
+    else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory();
+})(this, function() {
+    "use strict";
+    class Foo {
+        bar = 5;
+        getThing(a, b = this.bar) {
+            return a + b;
+        }
+    }
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/input.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/input.js
new file mode 100644
index 0000000000..58230ec937
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/input.js
@@ -0,0 +1,28 @@
+export class Foo {
+    [this] = this;
+
+    [this](a, b = this.x) {
+        return a + b;
+    }
+
+    static [this] = this;
+    static [this](a, b = this.x) {
+        return a + b;
+    }
+}
+
+export function foo(a = this) {
+    console.log(a);
+}
+
+export default {
+    [this]: this,
+
+    [this](a, b = this.x) {
+        return a + b;
+    },
+
+    [this]: function (a, b = this.x) {
+        return a + b;
+    },
+};
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.amd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.amd.js
new file mode 100644
index 0000000000..d95bc54a64
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.amd.js
@@ -0,0 +1,42 @@
+define([
+    "require",
+    "exports"
+], function(require, exports) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    function _export(target, all) {
+        for(var name in all)Object.defineProperty(target, name, {
+            get: all[name],
+            enumerable: true
+        });
+    }
+    _export(exports, {
+        Foo: ()=>Foo,
+        default: ()=>_default,
+        foo: ()=>foo
+    });
+    class Foo {
+        [void 0] = this;
+        [void 0](a, b = this.x) {
+            return a + b;
+        }
+        static [void 0] = this;
+        static [void 0](a, b = this.x) {
+            return a + b;
+        }
+    }
+    function foo(a = this) {
+        console.log(a);
+    }
+    var _default = {
+        [void 0]: void 0,
+        [void 0] (a, b = this.x) {
+            return a + b;
+        },
+        [void 0]: function(a, b = this.x) {
+            return a + b;
+        }
+    };
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.cjs b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.cjs
new file mode 100644
index 0000000000..a662fd48e7
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.cjs
@@ -0,0 +1,37 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", {
+    value: true
+});
+function _export(target, all) {
+    for(var name in all)Object.defineProperty(target, name, {
+        get: all[name],
+        enumerable: true
+    });
+}
+_export(exports, {
+    Foo: ()=>Foo,
+    default: ()=>_default,
+    foo: ()=>foo
+});
+class Foo {
+    [void 0] = this;
+    [void 0](a, b = this.x) {
+        return a + b;
+    }
+    static [void 0] = this;
+    static [void 0](a, b = this.x) {
+        return a + b;
+    }
+}
+function foo(a = this) {
+    console.log(a);
+}
+var _default = {
+    [void 0]: void 0,
+    [void 0] (a, b = this.x) {
+        return a + b;
+    },
+    [void 0]: function(a, b = this.x) {
+        return a + b;
+    }
+};
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.umd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.umd.js
new file mode 100644
index 0000000000..fc95c4aef7
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-5063/2/output.umd.js
@@ -0,0 +1,45 @@
+(function(global, factory) {
+    if (typeof module === "object" && typeof module.exports === "object") factory(exports);
+    else if (typeof define === "function" && define.amd) define([
+        "exports"
+    ], factory);
+    else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {});
+})(this, function(exports) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    function _export(target, all) {
+        for(var name in all)Object.defineProperty(target, name, {
+            get: all[name],
+            enumerable: true
+        });
+    }
+    _export(exports, {
+        Foo: ()=>Foo,
+        default: ()=>_default,
+        foo: ()=>foo
+    });
+    class Foo {
+        [void 0] = this;
+        [void 0](a, b = this.x) {
+            return a + b;
+        }
+        static [void 0] = this;
+        static [void 0](a, b = this.x) {
+            return a + b;
+        }
+    }
+    function foo(a = this) {
+        console.log(a);
+    }
+    var _default = {
+        [void 0]: void 0,
+        [void 0] (a, b = this.x) {
+            return a + b;
+        },
+        [void 0]: function(a, b = this.x) {
+            return a + b;
+        }
+    };
+});