Repository: swc-project/swc
Pull request #10459: perf(es/minifier): Use `bitflags` for var info
Author: login: bvanjoi
Created: 2025-05-13T10:43:57Z | Merged: 2025-05-14T02:40:00Z

**Description**:

Convert lots of boolean flags into a single field with `bitflags`. This reduces the memory consumption a bit, and makes it a bit faster.


Diff:
diff --git a/crates/swc_ecma_minifier/src/compress/hoist_decls.rs b/crates/swc_ecma_minifier/src/compress/hoist_decls.rs
index ef45b73779a4..713803a13de9 100644
--- a/crates/swc_ecma_minifier/src/compress/hoist_decls.rs
+++ b/crates/swc_ecma_minifier/src/compress/hoist_decls.rs
@@ -8,7 +8,7 @@ use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
 
 use super::util::drop_invalid_stmts;
 use crate::{
-    program_data::ProgramData,
+    program_data::{ProgramData, VarUsageInfoFlags},
     util::{is_hoisted_var_decl_without_init, sort::is_sorted_by, IsModuleItem, ModuleItemExt},
 };
 
@@ -61,7 +61,7 @@ impl Hoister<'_> {
                             self.data
                                 .vars
                                 .get(id)
-                                .map(|v| !v.used_above_decl)
+                                .map(|v| !v.flags.contains(VarUsageInfoFlags::USED_ABOVE_DECL))
                                 .unwrap_or(false)
                         }) {
                             2
@@ -130,7 +130,11 @@ impl Hoister<'_> {
                                                 .data
                                                 .vars
                                                 .get(&id.to_id())
-                                                .map(|v| v.declared_as_fn_param)
+                                                .map(|v| {
+                                                    v.flags.contains(
+                                                        VarUsageInfoFlags::DECLARED_AS_FN_PARAM,
+                                                    )
+                                                })
                                                 .unwrap_or(false)
                                         {
                                             continue;
@@ -212,7 +216,11 @@ impl Hoister<'_> {
                                                 .data
                                                 .vars
                                                 .get(&name.to_id())
-                                                .map(|v| v.declared_as_fn_param)
+                                                .map(|v| {
+                                                    v.flags.contains(
+                                                        VarUsageInfoFlags::DECLARED_AS_FN_PARAM,
+                                                    )
+                                                })
                                                 .unwrap_or(false)
                                         {
                                             return false;
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/bools.rs b/crates/swc_ecma_minifier/src/compress/optimize/bools.rs
index 44ec71747338..5ef46f3fde6f 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/bools.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/bools.rs
@@ -3,6 +3,7 @@ use swc_ecma_ast::*;
 use swc_ecma_utils::{ExprExt, Type, Value};
 
 use super::Optimizer;
+use crate::program_data::VarUsageInfoFlags;
 
 /// Methods related to the options `bools` and `bool_as_ints`.
 impl Optimizer<'_> {
@@ -22,7 +23,7 @@ impl Optimizer<'_> {
                     // TODO?
                     if let Expr::Ident(arg) = &**arg {
                         if let Some(usage) = o.data.vars.get(&arg.to_id()) {
-                            if !usage.declared {
+                            if !usage.flags.contains(VarUsageInfoFlags::DECLARED) {
                                 return false;
                             }
                         }
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs b/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs
index d52bec6c6977..e1bc8453dc4e 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs
@@ -12,6 +12,7 @@ use crate::{
         optimize::BitCtx,
         util::{negate, negate_cost},
     },
+    program_data::VarUsageInfoFlags,
     DISABLE_BUGGY_PASSES,
 };
 
@@ -398,7 +399,11 @@ impl Optimizer<'_> {
                     .data
                     .vars
                     .get(&cons_callee.to_id())
-                    .map(|v| v.is_fn_local && v.declared)
+                    .map(|v| {
+                        v.flags.contains(
+                            VarUsageInfoFlags::IS_FN_LOCAL.union(VarUsageInfoFlags::DECLARED),
+                        )
+                    })
                     .unwrap_or(false);
 
                 if side_effect_free
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs b/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs
index 0efa4e213f02..0d365eda7755 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/dead_code.rs
@@ -2,6 +2,7 @@ use swc_common::util::take::Take;
 use swc_ecma_ast::*;
 
 use super::{BitCtx, Optimizer};
+use crate::program_data::VarUsageInfoFlags;
 
 /// Methods related to option `dead_code`.
 impl Optimizer<'_> {
@@ -51,7 +52,11 @@ impl Optimizer<'_> {
                     .data
                     .vars
                     .get(&lhs.to_id())
-                    .map(|var| var.declared && var.is_fn_local && !var.declared_as_fn_param)
+                    .map(|var| {
+                        var.flags.contains(
+                            VarUsageInfoFlags::DECLARED.union(VarUsageInfoFlags::IS_FN_LOCAL),
+                        ) && !var.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_PARAM)
+                    })
                     .unwrap_or(false)
                 {
                     report_change!(
@@ -78,7 +83,11 @@ impl Optimizer<'_> {
                         .data
                         .vars
                         .get(&lhs.to_id())
-                        .map(|var| var.declared && var.is_fn_local)
+                        .map(|var| {
+                            var.flags.contains(
+                                VarUsageInfoFlags::DECLARED.union(VarUsageInfoFlags::IS_FN_LOCAL),
+                            )
+                        })
                         .unwrap_or(false)
                     {
                         report_change!(
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs
index 698b7b2c3fc3..53f547577e5c 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs
@@ -6,7 +6,10 @@ use swc_ecma_ast::*;
 use swc_ecma_utils::{ExprExt, Value::Known};
 
 use super::{BitCtx, Optimizer};
-use crate::{compress::util::eval_as_number, maybe_par, DISABLE_BUGGY_PASSES};
+use crate::{
+    compress::util::eval_as_number, maybe_par, program_data::VarUsageInfoFlags,
+    DISABLE_BUGGY_PASSES,
+};
 
 /// Methods related to the option `evaluate`.
 impl Optimizer<'_> {
@@ -44,7 +47,7 @@ impl Optimizer<'_> {
 
                 let usage = self.data.vars.get(&obj.to_id())?;
 
-                if usage.reassigned {
+                if usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                     return None;
                 }
 
@@ -100,7 +103,7 @@ impl Optimizer<'_> {
                 .data
                 .vars
                 .get(&i.to_id())
-                .map(|var| var.declared)
+                .map(|var| var.flags.contains(VarUsageInfoFlags::DECLARED))
                 .unwrap_or(false)
             {
                 return;
@@ -424,7 +427,9 @@ impl Optimizer<'_> {
                             // If a variable named `NaN` is in scope, don't convert e into NaN.
                             let data = &self.data.vars;
                             if maybe_par!(
-                                data.iter().any(|(name, v)| v.declared && name.0 == "NaN"),
+                                data.iter()
+                                    .any(|(name, v)| v.flags.contains(VarUsageInfoFlags::DECLARED)
+                                        && name.0 == "NaN"),
                                 *crate::LIGHT_TASK_PARALLELS
                             ) {
                                 return;
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs
index 5a146a0b0ca3..df84272415ab 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs
@@ -10,7 +10,7 @@ use super::{util::NormalMultiReplacer, BitCtx, Optimizer};
 #[cfg(feature = "debug")]
 use crate::debug::dump;
 use crate::{
-    program_data::{ProgramData, ScopeData},
+    program_data::{ProgramData, ScopeData, VarUsageInfoFlags},
     util::{idents_captured_by, make_number},
 };
 
@@ -156,7 +156,7 @@ impl Optimizer<'_> {
         };
 
         if let Some(scope) = find_scope(self.data, callee) {
-            if scope.used_arguments {
+            if scope.contains(ScopeData::USED_ARGUMENTS) {
                 log_abort!("iife: [x] Found usage of arguments");
                 return;
             }
@@ -184,7 +184,7 @@ impl Optimizer<'_> {
                 .data
                 .vars
                 .get(&ident.to_id())
-                .filter(|usage| usage.used_recursively)
+                .filter(|usage| usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY))
                 .is_some()
             {
                 log_abort!("iife: [x] Recursive?");
@@ -203,7 +203,7 @@ impl Optimizer<'_> {
                             continue;
                         }
                         if let Some(usage) = self.data.vars.get(&param.to_id()) {
-                            if usage.reassigned {
+                            if usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                                 continue;
                             }
                         }
@@ -247,9 +247,9 @@ impl Optimizer<'_> {
                     Pat::Rest(rest_pat) => {
                         if let Pat::Ident(param_id) = &*rest_pat.arg {
                             if let Some(usage) = self.data.vars.get(&param_id.to_id()) {
-                                if usage.reassigned
+                                if usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
                                     || usage.ref_count != 1
-                                    || !usage.has_property_access
+                                    || !usage.flags.contains(VarUsageInfoFlags::HAS_PROPERTY_ACCESS)
                                 {
                                     continue;
                                 }
@@ -354,7 +354,7 @@ impl Optimizer<'_> {
                 .data
                 .vars
                 .get(&ident.to_id())
-                .filter(|usage| usage.used_recursively)
+                .filter(|usage| usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY))
                 .is_some()
             {
                 return;
@@ -507,7 +507,7 @@ impl Optimizer<'_> {
                         .data
                         .vars
                         .get(&i.to_id())
-                        .filter(|usage| usage.used_recursively)
+                        .filter(|usage| usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY))
                         .is_some()
                     {
                         log_abort!("iife: [x] Recursive?");
@@ -747,7 +747,10 @@ impl Optimizer<'_> {
         if !param_ids.is_empty() && !self.may_add_ident() {
             for pid in param_ids {
                 if let Some(usage) = self.data.vars.get(&pid.to_id()) {
-                    if usage.ref_count > 1 || usage.assign_count > 0 || usage.inline_prevented {
+                    if usage.ref_count > 1
+                        || usage.assign_count > 0
+                        || usage.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED)
+                    {
                         log_abort!("iife: [x] Cannot inline because of usage of `{}`", pid);
                         return false;
                     }
@@ -789,7 +792,7 @@ impl Optimizer<'_> {
         // We completely abort on eval, because we cannot know whether a variable in
         // upper scope will be afftected by eval.
         // https://github.com/swc-project/swc/issues/6628
-        if self.data.top.has_eval_call {
+        if self.data.top.contains(ScopeData::HAS_EVAL_CALL) {
             log_abort!("iife: [x] Aborting because of eval");
             return false;
         }
@@ -908,7 +911,7 @@ impl Optimizer<'_> {
             if let Some(arg) = arg {
                 if let Some(usage) = self.data.vars.get_mut(&params[idx].to_id()) {
                     if usage.ref_count == 1
-                        && !usage.reassigned
+                        && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
                         && usage.property_mutation_count == 0
                         && matches!(
                             &*arg,
@@ -964,7 +967,7 @@ impl Optimizer<'_> {
             if let Some(arg) = &mut arg {
                 if let Some(usage) = self.data.vars.get_mut(&params[idx].to_id()) {
                     if usage.ref_count == 1
-                        && !usage.reassigned
+                        && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
                         && usage.property_mutation_count == 0
                         && matches!(
                             &**arg,
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs
index ecbac563d392..f2bf36ccb742 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs
@@ -8,7 +8,7 @@ use swc_ecma_visit::VisitMutWith;
 use super::Optimizer;
 use crate::{
     compress::optimize::{util::is_valid_for_lhs, BitCtx},
-    program_data::VarUsageInfo,
+    program_data::{ScopeData, VarUsageInfo, VarUsageInfoFlags},
     util::{
         idents_captured_by, idents_used_by, idents_used_by_ignoring_nested, size::SizeWithCtxt,
     },
@@ -34,7 +34,7 @@ impl Optimizer<'_> {
             may_remove
         );
 
-        if self.data.top.has_eval_call {
+        if self.data.top.contains(ScopeData::HAS_EVAL_CALL) {
             return;
         }
 
@@ -45,17 +45,24 @@ impl Optimizer<'_> {
 
         if let Some(usage) = self.data.vars.get(&ident.to_id()) {
             let ref_count = usage.ref_count - u32::from(can_drop && usage.ref_count > 1);
-            if !usage.var_initialized {
+            if !usage.flags.contains(VarUsageInfoFlags::VAR_INITIALIZED) {
                 return;
             }
 
-            if self.data.top.used_arguments && usage.declared_as_fn_param {
+            if self.data.top.contains(ScopeData::USED_ARGUMENTS)
+                && usage
+                    .flags
+                    .contains(VarUsageInfoFlags::DECLARED_AS_FN_PARAM)
+            {
                 return;
             }
-            if usage.declared_as_catch_param {
+            if usage
+                .flags
+                .contains(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM)
+            {
                 return;
             }
-            if usage.inline_prevented {
+            if usage.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED) {
                 return;
             }
 
@@ -67,7 +74,7 @@ impl Optimizer<'_> {
                 return;
             }
 
-            if usage.used_above_decl {
+            if usage.flags.contains(VarUsageInfoFlags::USED_ABOVE_DECL) {
                 log_abort!("inline: [x] It's cond init or used before decl",);
                 return;
             }
@@ -98,13 +105,15 @@ impl Optimizer<'_> {
             // literal key.
             //
             // TODO: Allow `length` in usage.accessed_props
-            if usage.declared
+            if usage.flags.contains(VarUsageInfoFlags::DECLARED)
                 && !usage.mutated()
                 && usage.accessed_props.is_empty()
-                && !usage.indexed_with_dynamic_key
+                && !usage.flags.intersects(
+                    VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY
+                        .union(VarUsageInfoFlags::USED_AS_REF),
+                )
                 && !usage.is_infected()
                 && is_inline_enabled
-                && !usage.used_as_ref
             {
                 if let Expr::Array(arr) = init {
                     if arr.elems.len() < 32
@@ -130,7 +139,7 @@ impl Optimizer<'_> {
                 }
             }
 
-            if !usage.is_fn_local {
+            if !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL) {
                 match init {
                     Expr::Lit(..) | Expr::Ident(..) => {}
 
@@ -156,7 +165,7 @@ impl Optimizer<'_> {
                 }
             }
 
-            if !usage.reassigned {
+            if !usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                 match init {
                     Expr::Fn(..) | Expr::Arrow(..) | Expr::Class(..) => {
                         self.typeofs.insert(ident.to_id(), "function".into());
@@ -172,7 +181,7 @@ impl Optimizer<'_> {
                 self.mode.store(ident.to_id(), &*init);
             }
 
-            if usage.used_recursively {
+            if usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY) {
                 return;
             }
 
@@ -181,16 +190,19 @@ impl Optimizer<'_> {
             if is_inline_enabled
                 && usage.declared_count == 1
                 && usage.assign_count == 1
-                && !usage.reassigned
-                && (usage.property_mutation_count == 0 || !usage.reassigned)
+                && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                && (usage.property_mutation_count == 0
+                    || !usage.flags.contains(VarUsageInfoFlags::REASSIGNED))
                 && match init {
                     Expr::Ident(Ident { sym, .. }) if &**sym == "eval" => false,
 
                     Expr::Ident(id) if !id.eq_ignore_span(ident) => {
-                        if !usage.assigned_fn_local {
+                        if !usage.flags.contains(VarUsageInfoFlags::ASSIGNED_FN_LOCAL) {
                             false
                         } else if let Some(u) = self.data.vars.get(&id.to_id()) {
-                            let mut should_inline = !u.reassigned && u.declared;
+                            let mut should_inline =
+                                !u.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                                    && u.flags.contains(VarUsageInfoFlags::DECLARED);
 
                             should_inline &=
                                 // Function declarations are hoisted
@@ -199,18 +211,23 @@ impl Optimizer<'_> {
                                 // See https://github.com/swc-project/swc/issues/6463
                                 //
                                 // We check callee_count of `usage` because we copy simple functions
-                                !u.used_above_decl
-                                    || !u.declared_as_fn_decl
+                                !u.flags.contains(VarUsageInfoFlags::USED_ABOVE_DECL)
+                                    || !u.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_DECL)
                                     || usage.callee_count == 0;
 
-                            if u.declared_as_for_init && !usage.is_fn_local {
+                            if u.flags.contains(VarUsageInfoFlags::DECLARED_AS_FOR_INIT)
+                                && !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                            {
                                 should_inline &= !matches!(
                                     u.var_kind,
                                     Some(VarDeclKind::Let | VarDeclKind::Const)
                                 )
                             }
 
-                            if u.declared_as_fn_decl || u.declared_as_fn_expr {
+                            if u.flags.intersects(
+                                VarUsageInfoFlags::DECLARED_AS_FN_DECL
+                                    .union(VarUsageInfoFlags::DECLARED_AS_FN_EXPR),
+                            ) {
                                 if self.options.keep_fnames
                                     || self.mangle_options.is_some_and(|v| v.keep_fn_names)
                                 {
@@ -218,7 +235,7 @@ impl Optimizer<'_> {
                                 }
                             }
 
-                            if u.declared_as_fn_expr {
+                            if u.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_EXPR) {
                                 if self.options.inline != 3 {
                                     return;
                                 }
@@ -248,12 +265,15 @@ impl Optimizer<'_> {
                     Expr::Unary(UnaryExpr {
                         op: op!("!"), arg, ..
                     }) => arg.is_lit(),
-                    Expr::This(..) => usage.is_fn_local,
+                    Expr::This(..) => usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL),
                     Expr::Arrow(arr) => {
                         is_arrow_simple_enough_for_copy(arr).is_some_and(|cost| cost <= 8)
                             && !(usage.property_mutation_count > 0
-                                || usage.executed_multiple_time
-                                || usage.used_as_arg && ref_count > 1)
+                                || usage
+                                    .flags
+                                    .contains(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME)
+                                || usage.flags.contains(VarUsageInfoFlags::USED_AS_ARG)
+                                    && ref_count > 1)
                             && ref_count - 1 <= usage.callee_count
                     }
                     _ => false,
@@ -267,36 +287,32 @@ impl Optimizer<'_> {
                 self.mode.store(id.clone(), &*init);
 
                 let VarUsageInfo {
-                    used_as_arg,
-                    used_as_ref,
-                    indexed_with_dynamic_key,
                     usage_count,
-                    has_property_access,
                     property_mutation_count,
-                    used_above_decl,
-                    executed_multiple_time,
-                    used_in_cond,
-                    used_recursively,
-                    no_side_effect_for_member_access,
+                    flags,
                     ..
                 } = **usage;
                 let mut inc_usage = || {
                     if let Expr::Ident(i) = &*init {
                         if let Some(u) = self.data.vars.get_mut(&i.to_id()) {
-                            u.used_as_arg |= used_as_arg;
-                            u.used_as_ref |= used_as_ref;
-                            u.indexed_with_dynamic_key |= indexed_with_dynamic_key;
-                            u.has_property_access |= has_property_access;
-                            u.property_mutation_count += property_mutation_count;
-                            u.used_above_decl |= used_above_decl;
-                            u.executed_multiple_time |= executed_multiple_time;
-                            u.used_in_cond |= used_in_cond;
-                            u.used_recursively |= used_recursively;
-
-                            u.no_side_effect_for_member_access &= no_side_effect_for_member_access;
+                            u.flags |= flags & VarUsageInfoFlags::USED_AS_ARG;
+                            u.flags |= flags & VarUsageInfoFlags::USED_AS_REF;
+                            u.flags |= flags & VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY;
+                            u.flags |= flags & VarUsageInfoFlags::HAS_PROPERTY_ACCESS;
+                            u.flags |= flags & VarUsageInfoFlags::USED_ABOVE_DECL;
+                            u.flags |= flags & VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME;
+                            u.flags |= flags & VarUsageInfoFlags::USED_IN_COND;
+                            u.flags |= flags & VarUsageInfoFlags::USED_RECURSIVELY;
+
+                            if !flags.contains(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS)
+                            {
+                                u.flags
+                                    .remove(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS)
+                            }
 
                             u.ref_count += ref_count;
                             u.usage_count += usage_count;
+                            u.property_mutation_count += property_mutation_count;
                         }
                     }
                 };
@@ -341,10 +357,12 @@ impl Optimizer<'_> {
             // Single use => inlined
             if !self.ctx.bit_ctx.contains(BitCtx::IsExported)
                 && is_inline_enabled
-                && usage.declared
+                && usage.flags.contains(VarUsageInfoFlags::DECLARED)
                 && may_remove
-                && !usage.reassigned
-                && !usage.declared_as_for_init
+                && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                && !usage
+                    .flags
+                    .contains(VarUsageInfoFlags::DECLARED_AS_FOR_INIT)
                 && usage.assign_count == 1
                 && ref_count == 1
             {
@@ -367,14 +385,18 @@ impl Optimizer<'_> {
                     }) => return,
 
                     Expr::Lit(Lit::Regex(..)) => {
-                        if !usage.is_fn_local || usage.executed_multiple_time {
+                        if !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                            || usage
+                                .flags
+                                .contains(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME)
+                        {
                             return;
                         }
                     }
 
                     Expr::This(..) => {
                         // Don't inline this if it passes function boundaries.
-                        if !usage.is_fn_local {
+                        if !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL) {
                             return;
                         }
                     }
@@ -393,7 +415,7 @@ impl Optimizer<'_> {
                                 continue;
                             }
                             if let Some(v_usage) = self.data.vars.get(&id) {
-                                if v_usage.reassigned {
+                                if v_usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                                     return;
                                 }
                             } else {
@@ -410,7 +432,7 @@ impl Optimizer<'_> {
                                 continue;
                             }
                             if let Some(v_usage) = self.data.vars.get(&id) {
-                                if v_usage.reassigned {
+                                if v_usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                                     return;
                                 }
                             } else {
@@ -422,7 +444,7 @@ impl Optimizer<'_> {
                     Expr::Object(..) if self.options.pristine_globals => {
                         for id in idents_used_by_ignoring_nested(init) {
                             if let Some(v_usage) = self.data.vars.get(&id) {
-                                if v_usage.reassigned {
+                                if v_usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                                     return;
                                 }
                             }
@@ -430,23 +452,34 @@ impl Optimizer<'_> {
                     }
 
                     Expr::Ident(id) if !id.eq_ignore_span(ident) => {
-                        if !usage.assigned_fn_local {
+                        if !usage.flags.contains(VarUsageInfoFlags::ASSIGNED_FN_LOCAL) {
                             return;
                         }
 
                         if let Some(init_usage) = self.data.vars.get(&id.to_id()) {
-                            if init_usage.reassigned || !init_usage.declared {
+                            if init_usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                                || !init_usage.flags.contains(VarUsageInfoFlags::DECLARED)
+                            {
                                 return;
                             }
 
-                            if init_usage.declared_as_fn_decl || init_usage.declared_as_fn_expr {
+                            if init_usage
+                                .flags
+                                .contains(VarUsageInfoFlags::DECLARED_AS_FN_DECL)
+                                || init_usage
+                                    .flags
+                                    .contains(VarUsageInfoFlags::DECLARED_AS_FN_EXPR)
+                            {
                                 if self.options.keep_fnames
                                     || self.mangle_options.is_some_and(|v| v.keep_fn_names)
                                 {
                                     return;
                                 }
                             }
-                            if init_usage.declared_as_fn_expr {
+                            if init_usage
+                                .flags
+                                .contains(VarUsageInfoFlags::DECLARED_AS_FN_EXPR)
+                            {
                                 if self.options.inline != 3 {
                                     return;
                                 }
@@ -457,10 +490,11 @@ impl Optimizer<'_> {
                     _ => {
                         for id in idents_used_by(init) {
                             if let Some(v_usage) = self.data.vars.get(&id) {
-                                if v_usage.reassigned
-                                    || v_usage.property_mutation_count
-                                        > usage.property_mutation_count
-                                    || v_usage.has_property_access
+                                if v_usage.property_mutation_count > usage.property_mutation_count
+                                    || v_usage.flags.intersects(
+                                        VarUsageInfoFlags::HAS_PROPERTY_ACCESS
+                                            .union(VarUsageInfoFlags::REASSIGNED),
+                                    )
                                 {
                                     return;
                                 }
@@ -469,13 +503,18 @@ impl Optimizer<'_> {
                     }
                 }
 
-                if usage.used_as_arg && !usage.is_fn_local {
+                if usage.flags.contains(VarUsageInfoFlags::USED_AS_ARG)
+                    && !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                {
                     if let Expr::Fn(..) | Expr::Arrow(..) = init {
                         return;
                     }
                 }
 
-                if usage.executed_multiple_time {
+                if usage
+                    .flags
+                    .contains(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME)
+                {
                     match init {
                         Expr::Lit(..) => {}
                         Expr::Fn(f) => {
@@ -577,7 +616,7 @@ impl Optimizer<'_> {
         }
 
         if let Some(usage) = self.data.vars.get(&i.to_id()) {
-            if !usage.reassigned {
+            if !usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                 trace_op!("typeofs: Storing typeof `{}{:?}`", i.sym, i.ctxt);
                 match &*decl {
                     Decl::Fn(..) | Decl::Class(..) => {
@@ -628,26 +667,35 @@ impl Optimizer<'_> {
             return;
         }
 
-        if self.data.top.has_eval_call || self.data.top.has_with_stmt {
+        if self
+            .data
+            .top
+            .intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT))
+        {
             return;
         }
 
         if let Some(usage) = self.data.vars.get(&i.to_id()) {
-            if usage.declared_as_catch_param {
+            if usage
+                .flags
+                .contains(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM)
+            {
                 log_abort!("inline: Declared as a catch parameter");
                 return;
             }
 
-            if usage.used_as_arg && usage.ref_count > 1 {
+            if usage.flags.contains(VarUsageInfoFlags::USED_AS_ARG) && usage.ref_count > 1 {
                 log_abort!("inline: Used as an arugment");
                 return;
             }
 
-            if usage.reassigned || usage.inline_prevented {
+            if usage.flags.intersects(
+                VarUsageInfoFlags::REASSIGNED.union(VarUsageInfoFlags::INLINE_PREVENTED),
+            ) {
                 log_abort!(
                     "inline: [x] reassigned = {}, inline_prevented = {}",
-                    usage.reassigned,
-                    usage.inline_prevented
+                    usage.flags.contains(VarUsageInfoFlags::REASSIGNED),
+                    usage.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED)
                 );
                 return;
             }
@@ -657,7 +705,7 @@ impl Optimizer<'_> {
             match decl {
                 Decl::Fn(f) if self.options.inline >= 2 && f.ident.sym != *"arguments" => {
                     if let Some(body) = &f.function.body {
-                        if !usage.used_recursively
+                        if !usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY)
                             // only callees can be inlined multiple times
                             && usage.callee_count > 0
                             // prefer single inline
@@ -712,7 +760,8 @@ impl Optimizer<'_> {
 
             // TODO(kdy1):
             //
-            // (usage.is_fn_local || self.options.inline == 3)
+            // (usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL) || self.options.inline
+            // == 3)
             //
             // seems like a correct check, but it's way to aggressive.
             // It does not break the code, but everything like _asyncToGenerator is inlined.
@@ -721,7 +770,7 @@ impl Optimizer<'_> {
                 && usage.ref_count == 1
                 && usage.can_inline_fn_once()
                 && (match decl {
-                    Decl::Class(..) => !usage.used_above_decl,
+                    Decl::Class(..) => !usage.flags.contains(VarUsageInfoFlags::USED_ABOVE_DECL),
                     Decl::Fn(..) => true,
                     _ => false,
                 })
@@ -775,7 +824,7 @@ impl Optimizer<'_> {
                     }
                     .into(),
                     Decl::Fn(f) => FnExpr {
-                        ident: if usage.used_recursively {
+                        ident: if usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY) {
                             Some(f.ident)
                         } else {
                             None
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs
index dc823be5ebbf..a203d0eecba2 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs
@@ -30,7 +30,7 @@ use crate::{
     maybe_par,
     mode::Mode,
     option::{CompressOptions, MangleOptions},
-    program_data::{ProgramData, VarUsageInfo},
+    program_data::{ProgramData, ScopeData, VarUsageInfoFlags},
     util::{
         contains_eval, contains_leaping_continue_with_label, make_number, ExprOptExt, ModuleItemExt,
     },
@@ -333,8 +333,11 @@ impl From<&Function> for FnMetadata {
 
 impl Optimizer<'_> {
     fn may_remove_ident(&self, id: &Ident) -> bool {
-        if let Some(VarUsageInfo { exported: true, .. }) =
-            self.data.vars.get(&id.clone().to_id()).map(|v| &**v)
+        if self
+            .data
+            .vars
+            .get(&id.to_id())
+            .is_some_and(|v| v.flags.contains(VarUsageInfoFlags::EXPORTED))
         {
             return false;
         }
@@ -351,11 +354,17 @@ impl Optimizer<'_> {
     }
 
     fn may_add_ident(&self) -> bool {
-        if self.ctx.in_top_level() && self.data.top.has_eval_call {
+        if self.ctx.in_top_level() && self.data.top.contains(ScopeData::HAS_EVAL_CALL) {
             return false;
         }
 
-        if self.data.scopes.get(&self.ctx.scope).unwrap().has_eval_call {
+        if self
+            .data
+            .scopes
+            .get(&self.ctx.scope)
+            .unwrap()
+            .contains(ScopeData::HAS_EVAL_CALL)
+        {
             return false;
         }
 
@@ -787,7 +796,9 @@ impl Optimizer<'_> {
                 if let Expr::Ident(callee) = &**callee {
                     if self.options.reduce_vars && self.options.side_effects {
                         if let Some(usage) = self.data.vars.get(&callee.to_id()) {
-                            if !usage.reassigned && usage.pure_fn {
+                            if !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                                && usage.flags.contains(VarUsageInfoFlags::PURE_FN)
+                            {
                                 self.changed = true;
                                 report_change!("Reducing function call to a variable");
 
@@ -2831,7 +2842,12 @@ impl VisitMut for Optimizer<'_> {
             true
         });
 
-        let uses_eval = self.data.scopes.get(&self.ctx.scope).unwrap().has_eval_call;
+        let uses_eval = self
+            .data
+            .scopes
+            .get(&self.ctx.scope)
+            .unwrap()
+            .contains(ScopeData::HAS_EVAL_CALL);
 
         if !uses_eval && !self.ctx.bit_ctx.contains(BitCtx::DontUsePrependNorAppend) {
             for v in vars.iter_mut() {
@@ -2933,7 +2949,10 @@ impl VisitMut for Optimizer<'_> {
                 if let Some(Expr::Invalid(..)) = var.init.as_deref() {
                     if let Pat::Ident(i) = &var.name {
                         if let Some(usage) = self.data.vars.get(&i.id.to_id()) {
-                            if usage.declared_as_catch_param {
+                            if usage
+                                .flags
+                                .contains(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM)
+                            {
                                 var.init = None;
                                 debug_assert_valid(var);
                                 return true;
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/props.rs b/crates/swc_ecma_minifier/src/compress/optimize/props.rs
index db60c69a3a83..b6e4788c2510 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/props.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/props.rs
@@ -3,7 +3,7 @@ use swc_ecma_ast::*;
 use swc_ecma_utils::{contains_this_expr, private_ident, prop_name_eq, ExprExt};
 
 use super::{unused::PropertyAccessOpts, BitCtx, Optimizer};
-use crate::util::deeply_contains_this_expr;
+use crate::{program_data::VarUsageInfoFlags, util::deeply_contains_this_expr};
 
 /// Methods related to the option `hoist_props`.
 impl Optimizer<'_> {
@@ -40,12 +40,14 @@ impl Optimizer<'_> {
             // smart.
             let usage = self.data.vars.get(&name.to_id())?;
             if usage.mutated()
-                || usage.used_in_cond
-                || usage.used_above_decl
-                || usage.used_as_ref
-                || usage.used_as_arg
-                || usage.indexed_with_dynamic_key
-                || usage.used_recursively
+                || usage.flags.intersects(
+                    VarUsageInfoFlags::USED_IN_COND
+                        .union(VarUsageInfoFlags::USED_ABOVE_DECL)
+                        .union(VarUsageInfoFlags::USED_AS_REF)
+                        .union(VarUsageInfoFlags::USED_AS_ARG)
+                        .union(VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY)
+                        .union(VarUsageInfoFlags::USED_RECURSIVELY),
+                )
             {
                 log_abort!("hoist_props: Variable `{}` is not a candidate", name.id);
                 return None;
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
index f32845b64744..933952be2633 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
@@ -23,6 +23,7 @@ use crate::{
         util::{is_directive, is_ident_used_by, replace_expr},
     },
     option::CompressOptions,
+    program_data::{ScopeData, VarUsageInfoFlags},
     util::{
         idents_used_by, idents_used_by_ignoring_nested, ExprOptExt, IdentUsageCollector,
         ModuleItemExt,
@@ -391,7 +392,8 @@ impl Optimizer<'_> {
                 })) => {
                     if let Some(id) = obj.as_ident() {
                         if let Some(usage) = self.data.vars.get(&id.to_id()) {
-                            id.ctxt != self.ctx.expr_ctx.unresolved_ctxt && !usage.reassigned
+                            id.ctxt != self.ctx.expr_ctx.unresolved_ctxt
+                                && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
                         } else {
                             false
                         }
@@ -529,7 +531,13 @@ impl Optimizer<'_> {
             return;
         }
 
-        if self.data.scopes.get(&self.ctx.scope).unwrap().has_eval_call {
+        if self
+            .data
+            .scopes
+            .get(&self.ctx.scope)
+            .unwrap()
+            .contains(ScopeData::HAS_EVAL_CALL)
+        {
             log_abort!("sequences: Eval call");
             return;
         }
@@ -657,7 +665,13 @@ impl Optimizer<'_> {
     pub(super) fn merge_sequences_in_seq_expr(&mut self, e: &mut SeqExpr) {
         self.normalize_sequences(e);
 
-        if self.data.scopes.get(&self.ctx.scope).unwrap().has_eval_call {
+        if self
+            .data
+            .scopes
+            .get(&self.ctx.scope)
+            .unwrap()
+            .contains(ScopeData::HAS_EVAL_CALL)
+        {
             log_abort!("sequences: Eval call");
             return;
         }
@@ -795,30 +809,33 @@ impl Optimizer<'_> {
                     // Merge sequentially
 
                     match b {
-                        Mergable::Var(b) => match b.init.as_deref_mut() {
-                            Some(b) => {
-                                if !merge_seq_cache.is_top_retain(self, a, a_idx)
-                                    && self.merge_sequential_expr(a, b)?
-                                {
-                                    changed = true;
-                                    merge_seq_cache.invalidate(a_idx);
-                                    merge_seq_cache.invalidate(b_idx);
-                                    break;
-                                }
-                            }
-                            None => {
-                                if let Mergable::Expr(Expr::Assign(a_exp)) = a {
-                                    if let (Some(a_id), Some(b_id)) =
-                                        (a_exp.left.as_ident(), b.name.as_ident())
+                        Mergable::Var(b) => {
+                            match b.init.as_deref_mut() {
+                                Some(b) => {
+                                    if !merge_seq_cache.is_top_retain(self, a, a_idx)
+                                        && self.merge_sequential_expr(a, b)?
                                     {
-                                        if a_id.id.eq_ignore_span(&b_id.id)
+                                        changed = true;
+                                        merge_seq_cache.invalidate(a_idx);
+                                        merge_seq_cache.invalidate(b_idx);
+                                        break;
+                                    }
+                                }
+                                None => {
+                                    if let Mergable::Expr(Expr::Assign(a_exp)) = a {
+                                        if let (Some(a_id), Some(b_id)) =
+                                            (a_exp.left.as_ident(), b.name.as_ident())
+                                        {
+                                            if a_id.id.eq_ignore_span(&b_id.id)
                                             && a_exp.op == op!("=")
                                             && self
                                                 .data
                                                 .vars
                                                 .get(&a_id.id.to_id())
                                                 .map(|u| {
-                                                    !u.inline_prevented && !u.declared_as_fn_expr
+                                                    !u.flags.intersects(
+                                                        VarUsageInfoFlags::INLINE_PREVENTED.union(VarUsageInfoFlags::DECLARED_AS_FN_EXPR)
+                                                    )
                                                 })
                                                 .unwrap_or(false)
                                         {
@@ -834,12 +851,13 @@ impl Optimizer<'_> {
 
                                             break;
                                         }
+                                        }
                                     }
-                                }
 
-                                continue;
+                                    continue;
+                                }
                             }
-                        },
+                        }
                         Mergable::Expr(b) => {
                             if !merge_seq_cache.is_top_retain(self, a, a_idx)
                                 && self.merge_sequential_expr(a, b)?
@@ -1433,7 +1451,12 @@ impl Optimizer<'_> {
                     }
                     _ => a.may_have_side_effects(self.ctx.expr_ctx),
                 };
-                if has_side_effect && !usgae.is_fn_local && (usgae.exported || usgae.reassigned) {
+                if has_side_effect
+                    && !usgae.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                    && (usgae.flags.intersects(
+                        VarUsageInfoFlags::EXPORTED.union(VarUsageInfoFlags::REASSIGNED),
+                    ))
+                {
                     log_abort!("a (expr) has side effect");
                     return false;
                 }
@@ -1441,8 +1464,10 @@ impl Optimizer<'_> {
             Mergable::Var(a) => {
                 if let Some(init) = &a.init {
                     if init.may_have_side_effects(self.ctx.expr_ctx)
-                        && !usgae.is_fn_local
-                        && (usgae.exported || usgae.reassigned)
+                        && !usgae.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                        && (usgae.flags.intersects(
+                            VarUsageInfoFlags::EXPORTED.union(VarUsageInfoFlags::REASSIGNED),
+                        ))
                     {
                         log_abort!("a (var) init has side effect");
                         return false;
@@ -1698,8 +1723,10 @@ impl Optimizer<'_> {
                             if let Some(left_obj) = b_left.obj.as_ident() {
                                 if let Some(usage) = self.data.vars.get(&left_obj.to_id()) {
                                     if left_obj.ctxt != self.ctx.expr_ctx.unresolved_ctxt
-                                        && !usage.inline_prevented
-                                        && !usage.reassigned
+                                        && !usage
+                                            .flags
+                                            .contains(VarUsageInfoFlags::INLINE_PREVENTED)
+                                        && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
                                         && !b_left.prop.is_computed()
                                     {
                                         match &*a {
@@ -2229,7 +2256,7 @@ impl Optimizer<'_> {
                         };
 
                         if let Some(usage) = self.data.vars.get(&left_id.to_id()) {
-                            if usage.inline_prevented {
+                            if usage.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED) {
                                 return Ok(false);
                             }
 
@@ -2238,7 +2265,7 @@ impl Optimizer<'_> {
                                 return Ok(false);
                             }
 
-                            if usage.declared_as_fn_expr {
+                            if usage.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_EXPR) {
                                 log_abort!(
                                     "sequences: Declared as fn expr ({}, {:?})",
                                     left_id.sym,
@@ -2248,10 +2275,12 @@ impl Optimizer<'_> {
                             }
 
                             // We can remove this variable same as unused pass
-                            if !usage.reassigned
-                                && usage.usage_count == 1
-                                && usage.declared
-                                && !usage.used_recursively
+                            if usage.usage_count == 1
+                                && usage.flags.contains(VarUsageInfoFlags::DECLARED)
+                                && !usage.flags.intersects(
+                                    VarUsageInfoFlags::USED_RECURSIVELY
+                                        .union(VarUsageInfoFlags::REASSIGNED),
+                                )
                             {
                                 can_remove = true;
                             }
@@ -2277,7 +2306,10 @@ impl Optimizer<'_> {
                         _ => false,
                     };
 
-                    if usage.ref_count != 1 || usage.reassigned || !usage.is_fn_local {
+                    if usage.ref_count != 1
+                        || usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                        || !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                    {
                         if is_lit {
                             can_take_init = false
                         } else {
@@ -2287,7 +2319,10 @@ impl Optimizer<'_> {
                         can_take_init = true;
                     }
 
-                    if usage.inline_prevented || usage.used_recursively {
+                    if usage.flags.intersects(
+                        VarUsageInfoFlags::INLINE_PREVENTED
+                            .union(VarUsageInfoFlags::USED_RECURSIVELY),
+                    ) {
                         return Ok(false);
                     }
 
@@ -2309,11 +2344,14 @@ impl Optimizer<'_> {
 
             Mergable::FnDecl(a) => {
                 if let Some(usage) = self.data.vars.get(&a.ident.to_id()) {
-                    if usage.ref_count != 1 || usage.reassigned || !usage.is_fn_local {
+                    if usage.ref_count != 1
+                        || usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                        || !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                    {
                         return Ok(false);
                     }
 
-                    if usage.inline_prevented {
+                    if usage.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED) {
                         return Ok(false);
                     }
 
@@ -2348,7 +2386,10 @@ impl Optimizer<'_> {
                         if let Some(usage) = self.data.vars.get(&left_id.to_id()) {
                             // We are eliminating one usage, so we use 1 instead of
                             // 0
-                            if !force_drop && usage.usage_count == 1 && !usage.reassigned {
+                            if !force_drop
+                                && usage.usage_count == 1
+                                && !usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                            {
                                 report_change!("sequences: Dropping inlined variable");
                                 a.name.take();
                             }
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/unused.rs b/crates/swc_ecma_minifier/src/compress/optimize/unused.rs
index 5fe7c0698aa1..c66f6992fc5b 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/unused.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/unused.rs
@@ -12,6 +12,7 @@ use crate::debug::dump;
 use crate::{
     compress::optimize::{util::extract_class_side_effect, BitCtx},
     option::PureGetterOption,
+    program_data::{ScopeData, VarUsageInfoFlags},
 };
 
 #[derive(Debug, Default, Clone, Copy)]
@@ -85,7 +86,7 @@ impl Optimizer<'_> {
         }
 
         if let Some(scope) = self.data.scopes.get(&self.ctx.scope) {
-            if scope.has_eval_call || scope.has_with_stmt {
+            if scope.intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) {
                 return;
             }
         }
@@ -121,7 +122,7 @@ impl Optimizer<'_> {
         }
 
         if let Some(scope) = self.data.scopes.get(&self.ctx.scope) {
-            if scope.has_eval_call || scope.has_with_stmt {
+            if scope.intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) {
                 log_abort!(
                     "unused: Preserving `{}` because of usages",
                     dump(&*name, false)
@@ -183,7 +184,7 @@ impl Optimizer<'_> {
         if let Some(v) = self.data.vars.get(&i.to_id()) {
             if v.ref_count == 0
                 && v.usage_count == 0
-                && !v.reassigned
+                && !v.flags.contains(VarUsageInfoFlags::REASSIGNED)
                 && v.property_mutation_count == 0
             {
                 self.changed = true;
@@ -243,11 +244,15 @@ impl Optimizer<'_> {
                 }
 
                 if let Some(usage) = self.data.vars.get(&e.to_id()) {
-                    if !usage.declared {
+                    if !usage.flags.contains(VarUsageInfoFlags::DECLARED) {
                         return true;
                     }
 
-                    if !usage.mutated() && usage.no_side_effect_for_member_access {
+                    if !usage.mutated()
+                        && usage
+                            .flags
+                            .contains(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS)
+                    {
                         return false;
                     }
                 }
@@ -461,7 +466,7 @@ impl Optimizer<'_> {
         }
 
         if let Some(scope) = self.data.scopes.get(&self.ctx.scope) {
-            if scope.has_eval_call || scope.has_with_stmt {
+            if scope.intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT)) {
                 return;
             }
         }
@@ -594,7 +599,11 @@ impl Optimizer<'_> {
         if let Expr::Ident(arg) = &*update.arg {
             if let Some(var) = self.data.vars.get(&arg.to_id()) {
                 // Update is counted as usage
-                if var.declared && var.is_fn_local && var.usage_count == 1 {
+                if var
+                    .flags
+                    .contains(VarUsageInfoFlags::DECLARED.union(VarUsageInfoFlags::IS_FN_LOCAL))
+                    && var.usage_count == 1
+                {
                     self.changed = true;
                     report_change!(
                         "unused: Dropping an update '{}{:?}' because it is not used",
@@ -619,7 +628,11 @@ impl Optimizer<'_> {
             return;
         }
 
-        if self.data.top.has_eval_call || self.data.top.has_with_stmt {
+        if self
+            .data
+            .top
+            .intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT))
+        {
             return;
         }
 
@@ -634,7 +647,11 @@ impl Optimizer<'_> {
         if let AssignTarget::Simple(SimpleAssignTarget::Ident(left)) = &assign.left {
             if let Some(var) = self.data.vars.get(&left.to_id()) {
                 // TODO: We don't need fn_local check
-                if var.declared && var.is_fn_local && var.usage_count == 1 {
+                if var
+                    .flags
+                    .contains(VarUsageInfoFlags::DECLARED.union(VarUsageInfoFlags::IS_FN_LOCAL))
+                    && var.usage_count == 1
+                {
                     self.changed = true;
                     report_change!(
                         "unused: Dropping an op-assign '{}{:?}' because it is not used",
@@ -654,7 +671,11 @@ impl Optimizer<'_> {
             return;
         }
 
-        if self.data.top.has_eval_call || self.data.top.has_with_stmt {
+        if self
+            .data
+            .top
+            .intersects(ScopeData::HAS_EVAL_CALL.union(ScopeData::HAS_WITH_STMT))
+        {
             return;
         }
 
@@ -677,7 +698,7 @@ impl Optimizer<'_> {
                     self.data.scopes, self.ctx.scope
                 )
             })
-            .used_arguments;
+            .contains(ScopeData::USED_ARGUMENTS);
 
         trace_op!(
             "unused: drop_unused_assignments: Target: `{}`",
@@ -691,11 +712,13 @@ impl Optimizer<'_> {
 
             if let Some(var) = self.data.vars.get(&i.to_id()) {
                 // technically this is inline
-                if !var.inline_prevented
-                    && !var.exported
-                    && var.usage_count == 0
-                    && var.declared
-                    && (!var.declared_as_fn_param || !used_arguments || self.ctx.expr_ctx.in_strict)
+                if !var.flags.intersects(
+                    VarUsageInfoFlags::INLINE_PREVENTED.union(VarUsageInfoFlags::EXPORTED),
+                ) && var.usage_count == 0
+                    && var.flags.contains(VarUsageInfoFlags::DECLARED)
+                    && (!var.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_PARAM)
+                        || !used_arguments
+                        || self.ctx.expr_ctx.in_strict)
                 {
                     report_change!(
                         "unused: Dropping assignment to var '{}{:?}', which is never used",
@@ -740,7 +763,9 @@ impl Optimizer<'_> {
                 .vars
                 .get(&i.to_id())
                 .map(|v| {
-                    (!v.used_recursively && v.ref_count == 0 && v.usage_count == 0)
+                    (!v.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY)
+                        && v.ref_count == 0
+                        && v.usage_count == 0)
                         || v.var_kind.is_some()
                 })
                 .unwrap_or(false);
@@ -767,9 +792,10 @@ impl Optimizer<'_> {
             if d.init.is_none() {
                 if let Pat::Ident(name) = &d.name {
                     if let Some(usage) = self.data.vars.get_mut(&name.to_id()) {
-                        if usage.is_fn_local
-                            && usage.declared_as_fn_param
-                            && usage.declared_count >= 2
+                        if usage.flags.contains(
+                            VarUsageInfoFlags::IS_FN_LOCAL
+                                .union(VarUsageInfoFlags::DECLARED_AS_FN_PARAM),
+                        ) && usage.declared_count >= 2
                         {
                             d.name.take();
                             usage.declared_count -= 1;
@@ -826,7 +852,11 @@ impl Optimizer<'_> {
 
         let usage = self.data.vars.get(&name.to_id())?;
 
-        if usage.indexed_with_dynamic_key || usage.used_as_ref || usage.used_recursively {
+        if usage.flags.intersects(
+            VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY
+                .union(VarUsageInfoFlags::USED_AS_REF)
+                .union(VarUsageInfoFlags::USED_RECURSIVELY),
+        ) {
             return None;
         }
 
diff --git a/crates/swc_ecma_minifier/src/pass/mangle_props.rs b/crates/swc_ecma_minifier/src/pass/mangle_props.rs
index 7fc5c0742968..109f9154f64d 100644
--- a/crates/swc_ecma_minifier/src/pass/mangle_props.rs
+++ b/crates/swc_ecma_minifier/src/pass/mangle_props.rs
@@ -11,7 +11,7 @@ use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
 
 use crate::{
     option::ManglePropertiesOptions,
-    program_data::{analyze, ProgramData},
+    program_data::{analyze, ProgramData, VarUsageInfoFlags},
     util::base54::Base54Chars,
 };
 
@@ -175,7 +175,7 @@ fn is_root_of_member_expr_declared(member_expr: &MemberExpr, data: &ProgramData)
         Expr::Ident(expr) => data
             .vars
             .get(&expr.to_id())
-            .map(|var| var.declared)
+            .map(|var| var.flags.contains(VarUsageInfoFlags::DECLARED))
             .unwrap_or(false),
 
         _ => false,
diff --git a/crates/swc_ecma_minifier/src/program_data.rs b/crates/swc_ecma_minifier/src/program_data.rs
index 5f60d1ab1e1a..ae96e7b77201 100644
--- a/crates/swc_ecma_minifier/src/program_data.rs
+++ b/crates/swc_ecma_minifier/src/program_data.rs
@@ -37,32 +37,61 @@ pub(crate) struct ProgramData {
     initialized_vars: IndexSet<Id, FxBuildHasher>,
 }
 
-#[derive(Debug, Default, Clone)]
-pub(crate) struct ScopeData {
-    pub(crate) has_with_stmt: bool,
-    pub(crate) has_eval_call: bool,
-    pub(crate) used_arguments: bool,
+bitflags::bitflags! {
+    #[derive(Debug, Clone, Copy)]
+    pub(crate) struct VarUsageInfoFlags: u32 {
+        const INLINE_PREVENTED          = 1 << 0;
+        /// `false` if it's only used.
+        const DECLARED                  = 1 << 1;
+        /// `true` if the enclosing function defines this variable as a parameter.
+        const DECLARED_AS_FN_PARAM      = 1 << 2;
+        const DECLARED_AS_FN_DECL       = 1 << 3;
+        const DECLARED_AS_FN_EXPR       = 1 << 4;
+        const DECLARED_AS_FOR_INIT      = 1 << 5;
+        /// The variable itself is assigned after reference.
+        const REASSIGNED                = 1 << 6;
+        const HAS_PROPERTY_ACCESS       = 1 << 7;
+        const EXPORTED                  = 1 << 8;
+        /// True if used **above** the declaration or in init. (Not eval order).
+        const USED_ABOVE_DECL           = 1 << 9;
+        /// `true` if it's declared by function parameters or variables declared in
+        /// a closest function and used only within it and not used by child
+        /// functions.
+        const IS_FN_LOCAL               = 1 << 10;
+        const USED_IN_NON_CHILD_FN      = 1 << 11;
+        /// `true` if all its assign happens in the same function scope it's defined
+        const ASSIGNED_FN_LOCAL         = 1 << 12;
+        const EXECUTED_MULTIPLE_TIME    = 1 << 13;
+        const USED_IN_COND              = 1 << 14;
+        const VAR_INITIALIZED           = 1 << 15;
+        const DECLARED_AS_CATCH_PARAM   = 1 << 16;
+        const NO_SIDE_EFFECT_FOR_MEMBER_ACCESS = 1 << 17;
+        /// `a` in `foo(a)` or `foo({ a })`.
+        const USED_AS_REF               = 1 << 18;
+        const USED_AS_ARG               = 1 << 19;
+        const INDEXED_WITH_DYNAMIC_KEY  = 1 << 20;
+        const PURE_FN                   = 1 << 21;
+        /// Is the variable declared in top level?
+        const IS_TOP_LEVEL              = 1 << 22;
+        const USED_RECURSIVELY          = 1 << 23;
+
+    }
+
+    #[derive(Debug, Default, Clone, Copy)]
+    pub(crate) struct ScopeData: u8 {
+        const HAS_WITH_STMT  = 1 << 0;
+        const HAS_EVAL_CALL  = 1 << 1;
+        const USED_ARGUMENTS = 1 << 2;
+    }
 }
 
 #[derive(Debug, Clone)]
 pub(crate) struct VarUsageInfo {
-    pub(crate) inline_prevented: bool,
-
+    pub(crate) flags: VarUsageInfoFlags,
     /// The number of direct reference to this identifier.
     pub(crate) ref_count: u32,
-
-    /// `false` if it's only used.
-    pub(crate) declared: bool,
     pub(crate) declared_count: u32,
 
-    /// `true` if the enclosing function defines this variable as a parameter.
-    pub(crate) declared_as_fn_param: bool,
-
-    pub(crate) declared_as_fn_decl: bool,
-    pub(crate) declared_as_fn_expr: bool,
-
-    pub(crate) declared_as_for_init: bool,
-
     /// The number of assign and initialization to this identifier.
     pub(crate) assign_count: u32,
 
@@ -72,96 +101,36 @@ pub(crate) struct VarUsageInfo {
     /// - Update is counted as usage, but assign is not
     pub(crate) usage_count: u32,
 
-    /// The variable itself is assigned after reference.
-    pub(crate) reassigned: bool,
-
-    pub(crate) has_property_access: bool,
     pub(crate) property_mutation_count: u32,
 
-    pub(crate) exported: bool,
-    /// True if used **above** the declaration or in init. (Not eval order).
-    pub(crate) used_above_decl: bool,
-    /// `true` if it's declared by function parameters or variables declared in
-    /// a closest function and used only within it and not used by child
-    /// functions.
-    pub(crate) is_fn_local: bool,
-
-    used_in_non_child_fn: bool,
-
-    /// `true` if all its assign happens in the same function scope it's defined
-    pub(crate) assigned_fn_local: bool,
-
-    pub(crate) executed_multiple_time: bool,
-    pub(crate) used_in_cond: bool,
-
     pub(crate) var_kind: Option<VarDeclKind>,
-    pub(crate) var_initialized: bool,
     pub(crate) merged_var_type: Option<Value<Type>>,
 
-    pub(crate) declared_as_catch_param: bool,
-
-    pub(crate) no_side_effect_for_member_access: bool,
-
     pub(crate) callee_count: u32,
 
-    /// `a` in `foo(a)` or `foo({ a })`.
-    pub(crate) used_as_ref: bool,
-
-    pub(crate) used_as_arg: bool,
-
-    pub(crate) indexed_with_dynamic_key: bool,
-
-    pub(crate) pure_fn: bool,
-
-    /// Is the variable declared in top level?
-    pub(crate) is_top_level: bool,
-
     /// `infects_to`. This should be renamed, but it will be done with another
     /// PR. (because it's hard to review)
     infects_to: Vec<Access>,
     /// Only **string** properties.
     pub(crate) accessed_props: FxHashMap<Atom, u32>,
-
-    pub(crate) used_recursively: bool,
 }
 
 impl Default for VarUsageInfo {
     fn default() -> Self {
+        const DEFAULT_FLAGS: VarUsageInfoFlags =
+            VarUsageInfoFlags::ASSIGNED_FN_LOCAL.union(VarUsageInfoFlags::IS_FN_LOCAL);
         Self {
-            inline_prevented: Default::default(),
+            flags: DEFAULT_FLAGS,
             ref_count: Default::default(),
-            declared: Default::default(),
             declared_count: Default::default(),
-            declared_as_fn_param: Default::default(),
-            declared_as_fn_decl: Default::default(),
-            declared_as_fn_expr: Default::default(),
-            declared_as_for_init: Default::default(),
             assign_count: Default::default(),
             usage_count: Default::default(),
-            reassigned: Default::default(),
-            has_property_access: Default::default(),
             property_mutation_count: Default::default(),
-            exported: Default::default(),
-            used_above_decl: Default::default(),
-            is_fn_local: true,
-            executed_multiple_time: Default::default(),
-            used_in_cond: Default::default(),
             var_kind: Default::default(),
-            var_initialized: Default::default(),
             merged_var_type: Default::default(),
-            declared_as_catch_param: Default::default(),
-            no_side_effect_for_member_access: Default::default(),
             callee_count: Default::default(),
-            used_as_arg: Default::default(),
-            indexed_with_dynamic_key: Default::default(),
-            pure_fn: Default::default(),
             infects_to: Default::default(),
-            used_in_non_child_fn: Default::default(),
             accessed_props: Default::default(),
-            used_recursively: Default::default(),
-            is_top_level: Default::default(),
-            assigned_fn_local: true,
-            used_as_ref: false,
         }
     }
 }
@@ -178,14 +147,22 @@ impl VarUsageInfo {
 
     pub(crate) fn can_inline_fn_once(&self) -> bool {
         (self.callee_count > 0
-            || !self.executed_multiple_time && (self.is_fn_local || !self.used_in_non_child_fn))
-            && !(self.used_recursively
-                && self.has_property_access
-                && self.property_mutation_count != 0)
+            || !self
+                .flags
+                .contains(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME)
+                && (self.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                    || !self.flags.contains(VarUsageInfoFlags::USED_IN_NON_CHILD_FN)))
+            && !(self.flags.contains(
+                VarUsageInfoFlags::USED_RECURSIVELY.union(VarUsageInfoFlags::HAS_PROPERTY_ACCESS),
+            ) && self.property_mutation_count != 0)
     }
 
     fn initialized(&self) -> bool {
-        self.var_initialized || self.declared_as_fn_param || self.declared_as_catch_param
+        self.flags.intersects(
+            VarUsageInfoFlags::VAR_INITIALIZED
+                .union(VarUsageInfoFlags::DECLARED_AS_FN_PARAM)
+                .union(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM),
+        )
     }
 }
 
@@ -210,7 +187,7 @@ impl Storage for ProgramData {
 
         for (ctxt, scope) in child.scopes {
             let to = self.scopes.entry(ctxt).or_default();
-            self.top.merge(scope.clone(), true);
+            self.top.merge(scope, true);
 
             to.merge(scope, false);
         }
@@ -222,100 +199,108 @@ impl Storage for ProgramData {
             let inited = self.initialized_vars.contains(&id);
             match self.vars.entry(id.clone()) {
                 Entry::Occupied(mut e) => {
-                    e.get_mut().inline_prevented |= var_info.inline_prevented;
+                    if var_info.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED) {
+                        e.get_mut()
+                            .flags
+                            .insert(VarUsageInfoFlags::INLINE_PREVENTED);
+                    }
                     let var_assigned = var_info.assign_count > 0
-                        || (var_info.var_initialized && !e.get().var_initialized);
+                        || (var_info.flags.contains(VarUsageInfoFlags::VAR_INITIALIZED)
+                            && !e.get().flags.contains(VarUsageInfoFlags::VAR_INITIALIZED));
 
                     if var_info.assign_count > 0 {
                         if e.get().initialized() {
-                            e.get_mut().reassigned = true
+                            e.get_mut().flags.insert(VarUsageInfoFlags::REASSIGNED);
                         }
                     }
 
-                    if var_info.var_initialized {
+                    if var_info.flags.contains(VarUsageInfoFlags::VAR_INITIALIZED) {
                         // If it is inited in some other child scope and also inited in current
                         // scope
-                        if e.get().var_initialized || e.get().ref_count > 0 {
-                            e.get_mut().reassigned = true;
+                        if e.get().flags.contains(VarUsageInfoFlags::VAR_INITIALIZED)
+                            || e.get().ref_count > 0
+                        {
+                            e.get_mut().flags.insert(VarUsageInfoFlags::REASSIGNED);
                         } else {
                             // If it is referred outside child scope, it will
                             // be marked as var_initialized false
-                            e.get_mut().var_initialized = true;
+                            e.get_mut().flags.insert(VarUsageInfoFlags::VAR_INITIALIZED);
                         }
                     } else {
                         // If it is inited in some other child scope, but referenced in
                         // current child scope
-                        if !inited && e.get().var_initialized && var_info.ref_count > 0 {
-                            e.get_mut().var_initialized = false;
-                            e.get_mut().reassigned = true
+                        if !inited
+                            && e.get().flags.contains(VarUsageInfoFlags::VAR_INITIALIZED)
+                            && var_info.ref_count > 0
+                        {
+                            e.get_mut().flags.remove(VarUsageInfoFlags::VAR_INITIALIZED);
+                            e.get_mut().flags.insert(VarUsageInfoFlags::REASSIGNED);
                         }
                     }
 
                     e.get_mut().merged_var_type.merge(var_info.merged_var_type);
 
                     e.get_mut().ref_count += var_info.ref_count;
-
-                    e.get_mut().reassigned |= var_info.reassigned;
-
-                    e.get_mut().has_property_access |= var_info.has_property_access;
                     e.get_mut().property_mutation_count |= var_info.property_mutation_count;
-                    e.get_mut().exported |= var_info.exported;
-
-                    e.get_mut().declared |= var_info.declared;
                     e.get_mut().declared_count += var_info.declared_count;
-                    e.get_mut().declared_as_fn_param |= var_info.declared_as_fn_param;
-                    e.get_mut().declared_as_fn_decl |= var_info.declared_as_fn_decl;
-                    e.get_mut().declared_as_fn_expr |= var_info.declared_as_fn_expr;
-                    e.get_mut().declared_as_catch_param |= var_info.declared_as_catch_param;
-
-                    // If a var is registered at a parent scope, it means that it's delcared before
-                    // usages.
-                    //
-                    // e.get_mut().used_above_decl |= var_info.used_above_decl;
-                    e.get_mut().executed_multiple_time |= var_info.executed_multiple_time;
-                    e.get_mut().used_in_cond |= var_info.used_in_cond;
                     e.get_mut().assign_count += var_info.assign_count;
                     e.get_mut().usage_count += var_info.usage_count;
-
                     e.get_mut().infects_to.extend(var_info.infects_to);
-
-                    e.get_mut().no_side_effect_for_member_access =
-                        e.get_mut().no_side_effect_for_member_access
-                            && var_info.no_side_effect_for_member_access;
-
                     e.get_mut().callee_count += var_info.callee_count;
-                    e.get_mut().used_as_arg |= var_info.used_as_arg;
-                    e.get_mut().used_as_ref |= var_info.used_as_ref;
-                    e.get_mut().indexed_with_dynamic_key |= var_info.indexed_with_dynamic_key;
 
-                    e.get_mut().pure_fn |= var_info.pure_fn;
-
-                    e.get_mut().used_recursively |= var_info.used_recursively;
+                    for (k, v) in var_info.accessed_props {
+                        *e.get_mut().accessed_props.entry(k).or_default() += v;
+                    }
 
-                    e.get_mut().is_fn_local &= var_info.is_fn_local;
-                    e.get_mut().used_in_non_child_fn |= var_info.used_in_non_child_fn;
+                    let var_info_flags = var_info.flags;
+                    let e_flags = &mut e.get_mut().flags;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::REASSIGNED;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::HAS_PROPERTY_ACCESS;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::EXPORTED;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::DECLARED;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::DECLARED_AS_FN_PARAM;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::DECLARED_AS_FN_DECL;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::DECLARED_AS_FN_EXPR;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::USED_IN_COND;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::USED_AS_ARG;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::USED_AS_REF;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::PURE_FN;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::USED_RECURSIVELY;
+                    *e_flags |= var_info_flags & VarUsageInfoFlags::USED_IN_NON_CHILD_FN;
 
-                    e.get_mut().assigned_fn_local &= var_info.assigned_fn_local;
+                    // If a var is registered at a parent scope, it means that it's delcared before
+                    // usages.
+                    //
+                    // e.get_mut().used_above_decl |= var_info.used_above_decl;
 
-                    for (k, v) in var_info.accessed_props {
-                        *e.get_mut().accessed_props.entry(k).or_default() += v;
+                    if !var_info_flags.contains(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS)
+                    {
+                        e_flags.remove(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS);
+                    }
+                    if !var_info_flags.contains(VarUsageInfoFlags::IS_FN_LOCAL) {
+                        e_flags.remove(VarUsageInfoFlags::IS_FN_LOCAL);
+                    }
+                    if !var_info_flags.contains(VarUsageInfoFlags::ASSIGNED_FN_LOCAL) {
+                        e_flags.remove(VarUsageInfoFlags::ASSIGNED_FN_LOCAL);
                     }
 
                     match kind {
                         ScopeKind::Fn => {
-                            e.get_mut().is_fn_local = false;
-                            if !var_info.used_recursively {
-                                e.get_mut().used_in_non_child_fn = true
+                            e_flags.remove(VarUsageInfoFlags::IS_FN_LOCAL);
+                            if !var_info_flags.contains(VarUsageInfoFlags::USED_RECURSIVELY) {
+                                e_flags.insert(VarUsageInfoFlags::USED_IN_NON_CHILD_FN);
                             }
-
                             if var_assigned {
-                                e.get_mut().assigned_fn_local = false
+                                e_flags.remove(VarUsageInfoFlags::ASSIGNED_FN_LOCAL);
                             }
                         }
                         ScopeKind::Block => {
-                            if e.get().used_in_non_child_fn {
-                                e.get_mut().is_fn_local = false;
-                                e.get_mut().used_in_non_child_fn = true;
+                            if e_flags.contains(VarUsageInfoFlags::USED_IN_NON_CHILD_FN) {
+                                e_flags.remove(VarUsageInfoFlags::IS_FN_LOCAL);
+                                e_flags.insert(VarUsageInfoFlags::USED_IN_NON_CHILD_FN);
                             }
                         }
                     }
@@ -323,8 +308,10 @@ impl Storage for ProgramData {
                 Entry::Vacant(e) => {
                     match kind {
                         ScopeKind::Fn => {
-                            if !var_info.used_recursively {
-                                var_info.used_in_non_child_fn = true
+                            if !var_info.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY) {
+                                var_info
+                                    .flags
+                                    .insert(VarUsageInfoFlags::USED_IN_NON_CHILD_FN);
                             }
                         }
                         ScopeKind::Block => {}
@@ -339,24 +326,30 @@ impl Storage for ProgramData {
         let inited = self.initialized_vars.contains(&i);
 
         let e = self.vars.entry(i.clone()).or_insert_with(|| {
-            Box::new(VarUsageInfo {
-                used_above_decl: true,
-                ..Default::default()
-            })
+            let mut default = VarUsageInfo::default();
+            default.flags.insert(VarUsageInfoFlags::USED_ABOVE_DECL);
+            Box::new(default)
         });
 
-        e.used_as_ref |= ctx.is_id_ref();
+        if ctx.is_id_ref() {
+            e.flags.insert(VarUsageInfoFlags::USED_AS_REF);
+        }
         e.ref_count += 1;
         e.usage_count += 1;
         // If it is inited in some child scope, but referenced in current scope
-        if !inited && e.var_initialized {
-            e.reassigned = true;
-            e.var_initialized = false;
+        if !inited && e.flags.contains(VarUsageInfoFlags::VAR_INITIALIZED) {
+            e.flags.insert(VarUsageInfoFlags::REASSIGNED);
+            e.flags.remove(VarUsageInfoFlags::VAR_INITIALIZED);
+        }
+        if ctx.inline_prevented() {
+            e.flags.insert(VarUsageInfoFlags::INLINE_PREVENTED);
+        }
+        if ctx.executed_multiple_time() {
+            e.flags.insert(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME);
+        }
+        if ctx.in_cond() {
+            e.flags.insert(VarUsageInfoFlags::USED_IN_COND);
         }
-
-        e.inline_prevented |= ctx.inline_prevented();
-        e.executed_multiple_time |= ctx.executed_multiple_time();
-        e.used_in_cond |= ctx.in_cond();
     }
 
     fn report_assign(&mut self, ctx: Ctx, i: Id, is_op: bool, ty: Value<Type>) {
@@ -365,7 +358,7 @@ impl Storage for ProgramData {
         let inited = self.initialized_vars.contains(&i);
 
         if e.assign_count > 0 || e.initialized() {
-            e.reassigned = true
+            e.flags.insert(VarUsageInfoFlags::REASSIGNED);
         }
 
         e.merged_var_type.merge(Some(ty));
@@ -374,13 +367,13 @@ impl Storage for ProgramData {
         if !is_op {
             self.initialized_vars.insert(i.clone());
             if e.ref_count == 1 && e.var_kind != Some(VarDeclKind::Const) && !inited {
-                e.var_initialized = true;
+                e.flags.insert(VarUsageInfoFlags::VAR_INITIALIZED);
             } else {
-                e.reassigned = true;
+                e.flags.insert(VarUsageInfoFlags::REASSIGNED);
             }
 
-            if e.ref_count == 1 && e.used_above_decl {
-                e.used_above_decl = false;
+            if e.ref_count == 1 && e.flags.contains(VarUsageInfoFlags::USED_ABOVE_DECL) {
+                e.flags.remove(VarUsageInfoFlags::USED_ABOVE_DECL);
             }
 
             e.usage_count = e.usage_count.saturating_sub(1);
@@ -395,9 +388,17 @@ impl Storage for ProgramData {
             let curr = &to_visit[idx];
 
             if let Some(usage) = self.vars.get_mut(curr) {
-                usage.inline_prevented |= ctx.inline_prevented();
-                usage.executed_multiple_time |= ctx.executed_multiple_time();
-                usage.used_in_cond |= ctx.in_cond();
+                if ctx.inline_prevented() {
+                    usage.flags.insert(VarUsageInfoFlags::INLINE_PREVENTED);
+                }
+                if ctx.executed_multiple_time() {
+                    usage
+                        .flags
+                        .insert(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME);
+                }
+                if ctx.in_cond() {
+                    usage.flags.insert(VarUsageInfoFlags::USED_IN_COND);
+                }
 
                 if is_op {
                     usage.usage_count += 1;
@@ -422,34 +423,46 @@ impl Storage for ProgramData {
         // }
 
         let v = self.vars.entry(i.to_id()).or_default();
-        v.is_top_level |= ctx.is_top_level();
+        if ctx.is_top_level() {
+            v.flags |= VarUsageInfoFlags::IS_TOP_LEVEL;
+        }
 
         // assigned or declared before this declaration
         if init_type.is_some() {
-            if v.declared || v.var_initialized || v.assign_count > 0 {
+            if v.flags
+                .intersects(VarUsageInfoFlags::DECLARED.union(VarUsageInfoFlags::VAR_INITIALIZED))
+                || v.assign_count > 0
+            {
                 #[cfg(feature = "debug")]
                 {
                     tracing::trace!("declare_decl(`{}`): Already declared", i);
                 }
 
-                v.reassigned = true;
+                v.flags |= VarUsageInfoFlags::REASSIGNED;
             }
 
             v.assign_count += 1;
         }
 
         // This is not delcared yet, so this is the first declaration.
-        if !v.declared {
+        if !v.flags.contains(VarUsageInfoFlags::DECLARED) {
             v.var_kind = kind;
-            v.no_side_effect_for_member_access =
-                ctx.in_decl_with_no_side_effect_for_member_access();
+            if ctx.in_decl_with_no_side_effect_for_member_access() {
+                v.flags
+                    .insert(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS);
+            } else {
+                v.flags
+                    .remove(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS);
+            }
         }
 
-        if v.used_in_non_child_fn {
-            v.is_fn_local = false;
+        if v.flags.contains(VarUsageInfoFlags::USED_IN_NON_CHILD_FN) {
+            v.flags.remove(VarUsageInfoFlags::IS_FN_LOCAL);
         }
 
-        v.var_initialized |= init_type.is_some();
+        if init_type.is_some() {
+            v.flags.insert(VarUsageInfoFlags::VAR_INITIALIZED);
+        }
 
         if ctx.in_pat_of_param() {
             v.merged_var_type = Some(Value::Unknown);
@@ -458,12 +471,14 @@ impl Storage for ProgramData {
         }
 
         v.declared_count += 1;
-        v.declared = true;
+        v.flags |= VarUsageInfoFlags::DECLARED;
         // not a VarDecl, thus always inited
         if init_type.is_some() || kind.is_none() {
             self.initialized_vars.insert(i.to_id());
         }
-        v.declared_as_catch_param |= ctx.in_catch_param();
+        if ctx.in_catch_param() {
+            v.flags |= VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM;
+        }
 
         v
     }
@@ -499,43 +514,43 @@ impl ScopeDataLike for ScopeData {
     fn add_declared_symbol(&mut self, _: &Ident) {}
 
     fn merge(&mut self, other: Self, _: bool) {
-        self.has_with_stmt |= other.has_with_stmt;
-        self.has_eval_call |= other.has_eval_call;
-        self.used_arguments |= other.used_arguments;
+        *self |= other & Self::HAS_WITH_STMT;
+        *self |= other & Self::HAS_EVAL_CALL;
+        *self |= other & Self::USED_ARGUMENTS;
     }
 
     fn mark_used_arguments(&mut self) {
-        self.used_arguments = true;
+        *self |= Self::USED_ARGUMENTS;
     }
 
     fn mark_eval_called(&mut self) {
-        self.has_eval_call = true;
+        *self |= Self::HAS_EVAL_CALL;
     }
 
     fn mark_with_stmt(&mut self) {
-        self.has_with_stmt = true;
+        *self |= Self::HAS_WITH_STMT;
     }
 }
 
 impl VarDataLike for VarUsageInfo {
     fn mark_declared_as_fn_param(&mut self) {
-        self.declared_as_fn_param = true;
+        self.flags.insert(VarUsageInfoFlags::DECLARED_AS_FN_PARAM);
     }
 
     fn mark_declared_as_fn_decl(&mut self) {
-        self.declared_as_fn_decl = true;
+        self.flags.insert(VarUsageInfoFlags::DECLARED_AS_FN_DECL);
     }
 
     fn mark_declared_as_fn_expr(&mut self) {
-        self.declared_as_fn_expr = true;
+        self.flags.insert(VarUsageInfoFlags::DECLARED_AS_FN_EXPR);
     }
 
     fn mark_declared_as_for_init(&mut self) {
-        self.declared_as_for_init = true;
+        self.flags.insert(VarUsageInfoFlags::DECLARED_AS_FOR_INIT);
     }
 
     fn mark_has_property_access(&mut self) {
-        self.has_property_access = true;
+        self.flags.insert(VarUsageInfoFlags::HAS_PROPERTY_ACCESS);
     }
 
     fn mark_used_as_callee(&mut self) {
@@ -543,12 +558,13 @@ impl VarDataLike for VarUsageInfo {
     }
 
     fn mark_used_as_arg(&mut self) {
-        self.used_as_ref = true;
-        self.used_as_arg = true
+        self.flags.insert(VarUsageInfoFlags::USED_AS_REF);
+        self.flags.insert(VarUsageInfoFlags::USED_AS_ARG);
     }
 
     fn mark_indexed_with_dynamic_key(&mut self) {
-        self.indexed_with_dynamic_key = true;
+        self.flags
+            .insert(VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY);
     }
 
     fn add_accessed_property(&mut self, name: swc_atoms::Atom) {
@@ -556,7 +572,7 @@ impl VarDataLike for VarUsageInfo {
     }
 
     fn mark_used_as_ref(&mut self) {
-        self.used_as_ref = true;
+        self.flags.insert(VarUsageInfoFlags::USED_AS_REF);
     }
 
     fn add_infects_to(&mut self, other: Access) {
@@ -564,27 +580,28 @@ impl VarDataLike for VarUsageInfo {
     }
 
     fn prevent_inline(&mut self) {
-        self.inline_prevented = true;
+        self.flags.insert(VarUsageInfoFlags::INLINE_PREVENTED);
     }
 
     fn mark_as_exported(&mut self) {
-        self.exported = true;
+        self.flags.insert(VarUsageInfoFlags::EXPORTED);
     }
 
     fn mark_initialized_with_safe_value(&mut self) {
-        self.no_side_effect_for_member_access = true;
+        self.flags
+            .insert(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS);
     }
 
     fn mark_as_pure_fn(&mut self) {
-        self.pure_fn = true;
+        self.flags.insert(VarUsageInfoFlags::PURE_FN);
     }
 
     fn mark_used_above_decl(&mut self) {
-        self.used_above_decl = true;
+        self.flags.insert(VarUsageInfoFlags::USED_ABOVE_DECL);
     }
 
     fn mark_used_recursively(&mut self) {
-        self.used_recursively = true;
+        self.flags.insert(VarUsageInfoFlags::USED_RECURSIVELY);
     }
 }
 
@@ -675,7 +692,7 @@ impl ProgramData {
         }
 
         if let Some(v) = self.vars.get(&i.to_id()) {
-            return !v.declared;
+            return !v.flags.contains(VarUsageInfoFlags::DECLARED);
         }
 
         true


Reviews:
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:02:53Z
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:07:29Z
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:08:52Z
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:09:44Z
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:11:29Z
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:11:50Z
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:13:05Z
user: login: CPunisher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T12:15:16Z
user: login: chenjiahan
body: It would be helpful if you could provide some PR description 😄
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T02:31:01Z
user: login: CPunisher
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-14T02:34:12Z

Review comments:
diff_hunk: @@ -199,26 +211,30 @@ impl Optimizer<'_> {
                                 // See https://github.com/swc-project/swc/issues/6463
                                 //
                                 // We check callee_count of `usage` because we copy simple functions
-                                !u.used_above_decl
-                                    || !u.declared_as_fn_decl
+                                !u.flags.contains(VarUsageInfoFlags::USED_ABOVE_DECL)
+                                    || !u.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_DECL)
                                     || usage.callee_count == 0;
 
-                            if u.declared_as_for_init && !usage.is_fn_local {
+                            if u.flags.contains(VarUsageInfoFlags::DECLARED_AS_FOR_INIT)
+                                && !usage.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                            {
                                 should_inline &= !matches!(
                                     u.var_kind,
                                     Some(VarDeclKind::Let | VarDeclKind::Const)
                                 )
                             }
 
-                            if u.declared_as_fn_decl || u.declared_as_fn_expr {
+                            if u.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_DECL)
+                                || u.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_EXPR)
+                            {
path: crates/swc_ecma_minifier/src/compress/optimize/inline.rs
user: login: CPunisher
body: ```suggestion
                            if u.flags.intersects(VarUsageInfoFlags::DECLARED_AS_FN_DECL | VarUsageInfoFlags::DECLARED_AS_FN_EXPR)
                            {
```
created_at: 2025-05-13T12:02:53Z
author_association: MEMBER
diff_hunk: @@ -267,36 +286,48 @@ impl Optimizer<'_> {
                 self.mode.store(id.clone(), &*init);
 
                 let VarUsageInfo {
-                    used_as_arg,
-                    used_as_ref,
-                    indexed_with_dynamic_key,
                     usage_count,
-                    has_property_access,
                     property_mutation_count,
-                    used_above_decl,
-                    executed_multiple_time,
-                    used_in_cond,
-                    used_recursively,
-                    no_side_effect_for_member_access,
+                    flags,
                     ..
                 } = **usage;
                 let mut inc_usage = || {
                     if let Expr::Ident(i) = &*init {
                         if let Some(u) = self.data.vars.get_mut(&i.to_id()) {
-                            u.used_as_arg |= used_as_arg;
-                            u.used_as_ref |= used_as_ref;
-                            u.indexed_with_dynamic_key |= indexed_with_dynamic_key;
-                            u.has_property_access |= has_property_access;
-                            u.property_mutation_count += property_mutation_count;
-                            u.used_above_decl |= used_above_decl;
-                            u.executed_multiple_time |= executed_multiple_time;
-                            u.used_in_cond |= used_in_cond;
-                            u.used_recursively |= used_recursively;
+                            if flags.contains(VarUsageInfoFlags::USED_AS_ARG) {
+                                u.flags |= VarUsageInfoFlags::USED_AS_ARG;
+                            }
path: crates/swc_ecma_minifier/src/compress/optimize/inline.rs
user: login: CPunisher
body: ```suggestion
                            u.flags |= flags & VarUsageInfoFlags::USED_AS_ARG;
```
created_at: 2025-05-13T12:07:29Z
author_association: MEMBER
diff_hunk: @@ -267,36 +286,48 @@ impl Optimizer<'_> {
                 self.mode.store(id.clone(), &*init);
 
                 let VarUsageInfo {
-                    used_as_arg,
-                    used_as_ref,
-                    indexed_with_dynamic_key,
                     usage_count,
-                    has_property_access,
                     property_mutation_count,
-                    used_above_decl,
-                    executed_multiple_time,
-                    used_in_cond,
-                    used_recursively,
-                    no_side_effect_for_member_access,
+                    flags,
                     ..
                 } = **usage;
                 let mut inc_usage = || {
                     if let Expr::Ident(i) = &*init {
                         if let Some(u) = self.data.vars.get_mut(&i.to_id()) {
-                            u.used_as_arg |= used_as_arg;
-                            u.used_as_ref |= used_as_ref;
-                            u.indexed_with_dynamic_key |= indexed_with_dynamic_key;
-                            u.has_property_access |= has_property_access;
-                            u.property_mutation_count += property_mutation_count;
-                            u.used_above_decl |= used_above_decl;
-                            u.executed_multiple_time |= executed_multiple_time;
-                            u.used_in_cond |= used_in_cond;
-                            u.used_recursively |= used_recursively;
+                            if flags.contains(VarUsageInfoFlags::USED_AS_ARG) {
+                                u.flags |= VarUsageInfoFlags::USED_AS_ARG;
+                            }
+                            if flags.contains(VarUsageInfoFlags::USED_AS_REF) {
+                                u.flags |= VarUsageInfoFlags::USED_AS_REF;
+                            }
+                            if flags.contains(VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY) {
+                                u.flags |= VarUsageInfoFlags::INDEXED_WITH_DYNAMIC_KEY;
+                            }
+                            if flags.contains(VarUsageInfoFlags::HAS_PROPERTY_ACCESS) {
+                                u.flags |= VarUsageInfoFlags::HAS_PROPERTY_ACCESS;
+                            }
+                            if flags.contains(VarUsageInfoFlags::USED_ABOVE_DECL) {
+                                u.flags |= VarUsageInfoFlags::USED_ABOVE_DECL;
+                            }
+                            if flags.contains(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME) {
+                                u.flags |= VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME;
+                            }
+                            if flags.contains(VarUsageInfoFlags::USED_IN_COND) {
+                                u.flags |= VarUsageInfoFlags::USED_IN_COND;
+                            }
+                            if flags.contains(VarUsageInfoFlags::USED_RECURSIVELY) {
+                                u.flags |= VarUsageInfoFlags::USED_RECURSIVELY;
+                            }
 
-                            u.no_side_effect_for_member_access &= no_side_effect_for_member_access;
+                            if !flags.contains(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS)
+                            {
+                                u.flags
+                                    .remove(VarUsageInfoFlags::NO_SIDE_EFFECT_FOR_MEMBER_ACCESS)
+                            }
 
                             u.ref_count += ref_count;
                             u.usage_count += usage_count;
+                            u.property_mutation_count += property_mutation_count;
path: crates/swc_ecma_minifier/src/compress/optimize/inline.rs
user: login: CPunisher
body: Is this a bug?
created_at: 2025-05-13T12:08:51Z
author_association: MEMBER
diff_hunk: @@ -422,31 +459,42 @@ impl Optimizer<'_> {
                     Expr::Object(..) if self.options.pristine_globals => {
                         for id in idents_used_by_ignoring_nested(init) {
                             if let Some(v_usage) = self.data.vars.get(&id) {
-                                if v_usage.reassigned {
+                                if v_usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
                                     return;
                                 }
                             }
                         }
                     }
 
                     Expr::Ident(id) if !id.eq_ignore_span(ident) => {
-                        if !usage.assigned_fn_local {
+                        if !usage.flags.contains(VarUsageInfoFlags::ASSIGNED_FN_LOCAL) {
                             return;
                         }
 
                         if let Some(init_usage) = self.data.vars.get(&id.to_id()) {
-                            if init_usage.reassigned || !init_usage.declared {
+                            if init_usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
+                                || !init_usage.flags.contains(VarUsageInfoFlags::DECLARED)
+                            {
                                 return;
                             }
 
-                            if init_usage.declared_as_fn_decl || init_usage.declared_as_fn_expr {
+                            if init_usage
+                                .flags
+                                .contains(VarUsageInfoFlags::DECLARED_AS_FN_DECL)
+                                || init_usage
+                                    .flags
+                                    .contains(VarUsageInfoFlags::DECLARED_AS_FN_EXPR)
path: crates/swc_ecma_minifier/src/compress/optimize/inline.rs
user: login: CPunisher
body: use intersect
created_at: 2025-05-13T12:09:44Z
author_association: MEMBER
diff_hunk: @@ -40,12 +40,14 @@ impl Optimizer<'_> {
             // smart.
             let usage = self.data.vars.get(&name.to_id())?;
             if usage.mutated()
-                || usage.used_in_cond
-                || usage.used_above_decl
-                || usage.used_as_ref
-                || usage.used_as_arg
-                || usage.indexed_with_dynamic_key
-                || usage.used_recursively
+                || usage.flags.contains(VarUsageInfoFlags::USED_IN_COND)
path: crates/swc_ecma_minifier/src/compress/optimize/props.rs
user: login: CPunisher
body: use intersect
created_at: 2025-05-13T12:11:29Z
author_association: MEMBER
diff_hunk: @@ -818,7 +820,11 @@ impl Optimizer<'_> {
                                                 .vars
                                                 .get(&a_id.id.to_id())
                                                 .map(|u| {
-                                                    !u.inline_prevented && !u.declared_as_fn_expr
+                                                    !u.flags.contains(
path: crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
user: login: CPunisher
body: use intersect
created_at: 2025-05-13T12:11:50Z
author_association: MEMBER
diff_hunk: @@ -2287,7 +2303,9 @@ impl Optimizer<'_> {
                         can_take_init = true;
                     }
 
-                    if usage.inline_prevented || usage.used_recursively {
+                    if usage.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED)
+                        || usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY)
path: crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
user: login: CPunisher
body: use intersect
created_at: 2025-05-13T12:13:05Z
author_association: MEMBER
diff_hunk: @@ -178,14 +147,22 @@ impl VarUsageInfo {
 
     pub(crate) fn can_inline_fn_once(&self) -> bool {
         (self.callee_count > 0
-            || !self.executed_multiple_time && (self.is_fn_local || !self.used_in_non_child_fn))
-            && !(self.used_recursively
-                && self.has_property_access
+            || !self
+                .flags
+                .contains(VarUsageInfoFlags::EXECUTED_MULTIPLE_TIME)
+                && (self.flags.contains(VarUsageInfoFlags::IS_FN_LOCAL)
+                    || !self.flags.contains(VarUsageInfoFlags::USED_IN_NON_CHILD_FN)))
+            && !(self.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY)
+                && self.flags.contains(VarUsageInfoFlags::HAS_PROPERTY_ACCESS)
                 && self.property_mutation_count != 0)
     }
 
     fn initialized(&self) -> bool {
-        self.var_initialized || self.declared_as_fn_param || self.declared_as_catch_param
+        self.flags.contains(VarUsageInfoFlags::VAR_INITIALIZED)
+            || self.flags.contains(VarUsageInfoFlags::DECLARED_AS_FN_PARAM)
+            || self
+                .flags
+                .contains(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM)
path: crates/swc_ecma_minifier/src/program_data.rs
user: login: CPunisher
body: use intersect
created_at: 2025-05-13T12:15:16Z
author_association: MEMBER

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-05-13T10:44:07Z
body: ###  ⚠️  No Changeset found

Latest commit: f7075b16c43f6750bcb4dcd7f131ebe0bb3b3619

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**



[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/bvanjoi/swc/new/pref-minify?filename=.changeset/olive-mayflies-own.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0Arefactor(ecma%2Fminifier)%3A%20bitflags%20for%20var%20info%0A)


author_association: NONE
user: login: codspeed-hq[bot]
created_at: 2025-05-13T11:04:46Z
body: <!-- __CODSPEED_PERFORMANCE_REPORT_COMMENT__ -->
<!-- __CODSPEED_INSTRUMENTATION_PERFORMANCE_REPORT_COMMENT__ -->

## [CodSpeed Performance Report](https://codspeed.io/swc-project/swc/branches/bvanjoi%3Apref-minify)

### Merging #10459 will **not alter performance**

<sub>Comparing <code>bvanjoi:pref-minify</code> (f7075b1) with <code>main</code> (d344133)</sub>



### Summary

`✅ 152` untouched benchmarks  




author_association: NONE
user: login: CPunisher
created_at: 2025-05-13T12:22:43Z
body: There's improvement:

<img width="678" alt="image" src="https://github.com/user-attachments/assets/e889de93-b42e-4fa2-9a43-a317a010debb" />

author_association: MEMBER