Skip to content

Commit a4ac3b7

Browse files
authored
fix(es/minifier): Preserve block with block scoped declaration (#10335)
**Related issue:** - Closes #10328
1 parent e66b4d6 commit a4ac3b7

File tree

15 files changed

+101
-87
lines changed

15 files changed

+101
-87
lines changed

.changeset/wicked-carrots-glow.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
swc_ecma_minifier: patch
3+
swc_core: patch
4+
---
5+
6+
fix(es/minifier): Preserve block with block scoped declaration

crates/swc_ecma_minifier/src/compress/optimize/mod.rs

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,7 @@ impl Optimizer<'_> {
12421242
Some(e.take())
12431243
}
12441244

1245-
fn try_removing_block(&mut self, s: &mut Stmt, unwrap_more: bool, allow_fn_decl: bool) {
1245+
fn try_removing_block(&mut self, s: &mut Stmt, allow_fn_decl: bool) {
12461246
match s {
12471247
Stmt::Block(bs) => {
12481248
if bs.stmts.is_empty() {
@@ -1253,12 +1253,6 @@ impl Optimizer<'_> {
12531253

12541254
// Remove nested blocks
12551255
if bs.stmts.len() == 1 {
1256-
if bs.ctxt.has_mark(self.marks.fake_block) {
1257-
report_change!("Unwrapping a fake block");
1258-
*s = bs.stmts.take().into_iter().next().unwrap();
1259-
return;
1260-
}
1261-
12621256
if let Stmt::Block(block) = &mut bs.stmts[0] {
12631257
let stmts = &block.stmts;
12641258
if maybe_par!(
@@ -1272,31 +1266,6 @@ impl Optimizer<'_> {
12721266
}
12731267
}
12741268

1275-
// Unwrap a block with only `var`s.
1276-
//
1277-
// TODO: Support multiple statements.
1278-
if bs.stmts.len() == 1
1279-
&& bs.stmts.iter().all(|stmt| match stmt {
1280-
Stmt::Decl(Decl::Var(v))
1281-
if matches!(
1282-
&**v,
1283-
VarDecl {
1284-
kind: VarDeclKind::Var,
1285-
..
1286-
}
1287-
) =>
1288-
{
1289-
true
1290-
}
1291-
_ => false,
1292-
})
1293-
{
1294-
report_change!("optimizer: Unwrapping a block with variable statements");
1295-
self.changed = true;
1296-
*s = bs.stmts[0].take();
1297-
return;
1298-
}
1299-
13001269
for stmt in &mut bs.stmts {
13011270
if let Stmt::Block(block) = &stmt {
13021271
if block.stmts.is_empty() {
@@ -1308,49 +1277,74 @@ impl Optimizer<'_> {
13081277
}
13091278
}
13101279

1311-
if unwrap_more && bs.stmts.len() == 1 {
1280+
if bs.stmts.len() == 1 {
13121281
match &bs.stmts[0] {
13131282
Stmt::Expr(..) | Stmt::If(..) => {
13141283
*s = bs.stmts[0].take();
13151284
report_change!("optimizer: Unwrapping block stmt");
13161285
self.changed = true;
13171286
}
1318-
Stmt::Decl(Decl::Fn(..))
1319-
if allow_fn_decl && !self.ctx.expr_ctx.in_strict =>
1287+
// Annex B the darkest part of JS
1288+
Stmt::Decl(Decl::Fn(f))
1289+
if allow_fn_decl
1290+
&& !self.ctx.expr_ctx.in_strict
1291+
&& !f.function.is_generator
1292+
&& !f.function.is_async =>
13201293
{
13211294
*s = bs.stmts[0].take();
13221295
report_change!("optimizer: Unwrapping block stmt in non strcit mode");
13231296
self.changed = true;
13241297
}
1325-
_ => {}
1298+
Stmt::Decl(Decl::Var(v)) if v.kind == VarDeclKind::Var => {
1299+
report_change!("optimizer: Unwrapping a block with var decl statement");
1300+
self.changed = true;
1301+
*s = bs.stmts[0].take();
1302+
return;
1303+
}
1304+
Stmt::Decl(Decl::Class(_) | Decl::Var(_) | Decl::Fn(_)) => (),
1305+
_ => {
1306+
if bs.ctxt.has_mark(self.marks.fake_block) {
1307+
report_change!("Unwrapping a fake block");
1308+
*s = bs.stmts.take().into_iter().next().unwrap();
1309+
return;
1310+
}
1311+
}
13261312
}
13271313
}
13281314
}
13291315

13301316
Stmt::If(s) => {
1331-
self.try_removing_block(&mut s.cons, true, true);
1317+
self.try_removing_block(&mut s.cons, true);
13321318
let can_remove_block_of_alt = match &*s.cons {
13331319
Stmt::Expr(..) | Stmt::If(..) => true,
13341320
Stmt::Block(bs) if bs.stmts.len() == 1 => matches!(&bs.stmts[0], Stmt::For(..)),
13351321
_ => false,
13361322
};
13371323
if can_remove_block_of_alt {
13381324
if let Some(alt) = &mut s.alt {
1339-
self.try_removing_block(alt, true, false);
1325+
self.try_removing_block(alt, false);
13401326
}
13411327
}
13421328
}
13431329

13441330
Stmt::ForIn(s) => {
1345-
self.try_removing_block(&mut s.body, true, false);
1331+
self.try_removing_block(&mut s.body, false);
13461332
}
13471333

13481334
Stmt::For(s) => {
1349-
self.try_removing_block(&mut s.body, true, false);
1335+
self.try_removing_block(&mut s.body, false);
13501336
}
13511337

13521338
Stmt::ForOf(s) => {
1353-
self.try_removing_block(&mut s.body, true, false);
1339+
self.try_removing_block(&mut s.body, false);
1340+
}
1341+
1342+
Stmt::While(s) => {
1343+
self.try_removing_block(&mut s.body, false);
1344+
}
1345+
1346+
Stmt::DoWhile(s) => {
1347+
self.try_removing_block(&mut s.body, false);
13541348
}
13551349

13561350
_ => {}
@@ -2463,7 +2457,7 @@ impl VisitMut for Optimizer<'_> {
24632457

24642458
// visit_mut_children_with above may produce easily optimizable block
24652459
// statements.
2466-
self.try_removing_block(s, false, false);
2460+
self.try_removing_block(s, false);
24672461

24682462
debug_assert_valid(s);
24692463

@@ -2476,7 +2470,7 @@ impl VisitMut for Optimizer<'_> {
24762470

24772471
debug_assert_valid(s);
24782472

2479-
self.try_removing_block(s, false, false);
2473+
self.try_removing_block(s, false);
24802474

24812475
debug_assert_valid(s);
24822476

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function f() {
2+
const h = i({
3+
onCancel: () => h(),
4+
});
5+
}
6+
7+
function g(x, v) {
8+
if (x === "a") {
9+
f(v);
10+
} else {
11+
class A {}
12+
console.log(A, A);
13+
}
14+
}
15+
16+
g("a");
17+
g("b");
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
function g(x, v) {
2+
if ("a" === x) {
3+
const h = i({
4+
onCancel: ()=>h()
5+
});
6+
} else {
7+
class A {
8+
}
9+
console.log(A, A);
10+
}
11+
}
12+
g("a"), g("b");
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
var x = 3;
2-
if (foo())
3-
do {
4-
do {
5-
alert(x);
6-
} while (--x);
7-
} while (x);
2+
if (foo()) do {
3+
do alert(x);
4+
while (--x)
5+
}while (x)
86
else bar();
Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
var x = 3;
2-
3-
if (foo())
4-
do {
5-
do {
6-
alert(x);
7-
} while (--x);
8-
} while (x);
2+
if (foo()) do {
3+
do alert(x);
4+
while (--x)
5+
}while (x)
96
else bar();
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
var x = 3;
22
if (foo()) {
33
do {
4-
do {
5-
alert(x);
6-
}while (--x)
4+
do alert(x);
5+
while (--x)
76
}while (x)
87
} else bar();
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
var x = 3;
22
if (foo()) {
33
do {
4-
do {
5-
alert(x);
6-
}while (--x)
4+
do alert(x);
5+
while (--x)
76
}while (x)
87
} else bar();
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
var x = 3;
2-
32
if (foo()) {
43
do {
5-
do {
6-
alert(x);
7-
} while (--x);
8-
} while (x);
4+
do alert(x);
5+
while (--x)
6+
}while (x)
97
} else bar();
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
var x = 3;
22
if (foo()) {
33
do {
4-
do {
5-
alert(x);
6-
}while (--x)
4+
do alert(x);
5+
while (--x)
76
}while (x)
87
} else bar();

0 commit comments

Comments
 (0)