Skip to content

Commit aa2a4cb

Browse files
committed
feat(parser): add TS1274 error
1 parent b7e3849 commit aa2a4cb

File tree

5 files changed

+146
-2
lines changed

5 files changed

+146
-2
lines changed

crates/oxc_parser/src/diagnostics.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,15 @@ pub fn cannot_appear_on_a_type_parameter(modifier: &Modifier) -> OxcDiagnostic {
686686
.with_label(modifier.span)
687687
}
688688

689+
#[cold]
690+
pub fn can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
691+
modifier: ModifierKind,
692+
span: Span,
693+
) -> OxcDiagnostic {
694+
ts_error("1274", format!("'{modifier}' modifier can only appear on a type parameter of a class, interface or type alias."))
695+
.with_label(span)
696+
}
697+
689698
pub fn cannot_appear_on_a_parameter(modifier: &Modifier) -> OxcDiagnostic {
690699
ts_error("1090", format!("'{}' modifier cannot appear on a parameter.", modifier.kind))
691700
.with_label(modifier.span)

crates/oxc_parser/src/js/class.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,16 @@ impl<'a> ParserImpl<'a> {
317317
}
318318

319319
fn parse_class_element_name(&mut self, modifiers: &Modifiers<'a>) -> (PropertyKey<'a>, bool) {
320-
if let Some(modifier) = modifiers.iter().find(|m| m.kind == ModifierKind::Const) {
321-
self.error(diagnostics::const_class_member(modifier.span));
320+
for modifier in modifiers.iter() {
321+
match modifier.kind {
322+
ModifierKind::Const => {
323+
self.error(diagnostics::const_class_member(modifier.span));
324+
}
325+
ModifierKind::In | ModifierKind::Out => {
326+
self.error(diagnostics::can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(modifier.kind, modifier.span));
327+
}
328+
_ => {}
329+
}
322330
}
323331
match self.cur_kind() {
324332
Kind::PrivateIdentifier => {

crates/oxc_semantic/src/checker/typescript.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,39 @@ fn ts_error<M: Into<Cow<'static, str>>>(code: &'static str, message: M) -> OxcDi
1414
OxcDiagnostic::error(message).with_error_code("TS", code)
1515
}
1616

17+
fn can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
18+
modifier: &str,
19+
span: Span,
20+
) -> OxcDiagnostic {
21+
ts_error("1274", format!("'{modifier}' modifier can only appear on a type parameter of a class, interface or type alias."))
22+
.with_label(span)
23+
}
24+
1725
pub fn check_ts_type_parameter<'a>(param: &TSTypeParameter<'a>, ctx: &SemanticBuilder<'a>) {
1826
check_type_name_is_reserved(&param.name, ctx, "Type parameter");
27+
if param.r#in || param.out {
28+
let is_allowed_node = matches!(
29+
// skip parent TSTypeParameterDeclaration
30+
ctx.nodes.ancestor_kinds(ctx.current_node_id).nth(1),
31+
Some(
32+
AstKind::TSInterfaceDeclaration(_)
33+
| AstKind::Class(_)
34+
| AstKind::TSTypeAliasDeclaration(_)
35+
)
36+
);
37+
if !is_allowed_node {
38+
if param.r#in {
39+
ctx.error(can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
40+
"in", param.span,
41+
));
42+
}
43+
if param.out {
44+
ctx.error(can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
45+
"out", param.span,
46+
));
47+
}
48+
}
49+
}
1950
}
2051

2152
/// '?' at the end of a type is not valid TypeScript syntax. Did you mean to write 'number | null | undefined'?(17019)

tasks/coverage/snapshots/parser_babel.snap

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14852,6 +14852,38 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
1485214852
╰────
1485314853
help: Remove the duplicate modifier.
1485414854

14855+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14856+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:104:5]
14857+
103 │ class C {
14858+
104 │ in a = 0; // Error
14859+
· ──
14860+
105 │ out b = 0; // Error
14861+
╰────
14862+
14863+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14864+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:105:5]
14865+
104 │ in a = 0; // Error
14866+
105 │ out b = 0; // Error
14867+
· ───
14868+
106 │ }
14869+
╰────
14870+
14871+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14872+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:100:21]
14873+
99 │
14874+
100 │ declare function f1<in T>(x: T): void; // Error
14875+
· ────
14876+
101 │ declare function f2<out T>(): T; // Error
14877+
╰────
14878+
14879+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14880+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:101:21]
14881+
100 │ declare function f1<in T>(x: T): void; // Error
14882+
101 │ declare function f2<out T>(): T; // Error
14883+
· ─────
14884+
102 │
14885+
╰────
14886+
1485514887
× TS(1273): 'public' modifier cannot be used on a type parameter.
1485614888
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:95:10]
1485714889
94 │
@@ -14878,6 +14910,38 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
1487814910
╰────
1487914911
help: Remove the duplicate modifier.
1488014912

14913+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14914+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:104:5]
14915+
103 │ class C {
14916+
104 │ in a = 0; // Error
14917+
· ──
14918+
105 │ out b = 0; // Error
14919+
╰────
14920+
14921+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14922+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:105:5]
14923+
104 │ in a = 0; // Error
14924+
105 │ out b = 0; // Error
14925+
· ───
14926+
106 │ }
14927+
╰────
14928+
14929+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14930+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:100:21]
14931+
99 │
14932+
100 │ declare function f1<in T>(x: T): void; // Error
14933+
· ────
14934+
101 │ declare function f2<out T>(): T; // Error
14935+
╰────
14936+
14937+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14938+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:101:21]
14939+
100 │ declare function f1<in T>(x: T): void; // Error
14940+
101 │ declare function f2<out T>(): T; // Error
14941+
· ─────
14942+
102 │
14943+
╰────
14944+
1488114945
× Unexpected token. Did you mean `{'>'}` or `&gt;`?
1488214946
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-with-jsx/input.tsx:2:11]
1488314947
1 │ // valid JSX

tasks/coverage/snapshots/parser_typescript.snap

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27635,6 +27635,38 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
2763527635
╰────
2763627636
help: Remove the duplicate modifier.
2763727637

27638+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
27639+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:104:5]
27640+
103 │ class C {
27641+
104 │ in a = 0; // Error
27642+
· ──
27643+
105 │ out b = 0; // Error
27644+
╰────
27645+
27646+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
27647+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:105:5]
27648+
104 │ in a = 0; // Error
27649+
105 │ out b = 0; // Error
27650+
· ───
27651+
106 │ }
27652+
╰────
27653+
27654+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
27655+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:100:21]
27656+
99 │
27657+
100 │ declare function f1<in T>(x: T): void; // Error
27658+
· ────
27659+
101 │ declare function f2<out T>(): T; // Error
27660+
╰────
27661+
27662+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
27663+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:101:21]
27664+
100 │ declare function f1<in T>(x: T): void; // Error
27665+
101 │ declare function f2<out T>(): T; // Error
27666+
· ─────
27667+
102 │
27668+
╰────
27669+
2763827670
× Identifier expected. 'in' is a reserved word that cannot be used here.
2763927671
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotationsWithCircularlyReferencesError.ts:1:12]
2764027672
1 │ type T1<in in> = T1 // Error: circularly references

0 commit comments

Comments
 (0)