mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(minfier): drop last break from last switch case (#24673)
After many trial and errors, this seem to be the best way to remove break stmts in switch cases, This change targets only last break in last case of switch smts if its unlabelled this change differs from #23914 as its no longer targets all branches as that should not be no longer necessary if all cases are correctly rewritten https://github.com/oxc-project/oxc/issues/24672 ----- cases like `switch (a) { case 3: if (b) break; }` are not changed ----- ref: #17544
This commit is contained in:
1 parent
cb102dedd1
commit
7b045cd417
7 files changed
+103
-57
No files matched your search
@@ -518,7 +518,6 @@ function walkNode(node, visitors) {
|
||||
break;
|
||||
case "TSUnionType":
|
||||
walkTSUnionType(node, visitors);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -820,6 +820,12 @@ impl<'a> PeepholeOptimizations {
|
||||
ctx,
|
||||
));
|
||||
return;
|
||||
} else if let Some(last_case) = switch_stmt.cases.last_mut()
|
||||
&& let Some(Statement::BreakStatement(last_break)) = last_case.consequent.last()
|
||||
&& last_break.label.is_none()
|
||||
{
|
||||
let dropped = last_case.consequent.pop().unwrap();
|
||||
ctx.drop_statement(&dropped);
|
||||
}
|
||||
|
||||
result.push(Statement::SwitchStatement(switch_stmt));
|
||||
|
||||
@@ -129,13 +129,13 @@ fn test_handle_switch_statement() {
|
||||
test("switch (a()) {}", "a()");
|
||||
test("switch (a) { default: }", "a;");
|
||||
test("switch (a) { default: break;}", " a;");
|
||||
test_same("switch (a) { default: var b; break;}"); // a; var b;
|
||||
test("switch (a) { default: var b; break;}", "switch (a) { default: var b; }"); // a; var b;
|
||||
test_same("switch (a) { default: b()}"); // a; b();
|
||||
test_same("switch (a) { default: b(); return;}"); // a, b(); return;
|
||||
|
||||
test("switch (a) { case 1: break;}", "a;");
|
||||
test_same("switch (a) { case 1: b();}"); // a === 1 && b();
|
||||
test_same("switch (a) { case 1: b();break; }"); // a === 1 && b();
|
||||
test("switch (a) { case 1: b();break; }", "switch (a) { case 1: b(); }"); // a === 1 && b();
|
||||
test_same("switch (a) { case 1: b();return; }"); // if (a === 1) { b(); return; }
|
||||
|
||||
test("switch (a) { default: case 1: }", "a;");
|
||||
@@ -145,35 +145,41 @@ fn test_handle_switch_statement() {
|
||||
test_same("switch (a) { case 1: default: b(); case 2: c();}");
|
||||
test_same("switch (a) { case 1: b(); default: break; case 2: c()}");
|
||||
test_same("switch (a) { case 1: b(); case 2: break; case 3: c()}");
|
||||
test_same("switch (a) { case 1: b(); break; case 2: c();break;}");
|
||||
test(
|
||||
"switch (a) { case 1: b(); break; case 2: c();break;}",
|
||||
"switch (a) { case 1: b(); break; case 2: c();}",
|
||||
);
|
||||
test_same("switch (x) { default: foo(); case 1: }");
|
||||
test_same("switch (a) { case 1: b(); case 2: b();}");
|
||||
test_same("switch (a) { case 1: case 2: b(); }");
|
||||
test_same("switch (a) { case 1: var c=2; break;}"); // if (a === 1) { var c=2; }
|
||||
test(
|
||||
"switch (a) { case 1: case 2: default: b(); break;}",
|
||||
"switch (a) { default: b(); break;}",
|
||||
); // a, b();
|
||||
test("switch (a) { case 1: var c=2; break;}", "switch (a) { case 1: var c=2; }"); // if (a === 1) { var c=2; }
|
||||
test("switch (a) { case 1: case 2: default: b(); break;}", "switch (a) { default: b(); }"); // a, b();
|
||||
|
||||
test("switch (a) { default: break; case 1: break;}", "a;");
|
||||
test_same("switch (a) { default: b();break;case 1: c();break;}"); // a === 1 ? c() : b();
|
||||
test(
|
||||
"switch (a) { default: b();break;case 1: c();break;}",
|
||||
"switch (a) { default: b();break;case 1: c();}",
|
||||
); // a === 1 ? c() : b();
|
||||
test(
|
||||
"switch (a) { default: {b();break;} case 1: {c();break;}}",
|
||||
"switch (a) { default: b();break;case 1: c();break;}",
|
||||
"switch (a) { default: b();break;case 1: c(); }",
|
||||
); // a === 1 ? c() : b();
|
||||
|
||||
test("switch (a) { case b(): default:}", "switch (a) { case b(): }"); // a, b();
|
||||
test("switch (a) { case 2: case 1: break; default: break;}", "a;");
|
||||
test("switch (a) { case 3: b(); break; case 2: break;}", "switch (a) { case 3: b(); break; }"); // a === 3 && b();
|
||||
test("switch (a) { case 3: b(); break; case 2: break;}", "switch (a) { case 3: b(); }"); // a === 3 && b();
|
||||
test("switch (a) { case 3: b(); case 2: break;}", "switch (a) { case 3: b(); }"); // a === 3 && b();
|
||||
test_same("switch (a) { case 3: b(); case 2: c(); break;}");
|
||||
test(
|
||||
"switch (a) { case 3: b(); case 2: c(); break;}",
|
||||
"switch (a) { case 3: b(); case 2: c(); }",
|
||||
);
|
||||
test("switch (a) { case 3: b(); case 2: case 1: break;}", "switch (a) { case 3: b(); }"); // a === 3 && b();
|
||||
test("switch (a) { case 3: b(); case 2: case 1: }", "switch (a) { case 3: b(); }"); // a === 3 && b();
|
||||
test_same("switch (x) { default: case 1: foo(); case 2: }"); // x !== 2 && foo();
|
||||
test_same("switch (a) { case 3: if (b) break }"); // a === 3 && b;
|
||||
test("switch (a) { case 3: if (b) break }", "switch (a) { case 3: if (b) break; }"); // a === 3 && b;
|
||||
test(
|
||||
"switch (a) { case 3: { if(b) {c()} else {break;} }}",
|
||||
"switch (a) { case 3: if (b) c(); else break;}",
|
||||
"switch (a) { case 3: if (b) c(); else break; }",
|
||||
); // a === 3 && b && c();
|
||||
test(
|
||||
"switch (a) { case 3: { if(b) {c(); break;} else { d(); break;} }}",
|
||||
@@ -189,13 +195,13 @@ fn test_handle_switch_statement() {
|
||||
|
||||
test(
|
||||
"switch (a) { case 1: c(); case 2: default: b();break;}",
|
||||
"switch (a) { case 1: c(); default: b(); break;}",
|
||||
"switch (a) { case 1: c(); default: b(); }",
|
||||
); // a === 1 && c(); b();
|
||||
test_same("function f() { switch (a) { case 1: return;} }"); // function f() { a; }
|
||||
test("switch (a()) { default: {let y;} }", "switch (a()) { default: { let y; } }"); // a(); { let y; }
|
||||
test(
|
||||
"function f(){switch ('x') { case 'x': var x = 1;break; case 'y': break; }}",
|
||||
"function f(){switch ('x') { case 'x': var x = 1;break; }}",
|
||||
"function f(){switch ('x') { case 'x': var x = 1; }}",
|
||||
);
|
||||
test("switch (a) { default: if(a) {break;}c();}", "switch (a) { default: if(a) break;c();}"); // a, !a && c();
|
||||
test("switch (a) { case 1: if(a) {b();}c();}", "switch (a) { case 1: a && b(), c(); }"); // if (a === 1) { a && b(), c(); }
|
||||
@@ -213,26 +219,56 @@ fn test_handle_switch_statement() {
|
||||
"x: switch (a) { case 2: if (b) break outer; }",
|
||||
); // x: if (a === 2 && b) break outer;
|
||||
|
||||
test_same("switch ('r') { case 'r': a();break; case 'r': var x=0;break;}"); // a();
|
||||
test(
|
||||
"switch ('r') { case 'r': a();break; case 'r': var x=0;break;}",
|
||||
"switch ('r') { case 'r': a();break; case 'r': var x=0;}",
|
||||
); // a();
|
||||
test_same("switch (2) { default: a; case 1: b()}"); // a, b();
|
||||
test_same("switch (1) { case 1: a();break; default: b();}"); // a();
|
||||
test_same("switch ('e') { case 'e': case 'f': a();}"); // a();
|
||||
test_same("switch ('a') { case 'a': a();break; case 'b': b();break;}"); // a();
|
||||
test_same("switch ('c') { case 'a': a();break; case 'b': b();break;}"); // ;
|
||||
test_same("switch (1) { case 1: a();break; case 2: bar();break;}"); // a();
|
||||
test(
|
||||
"switch ('a') { case 'a': a();break; case 'b': b();break;}",
|
||||
"switch ('a') { case 'a': a();break; case 'b': b();}",
|
||||
); // a();
|
||||
test(
|
||||
"switch ('c') { case 'a': a();break; case 'b': b();break;}",
|
||||
"switch ('c') { case 'a': a();break; case 'b': b();}",
|
||||
); // ;
|
||||
test(
|
||||
"switch (1) { case 1: a();break; case 2: bar();break;}",
|
||||
"switch (1) { case 1: a();break; case 2: bar();}",
|
||||
); // a();
|
||||
test_same("switch ('f') { case 'f': a(); case 'b': b();}");
|
||||
test_same("switch ('f') { case 'f': if (a() > 0) {b();break;} c(); case 'd': f();}");
|
||||
test_same("switch ('f') { case 'b': bar();break; case x: x();break; case 'f': f();break;}");
|
||||
test(
|
||||
"switch ('f') { case 'b': bar();break; case x: x();break; case 'f': f();break;}",
|
||||
"switch ('f') { case 'b': bar();break; case x: x();break; case 'f': f(); }",
|
||||
);
|
||||
test(
|
||||
"switch (1) { case 1: case 2: {break;} case 3: case 4: default: b(); break;}",
|
||||
"switch (1) { case 1: case 2: break; default: b(); break; }",
|
||||
"switch (1) { case 1: case 2: break; default: b(); }",
|
||||
);
|
||||
test_same("switch ('d') { case 'foo': foo();break; default: bar();break;}"); // bar()
|
||||
test_same("switch (0) { case NaN: foobar();break;case -0: foo();break; case 2: bar();break;}"); // foo()
|
||||
test_same("let x = 1; switch ('x') { case 'x': let x = 2; break;}"); // let x = 1; { let x = 2; }
|
||||
test(
|
||||
"switch ('d') { case 'foo': foo();break; default: bar();break;}",
|
||||
"switch ('d') { case 'foo': foo();break; default: bar();}",
|
||||
); // bar()
|
||||
test(
|
||||
"switch (0) { case NaN: foobar();break;case -0: foo();break; case 2: bar();break;}",
|
||||
"switch (0) { case NaN: foobar();break;case -0: foo();break; case 2: bar();}",
|
||||
); // foo()
|
||||
test(
|
||||
"let x = 1; switch ('x') { case 'x': let x = 2; break;}",
|
||||
"let x = 1; switch ('x') { case 'x': let x = 2; }",
|
||||
); // let x = 1; { let x = 2; }
|
||||
test_same("switch (1) { case 2: var x=0;}"); // if (0) var x;
|
||||
test_same("switch (b) { case 2: switch (a) { case 2: a();break;case 3: foo();break;}}"); // ;
|
||||
test(
|
||||
"switch (b) { case 2: switch (a) { case 2: a();break;case 3: foo();break;}}",
|
||||
"switch (b) { case 2: switch (a) { case 2: a();break;case 3: foo();}}",
|
||||
); // ;
|
||||
test_same("switch (b) { case 2: switch (a) { case 2: foo()}}"); // if (b === 2 && a === 2) foo()
|
||||
|
||||
test_same("function f(){ switch (0) { case x: break; } let x = 1; }"); // TDZ
|
||||
test(
|
||||
"function f(){ switch (0) { case x: break; } let x = 1; }",
|
||||
"function f(){ switch (0) { case x: } let x = 1; }",
|
||||
); // TDZ
|
||||
}
|
||||
@@ -303,18 +303,24 @@ fn test_loop_optimization_edge_cases() {
|
||||
#[test]
|
||||
fn test_switch_statement_edge_cases() {
|
||||
// Test switch with constant discriminant - might be optimized in future
|
||||
test_same("switch (2) { case 1: a(); break; case 2: b(); break; case 3: c(); break; }");
|
||||
test_same("switch (2) { case 1: a(); break; case 2: b(); break; case 3: c(); }");
|
||||
// Could be optimized to just: b();
|
||||
|
||||
test_same("switch ('test') { case 'foo': a(); break; case 'test': b(); break; default: c(); }");
|
||||
// Could be optimized to just: b();
|
||||
|
||||
// Test switch with no matching case
|
||||
test_same("switch (5) { case 1: a(); break; case 2: b(); break; }");
|
||||
test(
|
||||
"switch (5) { case 1: a(); break; case 2: b(); break; }",
|
||||
"switch (5) { case 1: a(); break; case 2: b(); }",
|
||||
);
|
||||
// Could be optimized to empty
|
||||
|
||||
// Test switch with default
|
||||
test_same("switch (5) { case 1: a(); break; default: b(); break; }");
|
||||
test(
|
||||
"switch (5) { case 1: a(); break; default: b(); break; }",
|
||||
"switch (5) { case 1: a(); break; default: b(); }",
|
||||
);
|
||||
// Could be optimized to just: b();
|
||||
|
||||
// Test switch with fall-through - more complex, keep as same for safety
|
||||
|
||||
@@ -504,7 +504,6 @@ function walkNode(node, visitors) {
|
||||
break;
|
||||
case "TSUnionType":
|
||||
walkTSUnionType(node, visitors);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -3,25 +3,25 @@ Original | minified | minified | gzip | gzip | Iterations | Fi
|
||||
-------------------------------------------------------------------------------------
|
||||
72.14 kB | 23.12 kB | 23.70 kB | 8.34 kB | 8.54 kB | 2 | react.development.js
|
||||
|
||||
173.90 kB | 59.40 kB | 59.82 kB | 19.15 kB | 19.33 kB | 2 | moment.js
|
||||
173.90 kB | 59.37 kB | 59.82 kB | 19.15 kB | 19.33 kB | 2 | moment.js
|
||||
|
||||
287.63 kB | 89.24 kB | 90.07 kB | 30.91 kB | 31.95 kB | 2 | jquery.js
|
||||
|
||||
342.15 kB | 116.97 kB | 118.14 kB | 43.17 kB | 44.37 kB | 2 | vue.js
|
||||
342.15 kB | 116.95 kB | 118.14 kB | 43.17 kB | 44.37 kB | 2 | vue.js
|
||||
|
||||
544.10 kB | 70.92 kB | 72.48 kB | 25.73 kB | 26.20 kB | 2 | lodash.js
|
||||
544.10 kB | 70.91 kB | 72.48 kB | 25.73 kB | 26.20 kB | 2 | lodash.js
|
||||
|
||||
555.77 kB | 267.38 kB | 270.13 kB | 88.00 kB | 90.80 kB | 2 | d3.js
|
||||
555.77 kB | 267.20 kB | 270.13 kB | 87.98 kB | 90.80 kB | 2 | d3.js
|
||||
|
||||
1.01 MB | 439.33 kB | 458.89 kB | 122.04 kB | 126.71 kB | 2 | bundle.min.js
|
||||
1.01 MB | 439.29 kB | 458.89 kB | 122.05 kB | 126.71 kB | 2 | bundle.min.js
|
||||
|
||||
1.25 MB | 642.61 kB | 646.76 kB | 159.40 kB | 163.73 kB | 2 | three.js
|
||||
1.25 MB | 642.52 kB | 646.76 kB | 159.39 kB | 163.73 kB | 2 | three.js
|
||||
|
||||
2.14 MB | 711.03 kB | 724.14 kB | 160.38 kB | 181.07 kB | 2 | victory.js
|
||||
2.14 MB | 710.90 kB | 724.14 kB | 160.38 kB | 181.07 kB | 2 | victory.js
|
||||
|
||||
3.20 MB | 1.00 MB | 1.01 MB | 322.59 kB | 331.56 kB | 2 | echarts.js
|
||||
3.20 MB | 1.00 MB | 1.01 MB | 322.56 kB | 331.56 kB | 2 | echarts.js
|
||||
|
||||
6.69 MB | 2.12 MB | 2.31 MB | 453.85 kB | 488.28 kB | 5 | antd.js
|
||||
6.69 MB | 2.12 MB | 2.31 MB | 453.83 kB | 488.28 kB | 5 | antd.js
|
||||
|
||||
10.95 MB | 3.33 MB | 3.49 MB | 853.03 kB | 915.50 kB | 4 | typescript.js
|
||||
10.95 MB | 3.33 MB | 3.49 MB | 852.92 kB | 915.50 kB | 4 | typescript.js
|
||||
|
||||
@@ -5,9 +5,9 @@ checker.ts:
|
||||
sys deallocs: 152
|
||||
sys alloc bytes: 15028748 # 15.03 MB
|
||||
sys peak growth: 10203896 # 10.20 MB
|
||||
arena allocs: 152763
|
||||
arena reallocs: 28276
|
||||
arena size: 19312968 # 19.31 MB
|
||||
arena allocs: 152706
|
||||
arena reallocs: 28225
|
||||
arena size: 19309904 # 19.31 MB
|
||||
|
||||
App.tsx:
|
||||
file size: 415342 # 415.34 kB
|
||||
@@ -16,8 +16,8 @@ App.tsx:
|
||||
sys deallocs: 63
|
||||
sys alloc bytes: 2136669 # 2.14 MB
|
||||
sys peak growth: 1620605 # 1.62 MB
|
||||
arena allocs: 17029
|
||||
arena reallocs: 2702
|
||||
arena allocs: 17027
|
||||
arena reallocs: 2700
|
||||
arena size: 2915736 # 2.92 MB
|
||||
|
||||
RadixUIAdoptionSection.jsx:
|
||||
@@ -38,9 +38,9 @@ pdf.mjs:
|
||||
sys deallocs: 2467
|
||||
sys alloc bytes: 5348727 # 5.35 MB
|
||||
sys peak growth: 3707391 # 3.71 MB
|
||||
arena allocs: 47452
|
||||
arena reallocs: 7743
|
||||
arena size: 6375424 # 6.38 MB
|
||||
arena allocs: 47424
|
||||
arena reallocs: 7715
|
||||
arena size: 6374064 # 6.37 MB
|
||||
|
||||
antd.js:
|
||||
file size: 6686316 # 6.69 MB
|
||||
@@ -49,9 +49,9 @@ antd.js:
|
||||
sys deallocs: 1038
|
||||
sys alloc bytes: 29987563 # 29.99 MB
|
||||
sys peak growth: 19934725 # 19.93 MB
|
||||
arena allocs: 371535
|
||||
arena reallocs: 76376
|
||||
arena size: 49107608 # 49.11 MB
|
||||
arena allocs: 371435
|
||||
arena reallocs: 76276
|
||||
arena size: 49102648 # 49.10 MB
|
||||
|
||||
binder.ts:
|
||||
file size: 193077 # 193.08 kB
|
||||
@@ -60,8 +60,8 @@ binder.ts:
|
||||
sys deallocs: 33
|
||||
sys alloc bytes: 963614 # 963.61 kB
|
||||
sys peak growth: 658042 # 658.04 kB
|
||||
arena allocs: 7084
|
||||
arena reallocs: 840
|
||||
arena allocs: 7082
|
||||
arena reallocs: 838
|
||||
arena size: 1169808 # 1.17 MB
|
||||
|
||||
kitchen-sink.tsx:
|
||||
@@ -71,7 +71,7 @@ kitchen-sink.tsx:
|
||||
sys deallocs: 1867
|
||||
sys alloc bytes: 5346850 # 5.35 MB
|
||||
sys peak growth: 3738631 # 3.74 MB
|
||||
arena allocs: 71947
|
||||
arena reallocs: 12262
|
||||
arena allocs: 71929
|
||||
arena reallocs: 12244
|
||||
arena size: 9560960 # 9.56 MB
|
||||
|
||||
Reference in new issue
Block a user