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
9 changes: 9 additions & 0 deletions crates/oxc_parser/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,15 @@ pub fn cannot_appear_on_a_type_parameter(modifier: &Modifier) -> OxcDiagnostic {
.with_label(modifier.span)
}

#[cold]
pub fn can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
modifier: ModifierKind,
span: Span,
) -> OxcDiagnostic {
ts_error("1274", format!("'{modifier}' modifier can only appear on a type parameter of a class, interface or type alias."))
.with_label(span)
}

pub fn cannot_appear_on_a_parameter(modifier: &Modifier) -> OxcDiagnostic {
ts_error("1090", format!("'{}' modifier cannot appear on a parameter.", modifier.kind))
.with_label(modifier.span)
Expand Down
12 changes: 10 additions & 2 deletions crates/oxc_parser/src/js/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,16 @@ impl<'a> ParserImpl<'a> {
}

fn parse_class_element_name(&mut self, modifiers: &Modifiers<'a>) -> (PropertyKey<'a>, bool) {
if let Some(modifier) = modifiers.iter().find(|m| m.kind == ModifierKind::Const) {
self.error(diagnostics::const_class_member(modifier.span));
for modifier in modifiers.iter() {
match modifier.kind {
ModifierKind::Const => {
self.error(diagnostics::const_class_member(modifier.span));
}
ModifierKind::In | ModifierKind::Out => {
self.error(diagnostics::can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(modifier.kind, modifier.span));
}
_ => {}
}
}
match self.cur_kind() {
Kind::PrivateIdentifier => {
Expand Down
31 changes: 31 additions & 0 deletions crates/oxc_semantic/src/checker/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,39 @@ fn ts_error<M: Into<Cow<'static, str>>>(code: &'static str, message: M) -> OxcDi
OxcDiagnostic::error(message).with_error_code("TS", code)
}

fn can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
modifier: &str,
span: Span,
) -> OxcDiagnostic {
ts_error("1274", format!("'{modifier}' modifier can only appear on a type parameter of a class, interface or type alias."))
.with_label(span)
}

pub fn check_ts_type_parameter<'a>(param: &TSTypeParameter<'a>, ctx: &SemanticBuilder<'a>) {
check_type_name_is_reserved(&param.name, ctx, "Type parameter");
if param.r#in || param.out {
let is_allowed_node = matches!(
// skip parent TSTypeParameterDeclaration
ctx.nodes.ancestor_kinds(ctx.current_node_id).nth(1),
Some(
AstKind::TSInterfaceDeclaration(_)
| AstKind::Class(_)
| AstKind::TSTypeAliasDeclaration(_)
)
);
if !is_allowed_node {
if param.r#in {
ctx.error(can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
"in", param.span,
));
}
if param.out {
ctx.error(can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias(
"out", param.span,
));
}
}
}
}

/// '?' at the end of a type is not valid TypeScript syntax. Did you mean to write 'number | null | undefined'?(17019)
Expand Down
64 changes: 64 additions & 0 deletions tasks/coverage/snapshots/parser_babel.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14878,6 +14878,38 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: Remove the duplicate modifier.

× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:104:5]
103 │ class C {
104 │ in a = 0; // Error
· ──
105 │ out b = 0; // Error
╰────

× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:105:5]
104 │ in a = 0; // Error
105 │ out b = 0; // Error
· ───
106 │ }
╰────

× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:100:21]
99 │
100 │ declare function f1<in T>(x: T): void; // Error
· ────
101 │ declare function f2<out T>(): T; // Error
╰────

× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations/input.ts:101:21]
100 │ declare function f1<in T>(x: T): void; // Error
101 │ declare function f2<out T>(): T; // Error
· ─────
102 │
╰────

× TS(1273): 'public' modifier cannot be used on a type parameter.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:95:10]
94 │
Expand All @@ -14904,6 +14936,38 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: Remove the duplicate modifier.

× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:104:5]
103 │ class C {
104 │ in a = 0; // Error
· ──
105 │ out b = 0; // Error
╰────

× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:105:5]
104 │ in a = 0; // Error
105 │ out b = 0; // Error
· ───
106 │ }
╰────

× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:100:21]
99 │
100 │ declare function f1<in T>(x: T): void; // Error
· ────
101 │ declare function f2<out T>(): T; // Error
╰────

× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-babel-7/input.ts:101:21]
100 │ declare function f1<in T>(x: T): void; // Error
101 │ declare function f2<out T>(): T; // Error
· ─────
102 │
╰────

× Unexpected token. Did you mean `{'>'}` or `&gt;`?
╭─[babel/packages/babel-parser/test/fixtures/typescript/types/variance-annotations-with-jsx/input.tsx:2:11]
1 │ // valid JSX
Expand Down
32 changes: 32 additions & 0 deletions tasks/coverage/snapshots/parser_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -27683,6 +27683,38 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
╰────
help: Remove the duplicate modifier.

× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:104:5]
103 │ class C {
104 │ in a = 0; // Error
· ──
105 │ out b = 0; // Error
╰────

× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:105:5]
104 │ in a = 0; // Error
105 │ out b = 0; // Error
· ───
106 │ }
╰────

× TS(1274): 'in' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:100:21]
99 │
100 │ declare function f1<in T>(x: T): void; // Error
· ────
101 │ declare function f2<out T>(): T; // Error
╰────

× TS(1274): 'out' modifier can only appear on a type parameter of a class, interface or type alias.
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:101:21]
100 │ declare function f1<in T>(x: T): void; // Error
101 │ declare function f2<out T>(): T; // Error
· ─────
102 │
╰────

× Identifier expected. 'in' is a reserved word that cannot be used here.
╭─[typescript/tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotationsWithCircularlyReferencesError.ts:1:12]
1 │ type T1<in in> = T1 // Error: circularly references
Expand Down
Loading