Repository: swc-project/swc (rust)

Issue:
Panic error when attempting to do spread operator
### Describe the bug

As part of some testing, when going through the [test262 suite](https://github.com/tc39/test262) and most specifically test case [obj-rest-not-last-element-invalid.js](https://github.com/tc39/test262/blob/main/test/language/statements/for-of/dstr/obj-rest-not-last-element-invalid.js), SWC is crashing with the following error (Detailed log when using `RUST_BACKTRACE=1 SWC_DEBUG=1 npx swc --sync <file>`):

```log
Panic: PanicInfo { payload: Any { .. }, message: Some(internal error: entered unreachable code: Object rest pattern should be removed by es2018::object_rest_spread pass), location: Location { file: "crates/swc_ecma_transforms_compat/src/es2015/destructuring.rs", line: 424, col: 52 } }
Backtrace:    0: <unknown>
   1: <unknown>
   2: <unknown>
   3: _rust_eh_personality
   4: _rust_eh_personality
   5: _rust_eh_personality
   6: _rust_eh_personality
   7: _wasmer_vm_f64_nearest
   8: _rust_eh_personality
   9: _rust_eh_personality
  10: _rust_eh_personality
  11: _rust_eh_personality
  12: _rust_eh_personality
  13: _rust_eh_personality
  14: _rust_eh_personality
  15: _rust_eh_personality
  16: _rust_eh_personality
  17: _rust_eh_personality
  18: _rust_eh_personality
  19: <unknown>
  20: __ZN6v8impl12_GLOBAL__N_123FunctionCallbackWrapper6InvokeERKN2v820FunctionCallbackInfoINS2_5ValueEEE
  21: __ZN2v88internal25FunctionCallbackArguments4CallENS0_15CallHandlerInfoE
  22: __ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0_11MaybeHandleINS0_6ObjectEEEPNS0_7IsolateENS0_6HandleINS0_10HeapObjectEEESA_NS8_INS0_20FunctionTemplateInfoEEENS8_IS4_EENS0_16BuiltinArgumentsE
  23: __ZN2v88internalL26Builtin_Impl_HandleApiCallENS0_16BuiltinArgumentsEPNS0_7IsolateE

failed to handle: internal error: entered unreachable code: Object rest pattern should be removed by es2018::object_rest_spread pass

Stack backtrace:
   0: _rust_eh_personality
   1: _wasmer_vm_f64_nearest
   2: <unknown>
   3: __ZN6v8impl12_GLOBAL__N_123FunctionCallbackWrapper6InvokeERKN2v820FunctionCallbackInfoINS2_5ValueEEE
   4: __ZN2v88internal25FunctionCallbackArguments4CallENS0_15CallHandlerInfoE
   5: __ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0_11MaybeHandleINS0_6ObjectEEEPNS0_7IsolateENS0_6HandleINS0_10HeapObjectEEESA_NS8_INS0_20FunctionTemplateInfoEEENS8_IS4_EENS0_16BuiltinArgumentsE
   6: __ZN2v88internalL26Builtin_Impl_HandleApiCallENS0_16BuiltinArgumentsEPNS0_7IsolateE
Error: Failed to compile 1 file with swc.
    at Object.assertCompilationResult (/Users/edwin.coronado/Desktop/test/node_modules/@swc/cli/lib/swc/util.js:115:15)
    at files (/Users/edwin.coronado/Desktop/test/node_modules/@swc/cli/lib/swc/file.js:175:18)
    at async _default (/Users/edwin.coronado/Desktop/test/node_modules/@swc/cli/lib/swc/file.js:194:9)
```

### Input code

```typescript
var rest, b;

for ({...rest, b} of [{}
]) ;
```


### Config

```json
{
  "jsc": {
    "target": "es5",
    "parser": {
      "syntax": "ecmascript"
    }
  },
  "module": {
    "type": "commonjs"
  },
  "sourceMaps": true
}
```


### Playground link

https://play.swc.rs/?version=1.2.138&code=H4sIAAAAAAAAAytLLFIoSi0u0VFIsubiSssvUtCo1tPTgwrVKuSnKURX13LFaipYAwCIhfdPKwAAAA%3D%3D&config=H4sIAAAAAAAAAx3LSwrAIAxF0b28sdNO3EMXEdJQKrVKEqEi7r2f0R0c7kAyRhxw0l0cEWILAiqpiX5g%2FXK6P%2BBMxnpUx5wBuWztlH%2Ft9S245FyuZHjRSlOWlaohujaZDx1euC9oAAAA

### Expected behavior

SWC should not crash and should give an error of `unexpected comma` or `rest operator should be last`. 

NodeJS handles this error like this:
```log
for ({...rest, b} of [{}
         ^^^^

SyntaxError: Rest element must be last element
    at wrapSafe (internal/modules/cjs/loader.js:1001:16)
    at Module._compile (internal/modules/cjs/loader.js:1049:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
    at internal/main/run_main_module.js:17:47
```

And Babel handles it like this:
```log
/repl.jsx: Unexpected trailing comma after rest element. (3:6)

  1 | var rest, b;
  2 |
> 3 | for ({...rest, b} of [{}
    |       ^
  4 | ]) ;
```

### Actual behavior

SWC crashes with error above.

### Version

v1.2.138

### Additional context

_No response_

Pull request:
fix(ecma/parser): non last rest element should be error in object pattern
…tern

<!-- 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):**
closes #3523 

Patch:
diff --git a/crates/swc_ecma_parser/src/parser/pat.rs b/crates/swc_ecma_parser/src/parser/pat.rs
index d84ab7c122..80381cdd4b 100644
--- a/crates/swc_ecma_parser/src/parser/pat.rs
+++ b/crates/swc_ecma_parser/src/parser/pat.rs
@@ -510,11 +510,7 @@ impl<'a, I: Tokens> Parser<I> {
         self.reparse_expr_as_pat_inner(pat_ty, expr)
     }
 
-    pub(super) fn reparse_expr_as_pat_inner(
-        &mut self,
-        pat_ty: PatType,
-        expr: Box<Expr>,
-    ) -> PResult<Pat> {
+    fn reparse_expr_as_pat_inner(&mut self, pat_ty: PatType, expr: Box<Expr>) -> PResult<Pat> {
         // In dts, we do not reparse.
         debug_assert!(!self.input.syntax().dts());
 
@@ -608,11 +604,13 @@ impl<'a, I: Tokens> Parser<I> {
             }
             Expr::Object(ObjectLit { span, props }) => {
                 // {}
+                let len = props.len();
                 Ok(Pat::Object(ObjectPat {
                     span,
                     props: props
                         .into_iter()
-                        .map(|prop| {
+                        .enumerate()
+                        .map(|(idx, prop)| {
                             let span = prop.span();
                             match prop {
                                 PropOrSpread::Prop(prop) => match *prop {
@@ -643,6 +641,9 @@ impl<'a, I: Tokens> Parser<I> {
                                 },
 
                                 PropOrSpread::Spread(SpreadElement { dot3_token, expr }) => {
+                                    if idx != len - 1 {
+                                        self.emit_err(span, SyntaxError::NonLastRestParam)
+                                    };
                                     Ok(ObjectPatProp::Rest(RestPat {
                                         span,
                                         dot3_token,


Test patch:
diff --git a/crates/swc_ecma_parser/tests/jsx/errors/issue-3523/input.js b/crates/swc_ecma_parser/tests/jsx/errors/issue-3523/input.js
new file mode 100644
index 0000000000..1dbafa6597
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/jsx/errors/issue-3523/input.js
@@ -0,0 +1,4 @@
+var rest, b;
+
+for ({...rest, b} of [{}
+]) ;
\ No newline at end of file
diff --git a/crates/swc_ecma_parser/tests/jsx/errors/issue-3523/input.js.stderr b/crates/swc_ecma_parser/tests/jsx/errors/issue-3523/input.js.stderr
new file mode 100644
index 0000000000..d678014aab
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/jsx/errors/issue-3523/input.js.stderr
@@ -0,0 +1,6 @@
+error: Rest element must be final element
+ --> $DIR/tests/jsx/errors/issue-3523/input.js:3:7
+  |
+3 | for ({...rest, b} of [{}
+  |       ^^^^^^^
+