Repository: swc-project/swc
File: crates/swc_ecma_minifier/src/program_data.rs (Rust)

Code before:
                VarUsageInfoFlags::USED_RECURSIVELY.union(VarUsageInfoFlags::HAS_PROPERTY_ACCESS),
            ) && self.property_mutation_count != 0)
    }

    fn initialized(&self) -> bool {
        self.flags.intersects(
            VarUsageInfoFlags::VAR_INITIALIZED
                .union(VarUsageInfoFlags::DECLARED_AS_FN_PARAM)
                .union(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM),
        )
    }
}

impl Storage for ProgramData {
    type ScopeData = ScopeData;
    type VarData = VarUsageInfo;

    fn new_child(&mut self) -> Self {
        let scopes = std::mem::take(&mut self.scopes);
        let property_atoms = std::mem::take(&mut self.property_atoms);
        Self {
            scopes,
            property_atoms,
            vars: FxHashMap::default(),
            initialized_vars: IndexSet::default(),
            top: ScopeData::default(),
        }
    }

    fn scope(&mut self, ctxt: swc_common::SyntaxContext) -> &mut Self::ScopeData {
        let ctxt = ctxt.as_u32() as usize;
        if self.scopes.len() <= ctxt {
            self.scopes.resize(ctxt + 1, ScopeData::default());
        }
        &mut self.scopes[ctxt]
    }

    fn scopes(&self) -> &[ScopeData] {
        &self.scopes
    }

    fn top_scope(&mut self) -> &mut Self::ScopeData {
        &mut self.top
    }

    fn var_or_default(&mut self, id: Id) -> &mut Self::VarData {
        self.vars.entry(id).or_default()
    }

    fn merge(&mut self, kind: ScopeKind, child: Self) {
        // Take the data back

Review comment (bug):
Consider adding a debug assertion or comment to document the assumption that SyntaxContext values are dense. If SyntaxContext values become sparse in the future, this Vec-based implementation could consume excessive memory with many default-initialized entries. A comment explaining the density assumption would help future maintainers understand this design choice.

Code after:
                .union(VarUsageInfoFlags::DECLARED_AS_CATCH_PARAM),
        )
    }
}

impl Storage for ProgramData {
    type ScopeData = ScopeData;
    type VarData = VarUsageInfo;

    fn new_child(&mut self) -> Self {
        let scopes = std::mem::take(&mut self.scopes);
        let property_atoms = std::mem::take(&mut self.property_atoms);
        Self {
            scopes,
            property_atoms,
            ..Default::default()
        }
    }

    fn scope(&mut self, ctxt: swc_common::SyntaxContext) -> &mut Self::ScopeData {
        let ctxt = ctxt.as_u32() as usize;
        if self.scopes.len() <= ctxt {
            self.scopes.resize(ctxt + 1, ScopeData::default());
        }
        &mut self.scopes[ctxt]
    }

    fn scopes(&self) -> &[ScopeData] {
        &self.scopes
    }

    fn top_scope(&mut self) -> &mut Self::ScopeData {
        &mut self.top
    }

    fn var_or_default(&mut self, id: Id) -> &mut Self::VarData {
        self.vars.entry(id).or_default()
    }

    fn merge(&mut self, kind: ScopeKind, child: Self) {
        // Take the data back
        // Corresponding to [Self::new_child]
        self.scopes = child.scopes;
        self.property_atoms = child.property_atoms;

        self.vars.reserve(child.vars.len());
        for (id, mut var_info) in child.vars {
            // trace!("merge({:?},{}{:?})", kind, id.0, id.1);
            let inited = self.initialized_vars.contains(&id);
            match self.vars.entry(id) {
                Entry::Occupied(mut e) => {