feat(parser): more friendly error messages for rest assignment target and rest binding element (#22719)

Made the errors for `({...[]} = {});` and `const {...[]} = obj;` a bit more easier to understand:

```
  × Invalid rest element target in destructuring assignment
   ╭─[misc/fail/rest-assignment-target.js:1:6]
 1 │ ({...[]} = {});
   ·      ──
   ╰────
  help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
```

```
  × Invalid rest element target in destructuring pattern
   ╭─[misc/fail/rest-binding-element.js:1:11]
 1 │ const {...[]} = obj;
   ·           ──
   ╰────
  help: Expected an identifier, like `...rest`.
```
This commit is contained in:
sapphi-red committed 2026-05-25 12:47:34 +00:00
1 parent 52bd016237
commit 661132d5ac
7 files changed
+64 -33

No files matched your search

+5 -3
View File
@@ -420,8 +420,8 @@ pub fn rest_element_trailing_comma(span: Span) -> OxcDiagnostic {
#[cold]
pub fn invalid_binding_rest_element(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Invalid rest element")
.with_help("Expected identifier in rest element")
OxcDiagnostic::error("Invalid rest element target in destructuring pattern")
.with_help("Expected an identifier, like `...rest`.")
.with_label(span)
}
@@ -1238,7 +1238,9 @@ pub fn invalid_assignment_target_default_value_operator(span: Span) -> OxcDiagno
#[cold]
pub fn invalid_rest_assignment_target(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Invalid rest operator's argument.").with_label(span)
OxcDiagnostic::error("Invalid rest element target in destructuring assignment")
.with_help("Expected an identifier or member expression, like `...rest` or `...obj.prop`.")
.with_label(span)
}
#[cold]
@@ -0,0 +1 @@
({...[]} = {});
@@ -0,0 +1 @@
const {...[]} = obj;
+26 -21
View File
@@ -5672,39 +5672,40 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ╰── It can not be redeclared here
╰────
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/16/input.js:1:9]
1 │ var {...{z}} = { z: 1};
· ───
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/17/input.js:1:10]
1 │ var { ...{ x = 5 } } = {x : 1};
· ─────────
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/19/input.js:1:19]
1 │ function test({...{}}) {}
· ──
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/20/input.js:1:19]
1 │ function test({...{a}}) {}
· ───
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/21/input.js:1:6]
1 │ ({...x = 1} = {})
· ─────
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/21/input.js:1:6]
@@ -5718,12 +5719,12 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ─────
╰────
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/22/input.js:1:9]
1 │ var {...x = 1} = {}
· ─────
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× A rest element cannot have an initializer.
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/23/input.js:1:19]
@@ -5731,32 +5732,33 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ─────
╰────
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/23/input.js:1:19]
1 │ function test({...x = 1}) {}
· ─────
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/24/input.js:1:6]
1 │ ({...[]} = {})
· ──
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/25/input.js:1:9]
1 │ var {...[]} = {}
· ──
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× Invalid rest element
× Invalid rest element target in destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/26/input.js:1:19]
1 │ function test({...[]}) {}
· ──
╰────
help: Expected identifier in rest element
help: Expected an identifier, like `...rest`.
× A rest element must be last in a destructuring pattern
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/7/input.js:1:7]
@@ -5804,17 +5806,19 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ───────
╰────
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/no-pattern-in-rest/input.js:1:6]
1 │ ({...{}} = {})
· ──
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[babel/packages/babel-parser/test/fixtures/es2018/object-rest-spread/no-pattern-in-rest-with-ts/input.js:1:6]
1 │ ({...{}} = {})
· ──
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Invalid characters after number
╭─[babel/packages/babel-parser/test/fixtures/es2020/bigint/invalid-decimal/input.js:1:4]
@@ -12370,12 +12374,13 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: Try inserting a semicolon here
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[babel/packages/babel-parser/test/fixtures/typescript/cast/destructuring-assignent-rest-invalid/input.ts:1:9]
1 │ 0, { ...{} as T} = b;
· ───────
2 │ [...[] as T] = b;
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[babel/packages/babel-parser/test/fixtures/typescript/cast/destructuring-assignent-rest-invalid/input.ts:1:9]
+15 -1
View File
@@ -1,7 +1,7 @@
parser_misc Summary:
AST Parsed : 67/67 (100.00%)
Positive Passed: 67/67 (100.00%)
Negative Passed: 138/138 (100.00%)
Negative Passed: 140/140 (100.00%)
× Cannot assign to 'arguments' in strict mode
╭─[misc/fail/arguments-eval.ts:1:10]
@@ -3819,6 +3819,20 @@ Negative Passed: 138/138 (100.00%)
╰────
help: Add an identifier after '?.'
× Invalid rest element target in destructuring assignment
╭─[misc/fail/rest-assignment-target.js:1:6]
1 │ ({...[]} = {});
· ──
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Invalid rest element target in destructuring pattern
╭─[misc/fail/rest-binding-element.js:1:11]
1 │ const {...[]} = obj;
· ──
╰────
help: Expected an identifier, like `...rest`.
× 'using' declarations are not allowed at the top level of a script
╭─[misc/fail/script-top-level-using.js:2:1]
1 │ // 'using' is not allowed at top level in scripts
+10 -5
View File
@@ -4020,12 +4020,13 @@ Negative Passed: 4588/4588 (100.00%)
╰────
help: Remove the trailing comma here
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[test262/test/language/expressions/assignment/dstr/array-rest-init.js:25:8]
24 │
25 │ 0, [...x = 1] = [];
· ─────
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[test262/test/language/expressions/assignment/dstr/array-rest-init.js:25:8]
@@ -18118,12 +18119,13 @@ Negative Passed: 4588/4588 (100.00%)
· ───────────
╰────
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[test262/test/language/expressions/import.meta/syntax/invalid-assignment-target-array-rest-destructuring-expr.js:31:5]
30 │
31 │ [...import.meta] = [];
· ───────────
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[test262/test/language/expressions/import.meta/syntax/invalid-assignment-target-array-rest-destructuring-expr.js:31:5]
@@ -18168,12 +18170,13 @@ Negative Passed: 4588/4588 (100.00%)
· ───────────
╰────
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[test262/test/language/expressions/import.meta/syntax/invalid-assignment-target-object-rest-destructuring-expr.js:31:6]
30 │
31 │ ({...import.meta} = {});
· ───────────
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[test262/test/language/expressions/import.meta/syntax/invalid-assignment-target-object-rest-destructuring-expr.js:31:6]
@@ -35785,12 +35788,13 @@ Negative Passed: 4588/4588 (100.00%)
╰────
help: Remove the trailing comma here
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[test262/test/language/statements/for-in/dstr/array-rest-init.js:34:10]
33 │
34 │ for ([...x = 1] in [[]]) ;
· ─────
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[test262/test/language/statements/for-in/dstr/array-rest-init.js:34:10]
@@ -36301,12 +36305,13 @@ Negative Passed: 4588/4588 (100.00%)
╰────
help: Remove the trailing comma here
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[test262/test/language/statements/for-of/dstr/array-rest-init.js:34:10]
33 │
34 │ for ([...x = 1] of [[]]) ;
· ─────
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[test262/test/language/statements/for-of/dstr/array-rest-init.js:34:10]
@@ -17671,12 +17671,13 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
· ─────
╰────
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[typescript/tests/cases/conformance/es6/destructuring/restElementWithInitializer2.ts:3:5]
2 │ var x: number[];
3 │ [...x = a] = a; // Error, rest element cannot have initializer
· ─────
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[typescript/tests/cases/conformance/es6/destructuring/restElementWithInitializer2.ts:3:5]
@@ -17685,20 +17686,22 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
· ─────
╰────
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[typescript/tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts:1:6]
1 │ ({...{}} = {});
· ──
2 │ ({...({})} = {});
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Invalid rest operator's argument.
× Invalid rest element target in destructuring assignment
╭─[typescript/tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts:2:6]
1 │ ({...{}} = {});
2 │ ({...({})} = {});
· ────
3 │ ({...[]} = {});
╰────
help: Expected an identifier or member expression, like `...rest` or `...obj.prop`.
× Cannot assign to this expression
╭─[typescript/tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts:2:6]