Skip to content

Commit

Permalink
feat(semantic): check for invalid interface heritage clauses (#4928)
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac committed Aug 16, 2024
1 parent 9c64b12 commit 80d0d1f
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 3 deletions.
1 change: 1 addition & 0 deletions crates/oxc_semantic/src/checker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
AstKind::YieldExpression(expr) => js::check_yield_expression(expr, node, ctx),
AstKind::VariableDeclarator(decl) => ts::check_variable_declarator(decl, ctx),
AstKind::SimpleAssignmentTarget(target) => ts::check_simple_assignment_target(target, ctx),
AstKind::TSInterfaceDeclaration(decl) => ts::check_ts_interface_declaration(decl, ctx),
AstKind::TSTypeParameterDeclaration(declaration) => {
ts::check_ts_type_parameter_declaration(declaration, ctx);
}
Expand Down
25 changes: 25 additions & 0 deletions crates/oxc_semantic/src/checker/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,31 @@ pub fn check_array_pattern<'a>(pattern: &ArrayPattern<'a>, ctx: &SemanticBuilder
}
}

/// An interface can only extend an identifier/qualified-name with optional type arguments.(2499)
fn invalid_interface_extend(span0: Span) -> OxcDiagnostic {
ts_error(
"2499",
"An interface can only extend an identifier/qualified-name with optional type arguments.",
)
.with_label(span0)
}

pub fn check_ts_interface_declaration<'a>(
decl: &TSInterfaceDeclaration<'a>,
ctx: &SemanticBuilder<'a>,
) {
if let Some(extends) = &decl.extends {
for extend in extends {
if !matches!(
&extend.expression,
Expression::Identifier(_) | Expression::StaticMemberExpression(_),
) {
ctx.error(invalid_interface_extend(extend.span));
}
}
}
}

fn not_allowed_namespace_declaration(span0: Span) -> OxcDiagnostic {
OxcDiagnostic::error(
"A namespace declaration is only allowed at the top level of a namespace or module.",
Expand Down
3 changes: 3 additions & 0 deletions crates/oxc_semantic/tests/integration/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,12 +342,15 @@ fn test_type_query() {

#[test]
fn test_ts_interface_heritage() {
// NOTE: interface heritage clauses can only be identifiers or qualified
// names, but we handle references on invalid heritage clauses anyways.
SemanticTester::ts(
"
type Heritage = { x: number; y: string; };
interface A extends (Heritage.x) {}
",
)
.expect_errors(true)
.has_some_symbol("Heritage")
.has_number_of_references(1)
.test();
Expand Down
19 changes: 16 additions & 3 deletions tasks/coverage/parser_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ commit: d8086f14
parser_typescript Summary:
AST Parsed : 6446/6456 (99.85%)
Positive Passed: 6423/6456 (99.49%)
Negative Passed: 1167/5653 (20.64%)
Negative Passed: 1169/5653 (20.68%)
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
Expand Down Expand Up @@ -1158,7 +1158,6 @@ Expect Syntax Error: "compiler/interfaceImplementation6.ts"
Expect Syntax Error: "compiler/interfaceImplementation7.ts"
Expect Syntax Error: "compiler/interfaceImplementation8.ts"
Expect Syntax Error: "compiler/interfaceInheritance.ts"
Expect Syntax Error: "compiler/interfaceMayNotBeExtendedWitACall.ts"
Expect Syntax Error: "compiler/interfaceMemberValidation.ts"
Expect Syntax Error: "compiler/interfaceNameAsIdentifier.ts"
Expect Syntax Error: "compiler/interfacePropertiesWithSameName2.ts"
Expand Down Expand Up @@ -3317,7 +3316,6 @@ Expect Syntax Error: "conformance/interfaces/declarationMerging/twoGenericInterf
Expect Syntax Error: "conformance/interfaces/declarationMerging/twoInterfacesDifferentRootModule.ts"
Expect Syntax Error: "conformance/interfaces/declarationMerging/twoInterfacesDifferentRootModule2.ts"
Expect Syntax Error: "conformance/interfaces/interfaceDeclarations/derivedInterfaceIncompatibleWithBaseIndexer.ts"
Expect Syntax Error: "conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts"
Expect Syntax Error: "conformance/interfaces/interfaceDeclarations/interfaceExtendsObjectIntersectionErrors.ts"
Expect Syntax Error: "conformance/interfaces/interfaceDeclarations/interfaceThatHidesBaseProperty2.ts"
Expect Syntax Error: "conformance/interfaces/interfaceDeclarations/interfaceThatIndirectlyInheritsFromItself.ts"
Expand Down Expand Up @@ -8119,6 +8117,14 @@ Expect to Parse: "conformance/salsa/typeFromPropertyAssignmentWithExport.ts"
· ╰── `{` expected
╰────

× TS(2499): An interface can only extend an identifier/qualified-name with optional type arguments.
╭─[compiler/interfaceMayNotBeExtendedWitACall.ts:3:24]
2 │
3 │ interface blue extends color() { // error
· ───────
4 │
╰────

× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[compiler/interfaceNaming1.ts:1:10]
1 │ interface { }
Expand Down Expand Up @@ -17990,6 +17996,13 @@ Expect to Parse: "conformance/salsa/typeFromPropertyAssignmentWithExport.ts"
11 │ I // This should be the identifier 'I'
╰────

× TS(2499): An interface can only extend an identifier/qualified-name with optional type arguments.
╭─[conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts:5:22]
4 │
5 │ interface C1 extends Foo?.Bar {}
· ────────
╰────

× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[conformance/interfaces/interfaceDeclarations/interfacesWithPredefinedTypesAsNames.ts:5:10]
4 │ interface boolean { }
Expand Down

0 comments on commit 80d0d1f

Please sign in to comment.