fix(minifier): do not change const to let if assignment to constant variable. (#8761)

This commit is contained in:
Boshen 2025-01-28 06:04:25 +00:00
parent 003c190d93
commit 8a6ae8a062
2 changed files with 9 additions and 6 deletions

View file

@ -152,13 +152,12 @@ impl<'a> Normalize {
// checking whether the current scope is the root scope instead of
// checking whether any variables are exposed to outside (e.g. `export` in ESM)
if decl.kind.is_const() && ctx.current_scope_id() != ctx.scopes().root_scope_id() {
let all_declarations_are_only_read = decl.declarations.iter().all(|decl| {
decl.id.get_binding_identifiers().iter().all(|id| {
let all_declarations_are_only_read =
decl.declarations.iter().flat_map(|d| d.id.get_binding_identifiers()).all(|id| {
ctx.symbols()
.get_resolved_references(id.symbol_id())
.all(|reference| reference.flags().is_read_only())
})
});
});
if all_declarations_are_only_read {
decl.kind = VariableDeclarationKind::Let;
}
@ -226,6 +225,10 @@ mod test {
test("{ const [x] = [1] }", "{ let [x] = [1] }");
test("{ const [x = 1] = [] }", "{ let [x = 1] = [] }");
test("for (const x in y);", "for (let x in y);");
// TypeError: Assignment to constant variable.
test_same("for (const i = 0; i < 1; i++);");
test_same("for (const x in [1, 2, 3]) x++");
test_same("for (const x of [1, 2, 3]) x++");
}
#[test]

View file

@ -159,7 +159,7 @@ impl ReferenceFlags {
/// The identifier is only read from.
#[inline]
pub const fn is_read_only(&self) -> bool {
self.contains(Self::Read)
!self.contains(Self::Write)
}
/// The identifier is written to. It may also be read from.
@ -171,7 +171,7 @@ impl ReferenceFlags {
/// The identifier is only written to. It is not read from in this reference.
#[inline]
pub const fn is_write_only(&self) -> bool {
self.contains(Self::Write)
!self.contains(Self::Read)
}
/// The identifier is both read from and written to, e.g `a += 1`.