From 6bd29ddc9ed4ae4d9e45322a4ac2e4d7422ba37a Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Fri, 27 Sep 2024 04:28:52 +0000 Subject: [PATCH] refactor(transformer): add more debug assertions (#6090) Test stacks are in expected state at end of traversal. --- .../src/es2015/arrow_functions.rs | 1 + .../src/es2016/exponentiation_operator.rs | 1 + .../src/es2020/nullish_coalescing_operator.rs | 1 + .../src/es2021/logical_assignment_operators.rs | 1 + crates/oxc_transformer/src/helpers/stack.rs | 18 ++++++++++++++++++ 5 files changed, 22 insertions(+) diff --git a/crates/oxc_transformer/src/es2015/arrow_functions.rs b/crates/oxc_transformer/src/es2015/arrow_functions.rs index 3fc1ef2f34afe..cc5b1a383920d 100644 --- a/crates/oxc_transformer/src/es2015/arrow_functions.rs +++ b/crates/oxc_transformer/src/es2015/arrow_functions.rs @@ -169,6 +169,7 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> { ); } debug_assert!(self.this_var_stack.len() == 1); + debug_assert!(self.this_var_stack.last().is_none()); } fn enter_function(&mut self, _func: &mut Function<'a>, _ctx: &mut TraverseCtx<'a>) { diff --git a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs index bd3548ca53a03..5cd69a40739db 100644 --- a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs +++ b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs @@ -65,6 +65,7 @@ impl<'a> Traverse<'a> for ExponentiationOperator<'a> { #[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.len() == 1); + debug_assert!(self.var_declarations.last().is_none()); } fn enter_statements( diff --git a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs index 5499fd41aaf57..41613b8a491c0 100644 --- a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs +++ b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs @@ -51,6 +51,7 @@ impl<'a> Traverse<'a> for NullishCoalescingOperator<'a> { #[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.len() == 1); + debug_assert!(self.var_declarations.last().is_none()); } fn enter_statements( diff --git a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs index eae3268231f5b..93d81632cd7c6 100644 --- a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs +++ b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs @@ -76,6 +76,7 @@ impl<'a> Traverse<'a> for LogicalAssignmentOperators<'a> { #[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.len() == 1); + debug_assert!(self.var_declarations.last().is_none()); } fn enter_statements( diff --git a/crates/oxc_transformer/src/helpers/stack.rs b/crates/oxc_transformer/src/helpers/stack.rs index d9a975490be1c..bb768ce61b637 100644 --- a/crates/oxc_transformer/src/helpers/stack.rs +++ b/crates/oxc_transformer/src/helpers/stack.rs @@ -85,6 +85,24 @@ impl SparseStack { } } + /// Get value of last entry on the stack. + #[inline] + pub fn last(&self) -> Option<&T> { + debug_assert!(!self.has_values.is_empty()); + // SAFETY: `self.has_values` starts with 1 entry. Only `pop` removes entries from it, + // and it ensures `self.has_values` always has at least 1 entry. + let has_value = unsafe { *self.has_values.last().unwrap_unchecked() }; + if has_value { + debug_assert!(!self.values.is_empty()); + // SAFETY: Last `self.has_values` is only `true` if there's a corresponding value in `self.values`. + // This invariant is maintained in `push`, `pop`, `take_last`, `last_or_init`, and `last_mut_or_init`. + let value = unsafe { self.values.last().unwrap_unchecked() }; + Some(value) + } else { + None + } + } + /// Take value from last entry on the stack, leaving last entry empty. #[inline] pub fn take_last(&mut self) -> Option {