From 5f9bee553ee68e022e9eefab7aea83a1fe744405 Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:42:31 +0000 Subject: [PATCH] perf(parser): store `Modifiers` on stack (#20742) `Modifiers` represents a set of 0 or more modifier keywords (`public`, `private`, `static` etc), up to a maximum of 15 possible modifiers. Previously it was stored as: ```rs pub struct Modifiers<'a> { /// Set of `Modifier`s, each containing `Span` of modifier keyword + modifier kind. modifiers: Option>, /// Bitfield of which modifiers are present. kinds: ModifierKinds, } ``` This is inefficient in a few ways: 1. `Modifiers` is not part of the AST, only temporary data used during parsing. Using a `Vec<'a, Modifier>` results in this temporary data taking up space in the AST arena, which hangs around unused for the whole life of the AST. 2. `modifiers` `Vec` can contains duplicates. This is pointless because using the same modifier twice is always a syntax error, and this is already handled by `check_modifier`. 3. `Modifier` contains the `Span` of the modifier keyword. The length of modifier keywords is statically known from their kind (e.g. `public` is always 6 bytes). Storing just the start offsets of keywords is sufficient. This PR switches to a more efficient representation: ```rs pub struct Modifiers { /// Start offset for each modifier, indexed by `ModifierKind` discriminant. offsets: [MaybeUninit; 15], /// Bitfield of which modifiers are present. kinds: ModifierKinds, } ``` This type contains all its data inline, and can be stored on the stack (64 bytes) - versus previous 32 bytes on stack + 16 bytes for each modifier in arena. Despite the larger footprint on stack, the use of `MaybeUninit` means that constructing an empty `Modifiers` requires less memory ops: * Now: 2-byte write to set `kinds = ModifierKinds::none()`. * Previously: 2-byte write for `kinds` + 8-byte write to set `modifiers = None`. Offsets are only written to `offsets` when a modifier is added. The `kinds` bitfield indicates which entries in `offsets` are present and initialized. All methods check `kinds` before accessing `offsets`, to avoid reading uninitialized memory (which would be UB). Small positive impact on some benchmarks (+0.2%). To be honest, it's more of a "the principle of the matter" thing - temporary data should not be stored in the arena. This stack was also an experiment in getting Claude to create a stack of PRs unattended from an initial step-by-step plan. --- crates/oxc_parser/src/js/class.rs | 22 +-- crates/oxc_parser/src/js/function.rs | 4 +- crates/oxc_parser/src/js/module.rs | 10 +- crates/oxc_parser/src/js/object.rs | 2 +- crates/oxc_parser/src/js/statement.rs | 6 +- crates/oxc_parser/src/modifiers.rs | 174 ++++++++++-------- crates/oxc_parser/src/ts/statement.rs | 18 +- crates/oxc_parser/src/ts/types.rs | 4 +- .../allocs_parser.snap | 8 +- 9 files changed, 133 insertions(+), 115 deletions(-) diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index e2ac7498e934b..1e423594d70fc 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -20,7 +20,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { &mut self, start_span: u32, stmt_ctx: StatementContext, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> Statement<'a> { let decl = self.parse_class_declaration(start_span, modifiers, decorators); @@ -37,7 +37,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_class_declaration( &mut self, start_span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> Box<'a, Class<'a>> { self.parse_class(start_span, ClassType::ClassDeclaration, modifiers, decorators) @@ -49,7 +49,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_class_expression( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> Expression<'a> { let class = self.parse_class(span, ClassType::ClassExpression, modifiers, decorators); @@ -60,7 +60,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { &mut self, start_span: u32, r#type: ClassType, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> Box<'a, Class<'a>> { self.bump_any(); // advance `class` @@ -320,7 +320,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { self.unexpected() } - fn parse_class_element_name(&mut self, modifiers: &Modifiers<'a>) -> (PropertyKey<'a>, bool) { + fn parse_class_element_name(&mut self, modifiers: &Modifiers) -> (PropertyKey<'a>, bool) { self.verify_modifiers( modifiers, ModifierKinds::all_except([ModifierKind::Const, ModifierKind::In, ModifierKind::Out]), @@ -377,7 +377,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { key: PropertyKey<'a>, computed: bool, definite: bool, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> ClassElement<'a> { let type_annotation = if self.is_ts { self.parse_ts_type_annotation() } else { None }; @@ -422,7 +422,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { span: u32, r#type: MethodDefinitionType, kind: MethodDefinitionKind, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> ClassElement<'a> { let (name, computed) = self.parse_class_element_name(modifiers); @@ -459,7 +459,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { span: u32, r#type: MethodDefinitionType, name: PropertyKey<'a>, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> ClassElement<'a> { if let Some(modifier) = modifiers.get(ModifierKind::Declare) { @@ -509,7 +509,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { &mut self, span: u32, r#type: MethodDefinitionType, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> ClassElement<'a> { let generator = self.eat(Kind::Star); @@ -596,7 +596,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { name: PropertyKey<'a>, computed: bool, optional: bool, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> ClassElement<'a> { let value = self.parse_method( @@ -628,7 +628,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { computed: bool, optional_span: Option, definite: bool, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> ClassElement<'a> { let type_annotation = if self.is_ts { self.parse_ts_type_annotation() } else { None }; diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 56f66f1574403..946848c0e9b32 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -241,7 +241,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { generator: bool, func_kind: FunctionKind, param_kind: FormalParameterKind, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, Function<'a>> { let ctx = self.ctx; self.ctx = self.ctx.and_in(true).and_await(r#async).and_yield(generator); @@ -366,7 +366,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { &mut self, start_span: u32, func_kind: FunctionKind, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, Function<'a>> { let r#async = modifiers.contains(ModifierKind::Async); self.expect(Kind::Function); diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index 5d69b1cc478f0..5fc59f2f7c00a 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -7,7 +7,7 @@ use super::FunctionKind; use crate::{ ParserConfig as Config, ParserImpl, diagnostics, lexer::Kind, - modifiers::{Modifier, ModifierKind, ModifierKinds, Modifiers}, + modifiers::{Modifier, ModifierKind, Modifiers}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -711,13 +711,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { if !cur_token.is_on_new_line() { // export default abstract class ... if is_abstract && kind == Kind::Class { - let modifiers = self - .ast - .vec1(Modifier::new(self.end_span(modifier_span), ModifierKind::Abstract)); - let modifiers = Modifiers::new( - Some(modifiers), - ModifierKinds::new([ModifierKind::Abstract]), - ); + let modifiers = Modifiers::new_single(ModifierKind::Abstract, modifier_span); return ExportDefaultDeclarationKind::ClassDeclaration( self.parse_class_declaration(decl_span, &modifiers, decorators), ); diff --git a/crates/oxc_parser/src/js/object.rs b/crates/oxc_parser/src/js/object.rs index 85b3391f9fe5d..d83ed2be3d0ba 100644 --- a/crates/oxc_parser/src/js/object.rs +++ b/crates/oxc_parser/src/js/object.rs @@ -208,7 +208,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { &mut self, span: u32, kind: PropertyKind, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, ObjectProperty<'a>> { let (key, computed) = self.parse_property_name(); let function = self.parse_method(false, false, FunctionKind::ObjectMethod); diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index f313d71c70e2c..38fbda5eeeea7 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -6,7 +6,7 @@ use super::{VariableDeclarationParent, grammar::CoverGrammar}; use crate::{ Context, ParserConfig as Config, ParserImpl, StatementContext, diagnostics, lexer::Kind, - modifiers::{Modifier, ModifierKind, ModifierKinds, Modifiers}, + modifiers::{ModifierKind, Modifiers}, }; impl<'a, C: Config> ParserImpl<'a, C> { @@ -794,9 +794,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { let span = self.start_span(); self.bump_any(); if self.is_ts && self.at(Kind::Enum) { - let modifiers = self.ast.vec1(Modifier::new(self.end_span(span), ModifierKind::Const)); - let modifiers = - Modifiers::new(Some(modifiers), ModifierKinds::new([ModifierKind::Const])); + let modifiers = Modifiers::new_single(ModifierKind::Const, span); Statement::from(self.parse_ts_enum_declaration(span, &modifiers)) } else { self.parse_variable_statement(span, VariableDeclarationKind::Const, stmt_ctx) diff --git a/crates/oxc_parser/src/modifiers.rs b/crates/oxc_parser/src/modifiers.rs index 72293e7b85ce4..5e544751f644b 100644 --- a/crates/oxc_parser/src/modifiers.rs +++ b/crates/oxc_parser/src/modifiers.rs @@ -1,10 +1,10 @@ use std::{ fmt::{self, Debug, Display}, - iter, mem, + iter, + mem::{self, MaybeUninit}, num::NonZeroU16, }; -use oxc_allocator::Vec; use oxc_ast::ast::TSAccessibility; use oxc_data_structures::fieldless_enum; use oxc_diagnostics::OxcDiagnostic; @@ -152,67 +152,66 @@ impl Modifier { /// // ^^^ This also counts as a modifier, but is also recorded separately as a /// // named export declaration /// ``` -#[derive(Debug)] -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). +/// +/// Stored as a fixed-size array of start offsets indexed by [`ModifierKind`] discriminant. +/// The `kinds` bitfield tracks which entries are populated. +/// Full `Span`s are reconstructed on demand, since each modifier keyword has a fixed length. +pub struct Modifiers { + /// Start offset for each modifier, indexed by `ModifierKind` discriminant. + /// Entries whose corresponding bit is set in `kinds` are initialized, other entries may not be. + /// Therefore it is only safe to assume that `offsets[kind as usize]` is initialized if `kinds.contains(kind)`. + offsets: [MaybeUninit; ModifierKind::VARIANTS.len()], + /// Bitfield of which modifier kinds are present. kinds: ModifierKinds, } -impl Default for Modifiers<'_> { - fn default() -> Self { - Self::empty() - } -} - -impl<'a> Modifiers<'a> { - /// Create a new set of modifiers - /// - /// # Invariants - /// `kinds` must correctly reflect the [`ModifierKind`]s within - /// `modifiers`. e.g., if `modifiers` is empty, then so is `kinds`. - #[must_use] - pub(crate) fn new(modifiers: Option>, kinds: ModifierKinds) -> Self { - // Debug check that `modifiers` and `kinds` are consistent with each other - #[cfg(debug_assertions)] - { - if let Some(modifiers) = &modifiers { - assert!(!modifiers.is_empty()); - - let mut found_kinds = ModifierKinds::none(); - for modifier in modifiers { - found_kinds = found_kinds.with(modifier.kind); - } - assert_eq!(found_kinds, kinds); - } else { - assert_eq!(kinds, ModifierKinds::none()); - } +impl Modifiers { + /// Create an empty set of modifiers. + pub const fn empty() -> Self { + Self { + offsets: [MaybeUninit::uninit(); ModifierKind::VARIANTS.len()], + kinds: ModifierKinds::none(), } + } - Self { modifiers, kinds } + /// Create a set of modifiers from a single modifier. + pub const fn new_single(kind: ModifierKind, start: u32) -> Self { + let mut modifiers = Self::empty(); + modifiers.add(kind, start); + modifiers } - pub fn empty() -> Self { - Self { modifiers: None, kinds: ModifierKinds::none() } + /// Add a modifier. + /// If a modifier with this [`ModifierKind`] has already been added, it is overwritten. + const fn add(&mut self, kind: ModifierKind, start: u32) { + self.kinds = self.kinds.with(kind); + self.offsets[kind as usize] = MaybeUninit::new(start); } pub fn contains(&self, target: ModifierKind) -> bool { self.kinds.contains(target) } - pub fn iter(&self) -> impl Iterator + '_ { - self.modifiers.as_ref().into_iter().flat_map(|modifiers| modifiers.iter()) + /// Iterate over all present modifiers. + /// + /// Order follows discriminant order (not source order). + pub fn iter(&self) -> impl Iterator { + self.kinds.iter().map(|kind| { + // SAFETY: Bits in `kinds` are set and the corresponding offset in `offsets` are initialized together + // (in `add` method). `kinds.iter()` only yields kinds whose bit is set. So `offsets[kind as usize]` + // must be initialized. + let start = unsafe { self.offsets[kind as usize].assume_init() }; + Modifier { span: Span::new(start, start + kind.len()), kind } + }) } /// Look up a specific modifier by [`ModifierKind`]. - pub fn get(&self, kind: ModifierKind) -> Option<&Modifier> { + pub fn get(&self, kind: ModifierKind) -> Option { if self.kinds.contains(kind) { - let modifier = self.iter().find(|m| m.kind == kind); - debug_assert!(modifier.is_some()); - modifier + // SAFETY: Bits in `kinds` are set and the corresponding offset in `offsets` are initialized together + // (in `add` method). Here, bit for `kind` is set, so `offsets[kind as usize]` must be initialized. + let start = unsafe { self.offsets[kind as usize].assume_init() }; + Some(Modifier { span: Span::new(start, start + kind.len()), kind }) } else { None } @@ -253,6 +252,12 @@ impl<'a> Modifiers<'a> { } } +impl Debug for Modifiers { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + // `fieldless_enum!` macro provides `ModifierKind::VARIANTS` constant listing all variants fieldless_enum! { #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -276,6 +281,22 @@ fieldless_enum! { } } +/// Length of each modifier keyword in bytes, indexed by [`ModifierKind`] discriminant. +static MODIFIER_LENGTHS: [u8; ModifierKind::VARIANTS.len()] = { + let mut lengths = [0; ModifierKind::VARIANTS.len()]; + + let mut i = 0; + while i < ModifierKind::VARIANTS.len() { + let kind = ModifierKind::VARIANTS[i]; + #[expect(clippy::cast_possible_truncation)] + let len = kind.as_str().len() as u8; + lengths[kind as usize] = len; + i += 1; + } + + lengths +}; + impl ModifierKind { /// Convert `usize` to [`ModifierKind`] without checks. /// @@ -291,7 +312,8 @@ impl ModifierKind { } } - pub fn as_str(self) -> &'static str { + /// Get this modifier keyword. + pub const fn as_str(self) -> &'static str { match self { Self::Abstract => "abstract", Self::Accessor => "accessor", @@ -310,6 +332,11 @@ impl ModifierKind { Self::Export => "export", } } + + /// Get length of this modifier keyword in bytes. + pub fn len(self) -> u32 { + u32::from(MODIFIER_LENGTHS[self as usize]) + } } impl TryFrom for ModifierKind { @@ -343,23 +370,21 @@ impl Display for ModifierKind { } } -impl<'a, C: Config> ParserImpl<'a, C> { - pub(crate) fn eat_modifiers_before_declaration(&mut self) -> Modifiers<'a> { +impl ParserImpl<'_, C> { + pub(crate) fn eat_modifiers_before_declaration(&mut self) -> Modifiers { if !self.at_modifier() { return Modifiers::empty(); } - let mut kinds = ModifierKinds::none(); - let mut modifiers = self.ast.vec(); + let mut modifiers = Modifiers::empty(); while self.at_modifier() { let span = self.start_span(); let kind = self.cur_kind(); self.bump_any(); let modifier = self.modifier(kind, self.end_span(span)); - self.check_modifier(kinds, &modifier); - kinds = kinds.with(modifier.kind); - modifiers.push(modifier); + self.check_modifier(modifiers.kinds, &modifier); + modifiers.add(modifier.kind, modifier.span.start); } - Modifiers::new(Some(modifiers), kinds) + modifiers } fn at_modifier(&mut self) -> bool { @@ -400,11 +425,9 @@ impl<'a, C: Config> ParserImpl<'a, C> { &mut self, permit_const_as_modifier: bool, stop_on_start_of_class_static_block: bool, - ) -> Modifiers<'a> { + ) -> Modifiers { let mut has_seen_static_modifier = false; - - let mut modifiers = None; - let mut modifier_kinds = ModifierKinds::none(); + let mut modifiers = Modifiers::empty(); while let Some(modifier) = self.try_parse_modifier( has_seen_static_modifier, @@ -414,12 +437,11 @@ impl<'a, C: Config> ParserImpl<'a, C> { if modifier.kind == ModifierKind::Static { has_seen_static_modifier = true; } - self.check_modifier(modifier_kinds, &modifier); - modifier_kinds = modifier_kinds.with(modifier.kind); - modifiers.get_or_insert_with(|| self.ast.vec()).push(modifier); + self.check_modifier(modifiers.kinds, &modifier); + modifiers.add(modifier.kind, modifier.span.start); } - Modifiers::new(modifiers, modifier_kinds) + modifiers } fn try_parse_modifier( @@ -643,7 +665,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { #[inline] pub(crate) fn verify_modifiers( &mut self, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, allowed: ModifierKinds, // If `true`, `allowed` is exact match; if `false`, `allowed` is a superset. // Used for whether to pass `allowed` to `create_diagnostic` function. @@ -657,23 +679,27 @@ impl<'a, C: Config> ParserImpl<'a, C> { // Also `#[inline(never)]` to help `verify_modifiers` to get inlined. #[cold] #[inline(never)] - fn report<'a, C: Config, F>( - parser: &mut ParserImpl<'a, C>, - modifiers: &Modifiers<'a>, + fn report( + parser: &mut ParserImpl<'_, C>, + modifiers: &Modifiers, allowed: ModifierKinds, strict: bool, create_diagnostic: F, ) where F: Fn(&Modifier, Option) -> OxcDiagnostic, { - let mut found_invalid_modifier = false; - for modifier in modifiers.iter() { - if !allowed.contains(modifier.kind) { - parser.error(create_diagnostic(modifier, strict.then_some(allowed))); - found_invalid_modifier = true; - } + // Sort modifiers to produce errors in source code order + let mut disallowed_modifiers = modifiers + .iter() + .filter(|modifier| !allowed.contains(modifier.kind)) + .collect::>(); + disallowed_modifiers.sort_unstable_by_key(|modifier| modifier.span.start); + + debug_assert!(!disallowed_modifiers.is_empty()); + + for modifier in &disallowed_modifiers { + parser.error(create_diagnostic(modifier, strict.then_some(allowed))); } - debug_assert!(found_invalid_modifier); } report(self, modifiers, allowed, strict, create_diagnostic); } diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 8d660e2d2e13c..70d21902829f4 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -21,7 +21,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_ts_enum_declaration( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Declaration<'a> { self.bump_any(); // bump `enum` let id = self.parse_binding_identifier(); @@ -124,7 +124,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_ts_type_alias_declaration( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Declaration<'a> { self.expect(Kind::Type); @@ -176,7 +176,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_ts_interface_declaration( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Declaration<'a> { let id = self.parse_binding_identifier(); let type_parameters = self.parse_ts_type_parameters(); @@ -300,7 +300,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { fn parse_ts_module_declaration( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, TSModuleDeclaration<'a>> { let kind = if self.eat(Kind::Namespace) { TSModuleDeclarationKind::Namespace @@ -317,7 +317,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { fn parse_ambient_external_module_declaration( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, TSModuleDeclaration<'a>> { let id = TSModuleDeclarationName::StringLiteral(self.parse_literal_string()); let body = if self.at(Kind::LCurly) { @@ -356,7 +356,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { &mut self, span: u32, kind: TSModuleDeclarationKind, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, TSModuleDeclaration<'a>> { let id = TSModuleDeclarationName::Identifier(self.parse_binding_identifier()); let body = if self.eat(Kind::Dot) { @@ -385,7 +385,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { fn parse_ts_global_declaration( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, TSGlobalDeclaration<'a>> { let keyword_span_start = self.start_span(); self.expect(Kind::Global); @@ -425,7 +425,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_declaration( &mut self, start_span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, decorators: Vec<'a, Decorator<'a>>, ) -> Declaration<'a> { let kind = self.cur_kind(); @@ -528,7 +528,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_ts_declare_function( &mut self, start_span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, Function<'a>> { let r#async = modifiers.contains(ModifierKind::Async); self.expect(Kind::Function); diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 8aa1c96670db0..aefd03ecd79ac 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -1418,7 +1418,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(super) fn parse_property_or_method_signature( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> TSSignature<'a> { let (key, computed) = self.parse_property_name(); let optional = self.eat(Kind::Question); @@ -1465,7 +1465,7 @@ impl<'a, C: Config> ParserImpl<'a, C> { pub(crate) fn parse_index_signature_declaration( &mut self, span: u32, - modifiers: &Modifiers<'a>, + modifiers: &Modifiers, ) -> Box<'a, TSIndexSignature<'a>> { let opening_span = self.cur_token().span(); self.expect(Kind::LBrack); diff --git a/tasks/track_memory_allocations/allocs_parser.snap b/tasks/track_memory_allocations/allocs_parser.snap index 0818977702630..778bde3e8f585 100644 --- a/tasks/track_memory_allocations/allocs_parser.snap +++ b/tasks/track_memory_allocations/allocs_parser.snap @@ -1,14 +1,14 @@ File | File size || Sys allocs | Sys reallocs || Arena allocs | Arena reallocs | Arena bytes ------------------------------------------------------------------------------------------------------------------------------------------- -checker.ts | 2.92 MB || 9672 | 21 || 267677 | 22847 +checker.ts | 2.92 MB || 9672 | 21 || 267640 | 22847 -cal.com.tsx | 1.06 MB || 1083 | 49 || 136164 | 13698 +cal.com.tsx | 1.06 MB || 1083 | 49 || 136127 | 13697 RadixUIAdoptionSection.jsx | 2.52 kB || 1 | 0 || 363 | 66 -pdf.mjs | 567.30 kB || 703 | 75 || 90678 | 8148 +pdf.mjs | 567.30 kB || 703 | 75 || 90547 | 8148 antd.js | 6.69 MB || 7132 | 235 || 528505 | 55357 -binder.ts | 193.08 kB || 530 | 7 || 16790 | 1467 +binder.ts | 193.08 kB || 530 | 7 || 16788 | 1467