Skip to content

Commit 5616ad5

Browse files
committed
feat(parser,semantic): add TS1274 error (#15441)
Added TS1274 error `'in' modifier can only appear on a type parameter of a class, interface or type alias.`.
1 parent 5fa6bb8 commit 5616ad5

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
@@ -701,6 +701,15 @@ pub fn cannot_appear_on_a_type_parameter(modifier: &Modifier) -> OxcDiagnostic {
701701
.with_label(modifier.span)
702702
}
703703

704+
#[cold]
705+
pub fn can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
706+
modifier: ModifierKind,
707+
span: Span,
708+
) -> OxcDiagnostic {
709+
ts_error("1274", format!("'{modifier}' modifier can only appear on a type parameter of a class, interface or type alias."))
710+
.with_label(span)
711+
}
712+
704713
pub fn cannot_appear_on_a_parameter(modifier: &Modifier) -> OxcDiagnostic {
705714
ts_error("1090", format!("'{}' modifier cannot appear on a parameter.", modifier.kind))
706715
.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
@@ -14878,6 +14878,38 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
1487814878
╰────
1487914879
help: Remove the duplicate modifier.
1488014880

14881+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14882+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:104:5]
14883+
103 │ class C {
14884+
104 │ in a = 0; // Error
14885+
· ──
14886+
105 │ out b = 0; // Error
14887+
╰────
14888+
14889+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14890+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:105:5]
14891+
104 │ in a = 0; // Error
14892+
105 │ out b = 0; // Error
14893+
· ───
14894+
106 │ }
14895+
╰────
14896+
14897+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14898+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:100:21]
14899+
99 │
14900+
100 │ declare function f1<in T>(x: T): void; // Error
14901+
· ────
14902+
101 │ declare function f2<out T>(): T; // Error
14903+
╰────
14904+
14905+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14906+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:101:21]
14907+
100 │ declare function f1<in T>(x: T): void; // Error
14908+
101 │ declare function f2<out T>(): T; // Error
14909+
· ─────
14910+
102 │
14911+
╰────
14912+
1488114913
× TS(1273): 'public' modifier cannot be used on a type parameter.
1488214914
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:95:10]
1488314915
94 │
@@ -14904,6 +14936,38 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
1490414936
╰────
1490514937
help: Remove the duplicate modifier.
1490614938

14939+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14940+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:104:5]
14941+
103 │ class C {
14942+
104 │ in a = 0; // Error
14943+
· ──
14944+
105 │ out b = 0; // Error
14945+
╰────
14946+
14947+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14948+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:105:5]
14949+
104 │ in a = 0; // Error
14950+
105 │ out b = 0; // Error
14951+
· ───
14952+
106 │ }
14953+
╰────
14954+
14955+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
14956+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:100:21]
14957+
99 │
14958+
100 │ declare function f1<in T>(x: T): void; // Error
14959+
· ────
14960+
101 │ declare function f2<out T>(): T; // Error
14961+
╰────
14962+
14963+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
14964+
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:101:21]
14965+
100 │ declare function f1<in T>(x: T): void; // Error
14966+
101 │ declare function f2<out T>(): T; // Error
14967+
· ─────
14968+
102 │
14969+
╰────
14970+
1490714971
× Unexpected token. Did you mean `{'>'}` or `&gt;`?
1490814972
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-with-jsx/input.tsx:2:11]
1490914973
1 │ // valid JSX

tasks/coverage/snapshots/parser_typescript.snap

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

27686+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
27687+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:104:5]
27688+
103 │ class C {
27689+
104 │ in a = 0; // Error
27690+
· ──
27691+
105 │ out b = 0; // Error
27692+
╰────
27693+
27694+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
27695+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:105:5]
27696+
104 │ in a = 0; // Error
27697+
105 │ out b = 0; // Error
27698+
· ───
27699+
106 │ }
27700+
╰────
27701+
27702+
× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
27703+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:100:21]
27704+
99 │
27705+
100 │ declare function f1<in T>(x: T): void; // Error
27706+
· ────
27707+
101 │ declare function f2<out T>(): T; // Error
27708+
╰────
27709+
27710+
× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
27711+
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:101:21]
27712+
100 │ declare function f1<in T>(x: T): void; // Error
27713+
101 │ declare function f2<out T>(): T; // Error
27714+
· ─────
27715+
102 │
27716+
╰────
27717+
2768627718
× Identifier expected. 'in' is a reserved word that cannot be used here.
2768727719
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotationsWithCircularlyReferencesError.ts:1:12]
2768827720
1 │ type T1<in in> = T1 // Error: circularly references

0 commit comments

Comments
 (0)