From 58467a53a121fe6f67c3d2c5fd416754ec992d0d Mon Sep 17 00:00:00 2001 From: DonIsaac <22823424+DonIsaac@users.noreply.github.com> Date: Sun, 13 Oct 2024 03:16:02 +0000 Subject: [PATCH] feat(parser): better handling of invalid modifiers (#6482) ## What This PR Does 1. Recover on, and provide a better message for, invalid `export` modifier on constructor parameters. Before, an `unexpected token` error would be produced and the parser would panic. Now, the parser recovers and produces a message saying `'export' modifier cannot appear on a parameter.` ```ts class Foo { constructor(export x: number) {} } ``` 2. Recover on, and provide a better message for, invalid modifiers on index signatures. Same recovery/message characteristics as above. ```ts class Foo { public [x: string]: string; } ``` --- crates/oxc_parser/src/diagnostics.rs | 6 ++++ crates/oxc_parser/src/ts/statement.rs | 1 + crates/oxc_parser/src/ts/types.rs | 16 +++++----- .../coverage/snapshots/parser_typescript.snap | 31 ++++++++++++++----- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index 5df7f02ff2e5a..67ebcaa1abfcb 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -471,6 +471,12 @@ pub fn cannot_appear_on_a_parameter(modifier: &Modifier) -> OxcDiagnostic { .with_label(modifier.span) } +/// TS(1071) +pub fn cannot_appear_on_an_index_signature(modifier: &Modifier) -> OxcDiagnostic { + ts_error("1071", format!("'{}' modifier cannot appear on an index signature.", modifier.kind)) + .with_label(modifier.span) +} + /// TS(18010) #[cold] pub fn accessibility_modifier_on_private_property(modifier: &Modifier) -> OxcDiagnostic { diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 6fb24353b15ba..4123f05b859ef 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -255,6 +255,7 @@ impl<'a> ParserImpl<'a> { | Kind::Readonly | Kind::Declare | Kind::Override + | Kind::Export )) { return false; } diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index ad0de032bc7c3..15ed0df805b40 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -1269,14 +1269,14 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_ts_index_signature_member(&mut self) -> Result> { let span = self.start_span(); - let mut readonly = false; - while self.is_nth_at_modifier(0, false) { - if self.eat(Kind::Readonly) { - readonly = true; - } else { - return Err(self.unexpected()); - } - } + + let modifiers = self.parse_class_element_modifiers(false); + self.verify_modifiers( + &modifiers, + ModifierFlags::READONLY, + diagnostics::cannot_appear_on_an_index_signature, + ); + let readonly = modifiers.contains(ModifierKind::Readonly); self.bump(Kind::LBrack); let index_name = self.parse_ts_index_signature_name()?; diff --git a/tasks/coverage/snapshots/parser_typescript.snap b/tasks/coverage/snapshots/parser_typescript.snap index 88996e6efd74a..b1d493bb5fc31 100644 --- a/tasks/coverage/snapshots/parser_typescript.snap +++ b/tasks/coverage/snapshots/parser_typescript.snap @@ -6629,7 +6629,7 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 3 │ } ╰──── - × Identifier expected. 'export' is a reserved word that cannot be used here. + × TS(1090): 'export' modifier cannot appear on a parameter. ╭─[typescript/tests/cases/compiler/constructorArgsErrors5.ts:2:18] 1 │ class foo { 2 │ constructor (export a: number) { @@ -9223,7 +9223,7 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 6 │ }; ╰──── - × Unexpected token + × TS(1071): 'public' modifier cannot appear on an index signature. ╭─[typescript/tests/cases/compiler/modifiersOnInterfaceIndexSignature1.ts:2:3] 1 │ interface I { 2 │ public [a: string]: number; @@ -15079,7 +15079,7 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 9 │ } ╰──── - × Unexpected token + × TS(1071): 'static' modifier cannot appear on an index signature. ╭─[typescript/tests/cases/conformance/classes/staticIndexSignature/staticIndexSignature4.ts:12:5] 11 │ interface IB { 12 │ static [s: string]: number; @@ -15087,7 +15087,15 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 13 │ static [s: number]: 42 | 233; ╰──── - × Unexpected token + × TS(1071): 'static' modifier cannot appear on an index signature. + ╭─[typescript/tests/cases/conformance/classes/staticIndexSignature/staticIndexSignature4.ts:13:5] + 12 │ static [s: string]: number; + 13 │ static [s: number]: 42 | 233; + · ────── + 14 │ } + ╰──── + + × TS(1071): 'static' modifier cannot appear on an index signature. ╭─[typescript/tests/cases/conformance/classes/staticIndexSignature/staticIndexSignature5.ts:7:5] 6 │ interface I { 7 │ static readonly [s: string]: number; @@ -15095,6 +15103,14 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 8 │ static readonly [s: number]: 42 | 233 ╰──── + × TS(1071): 'static' modifier cannot appear on an index signature. + ╭─[typescript/tests/cases/conformance/classes/staticIndexSignature/staticIndexSignature5.ts:8:5] + 7 │ static readonly [s: string]: number; + 8 │ static readonly [s: number]: 42 | 233 + · ────── + 9 │ } + ╰──── + × Expected `,` but found `is` ╭─[typescript/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:163:20] 162 │ get p1(): this is string; @@ -20758,14 +20774,13 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private · ─ ╰──── - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/tests/cases/conformance/parser/ecmascript5/IndexMemberDeclarations/parserIndexMemberDeclaration9.ts:2:10] + × TS(1071): 'export' modifier cannot appear on an index signature. + ╭─[typescript/tests/cases/conformance/parser/ecmascript5/IndexMemberDeclarations/parserIndexMemberDeclaration9.ts:2:4] 1 │ class C { 2 │ export [x: string]: string; - · ▲ + · ────── 3 │ } ╰──── - help: Try insert a semicolon here × Unexpected token ╭─[typescript/tests/cases/conformance/parser/ecmascript5/IndexSignatures/parserIndexSignature1.ts:2:4]