diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index 9358bc20234f5..e17af24b834da 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -1,6 +1,8 @@ use oxc_diagnostics::OxcDiagnostic; use oxc_span::Span; +use crate::modifiers::Modifier; + #[cold] pub fn redeclaration(x0: &str, declare_span: Span, redeclare_span: Span) -> OxcDiagnostic { OxcDiagnostic::error(format!("Identifier `{x0}` has already been declared")).with_labels([ @@ -399,7 +401,43 @@ pub fn jsx_element_no_match(span0: Span, span1: Span, name: &str) -> OxcDiagnost .with_labels([span0, span1]) } +// ================================= MODIFIERS ================================= + +#[cold] +pub fn modifier_cannot_be_used_here(modifier: &Modifier) -> OxcDiagnostic { + OxcDiagnostic::error(format!("'{}' modifier cannot be used here.", modifier.kind)) + .with_label(modifier.span) +} + +/// TS(1030) +#[cold] +pub fn modifier_already_seen(modifier: &Modifier) -> OxcDiagnostic { + OxcDiagnostic::error(format!("TS1030: '{}' modifier already seen.", modifier.kind)) + .with_label(modifier.span) + .with_help("Remove the duplicate modifier.") +} + +/// TS(1273) +#[cold] +pub fn cannot_appear_on_a_type_parameter(modifier: &Modifier) -> OxcDiagnostic { + OxcDiagnostic::error(format!( + "'{}' modifier cannot be used on a type parameter.", + modifier.kind + )) + .with_label(modifier.span) +} +/// TS(1090) +pub fn cannot_appear_on_a_parameter(modifier: &Modifier) -> OxcDiagnostic { + OxcDiagnostic::error(format!( + "TS1090: '{}' modifier cannot appear on a parameter.", + modifier.kind + )) + .with_label(modifier.span) +} + +/// TS(18010) #[cold] -pub fn modifier_cannot_be_used_here(span: Span, name: &str) -> OxcDiagnostic { - OxcDiagnostic::error(format!("'{name}' modifier cannot be used here.")).with_label(span) +pub fn accessibility_modifier_on_private_property(modifier: &Modifier) -> OxcDiagnostic { + OxcDiagnostic::error("An accessibility modifier cannot be used with a private identifier.") + .with_label(modifier.span) } diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index a4b5da73d0937..788a8d7daaf91 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -8,7 +8,7 @@ use crate::{ diagnostics, lexer::Kind, list::NormalList, - modifiers::{ModifierKind, Modifiers}, + modifiers::{ModifierFlags, ModifierKind, Modifiers}, Context, ParserImpl, StatementContext, }; @@ -25,7 +25,11 @@ impl<'a> ParserImpl<'a> { stmt_ctx: StatementContext, start_span: Span, ) -> Result> { - let decl = self.parse_class_declaration(start_span, &Modifiers::empty())?; + let modifiers = self.parse_modifiers( + /* allow_decorators */ true, /* permit_const_as_modifier */ false, + /* stop_on_start_of_class_static_block */ true, + ); + let decl = self.parse_class_declaration(start_span, &modifiers)?; if stmt_ctx.is_single_statement() { self.error(diagnostics::class_declaration(Span::new( @@ -86,14 +90,11 @@ impl<'a> ParserImpl<'a> { } let body = self.parse_class_body()?; - for modifier in modifiers.iter() { - if !matches!(modifier.kind, ModifierKind::Declare | ModifierKind::Abstract) { - self.error(diagnostics::modifier_cannot_be_used_here( - modifier.span, - modifier.kind.as_str(), - )); - } - } + self.verify_modifiers( + modifiers, + ModifierFlags::DECLARE | ModifierFlags::ABSTRACT, + diagnostics::modifier_cannot_be_used_here, + ); Ok(self.ast.class( r#type, @@ -105,8 +106,8 @@ impl<'a> ParserImpl<'a> { super_type_parameters, implements, decorators, - modifiers.is_contains_abstract(), - modifiers.is_contains_declare(), + modifiers.contains_abstract(), + modifiers.contains_declare(), )) } @@ -178,28 +179,21 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_class_element(&mut self) -> Result> { let span = self.start_span(); - self.eat_decorators()?; + let modifiers = self.parse_modifiers(true, false, true); let mut kind = MethodDefinitionKind::Method; - let mut r#async = false; let mut generator = false; let mut key_name = None; - let modifier = self.parse_class_element_modifiers(false); - - let accessor = { - let token = self.peek_token(); - !token.is_on_new_line && token.kind.is_class_element_name_start() - } && self.eat(Kind::Accessor); - - let accessibility = modifier.accessibility(); - - let declare = modifier.declare(); - let readonly = modifier.readonly(); - let r#override = modifier.r#override(); - let r#abstract = modifier.r#abstract(); - let mut r#static = modifier.r#static(); + let accessibility = modifiers.accessibility(); + let accessor = modifiers.contains(ModifierKind::Accessor); + let declare = modifiers.contains(ModifierKind::Declare); + let readonly = modifiers.contains(ModifierKind::Readonly); + let r#override = modifiers.contains(ModifierKind::Override); + let r#abstract = modifiers.contains(ModifierKind::Abstract); + let mut r#static = modifiers.contains(ModifierKind::Static); + let mut r#async = modifiers.contains(ModifierKind::Async); if self.at(Kind::Static) { // static { block } @@ -268,6 +262,14 @@ impl<'a> ParserImpl<'a> { let definite = self.eat(Kind::Bang); if let PropertyKey::PrivateIdentifier(private_ident) = &key { + // `private #foo`, etc. is illegal + if self.ts_enabled() { + self.verify_modifiers( + &modifiers, + ModifierFlags::all() - ModifierFlags::ACCESSIBILITY, + diagnostics::accessibility_modifier_on_private_property, + ); + } if private_ident.name == "constructor" { self.error(diagnostics::private_name_constructor(private_ident.span)); } diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index 88f774d50a5f7..08152dbae8ce0 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -7,7 +7,7 @@ use super::{VariableDeclarationContext, VariableDeclarationParent}; use crate::{ diagnostics, lexer::Kind, - modifiers::{ModifierKind, Modifiers}, + modifiers::{ModifierFlags, Modifiers}, ParserImpl, StatementContext, }; @@ -72,20 +72,17 @@ impl<'a> ParserImpl<'a> { self.asi()?; } - for modifier in modifiers.iter() { - if modifier.kind != ModifierKind::Declare { - self.error(diagnostics::modifier_cannot_be_used_here( - modifier.span, - modifier.kind.as_str(), - )); - } - } + self.verify_modifiers( + modifiers, + ModifierFlags::DECLARE, + diagnostics::modifier_cannot_be_used_here, + ); Ok(self.ast.variable_declaration( self.end_span(start_span), kind, declarations, - modifiers.is_contains_declare(), + modifiers.contains_declare(), )) } diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 1f549fb014342..de82711a61c82 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -10,7 +10,7 @@ use crate::{ diagnostics, lexer::Kind, list::SeparatedList, - modifiers::{ModifierKind, Modifiers}, + modifiers::{ModifierFlags, ModifierKind, Modifiers}, Context, ParserImpl, StatementContext, }; @@ -109,14 +109,11 @@ impl<'a> ParserImpl<'a> { self.asi()?; } - for modifier in modifiers.iter() { - if !matches!(modifier.kind, ModifierKind::Declare | ModifierKind::Async) { - self.error(diagnostics::modifier_cannot_be_used_here( - modifier.span, - modifier.kind.as_str(), - )); - } - } + self.verify_modifiers( + modifiers, + ModifierFlags::DECLARE | ModifierFlags::ASYNC, + diagnostics::modifier_cannot_be_used_here, + ); Ok(self.ast.function( function_type, @@ -124,7 +121,7 @@ impl<'a> ParserImpl<'a> { id, generator, r#async, - modifiers.is_contains_declare(), + modifiers.contains_declare(), this_param, params, body, diff --git a/crates/oxc_parser/src/js/list.rs b/crates/oxc_parser/src/js/list.rs index 7ac7cb5b918d2..72bb795c2fe07 100644 --- a/crates/oxc_parser/src/js/list.rs +++ b/crates/oxc_parser/src/js/list.rs @@ -8,6 +8,7 @@ use crate::{ diagnostics, lexer::Kind, list::{NormalList, SeparatedList}, + modifiers::ModifierFlags, ParserImpl, }; @@ -267,8 +268,15 @@ impl<'a> SeparatedList<'a> for FormalParameterList<'a> { let modifiers = p.parse_class_element_modifiers(true); let accessibility = modifiers.accessibility(); - let readonly = modifiers.readonly(); - let r#override = modifiers.r#override(); + let readonly = modifiers.contains_readonly(); + let r#override = modifiers.contains_override(); + p.verify_modifiers( + &modifiers, + ModifierFlags::ACCESSIBILITY + .union(ModifierFlags::READONLY) + .union(ModifierFlags::OVERRIDE), + diagnostics::cannot_appear_on_a_parameter, + ); match p.cur_kind() { Kind::This if p.ts_enabled() => { diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index 0ca9d89bada0a..bb94be48a3b20 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -289,7 +289,7 @@ impl<'a> ParserImpl<'a> { // For more information, please refer to self.eat_decorators()?; let modifiers = if self.ts_enabled() { - self.eat_modifiers_before_declaration().1 + self.eat_modifiers_before_declaration()? } else { Modifiers::empty() }; @@ -324,7 +324,7 @@ impl<'a> ParserImpl<'a> { .map(ExportDefaultDeclarationKind::ClassDeclaration)?, _ if self.at(Kind::Abstract) && self.peek_at(Kind::Class) && self.ts_enabled() => { // eat the abstract modifier - let (_, modifiers) = self.eat_modifiers_before_declaration(); + let modifiers = self.eat_modifiers_before_declaration()?; self.parse_class_declaration(decl_span, &modifiers) .map(ExportDefaultDeclarationKind::ClassDeclaration)? } diff --git a/crates/oxc_parser/src/js/object.rs b/crates/oxc_parser/src/js/object.rs index dcc4a0f0bfff0..21a54953aba38 100644 --- a/crates/oxc_parser/src/js/object.rs +++ b/crates/oxc_parser/src/js/object.rs @@ -5,7 +5,9 @@ use oxc_span::Span; use oxc_syntax::operator::AssignmentOperator; use super::list::ObjectExpressionProperties; -use crate::{lexer::Kind, list::SeparatedList, Context, ParserImpl}; +use crate::{ + diagnostics, lexer::Kind, list::SeparatedList, modifiers::Modifier, Context, ParserImpl, +}; impl<'a> ParserImpl<'a> { /// [Object Expression](https://tc39.es/ecma262/#sec-object-initializer) @@ -43,6 +45,23 @@ impl<'a> ParserImpl<'a> { } // GeneratorMethod Kind::Star if class_element_name => self.parse_property_definition_method(), + // Report and handle illegal modifiers + // e.g. const x = { public foo() {} } + modifier_kind + if self.ts_enabled() + && modifier_kind.is_modifier_kind() + && !matches!(peek_kind, Kind::Colon) => + { + if let Ok(modifier) = Modifier::try_from(self.cur_token()) { + self.error(diagnostics::modifier_cannot_be_used_here(&modifier)); + } else { + #[cfg(debug_assertions)] + panic!("Kind::is_modifier_kind() is true but the token could not be converted to a Modifier.") + } + // re-parse + self.bump_any(); + self.parse_property_definition() + } // IdentifierReference kind if kind.is_identifier_reference(false, false) // test Kind::Dot to ignore ({ foo.bar: baz }) diff --git a/crates/oxc_parser/src/lexer/kind.rs b/crates/oxc_parser/src/lexer/kind.rs index a9ac380097759..5d94a42558296 100644 --- a/crates/oxc_parser/src/lexer/kind.rs +++ b/crates/oxc_parser/src/lexer/kind.rs @@ -272,6 +272,12 @@ impl Kind { self.is_identifier_name() || self == Str || self.is_number() } + pub fn is_identifier_or_keyword(self) -> bool { + self.is_literal_property_name() + || matches!(self, Self::PrivateIdentifier) + || self.is_all_keyword() + } + pub fn is_variable_declaration(self) -> bool { matches!(self, Var | Let | Const) } diff --git a/crates/oxc_parser/src/modifiers.rs b/crates/oxc_parser/src/modifiers.rs index 89f088b12b7e0..4a7366574d122 100644 --- a/crates/oxc_parser/src/modifiers.rs +++ b/crates/oxc_parser/src/modifiers.rs @@ -2,10 +2,14 @@ use bitflags::bitflags; use oxc_allocator::Vec; use oxc_ast::ast::TSAccessibility; -use oxc_diagnostics::Result; -use oxc_span::Span; +use oxc_diagnostics::{OxcDiagnostic, Result}; +use oxc_span::{GetSpan, Span, SPAN}; -use crate::{lexer::Kind, ParserImpl}; +use crate::{ + diagnostics, + lexer::{Kind, Token}, + ParserImpl, +}; bitflags! { /// Bitflag of modifiers and contextual modifiers. @@ -57,6 +61,28 @@ impl From for ModifierFlags { } } +impl From for ModifierFlags { + fn from(kind: ModifierKind) -> Self { + match kind { + ModifierKind::Abstract => Self::ABSTRACT, + ModifierKind::Declare => Self::DECLARE, + ModifierKind::Private => Self::PRIVATE, + ModifierKind::Protected => Self::PROTECTED, + ModifierKind::Public => Self::PUBLIC, + ModifierKind::Static => Self::STATIC, + ModifierKind::Readonly => Self::READONLY, + ModifierKind::Override => Self::OVERRIDE, + ModifierKind::Async => Self::ASYNC, + ModifierKind::Const => Self::CONST, + ModifierKind::In => Self::IN, + ModifierKind::Out => Self::OUT, + ModifierKind::Export => Self::EXPORT, + ModifierKind::Default => Self::DEFAULT, + ModifierKind::Accessor => Self::ACCESSOR, + } + } +} + impl ModifierFlags { pub(crate) fn accessibility(self) -> Option { if self.contains(Self::PUBLIC) { @@ -71,70 +97,129 @@ impl ModifierFlags { } None } +} - pub(crate) fn readonly(self) -> bool { - self.contains(Self::READONLY) +#[derive(Debug, Hash)] +pub struct Modifier { + pub span: Span, + pub kind: ModifierKind, +} +impl Modifier { + #[inline] + pub fn is_static(&self) -> bool { + matches!(self.kind, ModifierKind::Static) } +} +impl TryFrom for Modifier { + type Error = >::Error; - pub(crate) fn declare(self) -> bool { - self.contains(Self::DECLARE) + fn try_from(tok: Token) -> std::result::Result { + ModifierKind::try_from(tok.kind).map(|kind| Self { span: tok.span(), kind }) } +} + +/// Symbol modifiers. Primarily used in TypeScript code, but some are also used +/// in JavaScript. +/// +/// ```ts +/// class Foo { +/// public readonly x: number +/// // ^^^^^^ ^^^^^^^^ +/// // these are modifiers +/// } +/// export const f = new foo() +/// // ^^^ This also counts as a modifier, but is also recorded separately as a +/// // named export declaration +/// ``` +#[derive(Debug, Hash)] +pub struct Modifiers<'a> { + /// May contain duplicates. + modifiers: Option>, + /// Bitflag representation of modifier kinds stored in [`Self::modifiers`]. + /// Pre-computed to save CPU cycles on [`Self::contains`] checks (`O(1)` + /// bitflag intersection vs `O(n)` linear search). + flags: ModifierFlags, +} - pub(crate) fn r#async(self) -> bool { - self.contains(Self::ASYNC) +impl<'a> Default for Modifiers<'a> { + fn default() -> Self { + Self::empty() } +} - pub(crate) fn r#override(self) -> bool { - self.contains(Self::OVERRIDE) +impl<'a> Modifiers<'a> { + /// Create a new set of modifiers + /// + /// # Invariants + /// `flags` must correctly reflect the [`ModifierKind`]s within + /// `modifiers`. E.g., if `modifiers` is empty, then so is `flags``. + #[must_use] + pub(crate) fn new(modifiers: Vec<'a, Modifier>, flags: ModifierFlags) -> Self { + if modifiers.is_empty() { + debug_assert!(flags.is_empty()); + Self::empty() + } else { + Self { modifiers: Some(modifiers), flags } + } } - pub(crate) fn r#abstract(self) -> bool { - self.contains(Self::ABSTRACT) + pub fn empty() -> Self { + Self { modifiers: None, flags: ModifierFlags::empty() } } - pub(crate) fn r#static(self) -> bool { - self.contains(Self::STATIC) + pub fn contains(&self, target: ModifierKind) -> bool { + self.flags.contains(target.into()) } -} -#[derive(Debug, Hash)] -pub struct Modifier { - pub span: Span, - pub kind: ModifierKind, -} + pub fn iter(&self) -> impl Iterator + '_ { + self.modifiers.as_ref().into_iter().flat_map(|modifiers| modifiers.iter()) + } -#[derive(Debug, Default, Hash)] -pub struct Modifiers<'a>(Option>); + pub fn accessibility(&self) -> Option { + self.flags.accessibility() + } -impl<'a> Modifiers<'a> { - pub fn new(modifiers: Vec<'a, Modifier>) -> Self { - Self(Some(modifiers)) + #[inline] + pub fn contains_async(&self) -> bool { + self.flags.contains(ModifierFlags::ASYNC) } - pub fn empty() -> Self { - Self(None) + #[inline] + pub fn contains_const(&self) -> bool { + self.flags.contains(ModifierFlags::CONST) } - pub fn contains(&self, target: ModifierKind) -> bool { - self.0 - .as_ref() - .map_or(false, |modifiers| modifiers.iter().any(|modifier| modifier.kind == target)) + #[inline] + pub fn contains_declare(&self) -> bool { + self.flags.contains(ModifierFlags::DECLARE) } - pub fn iter(&self) -> impl Iterator + '_ { - self.0.as_ref().into_iter().flat_map(|modifiers| modifiers.iter()) + #[inline] + pub fn contains_abstract(&self) -> bool { + self.flags.contains(ModifierFlags::ABSTRACT) } - pub fn is_contains_const(&self) -> bool { - self.contains(ModifierKind::Const) + #[inline] + pub fn contains_readonly(&self) -> bool { + self.flags.contains(ModifierFlags::READONLY) } - pub fn is_contains_declare(&self) -> bool { - self.contains(ModifierKind::Declare) + #[inline] + pub fn contains_override(&self) -> bool { + self.flags.contains(ModifierFlags::OVERRIDE) } +} - pub fn is_contains_abstract(&self) -> bool { - self.contains(ModifierKind::Abstract) +impl GetSpan for Modifiers<'_> { + fn span(&self) -> Span { + let Some(modifiers) = &self.modifiers else { return SPAN }; + debug_assert!(!modifiers.is_empty()); + // SAFETY: One of Modifier's invariants is that Some(modifiers) always + // contains a non-empty Vec; otherwise it must be `None`. + #[allow(unsafe_code)] + unsafe { + modifiers.iter().map(|m| m.span).reduce(|a, b| a.merge(&b)).unwrap_unchecked() + } } } @@ -178,20 +263,51 @@ impl ModifierKind { } } } +impl TryFrom for ModifierKind { + type Error = (); + fn try_from(kind: Kind) -> std::result::Result { + match kind { + Kind::Abstract => Ok(Self::Abstract), + Kind::Declare => Ok(Self::Declare), + Kind::Private => Ok(Self::Private), + Kind::Protected => Ok(Self::Protected), + Kind::Public => Ok(Self::Public), + Kind::Static => Ok(Self::Static), + Kind::Readonly => Ok(Self::Readonly), + Kind::Override => Ok(Self::Override), + Kind::Async => Ok(Self::Async), + Kind::Const => Ok(Self::Const), + Kind::In => Ok(Self::In), + Kind::Out => Ok(Self::Out), + Kind::Export => Ok(Self::Export), + Kind::Default => Ok(Self::Default), + Kind::Accessor => Ok(Self::Accessor), + _ => Err(()), + } + } +} + +impl std::fmt::Display for ModifierKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} impl<'a> ParserImpl<'a> { - pub(crate) fn eat_modifiers_before_declaration(&mut self) -> (ModifierFlags, Modifiers<'a>) { + pub(crate) fn eat_modifiers_before_declaration(&mut self) -> Result> { let mut flags = ModifierFlags::empty(); let mut modifiers = self.ast.new_vec(); while self.at_modifier() { let span = self.start_span(); let modifier_flag = self.cur_kind().into(); - flags.set(modifier_flag, true); let kind = self.cur_kind(); self.bump_any(); - modifiers.push(Self::modifier(kind, self.end_span(span))); + let modifier = self.modifier(kind, self.end_span(span))?; + self.check_for_duplicate_modifiers(flags, &modifier); + flags.set(modifier_flag, true); + modifiers.push(modifier); } - (flags, Modifiers::new(modifiers)) + Ok(Modifiers::new(modifiers, flags)) } fn at_modifier(&mut self) -> bool { @@ -230,45 +346,27 @@ impl<'a> ParserImpl<'a> { } } - fn modifier(kind: Kind, span: Span) -> Modifier { - let modifier_kind = match kind { - Kind::Abstract => ModifierKind::Abstract, - Kind::Declare => ModifierKind::Declare, - Kind::Private => ModifierKind::Private, - Kind::Protected => ModifierKind::Protected, - Kind::Public => ModifierKind::Public, - Kind::Static => ModifierKind::Static, - Kind::Readonly => ModifierKind::Readonly, - Kind::Override => ModifierKind::Override, - Kind::Async => ModifierKind::Async, - Kind::Const => ModifierKind::Const, - Kind::In => ModifierKind::In, - Kind::Out => ModifierKind::Out, - Kind::Export => ModifierKind::Export, - Kind::Default => ModifierKind::Default, - Kind::Accessor => ModifierKind::Accessor, - _ => unreachable!(), - }; - Modifier { span, kind: modifier_kind } + fn modifier(&mut self, kind: Kind, span: Span) -> Result { + Ok(Modifier { span, kind: kind.try_into().map_err(|()| self.unexpected())? }) } pub(crate) fn parse_modifiers( &mut self, - _allow_decorators: bool, + allow_decorators: bool, permit_const_as_modifier: bool, stop_on_start_of_class_static_block: bool, ) -> Modifiers<'a> { let mut has_seen_static_modifier = false; - // let mut has_leading_modifier = false; - // let mut has_trailing_decorator = false; + let mut has_leading_modifier = false; + let mut has_trailing_decorator = false; + let mut modifiers = self.ast.new_vec(); + let mut modifier_flags = ModifierFlags::empty(); // parse leading decorators - // if (allowDecorators && token() === SyntaxKind.AtToken) { - // while (decorator = tryParseDecorator()) { - // list = append(list, decorator); - // } - // } + if allow_decorators && matches!(self.cur_kind(), Kind::At) { + self.try_parse(Self::eat_decorators); + } // parse leading modifiers while let Some(modifier) = self.try_parse_modifier( @@ -276,58 +374,71 @@ impl<'a> ParserImpl<'a> { permit_const_as_modifier, stop_on_start_of_class_static_block, ) { - if modifier.kind == ModifierKind::Static { + if modifier.is_static() { has_seen_static_modifier = true; } + self.check_for_duplicate_modifiers(modifier_flags, &modifier); + modifier_flags.set(modifier.kind.into(), true); modifiers.push(modifier); + has_leading_modifier = true; } // parse trailing decorators, but only if we parsed any leading modifiers - // if (hasLeadingModifier && allowDecorators && token() === SyntaxKind.AtToken) { - // while (decorator = tryParseDecorator()) { - // list = append(list, decorator); - // hasTrailingDecorator = true; - // } - // } + if allow_decorators && has_leading_modifier && matches!(self.cur_kind(), Kind::At) { + has_trailing_decorator = self.try_parse(Self::eat_decorators).is_some(); + } // parse trailing modifiers, but only if we parsed any trailing decorators - // if (hasTrailingDecorator) { - // while (modifier = tryParseModifier(hasSeenStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock)) { - // if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStaticModifier = true; - // list = append(list, modifier); - // } - // } + if has_trailing_decorator { + while let Some(modifier) = self.try_parse_modifier( + has_seen_static_modifier, + permit_const_as_modifier, + stop_on_start_of_class_static_block, + ) { + if modifier.is_static() { + has_seen_static_modifier = true; + } + self.check_for_duplicate_modifiers(modifier_flags, &modifier); + modifier_flags.set(modifier.kind.into(), true); + modifiers.push(modifier); + } + } - Modifiers::new(modifiers) + Modifiers::new(modifiers, modifier_flags) } fn try_parse_modifier( &mut self, - _has_seen_static_modifier: bool, - _permit_const_as_modifier: bool, - _stop_on_start_of_class_static_block: bool, + has_seen_static_modifier: bool, + permit_const_as_modifier: bool, + stop_on_start_of_class_static_block: bool, ) -> Option { let span = self.start_span(); let kind = self.cur_kind(); - // if (token() === SyntaxKind.ConstKeyword && permitConstAsModifier) { - // We need to ensure that any subsequent modifiers appear on the same line - // so that when 'const' is a standalone declaration, we don't issue an error. - // if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { - // return undefined; - // } - // } - // else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { - // return undefined; - // } - // else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) { - // return undefined; - // } - // else { - if !self.parse_any_contextual_modifier() { + + if matches!(self.cur_kind(), Kind::Const) && permit_const_as_modifier { + // We need to ensure that any subsequent modifiers appear on the same line + // so that when 'const' is a standalone declaration, we don't issue + // an error. + self.try_parse(Self::try_next_token_is_on_same_line_and_can_follow_modifier)?; + } else if + // we're at the start of a static block + (stop_on_start_of_class_static_block + && matches!(self.cur_kind(), Kind::Static) + && self.lookahead(Self::next_token_is_open_brace)) + // we may be at the start of a static block + || (has_seen_static_modifier && matches!(self.cur_kind(), Kind::Static)) + // next token is not a modifier + || (!self.parse_any_contextual_modifier()) + { return None; } - // } - Some(Self::modifier(kind, self.end_span(span))) + self.modifier(kind, self.end_span(span)).ok() + } + + fn next_token_is_open_brace(&mut self) -> bool { + self.bump_any(); + self.at(Kind::LCurly) } fn parse_any_contextual_modifier(&mut self) -> bool { @@ -360,6 +471,14 @@ impl<'a> ParserImpl<'a> { } } + fn try_next_token_is_on_same_line_and_can_follow_modifier(&mut self) -> Result<()> { + if self.next_token_is_on_same_line_and_can_follow_modifier() { + Ok(()) + } else { + Err(self.unexpected()) + } + } + fn next_token_is_on_same_line_and_can_follow_modifier(&mut self) -> bool { self.bump_any(); if self.cur_token().is_on_new_line { @@ -398,8 +517,8 @@ impl<'a> ParserImpl<'a> { fn can_follow_modifier(&mut self) -> bool { match self.cur_kind() { - Kind::LBrack | Kind::LCurly | Kind::Star | Kind::Dot3 => true, - kind => kind.is_literal_property_name(), + Kind::PrivateIdentifier | Kind::LBrack | Kind::LCurly | Kind::Star | Kind::Dot3 => true, + kind => kind.is_identifier_or_keyword(), } } @@ -412,4 +531,25 @@ impl<'a> ParserImpl<'a> { self.bump_any(); self.cur_kind() == Kind::Function && !self.cur_token().is_on_new_line } + + fn check_for_duplicate_modifiers(&mut self, seen_flags: ModifierFlags, modifier: &Modifier) { + if seen_flags.contains(modifier.kind.into()) { + self.error(diagnostics::modifier_already_seen(modifier)); + } + } + + pub(crate) fn verify_modifiers( + &mut self, + modifiers: &Modifiers<'a>, + allowed: ModifierFlags, + diagnose: F, + ) where + F: Fn(&Modifier) -> OxcDiagnostic, + { + for modifier in modifiers.iter() { + if !allowed.contains(modifier.kind.into()) { + self.error(diagnose(modifier)); + } + } + } } diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 3ead79bc10ed5..aa98b72575adf 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -9,7 +9,7 @@ use crate::{ js::{FunctionKind, VariableDeclarationContext, VariableDeclarationParent}, lexer::Kind, list::{NormalList, SeparatedList}, - modifiers::{ModifierKind, Modifiers}, + modifiers::{ModifierFlags, ModifierKind, Modifiers}, ParserImpl, }; @@ -32,21 +32,18 @@ impl<'a> ParserImpl<'a> { let members = TSEnumMemberList::parse(self)?.members; let span = self.end_span(span); - for modifier in modifiers.iter() { - if !matches!(modifier.kind, ModifierKind::Declare | ModifierKind::Const) { - self.error(diagnostics::modifier_cannot_be_used_here( - modifier.span, - modifier.kind.as_str(), - )); - } - } + self.verify_modifiers( + modifiers, + ModifierFlags::DECLARE | ModifierFlags::CONST, + diagnostics::modifier_cannot_be_used_here, + ); Ok(self.ast.ts_enum_declaration( span, id, members, - modifiers.is_contains_const(), - modifiers.is_contains_declare(), + modifiers.contains_const(), + modifiers.contains_declare(), )) } @@ -117,21 +114,18 @@ impl<'a> ParserImpl<'a> { self.asi()?; let span = self.end_span(span); - for modifier in modifiers.iter() { - if modifier.kind != ModifierKind::Declare { - self.error(diagnostics::modifier_cannot_be_used_here( - modifier.span, - modifier.kind.as_str(), - )); - } - } + self.verify_modifiers( + modifiers, + ModifierFlags::DECLARE, + diagnostics::modifier_cannot_be_used_here, + ); Ok(self.ast.ts_type_alias_declaration( span, id, annotation, params, - modifiers.is_contains_declare(), + modifiers.contains_declare(), )) } @@ -149,14 +143,11 @@ impl<'a> ParserImpl<'a> { let body = self.parse_ts_interface_body()?; let extends = extends.map(|e| self.ast.ts_interface_heritages(e)); - for modifier in modifiers.iter() { - if modifier.kind != ModifierKind::Declare { - self.error(diagnostics::modifier_cannot_be_used_here( - modifier.span, - modifier.kind.as_str(), - )); - } - } + self.verify_modifiers( + modifiers, + ModifierFlags::DECLARE, + diagnostics::modifier_cannot_be_used_here, + ); Ok(self.ast.ts_interface_declaration( self.end_span(span), @@ -164,7 +155,7 @@ impl<'a> ParserImpl<'a> { body, type_parameters, extends, - modifiers.is_contains_declare(), + modifiers.contains_declare(), )) } @@ -291,20 +282,18 @@ impl<'a> ParserImpl<'a> { None }; - for modifier in modifiers.iter() { - if modifier.kind != ModifierKind::Declare { - self.error(diagnostics::modifier_cannot_be_used_here( - modifier.span, - modifier.kind.as_str(), - )); - } - } + self.verify_modifiers( + modifiers, + ModifierFlags::DECLARE, + diagnostics::modifier_cannot_be_used_here, + ); + Ok(self.ast.ts_module_declaration( self.end_span(span), id, body, kind, - modifiers.is_contains_declare(), + modifiers.contains_declare(), )) } @@ -315,8 +304,11 @@ impl<'a> ParserImpl<'a> { start_span: Span, ) -> Result> { let reserved_ctx = self.ctx; - let (flags, modifiers) = self.eat_modifiers_before_declaration(); - self.ctx = self.ctx.union_ambient_if(flags.declare()).and_await(flags.r#async()); + let modifiers = self.eat_modifiers_before_declaration()?; + self.ctx = self + .ctx + .union_ambient_if(modifiers.contains_declare()) + .and_await(modifiers.contains_async()); let result = self.parse_declaration(start_span, &modifiers); self.ctx = reserved_ctx; result.map(Statement::from) diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 82dcbbda3078c..53b3dfc3f023d 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -11,7 +11,7 @@ use crate::{ diagnostics, lexer::Kind, list::{NormalList, SeparatedList}, - modifiers::ModifierFlags, + modifiers::{Modifier, ModifierFlags, ModifierKind, Modifiers}, ts::list::TSImportAttributeList, Context, ParserImpl, }; @@ -164,30 +164,12 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_ts_type_parameter(&mut self) -> Result> { let span = self.start_span(); - let mut r#in = false; - let mut out = false; - let mut r#const = false; - - match self.cur_kind() { - Kind::In if self.peek_kind().is_identifier_name() => { - self.bump_any(); - r#in = true; - if self.at(Kind::Out) && self.peek_kind().is_identifier_name() { - // `` - self.bump_any(); - out = true; - } - } - Kind::Out if self.peek_kind().is_identifier_name() => { - self.bump_any(); - out = true; - } - Kind::Const if self.peek_kind().is_identifier_name() => { - self.bump_any(); - r#const = true; - } - _ => {} - } + let modifiers = self.parse_modifiers(false, true, false); + self.verify_modifiers( + &modifiers, + ModifierFlags::IN | ModifierFlags::OUT | ModifierFlags::CONST, + diagnostics::cannot_appear_on_a_type_parameter, + ); let name = self.parse_binding_identifier()?; let constraint = self.parse_ts_type_constraint()?; @@ -198,9 +180,9 @@ impl<'a> ParserImpl<'a> { name, constraint, default, - r#in, - out, - r#const, + modifiers.contains(ModifierKind::In), + modifiers.contains(ModifierKind::Out), + modifiers.contains(ModifierKind::Const), )) } @@ -1267,21 +1249,24 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_class_element_modifiers( &mut self, is_constructor_parameter: bool, - ) -> ModifierFlags { - let mut flags = ModifierFlags::empty(); - + ) -> Modifiers<'a> { if !self.ts_enabled() { - return flags; + return Modifiers::empty(); } + let mut flags = ModifierFlags::empty(); + let mut modifiers: Vec = self.ast.new_vec(); + loop { if !self.is_nth_at_modifier(0, is_constructor_parameter) { break; } #[allow(clippy::unnecessary_fallible_conversions)] - if let Ok(modifier_flag) = self.cur_kind().try_into() { - flags.set(modifier_flag, true); + if let Ok(kind) = ModifierKind::try_from(self.cur_kind()) { + let modifier = Modifier { kind, span: self.cur_token().span() }; + flags.set(kind.into(), true); + modifiers.push(modifier); } else { break; } @@ -1289,7 +1274,7 @@ impl<'a> ParserImpl<'a> { self.bump_any(); } - flags + Modifiers::new(modifiers, flags) } fn parse_js_doc_unknown_or_nullable_type(&mut self) -> Result> { diff --git a/tasks/coverage/misc/fail/oxc-3948.ts b/tasks/coverage/misc/fail/oxc-3948.ts new file mode 100644 index 0000000000000..9497f6151bc93 --- /dev/null +++ b/tasks/coverage/misc/fail/oxc-3948.ts @@ -0,0 +1,9 @@ +const x = { + readonly foo() { + + }, + public readonly async bar() { + + }, + public x: 1, +} diff --git a/tasks/coverage/parser_babel.snap b/tasks/coverage/parser_babel.snap index a5643ebeec0f1..bab5b0dafecae 100644 --- a/tasks/coverage/parser_babel.snap +++ b/tasks/coverage/parser_babel.snap @@ -1,9 +1,9 @@ commit: 12619ffe parser_babel Summary: -AST Parsed : 2091/2101 (99.52%) +AST Parsed : 2093/2101 (99.62%) Positive Passed: 2083/2101 (99.14%) -Negative Passed: 1364/1501 (90.87%) +Negative Passed: 1371/1501 (91.34%) Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js" @@ -38,6 +38,7 @@ Expect Syntax Error: "es2020/dynamic-import-createImportExpression-false/invalid Expect Syntax Error: "esprima/es2015-arrow-function/invalid-param-strict-mode/input.js" Expect Syntax Error: "esprima/es2015-generator/generator-parameter-binding-property-reserved/input.js" Expect Syntax Error: "esprima/invalid-syntax/migrated_0101/input.js" +Expect Syntax Error: "esprima/invalid-syntax/migrated_0276/input.js" Expect Syntax Error: "typescript/cast/satisfies-const-error/input.ts" Expect Syntax Error: "typescript/cast/unparenthesized-assert-and-assign/input.ts" Expect Syntax Error: "typescript/cast/unparenthesized-type-assertion-and-assign/input.ts" @@ -47,7 +48,6 @@ Expect Syntax Error: "typescript/class/abstract-method-in-non-abstract-class-3/i Expect Syntax Error: "typescript/class/abstract-method-with-body/input.ts" Expect Syntax Error: "typescript/class/abstract-method-with-body-computed/input.ts" Expect Syntax Error: "typescript/class/abstract-property-initializer/input.ts" -Expect Syntax Error: "typescript/class/accessor-invalid/input.ts" Expect Syntax Error: "typescript/class/constructor-with-invalid-order-modifiers-1/input.ts" Expect Syntax Error: "typescript/class/constructor-with-invalid-order-modifiers-2/input.ts" Expect Syntax Error: "typescript/class/constructor-with-invalid-order-modifiers-3/input.ts" @@ -58,9 +58,6 @@ Expect Syntax Error: "typescript/class/declare-field-initializer/input.ts" Expect Syntax Error: "typescript/class/declare-initializer/input.ts" Expect Syntax Error: "typescript/class/declare-method/input.ts" Expect Syntax Error: "typescript/class/declare-readonly-field-initializer-w-annotation/input.ts" -Expect Syntax Error: "typescript/class/duplicate-modifier-1/input.ts" -Expect Syntax Error: "typescript/class/duplicate-modifier-2/input.ts" -Expect Syntax Error: "typescript/class/duplicates-accessibility/input.ts" Expect Syntax Error: "typescript/class/generator-method-with-modifiers/input.ts" Expect Syntax Error: "typescript/class/index-signature-errors/input.ts" Expect Syntax Error: "typescript/class/invalid-modifiers-order/input.ts" @@ -71,9 +68,6 @@ Expect Syntax Error: "typescript/class/modifiers-invalid-order/input.ts" Expect Syntax Error: "typescript/class/modifiers-override-errors/input.ts" Expect Syntax Error: "typescript/class/parameter-properties-binding-patterns/input.ts" Expect Syntax Error: "typescript/class/private-fields-modifier-abstract/input.ts" -Expect Syntax Error: "typescript/class/private-fields-modifier-private/input.ts" -Expect Syntax Error: "typescript/class/private-fields-modifier-protected/input.ts" -Expect Syntax Error: "typescript/class/private-fields-modifier-public/input.ts" Expect Syntax Error: "typescript/class/property-optional-definite-assignment-not-allowed/input.ts" Expect Syntax Error: "typescript/declare/function/input.ts" Expect Syntax Error: "typescript/declare/module-class/input.ts" @@ -89,7 +83,6 @@ Expect Syntax Error: "typescript/dts/invalid-class-initializer/input.ts" Expect Syntax Error: "typescript/expect-plugin/export-interface/input.js" Expect Syntax Error: "typescript/expect-plugin/export-type/input.js" Expect Syntax Error: "typescript/expect-plugin/export-type-named/input.js" -Expect Syntax Error: "typescript/export/double-declare/input.ts" Expect Syntax Error: "typescript/export/equals-in-script/input.ts" Expect Syntax Error: "typescript/import/equals-in-script/input.ts" Expect Syntax Error: "typescript/import/equals-require-in-script/input.ts" @@ -383,21 +376,53 @@ Expect to Parse: "typescript/type-arguments-bit-shift-left-like-babel-7/jsx-open ╰──── Expect to Parse: "typescript/types/const-type-parameters/input.ts" - × Unexpected token - ╭─[typescript/types/const-type-parameters/input.ts:14:12] - 13 │ class C {} - 14 │ class D {} - · ───── - 15 │ class E {} + × Identifier `method` has already been declared + ╭─[typescript/types/const-type-parameters/input.ts:29:3] + 28 │ class _ { + 29 │ method() {} + · ───┬── + · ╰── `method` has already been declared here + 30 │ method() {} + · ───┬── + · ╰── It can not be redeclared here + 31 │ method() {} + ╰──── + + × Identifier `method` has already been declared + ╭─[typescript/types/const-type-parameters/input.ts:30:3] + 29 │ method() {} + 30 │ method() {} + · ───┬── + · ╰── `method` has already been declared here + 31 │ method() {} + · ───┬── + · ╰── It can not be redeclared here + 32 │ } ╰──── Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" - × Unexpected token - ╭─[typescript/types/const-type-parameters-babel-7/input.ts:14:12] - 13 │ class C {} - 14 │ class D {} - · ───── - 15 │ class E {} + × Identifier `method` has already been declared + ╭─[typescript/types/const-type-parameters-babel-7/input.ts:29:3] + 28 │ class _ { + 29 │ method() {} + · ───┬── + · ╰── `method` has already been declared here + 30 │ method() {} + · ───┬── + · ╰── It can not be redeclared here + 31 │ method() {} + ╰──── + + × Identifier `method` has already been declared + ╭─[typescript/types/const-type-parameters-babel-7/input.ts:30:3] + 29 │ method() {} + 30 │ method() {} + · ───┬── + · ╰── `method` has already been declared here + 31 │ method() {} + · ───┬── + · ╰── It can not be redeclared here + 32 │ } ╰──── × Identifier `f` has already been declared @@ -9653,13 +9678,6 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" ╰──── help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[esprima/invalid-syntax/migrated_0276/input.js:1:23] - 1 │ class A {static static static(){}} - · ─ - ╰──── - help: Try insert a semicolon here - × Unexpected token ╭─[esprima/invalid-syntax/migrated_0277/input.js:1:12] 1 │ class A {a(enum){}} @@ -9946,6 +9964,14 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" 2 │ func(a: T); ╰──── + × An accessibility modifier cannot be used with a private identifier. + ╭─[typescript/class/accessor-invalid/input.ts:3:3] + 2 │ declare accessor prop7: number; + 3 │ private accessor #p: any; + · ─────── + 4 │ + ╰──── + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[typescript/class/declare-new-line-abstract/input.ts:1:8] 1 │ declare abstract @@ -9954,6 +9980,33 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" ╰──── help: Try insert a semicolon here + × TS1030: 'declare' modifier already seen. + ╭─[typescript/class/duplicate-modifier-1/input.ts:2:18] + 1 │ class A { + 2 │ declare public declare foo; + · ─────── + 3 │ } + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'declare' modifier already seen. + ╭─[typescript/class/duplicate-modifier-2/input.ts:2:25] + 1 │ class A { + 2 │ declare public static declare foo; + · ─────── + 3 │ } + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'public' modifier already seen. + ╭─[typescript/class/duplicates-accessibility/input.ts:2:10] + 1 │ class Foo { + 2 │ public public a; + · ────── + 3 │ private public b; + ╰──── + help: Remove the duplicate modifier. + × Type parameter list cannot be empty. ╭─[typescript/class/empty-type-parameters/input.ts:1:8] 1 │ class C<> {} @@ -10060,6 +10113,30 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" 11 │ } ╰──── + × An accessibility modifier cannot be used with a private identifier. + ╭─[typescript/class/private-fields-modifier-private/input.ts:2:3] + 1 │ class A { + 2 │ private #a; + · ─────── + 3 │ } + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[typescript/class/private-fields-modifier-protected/input.ts:2:3] + 1 │ class A { + 2 │ protected #a; + · ───────── + 3 │ } + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[typescript/class/private-fields-modifier-public/input.ts:2:3] + 1 │ class A { + 2 │ public #a; + · ────── + 3 │ } + ╰──── + × Unexpected token ╭─[typescript/const/invalid-initializer-ambient-context/input.ts:2:35] 1 │ declare module N { @@ -10107,6 +10184,13 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" · ─── ╰──── + × TS1030: 'declare' modifier already seen. + ╭─[typescript/export/double-declare/input.ts:1:16] + 1 │ export declare declare var name; + · ─────── + ╰──── + help: Remove the duplicate modifier. + × Type parameter list cannot be empty. ╭─[typescript/function/empty-type-parameters/input.ts:1:13] 1 │ function foo<>() {} @@ -10506,68 +10590,61 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" · ╰── It can not be redeclared here ╰──── - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/static-blocks/invalid-static-block-with-accessibility-private-02/input.ts:2:17] + × Unexpected token + ╭─[typescript/static-blocks/invalid-static-block-with-accessibility-private-02/input.ts:2:18] 1 │ class Foo { 2 │ static private {} - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/static-blocks/invalid-static-block-with-accessibility-protected-02/input.ts:2:19] + × Unexpected token + ╭─[typescript/static-blocks/invalid-static-block-with-accessibility-protected-02/input.ts:2:20] 1 │ class Foo { 2 │ static protected {} - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/static-blocks/invalid-static-block-with-accessibility-public-02/input.ts:2:16] + × Unexpected token + ╭─[typescript/static-blocks/invalid-static-block-with-accessibility-public-02/input.ts:2:17] 1 │ class Foo { 2 │ static public {} - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/static-blocks/invalid-static-block-with-modifier-abstract-02/input.ts:2:18] + × Unexpected token + ╭─[typescript/static-blocks/invalid-static-block-with-modifier-abstract-02/input.ts:2:19] 1 │ class Foo { 2 │ static abstract {} - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/static-blocks/invalid-static-block-with-modifier-override-02/input.ts:2:18] + × Unexpected token + ╭─[typescript/static-blocks/invalid-static-block-with-modifier-override-02/input.ts:2:19] 1 │ class Foo { 2 │ static override {} - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/static-blocks/invalid-static-blocks-with-modifer-declare-02/input.ts:2:17] + × Unexpected token + ╭─[typescript/static-blocks/invalid-static-blocks-with-modifer-declare-02/input.ts:2:18] 1 │ class Foo { 2 │ static declare {} - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[typescript/static-blocks/invalid-static-blocks-with-modifier-readonly-02/input.ts:2:18] + × Unexpected token + ╭─[typescript/static-blocks/invalid-static-blocks-with-modifier-readonly-02/input.ts:2:19] 1 │ class Foo { 2 │ static readonly {} - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here × Unexpected token ╭─[typescript/tsx/anonymous-function-generator-invalid/input.ts:1:23] @@ -10700,42 +10777,110 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" · ╰── `,` expected ╰──── - × Expected `,` but found `Identifier` - ╭─[typescript/types/variance-annotations/input.ts:95:17] + × 'public' modifier cannot be used on a type parameter. + ╭─[typescript/types/variance-annotations/input.ts:95:10] 94 │ 95 │ type T20 = T; // Error - · ┬ - · ╰── `,` expected + · ────── 96 │ type T21 = T; // Error ╰──── - × Expected `,` but found `Identifier` - ╭─[typescript/types/variance-annotations-babel-7/input.ts:95:17] + × TS1030: 'in' modifier already seen. + ╭─[typescript/types/variance-annotations/input.ts:96:17] + 95 │ type T20 = T; // Error + 96 │ type T21 = T; // Error + · ── + 97 │ type T22 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'out' modifier already seen. + ╭─[typescript/types/variance-annotations/input.ts:97:17] + 96 │ type T21 = T; // Error + 97 │ type T22 = T; // Error + · ─── + 98 │ type T23 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × 'public' modifier cannot be used on a type parameter. + ╭─[typescript/types/variance-annotations-babel-7/input.ts:95:10] 94 │ 95 │ type T20 = T; // Error - · ┬ - · ╰── `,` expected + · ────── 96 │ type T21 = T; // Error ╰──── - × Expected `,` but found `Identifier` - ╭─[typescript/types/variance-annotations-with-jsx/input.tsx:98:17] + × TS1030: 'in' modifier already seen. + ╭─[typescript/types/variance-annotations-babel-7/input.ts:96:17] + 95 │ type T20 = T; // Error + 96 │ type T21 = T; // Error + · ── + 97 │ type T22 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'out' modifier already seen. + ╭─[typescript/types/variance-annotations-babel-7/input.ts:97:17] + 96 │ type T21 = T; // Error + 97 │ type T22 = T; // Error + · ─── + 98 │ type T23 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × 'public' modifier cannot be used on a type parameter. + ╭─[typescript/types/variance-annotations-with-jsx/input.tsx:98:10] 97 │ 98 │ type T20 = T; // Error - · ┬ - · ╰── `,` expected + · ────── 99 │ type T21 = T; // Error ╰──── - × Expected `,` but found `Identifier` - ╭─[typescript/types/variance-annotations-with-jsx-babel-7/input.tsx:98:17] + × TS1030: 'in' modifier already seen. + ╭─[typescript/types/variance-annotations-with-jsx/input.tsx:99:17] + 98 │ type T20 = T; // Error + 99 │ type T21 = T; // Error + · ── + 100 │ type T22 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'out' modifier already seen. + ╭─[typescript/types/variance-annotations-with-jsx/input.tsx:100:17] + 99 │ type T21 = T; // Error + 100 │ type T22 = T; // Error + · ─── + 101 │ type T23 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × 'public' modifier cannot be used on a type parameter. + ╭─[typescript/types/variance-annotations-with-jsx-babel-7/input.tsx:98:10] 97 │ 98 │ type T20 = T; // Error - · ┬ - · ╰── `,` expected + · ────── 99 │ type T21 = T; // Error ╰──── + × TS1030: 'in' modifier already seen. + ╭─[typescript/types/variance-annotations-with-jsx-babel-7/input.tsx:99:17] + 98 │ type T20 = T; // Error + 99 │ type T21 = T; // Error + · ── + 100 │ type T22 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'out' modifier already seen. + ╭─[typescript/types/variance-annotations-with-jsx-babel-7/input.tsx:100:17] + 99 │ type T21 = T; // Error + 100 │ type T22 = T; // Error + · ─── + 101 │ type T23 = T; // Error + ╰──── + help: Remove the duplicate modifier. + × Expected `]` but found `EOF` ╭─[typescript/types-arrow-function/invalid-incomplete-array-like/input.ts:2:1] 1 │ type F = ([ diff --git a/tasks/coverage/parser_misc.snap b/tasks/coverage/parser_misc.snap index a4e5acc9846a0..15826a2a639f4 100644 --- a/tasks/coverage/parser_misc.snap +++ b/tasks/coverage/parser_misc.snap @@ -1,7 +1,7 @@ parser_misc Summary: AST Parsed : 19/19 (100.00%) Positive Passed: 19/19 (100.00%) -Negative Passed: 10/10 (100.00%) +Negative Passed: 11/11 (100.00%) × Unexpected token ╭─[fail/oxc-169.js:2:1] @@ -127,6 +127,38 @@ Negative Passed: 10/10 (100.00%) · ──────────── ────── ╰──── + × 'readonly' modifier cannot be used here. + ╭─[fail/oxc-3948.ts:2:5] + 1 │ const x = { + 2 │ readonly foo() { + · ──────── + 3 │ + ╰──── + + × 'public' modifier cannot be used here. + ╭─[fail/oxc-3948.ts:5:5] + 4 │ }, + 5 │ public readonly async bar() { + · ────── + 6 │ + ╰──── + + × 'readonly' modifier cannot be used here. + ╭─[fail/oxc-3948.ts:5:12] + 4 │ }, + 5 │ public readonly async bar() { + · ──────── + 6 │ + ╰──── + + × 'public' modifier cannot be used here. + ╭─[fail/oxc-3948.ts:8:5] + 7 │ }, + 8 │ public x: 1, + · ────── + 9 │ } + ╰──── + × The keyword 'let' is reserved ╭─[fail/oxc.js:1:1] 1 │ let.a = 1; diff --git a/tasks/coverage/parser_typescript.snap b/tasks/coverage/parser_typescript.snap index d613b7363324a..cb1c27a9fccbe 100644 --- a/tasks/coverage/parser_typescript.snap +++ b/tasks/coverage/parser_typescript.snap @@ -3,7 +3,7 @@ commit: d8086f14 parser_typescript Summary: AST Parsed : 5280/5283 (99.94%) Positive Passed: 5273/5283 (99.81%) -Negative Passed: 1068/4875 (21.91%) +Negative Passed: 1077/4875 (22.09%) Expect Syntax Error: "compiler/ClassDeclaration10.ts" Expect Syntax Error: "compiler/ClassDeclaration11.ts" Expect Syntax Error: "compiler/ClassDeclaration13.ts" @@ -376,8 +376,6 @@ Expect Syntax Error: "compiler/constantEnumAssert.ts" Expect Syntax Error: "compiler/constraintErrors1.ts" Expect Syntax Error: "compiler/constraintWithIndexedAccess.ts" Expect Syntax Error: "compiler/constraints0.ts" -Expect Syntax Error: "compiler/constructorArgsErrors1.ts" -Expect Syntax Error: "compiler/constructorArgsErrors2.ts" Expect Syntax Error: "compiler/constructorArgsErrors3.ts" Expect Syntax Error: "compiler/constructorArgsErrors4.ts" Expect Syntax Error: "compiler/constructorAsType.ts" @@ -467,7 +465,6 @@ Expect Syntax Error: "compiler/declarationEmitUnknownImport.ts" Expect Syntax Error: "compiler/declarationEmitVarInElidedBlock.ts" Expect Syntax Error: "compiler/declarationFileNoCrashOnExtraExportModifier.ts" Expect Syntax Error: "compiler/declarationMapsWithoutDeclaration.ts" -Expect Syntax Error: "compiler/declareAlreadySeen.ts" Expect Syntax Error: "compiler/declareClassInterfaceImplementation.ts" Expect Syntax Error: "compiler/declareModifierOnImport1.ts" Expect Syntax Error: "compiler/decoratorInJsFile.ts" @@ -1166,7 +1163,6 @@ Expect Syntax Error: "compiler/missingTypeArguments2.ts" Expect Syntax Error: "compiler/mixedStaticAndInstanceClassMembers.ts" Expect Syntax Error: "compiler/mixinPrivateAndProtected.ts" Expect Syntax Error: "compiler/mixingStaticAndInstanceOverloads.ts" -Expect Syntax Error: "compiler/modifierOnParameter1.ts" Expect Syntax Error: "compiler/modularizeLibrary_ErrorFromUsingES6ArrayWithOnlyES6ArrayLib.ts" Expect Syntax Error: "compiler/modularizeLibrary_ErrorFromUsingES6FeaturesWithOnlyES5Lib.ts" Expect Syntax Error: "compiler/modularizeLibrary_ErrorFromUsingWellknownSymbolWithOutES6WellknownSymbolLib.ts" @@ -1204,7 +1200,6 @@ Expect Syntax Error: "compiler/multiLineContextDiagnosticWithPretty.ts" Expect Syntax Error: "compiler/multiLineErrors.ts" Expect Syntax Error: "compiler/multipleBaseInterfaesWithIncompatibleProperties.ts" Expect Syntax Error: "compiler/multipleClassPropertyModifiers.ts" -Expect Syntax Error: "compiler/multipleClassPropertyModifiersErrors.ts" Expect Syntax Error: "compiler/multipleExportAssignments.ts" Expect Syntax Error: "compiler/multipleExportAssignmentsInAmbientDeclaration.ts" Expect Syntax Error: "compiler/multipleExports.ts" @@ -1979,6 +1974,7 @@ Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractInstantiations2.ts" Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodInNonAbstractClass.ts" Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMethodWithImplementation.ts" +Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMixedWithModifiers.ts" Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverloads.ts" Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractOverrideWithAbstract.ts" Expect Syntax Error: "conformance/classes/classDeclarations/classAbstractKeyword/classAbstractProperties.ts" @@ -2000,6 +1996,7 @@ Expect Syntax Error: "conformance/classes/classDeclarations/classWithPredefinedT Expect Syntax Error: "conformance/classes/classExpressions/classWithStaticFieldInParameterBindingPattern.2.ts" Expect Syntax Error: "conformance/classes/classExpressions/classWithStaticFieldInParameterInitializer.2.ts" Expect Syntax Error: "conformance/classes/classStaticBlock/classStaticBlock19.ts" +Expect Syntax Error: "conformance/classes/classStaticBlock/classStaticBlock20.ts" Expect Syntax Error: "conformance/classes/classStaticBlock/classStaticBlock23.ts" Expect Syntax Error: "conformance/classes/classStaticBlock/classStaticBlock3.ts" Expect Syntax Error: "conformance/classes/classStaticBlock/classStaticBlock4.ts" @@ -2026,7 +2023,6 @@ Expect Syntax Error: "conformance/classes/constructorDeclarations/constructorPar Expect Syntax Error: "conformance/classes/constructorDeclarations/constructorParameters/readonlyConstructorAssignment.ts" Expect Syntax Error: "conformance/classes/constructorDeclarations/constructorParameters/readonlyInAmbientClass.ts" Expect Syntax Error: "conformance/classes/constructorDeclarations/constructorParameters/readonlyInConstructorParameters.ts" -Expect Syntax Error: "conformance/classes/constructorDeclarations/constructorParameters/readonlyReadonly.ts" Expect Syntax Error: "conformance/classes/constructorDeclarations/constructorWithAssignableReturnExpression.ts" Expect Syntax Error: "conformance/classes/constructorDeclarations/superCalls/derivedClassConstructorWithoutSuperCall.ts" Expect Syntax Error: "conformance/classes/constructorDeclarations/superCalls/derivedClassParameterProperties.ts" @@ -2102,6 +2098,7 @@ Expect Syntax Error: "conformance/classes/members/privateNames/privateNameStatic Expect Syntax Error: "conformance/classes/members/privateNames/privateNameStaticFieldAccess.ts" Expect Syntax Error: "conformance/classes/members/privateNames/privateNameStaticMethod.ts" Expect Syntax Error: "conformance/classes/members/privateNames/privateNameStaticMethodAssignment.ts" +Expect Syntax Error: "conformance/classes/members/privateNames/privateNameStaticMethodAsync.ts" Expect Syntax Error: "conformance/classes/members/privateNames/privateNameUnused.ts" Expect Syntax Error: "conformance/classes/members/privateNames/privateNamesAndDecorators.ts" Expect Syntax Error: "conformance/classes/members/privateNames/privateNamesAndStaticFields.ts" @@ -2120,7 +2117,6 @@ Expect Syntax Error: "conformance/classes/members/privateNames/privateWriteOnlyA Expect Syntax Error: "conformance/classes/mixinAbstractClasses.2.ts" Expect Syntax Error: "conformance/classes/mixinAccessModifiers.ts" Expect Syntax Error: "conformance/classes/propertyMemberDeclarations/abstractPropertyInitializer.ts" -Expect Syntax Error: "conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts" Expect Syntax Error: "conformance/classes/propertyMemberDeclarations/accessorsOverrideMethod.ts" Expect Syntax Error: "conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty.ts" Expect Syntax Error: "conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty2.ts" @@ -3024,11 +3020,10 @@ Expect Syntax Error: "conformance/override/override2.ts" Expect Syntax Error: "conformance/override/override20.ts" Expect Syntax Error: "conformance/override/override3.ts" Expect Syntax Error: "conformance/override/override4.ts" -Expect Syntax Error: "conformance/override/override5.ts" Expect Syntax Error: "conformance/override/override6.ts" -Expect Syntax Error: "conformance/override/override7.ts" Expect Syntax Error: "conformance/override/override8.ts" Expect Syntax Error: "conformance/override/override9.ts" +Expect Syntax Error: "conformance/override/overrideKeywordOrder.ts" Expect Syntax Error: "conformance/override/overrideParameterProperty.ts" Expect Syntax Error: "conformance/override/overrideWithoutNoImplicitOverride1.ts" Expect Syntax Error: "conformance/override/override_js2.ts" @@ -3083,7 +3078,6 @@ Expect Syntax Error: "conformance/parser/ecmascript5/ComputedPropertyNames/parse Expect Syntax Error: "conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration10.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration2.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration4.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration6.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration7.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration9.ts" Expect Syntax Error: "conformance/parser/ecmascript5/EnumDeclarations/parserEnum7.ts" @@ -3154,14 +3148,11 @@ Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/ Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration17.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration2.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration3.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration7.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration8.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration9.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration1.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration2.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration3.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration5.ts" -Expect Syntax Error: "conformance/parser/ecmascript5/MemberVariableDeclarations/parserMemberVariableDeclaration1.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberVariableDeclarations/parserMemberVariableDeclaration2.ts" Expect Syntax Error: "conformance/parser/ecmascript5/MemberVariableDeclarations/parserMemberVariableDeclaration3.ts" Expect Syntax Error: "conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration1.d.ts" @@ -4761,23 +4752,21 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ } ╰──── - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[compiler/classMemberWithMissingIdentifier.ts:2:11] + × Unexpected token + ╭─[compiler/classMemberWithMissingIdentifier.ts:2:12] 1 │ class C { 2 │ public {}; - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here - × Expected a semicolon or an implicit semicolon after a statement, but found none - ╭─[compiler/classMemberWithMissingIdentifier2.ts:2:11] + × Unexpected token + ╭─[compiler/classMemberWithMissingIdentifier2.ts:2:12] 1 │ class C { 2 │ public {[name:string]:VariableDeclaration}; - · ─ + · ─ 3 │ } ╰──── - help: Try insert a semicolon here × Identifier `foo` has already been declared ╭─[compiler/classOverloadForFunction.ts:1:7] @@ -5632,6 +5621,22 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" ╰──── help: Try insert a semicolon here + × TS1090: 'static' modifier cannot appear on a parameter. + ╭─[compiler/constructorArgsErrors1.ts:2:18] + 1 │ class foo { + 2 │ constructor (static a: number) { + · ────── + 3 │ } + ╰──── + + × TS1090: 'static' modifier cannot appear on a parameter. + ╭─[compiler/constructorArgsErrors2.ts:2:25] + 1 │ class foo { + 2 │ constructor (public static a: number) { + · ────── + 3 │ } + ╰──── + × Unexpected token ╭─[compiler/constructorArgsErrors5.ts:2:18] 1 │ class foo { @@ -5780,6 +5785,42 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 2 │ export default Foo ╰──── + × TS1030: 'declare' modifier already seen. + ╭─[compiler/declareAlreadySeen.ts:2:13] + 1 │ module M { + 2 │ declare declare var x; + · ─────── + 3 │ declare declare function f(); + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'declare' modifier already seen. + ╭─[compiler/declareAlreadySeen.ts:3:13] + 2 │ declare declare var x; + 3 │ declare declare function f(); + · ─────── + 4 │ + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'declare' modifier already seen. + ╭─[compiler/declareAlreadySeen.ts:5:13] + 4 │ + 5 │ declare declare module N { } + · ─────── + 6 │ + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'declare' modifier already seen. + ╭─[compiler/declareAlreadySeen.ts:7:13] + 6 │ + 7 │ declare declare class C { } + · ─────── + 8 │ } + ╰──── + help: Remove the duplicate modifier. + × Cannot assign to this expression ╭─[compiler/decrementAndIncrementOperators.ts:4:1] 3 │ // errors @@ -7701,15 +7742,46 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" · ──────── ╰──── - × Expected `,` but found `Identifier` - ╭─[compiler/modifiersInObjectLiterals.ts:2:9] + × TS1090: 'declare' modifier cannot appear on a parameter. + ╭─[compiler/modifierOnParameter1.ts:2:16] + 1 │ class C { + 2 │ constructor(declare p) { } + · ─────── + 3 │ } + ╰──── + + × 'public' modifier cannot be used here. + ╭─[compiler/modifiersInObjectLiterals.ts:2:2] 1 │ let data = { 2 │ public foo: 'hey', - · ─┬─ - · ╰── `,` expected + · ────── 3 │ private bar: 'nay', ╰──── + × 'private' modifier cannot be used here. + ╭─[compiler/modifiersInObjectLiterals.ts:3:2] + 2 │ public foo: 'hey', + 3 │ private bar: 'nay', + · ─────── + 4 │ protected baz: 'oh my', + ╰──── + + × 'protected' modifier cannot be used here. + ╭─[compiler/modifiersInObjectLiterals.ts:4:2] + 3 │ private bar: 'nay', + 4 │ protected baz: 'oh my', + · ───────── + 5 │ abstract noWay: 'yes' + ╰──── + + × 'abstract' modifier cannot be used here. + ╭─[compiler/modifiersInObjectLiterals.ts:5:2] + 4 │ protected baz: 'oh my', + 5 │ abstract noWay: 'yes' + · ──────── + 6 │ }; + ╰──── + × Unexpected token ╭─[compiler/modifiersOnInterfaceIndexSignature1.ts:2:3] 1 │ interface I { @@ -7893,6 +7965,24 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 2 │ .then((role: Role) => ╰──── + × TS1030: 'public' modifier already seen. + ╭─[compiler/multipleClassPropertyModifiersErrors.ts:2:9] + 1 │ class C { + 2 │ public public p1; + · ────── + 3 │ private private p2; + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'private' modifier already seen. + ╭─[compiler/multipleClassPropertyModifiersErrors.ts:3:10] + 2 │ public public p1; + 3 │ private private p2; + · ─────── + 4 │ static static p3; + ╰──── + help: Remove the duplicate modifier. + × Identifier `z` has already been declared ╭─[compiler/nameCollisions.ts:10:5] 9 │ @@ -8116,18 +8206,16 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 23 │ endState: state ╰──── - × Expected `,` but found `Identifier` - ╭─[compiler/objectLiteralMemberWithModifiers1.ts:1:18] + × 'public' modifier cannot be used here. + ╭─[compiler/objectLiteralMemberWithModifiers1.ts:1:11] 1 │ var v = { public foo() { } } - · ─┬─ - · ╰── `,` expected + · ────── ╰──── - × Expected `,` but found `get` - ╭─[compiler/objectLiteralMemberWithModifiers2.ts:1:18] + × 'public' modifier cannot be used here. + ╭─[compiler/objectLiteralMemberWithModifiers2.ts:1:11] 1 │ var v = { public get foo() { } } - · ─┬─ - · ╰── `,` expected + · ────── ╰──── × Expected `,` but found `?` @@ -10974,15 +11062,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 18 │ ╰──── - × Expected `(` but found `Identifier` - ╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMixedWithModifiers.ts:16:20] - 15 │ abstract async foo_f(); - 16 │ async abstract foo_g(); - · ──┬── - · ╰── `(` expected - 17 │ } - ╰──── - × 'abstract' modifier cannot be used here. ╭─[conformance/classes/classDeclarations/classAbstractKeyword/classAbstractWithInterface.ts:1:1] 1 │ abstract interface I {} @@ -11089,15 +11168,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 22 │ getY = (obj: D) => obj.#y; ╰──── - × Expected `(` but found `{` - ╭─[conformance/classes/classStaticBlock/classStaticBlock20.ts:2:18] - 1 │ class C { - 2 │ async static { - · ┬ - · ╰── `(` expected - 3 │ // something - ╰──── - × Cannot use `await` as an identifier in an async context ╭─[conformance/classes/classStaticBlock/classStaticBlock22.ts:4:9] 3 │ static { @@ -11268,6 +11338,15 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 9 │ } ╰──── + × TS1030: 'readonly' modifier already seen. + ╭─[conformance/classes/constructorDeclarations/constructorParameters/readonlyReadonly.ts:2:14] + 1 │ class C { + 2 │ readonly readonly x: number; + · ──────── + 3 │ constructor(readonly readonly y: number) {} + ╰──── + help: Remove the duplicate modifier. + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[conformance/classes/constructorDeclarations/superCalls/derivedClassSuperCallsInNonConstructorMembers.ts:8:13] 7 │ class Derived extends Base { @@ -11303,12 +11382,20 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" ╰──── help: either remove this super, or extend the class - × Expected `,` but found `[` - ╭─[conformance/classes/indexMemberDeclarations/privateIndexer2.ts:4:13] + × 'private' modifier cannot be used here. + ╭─[conformance/classes/indexMemberDeclarations/privateIndexer2.ts:4:5] 3 │ var x = { 4 │ private [x: string]: string; - · ┬ - · ╰── `,` expected + · ─────── + 5 │ } + ╰──── + + × Expected `]` but found `:` + ╭─[conformance/classes/indexMemberDeclarations/privateIndexer2.ts:4:15] + 3 │ var x = { + 4 │ private [x: string]: string; + · ┬ + · ╰── `]` expected 5 │ } ╰──── @@ -12013,15 +12100,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 13 │ } ╰──── - × Expected `(` but found `*` - ╭─[conformance/classes/members/privateNames/privateNameStaticMethodAsync.ts:11:18] - 10 │ } - 11 │ async static *#bazBad() { yield 42; } - · ┬ - · ╰── `(` expected - 12 │ } - ╰──── - × Private identifier '#method' is not allowed outside class bodies ╭─[conformance/classes/members/privateNames/privateNameStaticMethodClassExpression.ts:9:14] 8 │ console.log(C.getClass().getField()); @@ -12086,6 +12164,102 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 25 │ a = b; // Error ╰──── + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:2:5] + 1 │ class A { + 2 │ public #foo = 3; // Error + · ────── + 3 │ private #bar = 3; // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:3:5] + 2 │ public #foo = 3; // Error + 3 │ private #bar = 3; // Error + · ─────── + 4 │ protected #baz = 3; // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:4:5] + 3 │ private #bar = 3; // Error + 4 │ protected #baz = 3; // Error + · ───────── + 5 │ readonly #qux = 3; // OK + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:8:5] + 7 │ + 8 │ public #fooMethod() { return 3; } // Error + · ────── + 9 │ private #barMethod() { return 3; } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:9:5] + 8 │ public #fooMethod() { return 3; } // Error + 9 │ private #barMethod() { return 3; } // Error + · ─────── + 10 │ protected #bazMethod() { return 3; } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:10:5] + 9 │ private #barMethod() { return 3; } // Error + 10 │ protected #bazMethod() { return 3; } // Error + · ───────── + 11 │ readonly #quxMethod() { return 3; } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:17:5] + 16 │ + 17 │ public get #fooProp() { return 3; } // Error + · ────── + 18 │ public set #fooProp(value: number) { } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:18:5] + 17 │ public get #fooProp() { return 3; } // Error + 18 │ public set #fooProp(value: number) { } // Error + · ────── + 19 │ private get #barProp() { return 3; } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:19:5] + 18 │ public set #fooProp(value: number) { } // Error + 19 │ private get #barProp() { return 3; } // Error + · ─────── + 20 │ private set #barProp(value: number) { } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:20:5] + 19 │ private get #barProp() { return 3; } // Error + 20 │ private set #barProp(value: number) { } // Error + · ─────── + 21 │ protected get #bazProp() { return 3; } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:21:5] + 20 │ private set #barProp(value: number) { } // Error + 21 │ protected get #bazProp() { return 3; } // Error + · ───────── + 22 │ protected set #bazProp(value: number) { } // Error + ╰──── + + × An accessibility modifier cannot be used with a private identifier. + ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:22:5] + 21 │ protected get #bazProp() { return 3; } // Error + 22 │ protected set #bazProp(value: number) { } // Error + · ───────── + 23 │ readonly get #quxProp() { return 3; } // Error + ╰──── + × Expected `(` but found `#identifier` ╭─[conformance/classes/members/privateNames/privateNamesIncompatibleModifiers.ts:27:15] 26 │ declare set #whatProp(value: number) // Error @@ -12134,6 +12308,15 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" ╰──── help: Try insert a semicolon here + × TS1030: 'public' modifier already seen. + ╭─[conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts:42:12] + 41 │ private protected get getter() { return 0; } + 42 │ public public set setter(a: number) { } + · ────── + 43 │ } + ╰──── + help: Remove the duplicate modifier. + × Identifier `accessor` has already been declared ╭─[conformance/classes/propertyMemberDeclarations/autoAccessor11.ts:5:12] 4 │ @@ -12149,6 +12332,15 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 10 │ c ╰──── + × TS1030: 'accessor' modifier already seen. + ╭─[conformance/classes/propertyMemberDeclarations/autoAccessorDisallowedModifiers.ts:2:14] + 1 │ abstract class C1 { + 2 │ accessor accessor a: any; + · ──────── + 3 │ readonly accessor b: any; + ╰──── + help: Remove the duplicate modifier. + × Unexpected token ╭─[conformance/classes/propertyMemberDeclarations/autoAccessorDisallowedModifiers.ts:10:15] 9 │ accessor static h: any; @@ -16584,21 +16776,29 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 23 │ ; ╰──── - × Expected `(` but found `Identifier` - ╭─[conformance/override/overrideKeywordOrder.ts:12:18] - 11 │ override async m1() {} - 12 │ async override m2() {} // error - · ─┬ - · ╰── `(` expected - 13 │ } + × TS1030: 'override' modifier already seen. + ╭─[conformance/override/override5.ts:22:14] + 21 │ + 22 │ override override oop: number; + · ──────── + 23 │ ╰──── + help: Remove the duplicate modifier. - × Expected `,` but found `get` - ╭─[conformance/parser/ecmascript5/Accessors/parserAccessors10.ts:2:10] + × TS1030: 'override' modifier already seen. + ╭─[conformance/override/override7.ts:19:14] + 18 │ + 19 │ override override oop: number; + · ──────── + 20 │ + ╰──── + help: Remove the duplicate modifier. + + × 'public' modifier cannot be used here. + ╭─[conformance/parser/ecmascript5/Accessors/parserAccessors10.ts:2:3] 1 │ var v = { 2 │ public get foo() { } - · ─┬─ - · ╰── `,` expected + · ────── 3 │ }; ╰──── @@ -16657,6 +16857,15 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" ╰──── help: Try insert a semicolon here + × TS1030: 'public' modifier already seen. + ╭─[conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration6.ts:2:10] + 1 │ class C { + 2 │ public public constructor() { } + · ────── + 3 │ } + ╰──── + help: Remove the duplicate modifier. + × Classes can't have a field named 'constructor' ╭─[conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration8.ts:3:10] 2 │ // Not a constructor @@ -17555,6 +17764,24 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ } ╰──── + × TS1030: 'public' modifier already seen. + ╭─[conformance/parser/ecmascript5/MemberAccessorDeclarations/parserMemberAccessorDeclaration7.ts:2:12] + 1 │ class C { + 2 │ public public get Foo() { } + · ────── + 3 │ } + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'public' modifier already seen. + ╭─[conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration1.ts:2:12] + 1 │ class C { + 2 │ public public Foo() { } + · ────── + 3 │ } + ╰──── + help: Remove the duplicate modifier. + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[conformance/parser/ecmascript5/MemberFunctionDeclarations/parserMemberFunctionDeclaration4.ts:2:11] 1 │ class C { @@ -17620,6 +17847,15 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 13 │ } ╰──── + × TS1030: 'public' modifier already seen. + ╭─[conformance/parser/ecmascript5/MemberVariableDeclarations/parserMemberVariableDeclaration1.ts:2:10] + 1 │ class C { + 2 │ public public Foo; + · ────── + 3 │ } + ╰──── + help: Remove the duplicate modifier. + × Expected a semicolon or an implicit semicolon after a statement, but found none ╭─[conformance/parser/ecmascript5/MemberVariableDeclarations/parserMemberVariableDeclaration4.ts:2:9] 1 │ class C { @@ -18682,11 +18918,10 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 4 │ } ╰──── - × Expected `,` but found `get` - ╭─[conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts:1:18] + × 'public' modifier cannot be used here. + ╭─[conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts:1:11] 1 │ var v = { public get [e]() { } }; - · ─┬─ - · ╰── `,` expected + · ────── ╰──── × Expected `;` but found `Identifier` @@ -20839,14 +21074,31 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 19 │ const a9 = (f); // Error, no applicable signatures ╰──── - × Expected `,` but found `Identifier` - ╭─[conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:95:17] + × 'public' modifier cannot be used on a type parameter. + ╭─[conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:95:10] 94 │ 95 │ type T20 = T; // Error - · ┬ - · ╰── `,` expected + · ────── + 96 │ type T21 = T; // Error + ╰──── + + × TS1030: 'in' modifier already seen. + ╭─[conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:96:17] + 95 │ type T20 = T; // Error + 96 │ type T21 = T; // Error + · ── + 97 │ type T22 = T; // Error + ╰──── + help: Remove the duplicate modifier. + + × TS1030: 'out' modifier already seen. + ╭─[conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:97:17] 96 │ type T21 = T; // Error + 97 │ type T22 = T; // Error + · ─── + 98 │ type T23 = T; // Error ╰──── + help: Remove the duplicate modifier. × Unexpected token ╭─[conformance/types/typeParameters/typeParameterLists/varianceAnnotationsWithCircularlyReferencesError.ts:1:12] diff --git a/tasks/coverage/prettier_babel.snap b/tasks/coverage/prettier_babel.snap index 463f69f478f53..ab8be544c0273 100644 --- a/tasks/coverage/prettier_babel.snap +++ b/tasks/coverage/prettier_babel.snap @@ -2,7 +2,7 @@ commit: 12619ffe prettier_babel Summary: AST Parsed : 2101/2101 (100.00%) -Positive Passed: 1895/2101 (90.20%) +Positive Passed: 1893/2101 (90.10%) Expect to Parse: "comments/attachComment-false/array-expression-trailing-comma/input.js" Expect to Parse: "comments/basic/array-expression-trailing-comma/input.js" Expect to Parse: "comments/basic/object-expression-trailing-comma/input.js" @@ -154,6 +154,8 @@ Expect to Parse: "typescript/type-arguments-bit-shift-left-like-babel-7/type-arg Expect to Parse: "typescript/types/conditional/input.ts" Expect to Parse: "typescript/types/conditional-infer/input.ts" Expect to Parse: "typescript/types/conditional-infer-babel-7/input.ts" +Expect to Parse: "typescript/types/const-type-parameters/input.ts" +Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" Expect to Parse: "typescript/types/function/input.ts" Expect to Parse: "typescript/types/function-babel-7/input.ts" Expect to Parse: "typescript/types/function-generic/input.ts" diff --git a/tasks/coverage/prettier_test262.snap b/tasks/coverage/prettier_test262.snap index e6e3cf10d66ed..c0f65ebd7120b 100644 --- a/tasks/coverage/prettier_test262.snap +++ b/tasks/coverage/prettier_test262.snap @@ -2,7 +2,7 @@ commit: a1587416 prettier_test262 Summary: AST Parsed : 46406/46406 (100.00%) -Positive Passed: 43242/46406 (93.18%) +Positive Passed: 43244/46406 (93.19%) Expect to Parse: "annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js" Expect to Parse: "annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js" Expect to Parse: "annexB/built-ins/escape/to-primitive-err.js" @@ -2224,7 +2224,6 @@ Expect to Parse: "language/expressions/class/elements/async-gen-private-method-s Expect to Parse: "language/expressions/class/elements/async-gen-private-method-static/yield-star-sync-next.js" Expect to Parse: "language/expressions/class/elements/async-gen-private-method-static/yield-star-sync-return.js" Expect to Parse: "language/expressions/class/elements/async-gen-private-method-static/yield-star-sync-throw.js" -Expect to Parse: "language/expressions/class/elements/syntax/valid/grammar-field-accessor.js" Expect to Parse: "language/expressions/comma/S11.14_A2.1_T1.js" Expect to Parse: "language/expressions/comma/S11.14_A3.js" Expect to Parse: "language/expressions/compound-assignment/S11.13.2_A4.1_T2.8.js" @@ -2895,7 +2894,6 @@ Expect to Parse: "language/statements/class/elements/async-gen-private-method-st Expect to Parse: "language/statements/class/elements/async-gen-private-method-static/yield-star-sync-return.js" Expect to Parse: "language/statements/class/elements/async-gen-private-method-static/yield-star-sync-throw.js" Expect to Parse: "language/statements/class/elements/class-field-is-observable-by-proxy.js" -Expect to Parse: "language/statements/class/elements/syntax/valid/grammar-field-accessor.js" Expect to Parse: "language/statements/class/subclass/derived-class-return-override-for-of-arrow.js" Expect to Parse: "language/statements/class/subclass/derived-class-return-override-for-of.js" Expect to Parse: "language/statements/const/dstr/obj-ptrn-prop-eval-err.js" diff --git a/tasks/coverage/transformer_babel.snap b/tasks/coverage/transformer_babel.snap index 6ddf3e86ec88c..cc33537346a44 100644 --- a/tasks/coverage/transformer_babel.snap +++ b/tasks/coverage/transformer_babel.snap @@ -2,5 +2,4 @@ commit: 12619ffe transformer_babel Summary: AST Parsed : 2101/2101 (100.00%) -Positive Passed: 2100/2101 (99.95%) -Mismatch: "typescript/class/accessor/input.ts" +Positive Passed: 2101/2101 (100.00%) diff --git a/tasks/coverage/transformer_typescript.snap b/tasks/coverage/transformer_typescript.snap index 268234062061b..1854ec204b948 100644 --- a/tasks/coverage/transformer_typescript.snap +++ b/tasks/coverage/transformer_typescript.snap @@ -2,19 +2,5 @@ commit: d8086f14 transformer_typescript Summary: AST Parsed : 5283/5283 (100.00%) -Positive Passed: 5268/5283 (99.72%) +Positive Passed: 5282/5283 (99.98%) Mismatch: "compiler/elidedEmbeddedStatementsReplacedWithSemicolon.ts" -Mismatch: "compiler/esDecoratorsClassFieldsCrash.ts" -Mismatch: "compiler/useBeforeDeclaration_classDecorators.2.ts" -Mismatch: "conformance/classes/propertyMemberDeclarations/autoAccessor10.ts" -Mismatch: "conformance/classes/propertyMemberDeclarations/autoAccessor2.ts" -Mismatch: "conformance/classes/propertyMemberDeclarations/autoAccessor9.ts" -Mismatch: "conformance/classes/propertyMemberDeclarations/autoAccessorAllowedModifiers.ts" -Mismatch: "conformance/classes/propertyMemberDeclarations/staticAutoAccessors.ts" -Mismatch: "conformance/classes/propertyMemberDeclarations/staticAutoAccessorsWithDecorators.ts" -Mismatch: "conformance/decorators/legacyDecorators-contextualTypes.ts" -Mismatch: "conformance/esDecorators/classDeclaration/classThisReference/esDecorators-classDeclaration-classThisReference.ts" -Mismatch: "conformance/esDecorators/classDeclaration/fields/esDecorators-classDeclaration-fields-staticAccessor.ts" -Mismatch: "conformance/esDecorators/classDeclaration/fields/esDecorators-classDeclaration-fields-staticPrivateAccessor.ts" -Mismatch: "conformance/esDecorators/classExpression/esDecorators-classExpression-commentPreservation.ts" -Mismatch: "conformance/esDecorators/esDecorators-contextualTypes.ts" diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index 580cd26e07b2e..962d2d27ba8ec 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,6 +1,6 @@ commit: 12619ffe -Passed: 475/927 +Passed: 473/927 # All Passed: * babel-preset-react @@ -445,7 +445,9 @@ Passed: 475/927 * opts/optimizeConstEnums/input.ts * opts/rewriteImportExtensions/input.ts -# babel-plugin-transform-typescript (131/151) +# babel-plugin-transform-typescript (129/151) +* class/accessor-allowDeclareFields-false/input.ts +* class/accessor-allowDeclareFields-true/input.ts * enum/mix-references/input.ts * enum/ts5.0-const-foldable/input.ts * exports/declared-types/input.ts