diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index e668b1521b151..1f0dac1e8ff16 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -502,6 +502,13 @@ pub fn cannot_appear_on_an_index_signature(modifier: &Modifier) -> OxcDiagnostic .with_label(modifier.span) } +/// TS(1354) +#[cold] +pub fn readonly_in_array_or_tuple_type(span: Span) -> OxcDiagnostic { + ts_error("1354", "'readonly' type modifier is only permitted on array and tuple literal types.") + .with_label(span) +} + /// TS(18010) #[cold] pub fn accessibility_modifier_on_private_property(modifier: &Modifier) -> OxcDiagnostic { diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 6abf87e9129d6..85dcf1f6fffa4 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -214,7 +214,6 @@ impl<'a> ParserImpl<'a> { F: Fn(&mut Self) -> Result>, { let span = self.start_span(); - // let is_union_type = kind == Kind::Pipe; let has_leading_operator = self.eat(kind); /* hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType) ||*/ let mut ty = parse_constituent_type(self)?; @@ -253,8 +252,15 @@ impl<'a> ParserImpl<'a> { fn parse_type_operator(&mut self, operator: TSTypeOperatorOperator) -> Result> { let span = self.start_span(); self.bump_any(); // bump operator - let type_annotation = self.parse_type_operator_or_higher()?; - Ok(self.ast.ts_type_type_operator(self.end_span(span), operator, type_annotation)) + let operator_span = self.end_span(span); + let ty = self.parse_type_operator_or_higher()?; + if operator == TSTypeOperatorOperator::Readonly + && !matches!(ty, TSType::TSArrayType(_)) + && !matches!(ty, TSType::TSTupleType(_)) + { + self.error(diagnostics::readonly_in_array_or_tuple_type(operator_span)); + } + Ok(self.ast.ts_type_type_operator(self.end_span(span), operator, ty)) } fn parse_infer_type(&mut self) -> Result> { diff --git a/tasks/coverage/snapshots/parser_babel.snap b/tasks/coverage/snapshots/parser_babel.snap index a13e62038608c..f94da9ccdb9d7 100644 --- a/tasks/coverage/snapshots/parser_babel.snap +++ b/tasks/coverage/snapshots/parser_babel.snap @@ -3,7 +3,7 @@ commit: 54a8389f parser_babel Summary: AST Parsed : 2205/2218 (99.41%) Positive Passed: 2190/2218 (98.74%) -Negative Passed: 1516/1634 (92.78%) +Negative Passed: 1520/1634 (93.02%) Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/annex-b/enabled/3.1-sloppy-labeled-functions-if-body/input.js Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/input.js Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-loop/input.js @@ -115,10 +115,6 @@ Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/ty Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/import-type-declaration-error/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/import-type-dynamic-errors/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/intrinsic-keyword-error/input.ts -Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/read-only-1/input.ts -Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/read-only-2/input.ts -Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/read-only-3/input.ts -Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/read-only-4/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/tuple-labeled-invalid-optional/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/tuple-optional-invalid/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/types/tuple-required-after-labeled-optional/input.ts @@ -12487,6 +12483,30 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc · ──────── ╰──── + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[babel/packages/babel-parser/test/fixtures/typescript/types/read-only-1/input.ts:1:12] + 1 │ type T30 = readonly string; // Error + · ──────── + ╰──── + + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[babel/packages/babel-parser/test/fixtures/typescript/types/read-only-2/input.ts:1:12] + 1 │ type T31 = readonly T; // Error + · ──────── + ╰──── + + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[babel/packages/babel-parser/test/fixtures/typescript/types/read-only-3/input.ts:1:12] + 1 │ type T32 = readonly readonly string[]; // Error + · ──────── + ╰──── + + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[babel/packages/babel-parser/test/fixtures/typescript/types/read-only-4/input.ts:1:12] + 1 │ type T33 = readonly Array; // Error + · ──────── + ╰──── + × Expected `,` but found `:` ╭─[babel/packages/babel-parser/test/fixtures/typescript/types/tuple-invalid-label-1/input.ts:1:14] 1 │ type T = [x.y: A]; diff --git a/tasks/coverage/snapshots/parser_typescript.snap b/tasks/coverage/snapshots/parser_typescript.snap index 67835ef601869..50e1d61e74026 100644 --- a/tasks/coverage/snapshots/parser_typescript.snap +++ b/tasks/coverage/snapshots/parser_typescript.snap @@ -3,7 +3,7 @@ commit: d85767ab parser_typescript Summary: AST Parsed : 6494/6503 (99.86%) Positive Passed: 6483/6503 (99.69%) -Negative Passed: 1239/5747 (21.56%) +Negative Passed: 1240/5747 (21.58%) Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration10.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration11.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration13.ts @@ -4330,7 +4330,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tup Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tuple/indexerWithTuple.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tuple/optionalTupleElements1.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tuple/restTupleElements1.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tuple/strictTupleLength.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/tuple/tupleLengthCheck.ts @@ -24784,6 +24783,38 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 166 │ ╰──── + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[typescript/tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts:9:12] + 8 │ + 9 │ type T30 = readonly string; // Error + · ──────── + 10 │ type T31 = readonly T; // Error + ╰──── + + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[typescript/tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts:10:15] + 9 │ type T30 = readonly string; // Error + 10 │ type T31 = readonly T; // Error + · ──────── + 11 │ type T32 = readonly readonly string[]; // Error + ╰──── + + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[typescript/tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts:11:12] + 10 │ type T31 = readonly T; // Error + 11 │ type T32 = readonly readonly string[]; // Error + · ──────── + 12 │ type T33 = readonly Array; // Error + ╰──── + + × TS(1354): 'readonly' type modifier is only permitted on array and tuple literal types. + ╭─[typescript/tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts:12:12] + 11 │ type T32 = readonly readonly string[]; // Error + 12 │ type T33 = readonly Array; // Error + · ──────── + 13 │ + ╰──── + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[typescript/tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts:6:5] 5 │ type string = I;