Repository: swc-project/swc (rust)

Issue:
Error: Not a Pattern
### Describe the bug

There is only one special case where parentheses can be used ： The non modal part of the assignment statement , it can use parentheses.
SWC don't deal the special case and report a bug "Error: Not a Pattern".

### Input code

```typescript
[(b)] = [3]; //  correct 
({ p: (d) } = {}); //  correct 
[(parseInt.prop)] = [3]; //  correct
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "topLevelAwait": false,
      "importMeta": false
    },
    "transform": null,
    "target": "es5",
    "loose": false,
    "externalHelpers": false
  }
}
```


### Playground link

https://play.swc.rs/?version=1.2.111&code=H4sIAAAAAAAAA4vWSNKMVbBViDaOtVbQ11dQSM4vKkpNLlHg5dKoViiwUtBI0VSoBSqortVEVxCtUZBYVJzqmVeiV1CUX4DdHAAWcbcNYQAAAA%3D%3D&config=H4sIAAAAAAAAA0WMTQrEIAxG75K1286id5hDBCctFv9IUhgR714tlu7C915ehUMsrBUyshCPS0pU%2FMMKZAOKZZcVTNf6tKEXagYUeScdiiyd%2BZSEJjUQXHRbGSWbQmYSeRHG3T9m66GQfucYKmjJdAc%2F0N7G%2FHPynaLySe0Cj9ke9LUAAAA%3D

### Expected behavior

The non modal part of the assignment statement is specially treated.


### Version

1.2.111

### Additional context

I run swc use cmd as follows
```bash
npx swc --config-file=.swcrc poc.js -o poc.js
```
The environment is ubuntu 20.04 amd64.

Pull request:
fix(es/parser): parentheses in assignment target
**Description:**
**Related issue (if exists):**
closes #2834

Patch:
diff --git a/crates/swc_ecma_parser/src/parser/pat.rs b/crates/swc_ecma_parser/src/parser/pat.rs
index 9886601ec4..2fba5252f7 100644
--- a/crates/swc_ecma_parser/src/parser/pat.rs
+++ b/crates/swc_ecma_parser/src/parser/pat.rs
@@ -563,6 +563,7 @@ impl<'a, I: Tokens> Parser<I> {
                 | Expr::Ident(..)
                 | Expr::Fn(..)
                 | Expr::Class(..)
+                | Expr::Paren(..)
                 | Expr::Tpl(..) => {
                     if !expr.is_valid_simple_assignment_target(self.ctx().strict) {
                         self.emit_err(span, SyntaxError::NotSimpleAssign)
@@ -651,9 +652,8 @@ impl<'a, I: Tokens> Parser<I> {
                                     Ok(ObjectPatProp::Rest(RestPat {
                                         span,
                                         dot3_token,
-                                        // FIXME: is BindingPat correct?
                                         arg: Box::new(
-                                            self.reparse_expr_as_pat(PatType::BindingPat, expr)?,
+                                            self.reparse_expr_as_pat(pat_ty.element(), expr)?,
                                         ),
                                         type_ann: None,
                                     }))


Test patch:
diff --git a/crates/swc/tests/fixture/issue-2834/input/.swcrc b/crates/swc/tests/fixture/issue-2834/input/.swcrc
new file mode 100644
index 0000000000..f3199ae809
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-2834/input/.swcrc
@@ -0,0 +1,5 @@
+{
+    "jsc": {
+        "target": "es2022"
+    }
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issue-2834/input/index.js b/crates/swc/tests/fixture/issue-2834/input/index.js
new file mode 100644
index 0000000000..755a87a7c9
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-2834/input/index.js
@@ -0,0 +1,9 @@
+[(a)] = arr;
+[((a.b))] = arr;
+[...(a.b)] = arr;
+({ a: (b) } = obj);
+({ a: (b.c) } = obj);
+({ ...((a["b"])) } = obj);
+for ([(a)] of arr) {}
+for ([{ a: ((b)) }] of arr) {}
+for ([{ ...((a.b)) }] of arr) {}
diff --git a/crates/swc/tests/fixture/issue-2834/output/index.js b/crates/swc/tests/fixture/issue-2834/output/index.js
new file mode 100644
index 0000000000..f265ac0fc7
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-2834/output/index.js
@@ -0,0 +1,9 @@
+[a] = arr;
+[a.b] = arr;
+[...a.b] = arr;
+({ a: b  } = obj);
+({ a: b.c  } = obj);
+({ ...a["b"] } = obj);
+for ([a] of arr){}
+for ([{ a: b  }] of arr){}
+for ([{ ...a.b }] of arr){}
diff --git a/crates/swc_ecma_parser/tests/pat.rs b/crates/swc_ecma_parser/tests/pat.rs
new file mode 100644
index 0000000000..3140f74269
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/pat.rs
@@ -0,0 +1,80 @@
+use std::{
+    fs::read_to_string,
+    path::{Path, PathBuf},
+};
+
+use pretty_assertions::assert_eq;
+use swc_common::{errors::Handler, sync::Lrc, SourceMap};
+use swc_ecma_ast::*;
+use swc_ecma_parser::{lexer::Lexer, PResult, Parser, StringInput};
+use swc_ecma_visit::{Fold, FoldWith};
+use testing::{run_test, StdErr};
+
+fn parse_module(cm: Lrc<SourceMap>, handler: &Handler, file_name: &Path) -> Result<Module, ()> {
+    with_parser(cm, handler, file_name, |p| p.parse_module())
+}
+
+fn with_parser<F, Ret>(
+    cm: Lrc<SourceMap>,
+    handler: &Handler,
+    file_name: &Path,
+    f: F,
+) -> Result<Ret, ()>
+where
+    F: FnOnce(&mut Parser<Lexer<StringInput<'_>>>) -> PResult<Ret>,
+{
+    let fm = cm
+        .load_file(file_name)
+        .unwrap_or_else(|e| panic!("failed to load {}: {}", file_name.display(), e));
+
+    let mut p = Parser::new(
+        ::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
+            jsx: true,
+            ..Default::default()
+        }),
+        (&*fm).into(),
+        None,
+    );
+
+    let res = f(&mut p).map_err(|e| e.into_diagnostic(handler).emit());
+
+    for e in p.take_errors() {
+        e.into_diagnostic(handler).emit();
+    }
+
+    res
+}
+
+#[cfg(feature = "verify")]
+#[testing::fixture("tests/pat/errors/**/*.js")]
+fn error(entry: PathBuf) {
+    let input = read_to_string(&entry).unwrap();
+
+    eprintln!(
+        "\n\n========== Running error reporting test \nSource:\n{}\n",
+        input
+    );
+
+    let err = run_test(false, |cm, handler| {
+        if false {
+            // Type annotation
+            return Ok(());
+        }
+
+        // Parse source
+        let _ = parse_module(cm, handler, &entry);
+        if !handler.has_errors() {
+            panic!("should emit error, but parsed without error")
+        }
+
+        Err(())
+    })
+    .expect_err("should fail, but parsed as");
+
+    if err
+        .compare_to_file(format!("{}.stderr", entry.display()))
+        .is_err()
+    {
+        panic!()
+    }
+}
diff --git a/crates/swc_ecma_parser/tests/pat/errors/issue-2834/input.js b/crates/swc_ecma_parser/tests/pat/errors/issue-2834/input.js
new file mode 100644
index 0000000000..0ad9ee1ce7
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/pat/errors/issue-2834/input.js
@@ -0,0 +1,3 @@
+([(a)]) => {};
+({ a: (b) }) => {};
+for (const [(a)] of arr) {}
diff --git a/crates/swc_ecma_parser/tests/pat/errors/issue-2834/input.js.stderr b/crates/swc_ecma_parser/tests/pat/errors/issue-2834/input.js.stderr
new file mode 100644
index 0000000000..7858b8e7b4
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/pat/errors/issue-2834/input.js.stderr
@@ -0,0 +1,18 @@
+
+  x Unexpected token `(`. Expected yield, an identifier, [ or {
+   ,-[$DIR/tests/pat/errors/issue-2834/input.js:3:1]
+ 3 | for (const [(a)] of arr) {}
+   :             ^
+   `----
+
+  x Not a pattern
+   ,-[$DIR/tests/pat/errors/issue-2834/input.js:1:1]
+ 1 | ([(a)]) => {};
+   :   ^^^
+   `----
+
+  x Not a pattern
+   ,-[$DIR/tests/pat/errors/issue-2834/input.js:2:1]
+ 2 | ({ a: (b) }) => {};
+   :       ^^^
+   `----
diff --git a/crates/swc_ecma_parser/tests/test262-error-references/fail/50a060984b757dc1.js.stderr b/crates/swc_ecma_parser/tests/test262-error-references/fail/50a060984b757dc1.js.stderr
index c977b12b29..0cbc6211d2 100644
--- a/crates/swc_ecma_parser/tests/test262-error-references/fail/50a060984b757dc1.js.stderr
+++ b/crates/swc_ecma_parser/tests/test262-error-references/fail/50a060984b757dc1.js.stderr
@@ -1,5 +1,5 @@
 
-  x Not a pattern
+  x Cannot assign to this
    ,-[$DIR/tests/test262-parser/fail/50a060984b757dc1.js:1:1]
  1 | ({a:(b = 0)} = 1)
    :     ^^^^^^^
diff --git a/crates/swc_ecma_parser/tests/test262-error-references/fail/8bf8438d0a686b4e.js.stderr b/crates/swc_ecma_parser/tests/test262-error-references/fail/8bf8438d0a686b4e.js.stderr
index 58d49bae15..86da5f6785 100644
--- a/crates/swc_ecma_parser/tests/test262-error-references/fail/8bf8438d0a686b4e.js.stderr
+++ b/crates/swc_ecma_parser/tests/test262-error-references/fail/8bf8438d0a686b4e.js.stderr
@@ -1,5 +1,5 @@
 
-  x Not a pattern
+  x Cannot assign to this
    ,-[$DIR/tests/test262-parser/fail/8bf8438d0a686b4e.js:1:1]
  1 | [a, ...(b = c)] = 0
    :        ^^^^^^^
diff --git a/crates/swc_ecma_parser/tests/test262-error-references/fail/90cd97db35a1a503.js.stderr b/crates/swc_ecma_parser/tests/test262-error-references/fail/90cd97db35a1a503.js.stderr
index acd4ef2f80..34c4ff5fc3 100644
--- a/crates/swc_ecma_parser/tests/test262-error-references/fail/90cd97db35a1a503.js.stderr
+++ b/crates/swc_ecma_parser/tests/test262-error-references/fail/90cd97db35a1a503.js.stderr
@@ -1,5 +1,5 @@
 
-  x Not a pattern
+  x Cannot assign to this
    ,-[$DIR/tests/test262-parser/fail/90cd97db35a1a503.js:1:1]
  1 | ({a: (b = 0)} = {})
    :      ^^^^^^^
diff --git a/crates/swc_ecma_parser/tests/test262-error-references/fail/db41a80ccf646002.js.stderr b/crates/swc_ecma_parser/tests/test262-error-references/fail/db41a80ccf646002.js.stderr
index 70e1042119..02dcb0e251 100644
--- a/crates/swc_ecma_parser/tests/test262-error-references/fail/db41a80ccf646002.js.stderr
+++ b/crates/swc_ecma_parser/tests/test262-error-references/fail/db41a80ccf646002.js.stderr
@@ -1,5 +1,5 @@
 
-  x Not a pattern
+  x Cannot assign to this
    ,-[$DIR/tests/test262-parser/fail/db41a80ccf646002.js:1:1]
  1 | [(a = 0)] = 1
    :  ^^^^^^^
diff --git a/crates/swc_ecma_parser/tests/test262-error-references/fail/e4963d9605864d9a.js.stderr b/crates/swc_ecma_parser/tests/test262-error-references/fail/e4963d9605864d9a.js.stderr
index 630fb1e09b..877032b62b 100644
--- a/crates/swc_ecma_parser/tests/test262-error-references/fail/e4963d9605864d9a.js.stderr
+++ b/crates/swc_ecma_parser/tests/test262-error-references/fail/e4963d9605864d9a.js.stderr
@@ -5,7 +5,7 @@
    :                ^
    `----
 
-  x Not a pattern
+  x Cannot assign to this
    ,-[$DIR/tests/test262-parser/fail/e4963d9605864d9a.js:1:1]
  1 | ([(a = b)] = []
    :   ^^^^^^^
diff --git a/crates/swc_ecma_parser/tests/tsc/restPropertyWithBindingPattern.json b/crates/swc_ecma_parser/tests/tsc/restPropertyWithBindingPattern.json
index 952848b3dc..700f240f45 100644
--- a/crates/swc_ecma_parser/tests/tsc/restPropertyWithBindingPattern.json
+++ b/crates/swc_ecma_parser/tests/tsc/restPropertyWithBindingPattern.json
@@ -120,11 +120,20 @@
                   "ctxt": 0
                 },
                 "argument": {
-                  "type": "Invalid",
+                  "type": "ParenthesisExpression",
                   "span": {
                     "start": 21,
                     "end": 25,
                     "ctxt": 0
+                  },
+                  "expression": {
+                    "type": "ObjectExpression",
+                    "span": {
+                      "start": 22,
+                      "end": 24,
+                      "ctxt": 0
+                    },
+                    "properties": []
                   }
                 },
                 "typeAnnotation": null
@@ -259,11 +268,20 @@
                   "ctxt": 0
                 },
                 "argument": {
-                  "type": "Invalid",
+                  "type": "ParenthesisExpression",
                   "span": {
                     "start": 55,
                     "end": 59,
                     "ctxt": 0
+                  },
+                  "expression": {
+                    "type": "ArrayExpression",
+                    "span": {
+                      "start": 56,
+                      "end": 58,
+                      "ctxt": 0
+                    },
+                    "elements": []
                   }
                 },
                 "typeAnnotation": null