refactor(rome_js_parser): Inroduce TypeContext
MODIFY
crates/rome_js_parser/src/state.rs
crates/rome_js_parser/src/state.rs
@@ -164,12 +164,6 @@ impl ParserState {
.contains(ParsingContextFlags::BREAK_ALLOWED)
}
- pub fn allow_conditional_type(&self) -> bool {
- !self
- .parsing_context
- .contains(ParsingContextFlags::DISALLOW_CONDITIONAL_TYPE)
- }
-
pub fn strict(&self) -> Option<&StrictMode> {
self.strict.as_ref()
}
@@ -377,7 +371,7 @@ bitflags! {
/// snapshots each individual boolean field to allow restoring the previous state. With bitflags, all that
/// is needed is to copy away the flags field and restore it after.
#[derive(Default)]
- pub(crate) struct ParsingContextFlags: u16 {
+ pub(crate) struct ParsingContextFlags: u8 {
/// Whether the parser is in a generator function like `function* a() {}`
/// Matches the `Yield` parameter in the ECMA spec
const IN_GENERATOR = 1 << 0;
@@ -403,8 +397,6 @@ bitflags! {
/// Whatever the parser is in a TypeScript ambient context
const AMBIENT_CONTEXT = 1 << 7;
- const DISALLOW_CONDITIONAL_TYPE = 1 << 8;
-
const LOOP = Self::BREAK_ALLOWED.bits | Self::CONTINUE_ALLOWED.bits;
/// Bitmask of all the flags that must be reset (shouldn't be inherited) when the parser enters a function
@@ -588,27 +580,6 @@ impl ChangeParserStateFlags for EnterType {
}
}
-pub(crate) struct EnterConditionalTypes(bool);
-
-impl EnterConditionalTypes {
- pub(crate) const fn allow() -> Self {
- Self(true)
- }
- pub(crate) const fn disallow() -> Self {
- Self(false)
- }
-}
-
-impl ChangeParserStateFlags for EnterConditionalTypes {
- fn compute_new_flags(&self, existing: ParsingContextFlags) -> ParsingContextFlags {
- if self.0 {
- existing - ParsingContextFlags::DISALLOW_CONDITIONAL_TYPE
- } else {
- existing | ParsingContextFlags::DISALLOW_CONDITIONAL_TYPE
- }
- }
-}
-
#[derive(Default)]
pub(crate) struct EnterAmbientContextSnapshot {
flags: ParsingContextFlags,

MODIFY
crates/rome_js_parser/src/syntax/class.rs
crates/rome_js_parser/src/syntax/class.rs
@@ -30,7 +30,7 @@ use crate::syntax::typescript::ts_parse_error::{
use crate::syntax::typescript::{
is_reserved_type_name, parse_ts_implements_clause, parse_ts_return_type_annotation,
parse_ts_type_annotation, parse_ts_type_arguments, parse_ts_type_parameters,
- skip_ts_decorators,
+ skip_ts_decorators, TypeContext,
};
use crate::JsSyntaxFeature::TypeScript;
@@ -253,9 +253,13 @@ fn parse_class(p: &mut JsParser, kind: ClassKind) -> CompletedMarker {
// test ts ts_class_type_parameters
// class BuildError<A, B, C> {}
TypeScript
- .parse_exclusive_syntax(p, parse_ts_type_parameters, |p, type_parameters| {
+ .parse_exclusive_syntax(
+ p,
+ |p| parse_ts_type_parameters(p, TypeContext::default()),
+ |p, type_parameters| {
ts_only_syntax_error(p, "class type parameters", type_parameters.range(p))
- })
+ },
+ )
.ok();
eat_class_heritage_clause(p);
@@ -683,7 +687,7 @@ fn parse_class_member_impl(
// get a<A>(): A {}
// set a<A>(value: A) {}
// }
- if let Present(type_parameters) = parse_ts_type_parameters(p) {
+ if let Present(type_parameters) = parse_ts_type_parameters(p, TypeContext::default()) {
p.error(ts_accessor_type_parameters_error(p, &type_parameters))
}
@@ -1148,9 +1152,11 @@ fn parse_method_class_member_rest(
let optional = optional_member_token(p);
TypeScript
- .parse_exclusive_syntax(p, parse_ts_type_parameters, |p, marker| {
- ts_only_syntax_error(p, "type parameters", marker.range(p))
- })
+ .parse_exclusive_syntax(
+ p,
+ |p| parse_ts_type_parameters(p, TypeContext::default()),
+ |p, marker| ts_only_syntax_error(p, "type parameters", marker.range(p)),
+ )
.ok();
let parameter_context = if modifiers.is_signature() {
@@ -1431,7 +1437,7 @@ fn parse_constructor_class_member_body(
// test_err ts ts_constructor_type_parameters
// class A { constructor<A>(b) {} }
- if let Present(type_parameters) = parse_ts_type_parameters(p) {
+ if let Present(type_parameters) = parse_ts_type_parameters(p, TypeContext::default()) {
p.error(ts_constructor_type_parameters_error(p, &type_parameters));
}

MODIFY
crates/rome_js_parser/src/syntax/expr.rs
crates/rome_js_parser/src/syntax/expr.rs
@@ -592,7 +592,7 @@ fn parse_binary_or_logical_expression_recursive(
// as;
// let precedence = "hello" as const + 3 as number as number;
if op == T![as] {
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
let mut as_expression = m.complete(p, TS_AS_EXPRESSION);
if TypeScript.is_unsupported(p) {
@@ -621,7 +621,7 @@ fn parse_binary_or_logical_expression_recursive(
// test_err ts_satisfies_expression
// let x = "hello" satisfies string;
if op == T![satisfies] {
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
let mut satisfies_expression = m.complete(p, TS_SATISFIES_EXPRESSION);
if TypeScript.is_unsupported(p) {

MODIFY
crates/rome_js_parser/src/syntax/function.rs
crates/rome_js_parser/src/syntax/function.rs
@@ -14,7 +14,7 @@ use crate::syntax::stmt::{is_semi, parse_block_impl, semi, StatementContext};
use crate::syntax::typescript::ts_parse_error::ts_only_syntax_error;
use crate::syntax::typescript::{
parse_ts_return_type_annotation, parse_ts_type_annotation, parse_ts_type_parameters,
- skip_ts_decorators, try_parse,
+ skip_ts_decorators, try_parse, TypeContext,
};
use crate::JsSyntaxFeature::TypeScript;
@@ -229,12 +229,16 @@ fn parse_function(p: &mut JsParser, m: Marker, kind: FunctionKind) -> CompletedM
}
TypeScript
- .parse_exclusive_syntax(p, parse_ts_type_parameters, |p, marker| {
+ .parse_exclusive_syntax(
+ p,
+ |p| parse_ts_type_parameters(p, TypeContext::default()),
+ |p, marker| {
p.err_builder(
"type parameters can only be used in TypeScript files",
marker.range(p),
)
- })
+ },
+ )
.ok();
let parameter_context = if !kind.is_expression() && TypeScript.is_supported(p) {
@@ -407,7 +411,7 @@ fn parse_ambient_function(
let binding = parse_binding(p);
let binding_range = p.cur_range();
- parse_ts_type_parameters(p).ok();
+ parse_ts_type_parameters(p, TypeContext::default()).ok();
parse_parameter_list(p, ParameterContext::Declaration, SignatureFlags::empty())
.or_add_diagnostic(p, expected_parameters);
parse_ts_return_type_annotation(p).ok();
@@ -536,7 +540,7 @@ fn try_parse_parenthesized_arrow_function_head(
};
if p.at(T![<]) {
- parse_ts_type_parameters(p).ok();
+ parse_ts_type_parameters(p, TypeContext::default()).ok();
if ambiguity.is_disallowed() && p.last() != Some(T![>]) {
return Err(m);

MODIFY
crates/rome_js_parser/src/syntax/object.rs
crates/rome_js_parser/src/syntax/object.rs
@@ -17,6 +17,7 @@ use crate::syntax::typescript::ts_parse_error::{
};
use crate::syntax::typescript::{
parse_ts_return_type_annotation, parse_ts_type_annotation, parse_ts_type_parameters,
+ TypeContext,
};
use crate::JsSyntaxFeature::TypeScript;
use crate::{JsParser, ParseRecovery};
@@ -258,7 +259,7 @@ fn parse_getter_object_member(p: &mut JsParser) -> ParsedSyntax {
// test_err ts ts_object_getter_type_parameters
// ({ get a<A>(): A {} });
- if let Present(type_parameters) = parse_ts_type_parameters(p) {
+ if let Present(type_parameters) = parse_ts_type_parameters(p, TypeContext::default()) {
p.error(ts_accessor_type_parameters_error(p, &type_parameters))
}
@@ -290,7 +291,7 @@ fn parse_setter_object_member(p: &mut JsParser) -> ParsedSyntax {
// test_err ts ts_object_setter_type_parameters
// ({ set a<A>(value: A) {} });
- if let Present(type_parameters) = parse_ts_type_parameters(p) {
+ if let Present(type_parameters) = parse_ts_type_parameters(p, TypeContext::default()) {
p.error(ts_accessor_type_parameters_error(p, &type_parameters))
}
@@ -432,9 +433,13 @@ fn parse_method_object_member(p: &mut JsParser) -> ParsedSyntax {
/// Parses the body of a method object member starting right after the member name.
fn parse_method_object_member_body(p: &mut JsParser, flags: SignatureFlags) {
TypeScript
- .parse_exclusive_syntax(p, parse_ts_type_parameters, |p, type_parameters| {
+ .parse_exclusive_syntax(
+ p,
+ |p| parse_ts_type_parameters(p, TypeContext::default()),
+ |p, type_parameters| {
ts_only_syntax_error(p, "type parameters", type_parameters.range(p))
- })
+ },
+ )
.ok();
parse_parameter_list(p, ParameterContext::Implementation, flags)

MODIFY
crates/rome_js_parser/src/syntax/stmt.rs
crates/rome_js_parser/src/syntax/stmt.rs
@@ -1835,7 +1835,7 @@ fn parse_catch_declaration(p: &mut JsParser) -> ParsedSyntax {
let annotation = p.start();
p.bump(T![:]);
- if let Some(ty) = parse_ts_type(p).or_add_diagnostic(p, expected_ts_type) {
+ if let Some(ty) = parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type) {
if !matches!(ty.kind(p), TS_ANY_TYPE | TS_UNKNOWN_TYPE) {
p.error(
p

MODIFY
crates/rome_js_parser/src/syntax/typescript.rs
crates/rome_js_parser/src/syntax/typescript.rs
@@ -73,7 +73,7 @@ pub(crate) fn parse_ts_type_assertion_expression(
let m = p.start();
p.bump(T![<]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
p.expect(T![>]);
parse_unary_expr(p, context).or_add_diagnostic(p, expected_expression);
Present(m.complete(p, TS_TYPE_ASSERTION_EXPRESSION))

MODIFY
crates/rome_js_parser/src/syntax/typescript/statement.rs
crates/rome_js_parser/src/syntax/typescript/statement.rs
@@ -15,7 +15,7 @@ use crate::syntax::stmt::{semi, STMT_RECOVERY_SET};
use crate::syntax::typescript::ts_parse_error::expected_ts_type;
use crate::syntax::typescript::{
expect_ts_type_list, parse_ts_identifier_binding, parse_ts_implements_clause, parse_ts_name,
- parse_ts_type, parse_ts_type_parameters, TypeMembers,
+ parse_ts_type, parse_ts_type_parameters, TypeContext, TypeMembers,
};
use crate::{syntax, Absent, JsParser, ParseRecovery, ParsedSyntax, Present};
use rome_js_syntax::{JsSyntaxKind::*, *};
@@ -207,9 +207,9 @@ pub(crate) fn parse_ts_type_alias_declaration(p: &mut JsParser) -> ParsedSyntax
p.expect(T![type]);
parse_ts_identifier_binding(p, super::TsIdentifierContext::Type)
.or_add_diagnostic(p, expected_identifier);
- parse_ts_type_parameters(p).ok();
+ parse_ts_type_parameters(p, TypeContext::default()).ok();
p.expect(T![=]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
semi(p, TextRange::new(start, p.cur_range().end()));
@@ -298,7 +298,7 @@ pub(crate) fn parse_ts_interface_declaration(p: &mut JsParser) -> ParsedSyntax {
p.expect(T![interface]);
parse_ts_identifier_binding(p, super::TsIdentifierContext::Type)
.or_add_diagnostic(p, expected_identifier);
- parse_ts_type_parameters(p).ok();
+ parse_ts_type_parameters(p, TypeContext::default()).ok();
eat_interface_heritage_clause(p);
p.expect(T!['{']);
TypeMembers.parse_list(p);

MODIFY
crates/rome_js_parser/src/syntax/typescript/types.rs
crates/rome_js_parser/src/syntax/typescript/types.rs
use crate::parser::{RecoveryError, RecoveryResult};
use crate::prelude::*;
-use crate::state::{EnterConditionalTypes, EnterType, SignatureFlags};
+use crate::state::{EnterType, SignatureFlags};
use crate::syntax::expr::{
is_at_binary_operator, is_at_expression, is_at_identifier, is_nth_at_identifier,
is_nth_at_identifier_or_keyword, parse_big_int_literal_expression, parse_identifier,
@@ -20,7 +20,7 @@ use crate::syntax::object::{
use crate::syntax::stmt::optional_semi;
use crate::syntax::typescript::try_parse;
use crate::syntax::typescript::ts_parse_error::{expected_ts_type, expected_ts_type_parameter};
-
+use bitflags::bitflags;
use rome_parser::parse_lists::{ParseNodeList, ParseSeparatedList};
use crate::lexer::{LexContext, ReLexContext};
@@ -33,6 +33,36 @@ use rome_js_syntax::{JsSyntaxKind::*, *};
use super::{expect_ts_index_signature_member, is_at_ts_index_signature_member, MemberParent};
+bitflags! {
+ /// Context tracking state that applies to the parsing of all types
+ #[derive(Default)]
+ pub(crate) struct TypeContext: u8 {
+ /// Whether conditional types `extends string ? string : number` are allowed in the current context.
+ ///
+ /// By default, conditional types are allowed.
+ const DISALLOW_CONDITIONAL_TYPES = 1 << 0;
+ }
+}
+
+impl TypeContext {
+ pub(crate) fn and_allow_conditional_types(self, allow: bool) -> Self {
+ self.and(TypeContext::DISALLOW_CONDITIONAL_TYPES, !allow)
+ }
+
+ pub(crate) const fn is_conditional_type_allowed(&self) -> bool {
+ !self.contains(TypeContext::DISALLOW_CONDITIONAL_TYPES)
+ }
+
+ /// Adds the `flag` if `set` is `true`, otherwise removes the `flag`
+ fn and(self, flag: TypeContext, set: bool) -> Self {
+ if set {
+ self | flag
+ } else {
+ self - flag
+ }
+ }
+}
+
pub(crate) fn is_reserved_type_name(name: &str) -> bool {
name.len() <= 6
&& name.len() >= 3
@@ -63,7 +93,7 @@ pub(crate) fn parse_ts_type_annotation(p: &mut JsParser) -> ParsedSyntax {
let m = p.start();
p.bump(T![:]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
Present(m.complete(p, TS_TYPE_ANNOTATION))
}
@@ -80,12 +110,12 @@ pub(crate) fn parse_ts_return_type_annotation(p: &mut JsParser) -> ParsedSyntax
let m = p.start();
p.bump(T![:]);
- parse_ts_return_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_return_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
Present(m.complete(p, TS_RETURN_TYPE_ANNOTATION))
}
-fn parse_ts_call_signature(p: &mut JsParser) {
- parse_ts_type_parameters(p).ok();
+fn parse_ts_call_signature(p: &mut JsParser, context: TypeContext) {
+ parse_ts_type_parameters(p, context).ok();
parse_parameter_list(p, ParameterContext::Declaration, SignatureFlags::empty())
.or_add_diagnostic(p, expected_parameters);
parse_ts_return_type_annotation(p).ok();
@@ -100,7 +130,7 @@ fn parse_ts_type_parameter_name(p: &mut JsParser) -> ParsedSyntax {
//
// test_err ts ts_type_parameters_incomplete
// type A<T
-pub(crate) fn parse_ts_type_parameters(p: &mut JsParser) -> ParsedSyntax {
+pub(crate) fn parse_ts_type_parameters(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !is_nth_at_ts_type_parameters(p, 0) {
return Absent;
}
@@ -110,13 +140,13 @@ pub(crate) fn parse_ts_type_parameters(p: &mut JsParser) -> ParsedSyntax {
if p.at(T![>]) {
p.error(expected_ts_type_parameter(p, p.cur_range()));
}
- TsTypeParameterList.parse_list(p);
+ TsTypeParameterList(context).parse_list(p);
p.expect(T![>]);
Present(m.complete(p, TS_TYPE_PARAMETERS))
}
-struct TsTypeParameterList;
+struct TsTypeParameterList(TypeContext);
impl ParseSeparatedList for TsTypeParameterList {
type Kind = JsSyntaxKind;
@@ -125,7 +155,7 @@ impl ParseSeparatedList for TsTypeParameterList {
const LIST_KIND: Self::Kind = TS_TYPE_PARAMETER_LIST;
fn parse_element(&mut self, p: &mut JsParser) -> ParsedSyntax {
- parse_ts_type_parameter(p)
+ parse_ts_type_parameter(p, self.0)
}
fn is_at_list_end(&self, p: &mut JsParser) -> bool {
@@ -153,10 +183,10 @@ impl ParseSeparatedList for TsTypeParameterList {
}
}
-fn parse_ts_type_parameter(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_type_parameter(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
parse_ts_type_parameter_name(p).map(|name| {
let m = name.precede(p);
- parse_ts_type_constraint_clause(p).ok();
+ parse_ts_type_constraint_clause(p, context).ok();
parse_ts_default_type_clause(p).ok();
m.complete(p, TS_TYPE_PARAMETER)
})
@@ -165,7 +195,7 @@ fn parse_ts_type_parameter(p: &mut JsParser) -> ParsedSyntax {
// test ts ts_type_constraint_clause
// type A<X extends number> = X;
// type B<X extends number | string> = { a: X }
-fn parse_ts_type_constraint_clause(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_type_constraint_clause(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !p.at(T![extends]) {
return Absent;
}
@@ -173,7 +203,7 @@ fn parse_ts_type_constraint_clause(p: &mut JsParser) -> ParsedSyntax {
let m = p.start();
p.expect(T![extends]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
Present(m.complete(p, TS_TYPE_CONSTRAINT_CLAUSE))
}
@@ -187,7 +217,7 @@ fn parse_ts_default_type_clause(p: &mut JsParser) -> ParsedSyntax {
let m = p.start();
p.bump(T![=]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
Present(m.complete(p, TS_DEFAULT_TYPE_CLAUSE))
}
@@ -196,21 +226,21 @@ fn is_nth_at_ts_type_parameters(p: &mut JsParser, n: usize) -> bool {
}
#[inline(always)]
-pub(crate) fn parse_ts_type(p: &mut JsParser) -> ParsedSyntax {
+pub(crate) fn parse_ts_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
p.with_state(EnterType, |p| {
if is_at_constructor_type(p) {
- return parse_ts_constructor_type(p);
+ return parse_ts_constructor_type(p, context);
}
if is_at_function_type(p) {
- return parse_ts_function_type(p);
+ return parse_ts_function_type(p, context);
}
- let left = parse_ts_union_type_or_higher(p);
+ let left = parse_ts_union_type_or_higher(p, context);
// test ts ts_conditional_type_call_signature_lhs
// type X<V> = V extends (...args: any[]) => any ? (...args: Parameters<V>) => void : Function;
- if p.state().allow_conditional_type() {
+ if context.is_conditional_type_allowed() {
left.map(|left| {
// test ts ts_conditional_type
// type A = number;
@@ -226,12 +256,12 @@ pub(crate) fn parse_ts_type(p: &mut JsParser) -> ParsedSyntax {
let m = left.precede(p);
p.expect(T![extends]);
- p.with_state(EnterConditionalTypes::disallow(), parse_ts_type)
+ parse_ts_type(p, context.and_allow_conditional_types(false))
.or_add_diagnostic(p, expected_ts_type);
p.expect(T![?]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
p.expect(T![:]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
m.complete(p, TS_CONDITIONAL_TYPE)
} else {
left
@@ -247,15 +277,15 @@ pub(crate) fn parse_ts_type(p: &mut JsParser) -> ParsedSyntax {
// type A = string | number;
// type B = | A | void | null;
// type C = A & C | C;
-fn parse_ts_union_type_or_higher(p: &mut JsParser) -> ParsedSyntax {
- parse_ts_union_or_intersection_type(p, IntersectionOrUnionType::Union)
+fn parse_ts_union_type_or_higher(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
+ parse_ts_union_or_intersection_type(p, IntersectionOrUnionType::Union, context)
}
// test ts ts_intersection_type
// type A = string & number;
// type B = & A & void & null;
-fn parse_ts_intersection_type_or_higher(p: &mut JsParser) -> ParsedSyntax {
- parse_ts_union_or_intersection_type(p, IntersectionOrUnionType::Intersection)
+fn parse_ts_intersection_type_or_higher(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
+ parse_ts_union_or_intersection_type(p, IntersectionOrUnionType::Intersection, context)
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
@@ -290,10 +320,10 @@ impl IntersectionOrUnionType {
}
#[inline]
- fn parse_element(&self, p: &mut JsParser) -> ParsedSyntax {
+ fn parse_element(&self, p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
match self {
- IntersectionOrUnionType::Union => parse_ts_intersection_type_or_higher(p),
- IntersectionOrUnionType::Intersection => parse_ts_primary_type(p),
+ IntersectionOrUnionType::Union => parse_ts_intersection_type_or_higher(p, context),
+ IntersectionOrUnionType::Intersection => parse_ts_primary_type(p, context),
}
}
}
@@ -302,6 +332,7 @@ impl IntersectionOrUnionType {
fn parse_ts_union_or_intersection_type(
p: &mut JsParser,
ty_kind: IntersectionOrUnionType,
+ context: TypeContext,
) -> ParsedSyntax {
// Leading operator: `& A & B`
if p.at(ty_kind.operator()) {
@@ -309,21 +340,21 @@ fn parse_ts_union_or_intersection_type(
p.bump(ty_kind.operator());
let list = p.start();
ty_kind
- .parse_element(p)
+ .parse_element(p, context)
.or_add_diagnostic(p, expected_ts_type);
- eat_ts_union_or_intersection_type_elements(p, ty_kind);
+ eat_ts_union_or_intersection_type_elements(p, ty_kind, context);
list.complete(p, ty_kind.list_kind());
Present(m.complete(p, ty_kind.kind()))
} else {
- let first = ty_kind.parse_element(p);
+ let first = ty_kind.parse_element(p, context);
if p.at(ty_kind.operator()) {
let list = first.precede(p);
- eat_ts_union_or_intersection_type_elements(p, ty_kind);
+ eat_ts_union_or_intersection_type_elements(p, ty_kind, context);
let completed_list = list.complete(p, ty_kind.list_kind());
let m = completed_list.precede(p);
@@ -336,17 +367,21 @@ fn parse_ts_union_or_intersection_type(
}
#[inline]
-fn eat_ts_union_or_intersection_type_elements(p: &mut JsParser, ty_kind: IntersectionOrUnionType) {
+fn eat_ts_union_or_intersection_type_elements(
+ p: &mut JsParser,
+ ty_kind: IntersectionOrUnionType,
+ context: TypeContext,
+) {
while p.at(ty_kind.operator()) {
p.bump(ty_kind.operator());
ty_kind
- .parse_element(p)
+ .parse_element(p, context)
.or_add_diagnostic(p, expected_ts_type);
}
}
-fn parse_ts_primary_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_primary_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
// test ts ts_inferred_type
// type A = infer B;
// type B = { a: infer U; b: infer U};
@@ -354,7 +389,7 @@ fn parse_ts_primary_type(p: &mut JsParser) -> ParsedSyntax {
let m = p.start();
p.expect(T![infer]);
parse_ts_type_parameter_name(p).or_add_diagnostic(p, expected_identifier);
- try_parse_constraint_of_infer_type(p).ok();
+ try_parse_constraint_of_infer_type(p, context).ok();
return Present(m.complete(p, TS_INFER_TYPE));
}
@@ -367,29 +402,25 @@ fn parse_ts_primary_type(p: &mut JsParser) -> ParsedSyntax {
if is_type_operator {
let m = p.start();
p.bump_any();
- parse_ts_primary_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_primary_type(p, context).or_add_diagnostic(p, expected_ts_type);
return Present(m.complete(p, TS_TYPE_OPERATOR_TYPE));
}
- p.with_state(EnterConditionalTypes::allow(), parse_postfix_type_or_higher)
+ parse_postfix_type_or_higher(p, context.and_allow_conditional_types(true))
}
-fn try_parse_constraint_of_infer_type(p: &mut JsParser) -> ParsedSyntax {
+fn try_parse_constraint_of_infer_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !p.at(T![extends]) {
return Absent;
}
try_parse(p, |p| {
- let parsed = p
- .with_state(
- EnterConditionalTypes::disallow(),
- parse_ts_type_constraint_clause,
- )
+ let parsed = parse_ts_type_constraint_clause(p, context.and_allow_conditional_types(false))
.expect("Type constraint clause because parser is positioned at expect clause");
// Rewind if conditional types are allowed, and the parser is at the `?` token because
// this should instead be parsed as a conditional type.
- if p.state.allow_conditional_type() && p.at(T![?]) {
+ if context.is_conditional_type_allowed() && p.at(T![?]) {
Err(())
} else {
Ok(Present(parsed))
@@ -398,15 +429,15 @@ fn try_parse_constraint_of_infer_type(p: &mut JsParser) -> ParsedSyntax {
.unwrap_or(Absent)
}
-fn parse_postfix_type_or_higher(p: &mut JsParser) -> ParsedSyntax {
- parse_ts_non_array_type(p).map(|primary_type| {
+fn parse_postfix_type_or_higher(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
+ parse_ts_non_array_type(p, context).map(|primary_type| {
let mut left = primary_type;
while p.at(T!['[']) && !p.has_preceding_line_break() {
let m = left.precede(p);
p.bump(T!['[']);
- left = if parse_ts_type(p).is_present() {
+ left = if parse_ts_type(p, context).is_present() {
// test ts ts_indexed_access_type
// type A = string[number];
// type B = string[number][number][number][];
@@ -425,7 +456,7 @@ fn parse_postfix_type_or_higher(p: &mut JsParser) -> ParsedSyntax {
})
}
-fn parse_ts_non_array_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_non_array_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
// test ts ts_predefined_type
// type A = any
// type B = number;
@@ -442,12 +473,12 @@ fn parse_ts_non_array_type(p: &mut JsParser) -> ParsedSyntax {
T!['('] => parse_ts_parenthesized_type(p),
T!['{'] => {
if is_at_start_of_mapped_type(p) {
- parse_ts_mapped_type(p)
+ parse_ts_mapped_type(p, context)
} else {
parse_ts_object_type(p)
}
}
- T!['['] => parse_ts_tuple_type(p),
+ T!['['] => parse_ts_tuple_type(p, context),
T![void] => {
let m = p.start();
p.expect(T![void]);
@@ -456,7 +487,7 @@ fn parse_ts_non_array_type(p: &mut JsParser) -> ParsedSyntax {
JS_NUMBER_LITERAL | JS_STRING_LITERAL | TRUE_KW | FALSE_KW | T![null] => {
parse_ts_literal_type(p)
}
- BACKTICK => parse_ts_template_literal_type(p),
+ BACKTICK => parse_ts_template_literal_type(p, context),
T![-] if p.nth_at(1, JS_NUMBER_LITERAL) => parse_ts_literal_type(p),
T![this] => parse_ts_this_type(p),
T![typeof] => {
@@ -584,8 +615,7 @@ fn parse_ts_parenthesized_type(p: &mut JsParser) -> ParsedSyntax {
let m = p.start();
p.bump(T!['(']);
- p.with_state(EnterConditionalTypes::allow(), parse_ts_type)
- .or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
p.expect(T![')']);
Present(m.complete(p, TS_PARENTHESIZED_TYPE))
}
@@ -629,7 +659,7 @@ fn is_at_start_of_mapped_type(p: &mut JsParser) -> bool {
// type Getters<Type> = {
// [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
// };
-fn parse_ts_mapped_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_mapped_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !p.at(T!['{']) {
return Absent;
}
@@ -640,8 +670,8 @@ fn parse_ts_mapped_type(p: &mut JsParser) -> ParsedSyntax {
p.expect(T!['[']);
parse_ts_type_parameter_name(p).or_add_diagnostic(p, expected_ts_type_parameter);
p.expect(T![in]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
- parse_ts_mapped_type_as_clause(p).ok();
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_mapped_type_as_clause(p, context).ok();
p.expect(T![']']);
parse_ts_mapped_type_optional_modifier_clause(p).ok();
parse_ts_type_annotation(p).ok();
@@ -651,14 +681,14 @@ fn parse_ts_mapped_type(p: &mut JsParser) -> ParsedSyntax {
Present(m.complete(p, TS_MAPPED_TYPE))
}
-fn parse_ts_mapped_type_as_clause(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_mapped_type_as_clause(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !p.at(T![as]) {
return Absent;
}
let m = p.start();
p.bump_remap(T![as]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
Present(m.complete(p, TS_MAPPED_TYPE_AS_CLAUSE))
}
@@ -753,7 +783,7 @@ impl ParseNodeList for TypeMembers {
const LIST_KIND: Self::Kind = TS_TYPE_MEMBER_LIST;
fn parse_element(&mut self, p: &mut JsParser) -> ParsedSyntax {
- parse_ts_type_member(p)
+ parse_ts_type_member(p, TypeContext::default())
}
fn is_at_list_end(&self, p: &mut JsParser) -> bool {
@@ -770,7 +800,7 @@ impl ParseNodeList for TypeMembers {
}
}
-fn parse_ts_type_member(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_type_member(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
// test ts ts_index_signature_member
// type A = { [a: number]: string }
// type B = { readonly [a: number]: string }
@@ -787,13 +817,13 @@ fn parse_ts_type_member(p: &mut JsParser) -> ParsedSyntax {
}
match p.cur() {
- T!['('] | T![<] => parse_ts_call_signature_type_member(p),
+ T!['('] | T![<] => parse_ts_call_signature_type_member(p, context),
T![new] if is_at_ts_construct_signature_type_member(p) => {
- parse_ts_construct_signature_type_member(p)
+ parse_ts_construct_signature_type_member(p, context)
}
T![get] if is_nth_at_type_member_name(p, 1) => parse_ts_getter_signature_type_member(p),
T![set] if is_nth_at_type_member_name(p, 1) => parse_ts_setter_signature_type_member(p),
- _ => parse_ts_property_or_method_signature_type_member(p),
+ _ => parse_ts_property_or_method_signature_type_member(p, context),
}
}
@@ -803,7 +833,10 @@ fn parse_ts_type_member(p: &mut JsParser) -> ParsedSyntax {
// type C = { m(a: string, b: number, c: string): any }
// type D = { readonly: string, readonly a: number }
// type E = { m<A, B>(a: A, b: B): never }
-fn parse_ts_property_or_method_signature_type_member(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_property_or_method_signature_type_member(
+ p: &mut JsParser,
+ context: TypeContext,
+) -> ParsedSyntax {
if !is_at_object_member_name(p) {
return Absent;
}
@@ -822,7 +855,7 @@ fn parse_ts_property_or_method_signature_type_member(p: &mut JsParser) -> Parsed
p.eat(T![?]);
if p.at(T!['(']) || p.at(T![<]) {
- parse_ts_call_signature(p);
+ parse_ts_call_signature(p, context);
parse_ts_type_member_semi(p);
let method = m.complete(p, TS_METHOD_SIGNATURE_TYPE_MEMBER);
@@ -845,13 +878,13 @@ fn parse_ts_property_or_method_signature_type_member(p: &mut JsParser) -> Parsed
// type A = { (): string; }
// type B = { (a, b, c): number }
// type C = { <A, B>(a: A, b: B): number }
-fn parse_ts_call_signature_type_member(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_call_signature_type_member(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !(p.at(T!['(']) || p.at(T![<])) {
return Absent;
}
let m = p.start();
- parse_ts_call_signature(p);
+ parse_ts_call_signature(p, context);
parse_ts_type_member_semi(p);
Present(m.complete(p, TS_CALL_SIGNATURE_TYPE_MEMBER))
}
@@ -860,14 +893,17 @@ fn parse_ts_call_signature_type_member(p: &mut JsParser) -> ParsedSyntax {
// type A = { new (): string; }
// type B = { new (a: string, b: number) }
// type C = { new <A, B>(a: A, b: B): string }
-fn parse_ts_construct_signature_type_member(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_construct_signature_type_member(
+ p: &mut JsParser,
+ context: TypeContext,
+) -> ParsedSyntax {
if !is_at_ts_construct_signature_type_member(p) {
return Absent;
}
let m = p.start();
p.expect(T![new]);
- parse_ts_type_parameters(p).ok();
+ parse_ts_type_parameters(p, context).ok();
parse_parameter_list(p, ParameterContext::Declaration, SignatureFlags::empty())
.or_add_diagnostic(p, expected_parameters);
parse_ts_type_annotation(p).ok();
@@ -931,20 +967,20 @@ fn parse_ts_setter_signature_type_member(p: &mut JsParser) -> ParsedSyntax {
//
// test_err ts ts_tuple_type_incomplete
// type A = [string,
-fn parse_ts_tuple_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_tuple_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !p.at(T!['[']) {
return Absent;
}
let m = p.start();
p.bump(T!['[']);
- TsTupleTypeElementList.parse_list(p);
+ TsTupleTypeElementList(context).parse_list(p);
p.expect(T![']']);
Present(m.complete(p, TS_TUPLE_TYPE))
}
-struct TsTupleTypeElementList;
+struct TsTupleTypeElementList(TypeContext);
impl ParseSeparatedList for TsTupleTypeElementList {
type Kind = JsSyntaxKind;
@@ -959,7 +995,7 @@ impl ParseSeparatedList for TsTupleTypeElementList {
parse_name(p).or_add_diagnostic(p, expected_identifier);
let has_question_mark = p.eat(T![?]);
p.bump(T![:]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, self.0).or_add_diagnostic(p, expected_ts_type);
let mut syntax = m.complete(p, TS_NAMED_TUPLE_TYPE_ELEMENT);
@@ -980,11 +1016,11 @@ impl ParseSeparatedList for TsTupleTypeElementList {
if p.at(T![...]) {
let m = p.start();
p.bump(T![...]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, self.0).or_add_diagnostic(p, expected_ts_type);
return Present(m.complete(p, TS_REST_TUPLE_TYPE_ELEMENT));
}
- let ty = parse_ts_type(p);
+ let ty = parse_ts_type(p, self.0);
if p.at(T![?]) {
let m = ty.precede_or_add_diagnostic(p, expected_ts_type);
@@ -1097,7 +1133,7 @@ fn parse_ts_literal_type(p: &mut JsParser) -> ParsedSyntax {
// type B = "b"
// type C = `${A B}bcd`
// type D = `${A B`
-fn parse_ts_template_literal_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_template_literal_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !p.at(BACKTICK) {
return Absent;
}
@@ -1111,7 +1147,7 @@ fn parse_ts_template_literal_type(p: &mut JsParser) -> ParsedSyntax {
TS_TEMPLATE_CHUNK_ELEMENT,
TS_TEMPLATE_ELEMENT,
false,
- |p| parse_ts_type(p).or_add_diagnostic(p, expected_ts_type),
+ |p| parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type),
);
elements.complete(p, TS_TEMPLATE_ELEMENT_LIST);
p.expect(BACKTICK);
@@ -1127,7 +1163,7 @@ fn is_at_ts_construct_signature_type_member(p: &mut JsParser) -> bool {
// type B = abstract new(a: string, b: number) => string;
// type C = new<A, B>(a: A, b: B) => string;
// type D = abstract new<A, B>(a: A, b: B) => string;
-fn parse_ts_constructor_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_constructor_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !is_at_constructor_type(p) {
return Absent;
}
@@ -1136,11 +1172,11 @@ fn parse_ts_constructor_type(p: &mut JsParser) -> ParsedSyntax {
p.eat(T![abstract]);
p.expect(T![new]);
- parse_ts_type_parameters(p).ok();
+ parse_ts_type_parameters(p, context).ok();
parse_parameter_list(p, ParameterContext::Declaration, SignatureFlags::empty())
.or_add_diagnostic(p, expected_parameters);
p.expect(T![=>]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
Present(m.complete(p, TS_CONSTRUCTOR_TYPE))
}
@@ -1193,17 +1229,17 @@ fn is_at_function_type(p: &mut JsParser) -> bool {
// type G = <A, B>(a: A, b: B) => string
// type H = (a: any) => a is string;
// type I = ({ a, b }?) => string;
-fn parse_ts_function_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_function_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
if !p.at(T![<]) && !p.at(T!['(']) {
return Absent;
}
let m = p.start();
- parse_ts_type_parameters(p).ok();
+ parse_ts_type_parameters(p, context).ok();
parse_parameter_list(p, ParameterContext::Declaration, SignatureFlags::empty())
.or_add_diagnostic(p, expected_parameters);
p.expect(T![=>]);
- parse_ts_return_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_return_type(p, TypeContext::default()).or_add_diagnostic(p, expected_ts_type);
Present(m.complete(p, TS_FUNCTION_TYPE))
}
@@ -1215,18 +1251,16 @@ fn parse_ts_function_type(p: &mut JsParser) -> ParsedSyntax {
// bar(test: string): I
// asserts(): boolean;
// }
-fn parse_ts_return_type(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_return_type(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
let is_asserts_predicate =
p.at(T![asserts]) && (is_nth_at_identifier(p, 1) || p.nth_at(1, T![this]));
let is_is_predicate = (is_at_identifier(p) || p.at(T![this])) && p.nth_at(1, T![is]);
- p.with_state(EnterConditionalTypes::allow(), |p| {
if !p.has_nth_preceding_line_break(1) && (is_asserts_predicate || is_is_predicate) {
- parse_ts_type_predicate(p)
+ parse_ts_type_predicate(p, context)
} else {
- parse_ts_type(p)
+ parse_ts_type(p, context)
}
- })
}
// test ts ts_type_predicate
@@ -1235,7 +1269,7 @@ fn parse_ts_return_type(p: &mut JsParser) -> ParsedSyntax {
// type C = (a) => asserts a;
// type asserts = string;
// type D = () => asserts;
-fn parse_ts_type_predicate(p: &mut JsParser) -> ParsedSyntax {
+fn parse_ts_type_predicate(p: &mut JsParser, context: TypeContext) -> ParsedSyntax {
let m = p.start();
let is_asserts = p.eat(T![asserts]);
@@ -1246,11 +1280,11 @@ fn parse_ts_type_predicate(p: &mut JsParser) -> ParsedSyntax {
if is_asserts && p.at(T![is]) {
let condition = p.start();
p.expect(T![is]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
condition.complete(p, TS_ASSERTS_CONDITION);
} else if !is_asserts {
p.expect(T![is]);
- parse_ts_type(p).or_add_diagnostic(p, expected_ts_type);
+ parse_ts_type(p, context).or_add_diagnostic(p, expected_ts_type);
}
let kind = if is_asserts {
@@ -1596,7 +1630,7 @@ impl ParseSeparatedList for TypeArgumentsList {
const LIST_KIND: Self::Kind = TS_TYPE_ARGUMENT_LIST;
fn parse_element(&mut self, p: &mut JsParser) -> ParsedSyntax {
- parse_ts_type(p)
+ parse_ts_type(p, TypeContext::default())
}
fn is_at_list_end(&self, p: &mut JsParser) -> bool {

refactor(rome_js_parser): Inroduce TypeContext (#4123)