Skip to content

Commit

Permalink
fix(ast): parse rest parameter with the correct optional and type ann…
Browse files Browse the repository at this point in the history
…otation syntax (#2686)

closes #2653
  • Loading branch information
Boshen authored Mar 12, 2024
1 parent e86cd62 commit 6c6adb4
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 8 deletions.
5 changes: 5 additions & 0 deletions crates/oxc_parser/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()]
Expand Down
16 changes: 15 additions & 1 deletion crates/oxc_parser/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,21 @@ impl<'a> ParserImpl<'a> {
pub(super) fn parse_rest_element(&mut self) -> Result<Box<'a, BindingRestElement<'a>>> {
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) {
Expand Down
9 changes: 7 additions & 2 deletions tasks/coverage/parser_babel.snap
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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 │
Expand Down
45 changes: 40 additions & 5 deletions tasks/coverage/parser_typescript.snap
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -3175,15 +3175,13 @@ 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"
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList17.ts"
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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
╰────

Expand Down Expand Up @@ -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?) { }
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit 6c6adb4

Please sign in to comment.