Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions crates/oxc_parser/src/js/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl<'a> ParserImpl<'a> {
type_parameters,
super_class,
super_type_parameters,
implements,
implements.map_or_else(|| self.ast.vec(), |(_, implements)| implements),
body,
modifiers.contains_abstract(),
modifiers.contains_declare(),
Expand All @@ -116,9 +116,9 @@ impl<'a> ParserImpl<'a> {

pub(crate) fn parse_heritage_clause(
&mut self,
) -> (Option<Extends<'a>>, Vec<'a, TSClassImplements<'a>>) {
) -> (Option<Extends<'a>>, Option<(Span, Vec<'a, TSClassImplements<'a>>)>) {
let mut extends = None;
let mut implements = self.ast.vec();
let mut implements: Option<(Span, Vec<'a, TSClassImplements<'a>>)> = None;

loop {
match self.cur_kind() {
Expand All @@ -127,20 +127,28 @@ impl<'a> ParserImpl<'a> {
self.error(diagnostics::extends_clause_already_seen(
self.cur_token().span(),
));
} else if !implements.is_empty() {
} 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_empty() {
if implements.is_some() {
self.error(diagnostics::implements_clause_already_seen(
self.cur_token().span(),
));
}
implements.extend(self.parse_ts_implements_clause());
let implements_kw_span = self.cur_token().span();
if let Some((_, implements)) = implements.as_mut() {
implements.extend(self.parse_ts_implements_clause());
} else {
implements = Some((
implements_kw_span,
self.ast.vec_from_iter(self.parse_ts_implements_clause()),
));
}
}
_ => break,
}
Expand Down
7 changes: 2 additions & 5 deletions crates/oxc_parser/src/ts/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,8 @@ impl<'a> ParserImpl<'a> {
ModifierFlags::DECLARE,
diagnostics::modifier_cannot_be_used_here,
);
if !implements.is_empty() {
self.error(diagnostics::interface_implements(Span::new(
implements.first().unwrap().span.start,
implements.last().unwrap().span.end,
)));
if let Some((implements_kw_span, _)) = implements {
self.error(diagnostics::interface_implements(implements_kw_span));
}
for extend in &extends {
if !extend.expression.is_entity_name_expression() {
Expand Down
1 change: 1 addition & 0 deletions tasks/coverage/misc/fail/oxc-11789-1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
interface i<>implements
1 change: 1 addition & 0 deletions tasks/coverage/misc/fail/oxc-11789-2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
interface i<>implements K {}
25 changes: 24 additions & 1 deletion tasks/coverage/snapshots/parser_misc.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
parser_misc Summary:
AST Parsed : 43/43 (100.00%)
Positive Passed: 43/43 (100.00%)
Negative Passed: 45/45 (100.00%)
Negative Passed: 47/47 (100.00%)

× Identifier `b` has already been declared
╭─[misc/fail/oxc-10159.js:1:22]
Expand Down Expand Up @@ -118,6 +118,29 @@ Negative Passed: 45/45 (100.00%)
· ╰── `{` expected
╰────

× TS(1098): Type parameter list cannot be empty.
╭─[misc/fail/oxc-11789-1.ts:1:12]
1 │ interface i<>implements
· ──
╰────

× Unexpected token
╭─[misc/fail/oxc-11789-1.ts:1:25]
1 │ interface i<>implements
╰────

× TS(1098): Type parameter list cannot be empty.
╭─[misc/fail/oxc-11789-2.ts:1:12]
1 │ interface i<>implements K {}
· ──
╰────

× TS(1176): Interface declaration cannot have 'implements' clause.
╭─[misc/fail/oxc-11789-2.ts:1:14]
1 │ interface i<>implements K {}
· ──────────
╰────

× Unexpected token
╭─[misc/fail/oxc-169.js:2:1]
1 │ 1<(V=82<<t-j0<(V=$<LBI<(V=ut<I<(V=$<LBI<(V=uIV=82<<t-j0<(V=$<LBI<(V=ut<I<(V=$<LBI<(V<II>
Expand Down
12 changes: 6 additions & 6 deletions tasks/coverage/snapshots/parser_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -13180,10 +13180,10 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
help: Try insert a semicolon here

× TS(1176): Interface declaration cannot have 'implements' clause.
╭─[typescript/tests/cases/compiler/interfaceWithImplements1.ts:3:27]
╭─[typescript/tests/cases/compiler/interfaceWithImplements1.ts:3:16]
2 │
3 │ interface IBar implements IFoo {
· ────
· ──────────
4 │ }
╰────

Expand Down Expand Up @@ -25475,10 +25475,10 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
╰────

× TS(1176): Interface declaration cannot have 'implements' clause.
╭─[typescript/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceThatInheritsFromItself.ts:10:26]
╭─[typescript/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceThatInheritsFromItself.ts:10:15]
9 │
10 │ interface Bar implements Bar { // error
· ───
· ──────────
11 │ }
╰────

Expand Down Expand Up @@ -27522,9 +27522,9 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
╰────

× TS(1176): Interface declaration cannot have 'implements' clause.
╭─[typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration2.ts:1:24]
╭─[typescript/tests/cases/conformance/parser/ecmascript5/InterfaceDeclarations/parserInterfaceDeclaration2.ts:1:13]
1 │ interface I implements A {
·
· ─────────
2 │ }
╰────

Expand Down
Loading