diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index d34f090cfc8d7..9e09e2450ec09 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -148,6 +148,11 @@ pub struct BindingRestElementTrailingComma(#[label] pub Span); #[diagnostic(help("Expected identifier in rest element"))] pub struct InvalidBindingRestElement(#[label] pub Span); +#[derive(Debug, Error, Diagnostic)] +#[error("A rest parameter cannot be optional")] +#[diagnostic()] +pub struct ARestParameterCannotBeOptional(#[label] pub Span); + #[derive(Debug, Error, Diagnostic)] #[error("Cannot assign to this expression")] #[diagnostic()] diff --git a/crates/oxc_parser/src/js/binding.rs b/crates/oxc_parser/src/js/binding.rs index da72f7d09dd9d..7f9fccb9a3a1c 100644 --- a/crates/oxc_parser/src/js/binding.rs +++ b/crates/oxc_parser/src/js/binding.rs @@ -61,7 +61,21 @@ impl<'a> ParserImpl<'a> { pub(super) fn parse_rest_element(&mut self) -> Result>> { let span = self.start_span(); self.bump_any(); // advance `...` - let argument = self.parse_binding_pattern_with_initializer()?; + let init_span = self.start_span(); + + let kind = self.parse_binding_pattern_kind()?; + // Rest element does not allow `?`, checked in checker/typescript.rs + if self.at(Kind::Question) && self.ts_enabled() { + let span = self.cur_token().span(); + self.bump_any(); + self.error(diagnostics::ARestParameterCannotBeOptional(span)); + } + // The span is not extended to its type_annotation + let type_annotation = self.parse_ts_type_annotation()?; + let pattern = self.ast.binding_pattern(kind, type_annotation, false); + // Rest element does not allow `= initializer`, . + let argument = + self.with_context(Context::In, |p| p.parse_initializer(init_span, pattern))?; let span = self.end_span(span); if self.at(Kind::Comma) { diff --git a/tasks/coverage/parser_babel.snap b/tasks/coverage/parser_babel.snap index 3b311a216cd26..8b2f6f609be67 100644 --- a/tasks/coverage/parser_babel.snap +++ b/tasks/coverage/parser_babel.snap @@ -1,7 +1,7 @@ parser_babel Summary: AST Parsed : 2090/2096 (99.71%) Positive Passed: 2083/2096 (99.38%) -Negative Passed: 1361/1500 (90.73%) +Negative Passed: 1362/1500 (90.80%) Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js" @@ -36,7 +36,6 @@ Expect Syntax Error: "es2020/dynamic-import-createImportExpression-false/invalid Expect Syntax Error: "esprima/es2015-arrow-function/invalid-param-strict-mode/input.js" Expect Syntax Error: "esprima/es2015-generator/generator-parameter-binding-property-reserved/input.js" Expect Syntax Error: "esprima/invalid-syntax/migrated_0101/input.js" -Expect Syntax Error: "typescript/arrow-function/async-rest-optional-parameter/input.ts" Expect Syntax Error: "typescript/cast/satisfies-const-error/input.ts" Expect Syntax Error: "typescript/cast/unparenthesized-assert-and-assign/input.ts" Expect Syntax Error: "typescript/cast/unparenthesized-type-assertion-and-assign/input.ts" @@ -9720,6 +9719,12 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" ╰──── help: Try insert a semicolon here + × A rest parameter cannot be optional + ╭─[typescript/arrow-function/async-rest-optional-parameter/input.ts:1:14] + 1 │ async(...args?: any[]) : any => {} + · ─ + ╰──── + × Unexpected token ╭─[typescript/arrow-function/generic-tsx/input.ts:4:3] 3 │ diff --git a/tasks/coverage/parser_typescript.snap b/tasks/coverage/parser_typescript.snap index 442c581e178da..21b4aef406f73 100644 --- a/tasks/coverage/parser_typescript.snap +++ b/tasks/coverage/parser_typescript.snap @@ -1,7 +1,7 @@ parser_typescript Summary: AST Parsed : 5240/5243 (99.94%) Positive Passed: 5233/5243 (99.81%) -Negative Passed: 1060/4879 (21.73%) +Negative Passed: 1062/4879 (21.77%) Expect Syntax Error: "compiler/ClassDeclaration10.ts" Expect Syntax Error: "compiler/ClassDeclaration11.ts" Expect Syntax Error: "compiler/ClassDeclaration13.ts" @@ -3175,7 +3175,6 @@ Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserMo Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration3.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration4.d.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration5.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList11.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList14.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList15.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList16.ts" @@ -3183,7 +3182,6 @@ Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParame Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList2.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList7.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList8.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList9.ts" Expect Syntax Error: "conformance/parser/ecmascript5/Protected/Protected1.ts" Expect Syntax Error: "conformance/parser/ecmascript5/Protected/Protected2.ts" Expect Syntax Error: "conformance/parser/ecmascript5/Protected/Protected4.ts" @@ -6544,6 +6542,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" ╰──── help: Try insert a semicolon here + × A rest parameter cannot be optional + ╭─[compiler/fatarrowfunctionsOptionalArgsErrors1.ts:2:8] + 1 │ (arg1?, arg2) => 101; + 2 │ (...arg?) => 102; + · ─ + 3 │ (...arg) => 103; + ╰──── + × A required parameter cannot follow an optional parameter. ╭─[compiler/fatarrowfunctionsOptionalArgsErrors1.ts:1:9] 1 │ (arg1?, arg2) => 101; @@ -6630,8 +6636,8 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" × Identifier `b` has already been declared ╭─[compiler/functionCall15.ts:1:25] 1 │ function foo(a?:string, b?:number, ...b:number[]){} - · ────┬──── ─────┬──── - · │ ╰── It can not be redeclared here + · ────┬──── ┬ + · │ ╰── It can not be redeclared here · ╰── `b` has already been declared here ╰──── @@ -8610,6 +8616,13 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" · ─ ╰──── + × A rest parameter cannot be optional + ╭─[compiler/restParamAsOptional.ts:1:16] + 1 │ function f(...x?) { } + · ─ + 2 │ function f2(...x = []) { } + ╰──── + × A rest parameter cannot have an initializer ╭─[compiler/restParamAsOptional.ts:2:16] 1 │ function f(...x?) { } @@ -12489,6 +12502,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 8 │ a0([1, 2, [["world"]], "string"]); // Error ╰──── + × A rest parameter cannot be optional + ╭─[conformance/es6/destructuring/destructuringParameterDeclaration4.ts:14:17] + 13 │ function a2(...a: someArray) { } // Error, rest parameter must be array type + 14 │ function a3(...b?) { } // Error, can't be optional + · ─ + 15 │ function a4(...b = [1,2,3]) { } // Error, can't have initializer + ╰──── + × A rest parameter cannot have an initializer ╭─[conformance/es6/destructuring/destructuringParameterDeclaration4.ts:15:16] 14 │ function a3(...b?) { } // Error, can't be optional @@ -17267,6 +17288,12 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ } ╰──── + × A rest parameter cannot be optional + ╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList11.ts:1:8] + 1 │ (...arg?) => 102; + · ─ + ╰──── + × A parameter property is only allowed in a constructor implementation. ╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList13.ts:2:10] 1 │ interface I { @@ -17307,6 +17334,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ } ╰──── + × A rest parameter cannot be optional + ╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList9.ts:2:14] + 1 │ class C { + 2 │ foo(...bar?) { } + · ─ + 3 │ } + ╰──── + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[conformance/parser/ecmascript5/RealWorld/parserharness.ts:1431:16] 1430 │ // Regex for parsing options in the format "@Alpha: Value of any sort"