Repository: swc-project/swc (rust)

Issue:
Incorrectly captured `this` when destructuring async result
### Describe the bug

When destructuring the result of a call to `Promise.all()`, the `this` context is captured incorrectly. This results in a runtime error.

### Input code

```typescript
export class Test
{
    public async bad(): Promise<void>
    {
        let foo = false;

        [ foo ] = await Promise.all(
            [
                this.foo(),
            ]
        );
    }
    
    public async good(): Promise<void>
    {
        let [ foo ] = await Promise.all(
            [
                this.foo(),
            ]);
    }

    private async foo(): Promise<boolean>
    {
        return true;
    }
}
```


### Config

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


### Playground link (or link to the minimal reproduction)

https://play.swc.rs/?version=1.4.0&code=H4sIAAAAAAAAA7WOQQ6CMBBF95xilpAYDiDqGVy4MywGGLRJZUg7RY3h7kKRGnTjxr9oOv2vk0e3lo1AqdFaOJCV6BHBkNYVWpWA9t6UUGAVJ2vYG74oS5uOVbXz1MSO0SRQM8MWatSWsig0R%2F%2BeDw1eUcm8JUWt4wB5cDGNkbOy6fA7TlaLLg9Tkvlr789v8RPzT%2Bb%2FcAxqk5ZRHQq9vDz%2F1iqYNWHzaWZInGlAjKN5V%2F8EpDjXyrABAAA%3D&config=H4sIAAAAAAAAA1VPSQ7DIAy88wrkcw9tpV76hz4CUSciYhN2pKIofw%2BkkDY3exbPeBFSwkQannIpY1miSoTp2AtC2bP6FAQ4RySdTGS4dJapUoOyhDu0fhlglUbk6kK6X2%2BP5gAbAmF3NMwZb4b8n6mDiwmJzsIqVX60eE4ULRVceM872X6pfWuDcs0FPxH8lD3xuA6GXt3OaUaxbkujvRocAQAA

### SWC Info output

_No response_

### Expected behavior

Both the `good` and `bad` functions should correctly capture `this` by using `_this.foo()` in the call to `Promise.all()`. 

### Actual behavior

Only `good` is transpiling correctly, and `bad` is using `this.`, which will be `undefined` at runtime due to the use of `_async_to_generator`.

### Version

1.4.0

### Additional context

This bug does not exist on 1.3.7

Pull request description:
fix(es/compat): Visit AssignExpr right branch in FnEnvHoister
**Related issue:**

- fix #8632 


Patch:
diff --git a/crates/swc_ecma_utils/src/function/fn_env_hoister.rs b/crates/swc_ecma_utils/src/function/fn_env_hoister.rs
index 57755e9c8c..11d9126cf8 100644
--- a/crates/swc_ecma_utils/src/function/fn_env_hoister.rs
+++ b/crates/swc_ecma_utils/src/function/fn_env_hoister.rs
@@ -386,7 +386,7 @@ impl VisitMut for FnEnvHoister {
             }) => {
                 let expr = match left {
                     AssignTarget::Simple(e) => e,
-                    AssignTarget::Pat(e) => {
+                    AssignTarget::Pat(..) => {
                         e.visit_mut_children_with(self);
                         return;
                     }


Test patch:
diff --git a/crates/swc/tests/fixture/issues-8xxx/8632/input/.swcrc b/crates/swc/tests/fixture/issues-8xxx/8632/input/.swcrc
new file mode 100644
index 0000000000..ec753bb2de
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-8xxx/8632/input/.swcrc
@@ -0,0 +1,19 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "typescript",
+            "tsx": false
+        },
+        "target": "es2015",
+        "loose": false,
+        "minify": {
+            "compress": false,
+            "mangle": false
+        }
+    },
+    "module": {
+        "type": "commonjs"
+    },
+    "minify": false,
+    "isModule": true
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-8xxx/8632/input/index.ts b/crates/swc/tests/fixture/issues-8xxx/8632/input/index.ts
new file mode 100644
index 0000000000..f2046c8769
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-8xxx/8632/input/index.ts
@@ -0,0 +1,22 @@
+export class Test {
+    public async bad(): Promise<void> {
+        let foo = false;
+
+        [foo] = await Promise.all(
+            [
+                this.foo(),
+            ]
+        );
+    }
+
+    public async good(): Promise<void> {
+        let [foo] = await Promise.all(
+            [
+                this.foo(),
+            ]);
+    }
+
+    private async foo(): Promise<boolean> {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-8xxx/8632/output/index.ts b/crates/swc/tests/fixture/issues-8xxx/8632/output/index.ts
new file mode 100644
index 0000000000..ba5926a8ca
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-8xxx/8632/output/index.ts
@@ -0,0 +1,35 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", {
+    value: true
+});
+Object.defineProperty(exports, "Test", {
+    enumerable: true,
+    get: function() {
+        return Test;
+    }
+});
+const _async_to_generator = require("@swc/helpers/_/_async_to_generator");
+class Test {
+    bad() {
+        var _this = this;
+        return _async_to_generator._(function*() {
+            let foo = false;
+            [foo] = yield Promise.all([
+                _this.foo()
+            ]);
+        })();
+    }
+    good() {
+        var _this = this;
+        return _async_to_generator._(function*() {
+            let [foo] = yield Promise.all([
+                _this.foo()
+            ]);
+        })();
+    }
+    foo() {
+        return _async_to_generator._(function*() {
+            return true;
+        })();
+    }
+}