diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index 05d93172ba936..025a2382035d9 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -183,6 +183,24 @@ pub fn const_class_member(span: Span) -> OxcDiagnostic { .with_label(span) } +// 'extends' clause already seen. ts(1172) +#[cold] +pub fn extends_clause_already_seen(span: Span) -> OxcDiagnostic { + ts_error("1172", "'extends' clause already seen").with_label(span) +} + +// 'extends' clause must precede 'implements' clause. ts(1173) +#[cold] +pub fn extends_clause_must_precede_implements(span: Span) -> OxcDiagnostic { + ts_error("1173", "'extends' clause must precede 'implements' clause").with_label(span) +} + +// 'implements' clause already seen. ts(1175) +#[cold] +pub fn implements_clause_already_seen(span: Span) -> OxcDiagnostic { + ts_error("1175", "'implements' clause already seen").with_label(span) +} + #[cold] pub fn binding_rest_element_last(span: Span) -> OxcDiagnostic { OxcDiagnostic::error("A rest element must be last in a destructuring pattern").with_label(span) diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 7a59ac99ebfc1..87042d5365a76 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -117,9 +117,23 @@ impl<'a> ParserImpl<'a> { loop { match self.cur_kind() { Kind::Extends => { + if extends.is_some() { + self.error(diagnostics::extends_clause_already_seen( + self.cur_token().span(), + )); + } else if implements.is_some() { + self.error(diagnostics::extends_clause_must_precede_implements( + self.cur_token().span(), + )); + } extends = Some(self.parse_extends_clause()?); } Kind::Implements => { + if implements.is_some() { + self.error(diagnostics::implements_clause_already_seen( + self.cur_token().span(), + )); + } implements = Some(self.parse_ts_implements_clause()?); } _ => break, diff --git a/tasks/coverage/snapshots/estree_typescript.snap b/tasks/coverage/snapshots/estree_typescript.snap index 391a9242053dc..cab591ac1039a 100644 --- a/tasks/coverage/snapshots/estree_typescript.snap +++ b/tasks/coverage/snapshots/estree_typescript.snap @@ -2338,7 +2338,8 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc Unexpected token Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/IndexSignatures/parserIndexSignature9.ts Unexpected token -Mismatch: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration1.ts +Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration1.ts +'extends' clause already seen Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration6.ts 'export' modifier cannot be used here. Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration10.ts diff --git a/tasks/coverage/snapshots/parser_typescript.snap b/tasks/coverage/snapshots/parser_typescript.snap index f425968e09331..84e7e521ed9f2 100644 --- a/tasks/coverage/snapshots/parser_typescript.snap +++ b/tasks/coverage/snapshots/parser_typescript.snap @@ -3,7 +3,7 @@ commit: 15392346 parser_typescript Summary: AST Parsed : 6522/6531 (99.86%) Positive Passed: 6511/6531 (99.69%) -Negative Passed: 1297/5754 (22.54%) +Negative Passed: 1307/5754 (22.71%) Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration24.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment7.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment8.ts @@ -827,8 +827,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/extendGlobal Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/extendNonClassSymbol2.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/extendPrivateConstructorClass.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/extendedInterfacesWithDuplicateTypeParameters.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/extendsClauseAlreadySeen.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/extendsClauseAlreadySeen2.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/externSyntax.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/externalModuleExportingGenericClass.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/externalModuleImmutableBindings.ts @@ -997,10 +995,8 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/identityForS Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ifElseWithStatements1.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ignoredJsxAttributes.tsx Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implementArrayInterface.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implementClausePrecedingExtends.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implementGenericWithMismatchedTypes.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implementPublicPropertyAsPrivate.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implementsClauseAlreadySeen.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implementsIncorrectlyNoAssertion.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implicitAnyAmbients.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/implicitAnyCastedValue.ts @@ -3686,14 +3682,9 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/CatchClauses/parserCatchClauseWithTypeAnnotation1.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClass1.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClass2.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration1.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration12.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration18.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration2.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration24.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration3.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration4.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration5.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration6.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration7.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName1.ts @@ -3763,7 +3754,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/IndexMemberDeclarations/parserIndexMemberDeclaration5.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/IndexSignatures/parserIndexSignature4.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/IndexSignatures/parserIndexSignature5.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration1.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration2.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration8.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessor1.ts @@ -8125,6 +8115,22 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 5 │ } ╰──── + × TS(1172): 'extends' clause already seen + ╭─[typescript/tests/cases/compiler/extendsClauseAlreadySeen.ts:4:19] + 3 │ } + 4 │ class D extends C extends C { + · ─────── + 5 │ baz() { } + ╰──── + + × TS(1172): 'extends' clause already seen + ╭─[typescript/tests/cases/compiler/extendsClauseAlreadySeen2.ts:4:30] + 3 │ } + 4 │ class D extends C extends C { + · ─────── + 5 │ baz() { } + ╰──── + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[typescript/tests/cases/compiler/extendsUntypedModule.ts:3:5] 2 │ @@ -8420,6 +8426,21 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 17 │ } ╰──── + × TS(1173): 'extends' clause must precede 'implements' clause + ╭─[typescript/tests/cases/compiler/implementClausePrecedingExtends.ts:2:22] + 1 │ class C { foo: number } + 2 │ class D implements C extends C { } + · ─────── + ╰──── + + × TS(1175): 'implements' clause already seen + ╭─[typescript/tests/cases/compiler/implementsClauseAlreadySeen.ts:4:22] + 3 │ } + 4 │ class D implements C implements C { + · ────────── + 5 │ baz() { } + ╰──── + × Identifier `x` has already been declared ╭─[typescript/tests/cases/compiler/importAndVariableDeclarationConflict3.ts:5:8] 4 │ @@ -21037,6 +21058,13 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private · ╰── `,` expected ╰──── + × TS(1172): 'extends' clause already seen + ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration1.ts:1:19] + 1 │ class C extends A extends B { + · ─────── + 2 │ } + ╰──── + × Constructor implementation is missing. ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration10.ts:2:4] 1 │ class C { @@ -21093,6 +21121,13 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 3 │ constructor() { } ╰──── + × TS(1175): 'implements' clause already seen + ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration2.ts:1:22] + 1 │ class C implements A implements B { + · ────────── + 2 │ } + ╰──── + × Function implementation is missing or not immediately following the declaration. ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration21.ts:2:5] 1 │ class C { @@ -21125,6 +21160,27 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 8 │ } ╰──── + × TS(1173): 'extends' clause must precede 'implements' clause + ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration3.ts:1:22] + 1 │ class C implements A extends B { + · ─────── + 2 │ } + ╰──── + + × TS(1172): 'extends' clause already seen + ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration4.ts:1:32] + 1 │ class C extends A implements B extends C { + · ─────── + 2 │ } + ╰──── + + × TS(1175): 'implements' clause already seen + ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration5.ts:1:32] + 1 │ class C extends A implements B implements C { + · ────────── + 2 │ } + ╰──── + × Constructor implementation is missing. ╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration8.ts:2:3] 1 │ class C { @@ -22058,6 +22114,13 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private 3 │ } ╰──── + × TS(1172): 'extends' clause already seen + ╭─[typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration1.ts:1:23] + 1 │ interface I extends A extends B { + · ─────── + 2 │ } + ╰──── + × 'public' modifier cannot be used here. ╭─[typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration3.ts:1:1] 1 │ public interface I {