diff --git a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs index c0b1a7954..5ec9f86eb 100644 --- a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs +++ b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs @@ -60,22 +60,31 @@ use oxc_span::SPAN; use oxc_syntax::operator::{AssignmentOperator, LogicalOperator}; use oxc_traverse::{Traverse, TraverseCtx}; -use crate::context::Ctx; +use crate::{context::Ctx, helpers::stack::SparseStack}; pub struct LogicalAssignmentOperators<'a> { _ctx: Ctx<'a>, - var_declarations: std::vec::Vec>>, + var_declarations: SparseStack>>, } impl<'a> LogicalAssignmentOperators<'a> { pub fn new(ctx: Ctx<'a>) -> Self { - Self { _ctx: ctx, var_declarations: vec![] } + Self { _ctx: ctx, var_declarations: SparseStack::new() } } } impl<'a> Traverse<'a> for LogicalAssignmentOperators<'a> { - fn enter_statements(&mut self, _stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { - self.var_declarations.push(ctx.ast.vec()); + #[inline] // Inline because it's no-op in release mode + fn exit_program(&mut self, _program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) { + debug_assert!(self.var_declarations.is_empty()); + } + + fn enter_statements( + &mut self, + _stmts: &mut Vec<'a, Statement<'a>>, + _ctx: &mut TraverseCtx<'a>, + ) { + self.var_declarations.push(None); } fn exit_statements( @@ -84,9 +93,7 @@ impl<'a> Traverse<'a> for LogicalAssignmentOperators<'a> { ctx: &mut TraverseCtx<'a>, ) { if let Some(declarations) = self.var_declarations.pop() { - if declarations.is_empty() { - return; - } + debug_assert!(!declarations.is_empty()); let variable = ctx.ast.alloc_variable_declaration( SPAN, VariableDeclarationKind::Var, @@ -390,8 +397,7 @@ impl<'a> LogicalAssignmentOperators<'a> { let id = ctx.ast.binding_pattern_kind_from_binding_identifier(binding_identifier); let id = ctx.ast.binding_pattern(id, NONE, false); self.var_declarations - .last_mut() - .unwrap() + .get_mut_or_init(|| ctx.ast.vec()) .push(ctx.ast.variable_declarator(SPAN, kind, id, None, false)); // _name = name diff --git a/crates/oxc_transformer/src/es2021/mod.rs b/crates/oxc_transformer/src/es2021/mod.rs index 6a94877c2..2478da295 100644 --- a/crates/oxc_transformer/src/es2021/mod.rs +++ b/crates/oxc_transformer/src/es2021/mod.rs @@ -31,6 +31,13 @@ impl<'a> ES2021<'a> { } impl<'a> Traverse<'a> for ES2021<'a> { + #[inline] // Inline because it's no-op in release mode + fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { + if self.options.logical_assignment_operators { + self.logical_assignment_operators.exit_program(program, ctx); + } + } + fn enter_statements( &mut self, statements: &mut Vec<'a, Statement<'a>>, diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index c178f9ffb..d22ac9f4b 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -132,6 +132,7 @@ impl<'a> Traverse<'a> for Transformer<'a> { fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { self.x1_react.exit_program(program, ctx); self.x0_typescript.exit_program(program, ctx); + self.x2_es2021.exit_program(program, ctx); self.x2_es2020.exit_program(program, ctx); self.x2_es2016.exit_program(program, ctx); self.x3_es2015.exit_program(program, ctx);