mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 18:43:44 +00:00
fix(minifier): handle sequence exprs when folding if to expr statement (#27939)
Handle sequence expressions when converting if statements to logical expression statements: `if (a(), !b); else c();` -> `a(), b && c();` `if (a(), !b) c();` -> `a(), b || c();` this change has been extracted from #27664 --------- Co-authored-by: Cameron <cameron.clark@hey.com>
This commit is contained in:
1 parent
e3eca411d5
commit
6d7b372be7
7 files changed
+48
-36
No files matched your search
@@ -36,13 +36,12 @@ impl<'a> PeepholeOptimizations {
|
||||
ctx.replace_statement_with(stmt, |stmt, ctx| {
|
||||
let Statement::IfStatement(if_stmt) = stmt else { unreachable!() };
|
||||
let IfStatement { test, span, .. } = if_stmt.unbox();
|
||||
let (op, a) = match test {
|
||||
let (op, a) = if Self::has_negated_result(&test) {
|
||||
// `if (!a); else b();` => `a && b();`
|
||||
Expression::UnaryExpression(unary_expr) if unary_expr.operator.is_not() => {
|
||||
(LogicalOperator::And, unary_expr.unbox().argument)
|
||||
}
|
||||
(LogicalOperator::And, Self::minimize_not(span, test, ctx, true))
|
||||
} else {
|
||||
// `if (a); else b();` => `a || b();`
|
||||
e => (LogicalOperator::Or, e),
|
||||
(LogicalOperator::Or, test)
|
||||
};
|
||||
let b = expr_stmt.unbox().expression;
|
||||
let expr = Self::join_with_left_associative_op(span, op, a, b, ctx);
|
||||
@@ -98,13 +97,12 @@ impl<'a> PeepholeOptimizations {
|
||||
let Statement::IfStatement(if_stmt) = stmt else { unreachable!() };
|
||||
let IfStatement { test, consequent, span, .. } = if_stmt.unbox();
|
||||
let Statement::ExpressionStatement(b) = consequent else { unreachable!() };
|
||||
let (op, a) = match test {
|
||||
let (op, a) = if Self::has_negated_result(&test) {
|
||||
// `if (!a) b();` => `a || b();`
|
||||
Expression::UnaryExpression(unary_expr) if unary_expr.operator.is_not() => {
|
||||
(LogicalOperator::Or, unary_expr.unbox().argument)
|
||||
}
|
||||
(LogicalOperator::Or, Self::minimize_not(span, test, ctx, true))
|
||||
} else {
|
||||
// `if (a) b();` => `a && b();`
|
||||
e => (LogicalOperator::And, e),
|
||||
(LogicalOperator::And, test)
|
||||
};
|
||||
let b = b.unbox().expression;
|
||||
let expr = Self::join_with_left_associative_op(span, op, a, b, ctx);
|
||||
|
||||
@@ -245,4 +245,17 @@ impl<'a> PeepholeOptimizations {
|
||||
expr.operator = inverse;
|
||||
ctx.notice_change();
|
||||
}
|
||||
|
||||
pub fn has_negated_result(test: &Expression<'a>) -> bool {
|
||||
match test {
|
||||
// `(_, !a)`, `(_, a)`
|
||||
Expression::SequenceExpression(seq) => {
|
||||
Self::last_expression_in_sequence(seq).is_some_and(Self::has_negated_result)
|
||||
}
|
||||
// `!a`
|
||||
Expression::UnaryExpression(unary_expr) if unary_expr.operator.is_not() => true,
|
||||
// `a`
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,11 +218,8 @@ fn js_parser_test() {
|
||||
);
|
||||
test("while (x) { if (y) continue; z(); }", "for (; x; ) y || z();");
|
||||
test("while (x) { if (y) continue; else z(); w(); }", "for (; x; ) y || (z(), w());");
|
||||
test("while (x) { t(); if (y) continue; z(); }", "for (; x; ) t(), !y && z();");
|
||||
test(
|
||||
"while (x) { t(); if (y) continue; else z(); w(); }",
|
||||
"for (; x; ) t(), !y && (z(), w());",
|
||||
);
|
||||
test("while (x) { t(); if (y) continue; z(); }", "for (; x; ) t(), y || z();");
|
||||
test("while (x) { t(); if (y) continue; else z(); w(); }", "for (; x; ) t(), y || (z(), w());");
|
||||
test("while (x) { debugger; if (y) continue; z(); }", "for (; x; ) { debugger; y || z(); }");
|
||||
test(
|
||||
"while (x) { debugger; if (y) continue; else z(); w(); }",
|
||||
@@ -1153,10 +1150,10 @@ fn test_minimize_exit_statements() {
|
||||
test("if (a) return b; else return c; return d;", "return a ? b : c;");
|
||||
test("function x() { if (y) return; z(); }", "function x() { y || z();}");
|
||||
test("function x() { if (y) return; else z(); w(); }", "function x() { y || (z(), w());}");
|
||||
test("function x() { t(); if (y) return; z(); }", "function x() { t(), !y && z();}");
|
||||
test("function x() { t(); if (y) return; z(); }", "function x() { t(), y || z();}");
|
||||
test(
|
||||
"function x() { t(); if (y) return; else z(); w(); }",
|
||||
"function x() { t(), !y && (z(), w());}",
|
||||
"function x() { t(), y || (z(), w());}",
|
||||
);
|
||||
test("function x() { debugger; if (y) return; z(); }", "function x() { debugger; y || z();}");
|
||||
test(
|
||||
|
||||
@@ -177,7 +177,7 @@ fn test_while_continue_optimization() {
|
||||
test("while(true){if(a()){continue;}else{continue;} b();}", "for(;;)a();");
|
||||
test(
|
||||
"while(true){d();if(a()){continue;}else if(b()){c();continue;}else{continue;}}",
|
||||
"for(;;)d(),!a()&&b()&&c()",
|
||||
"for(;;)d(),a()||b()&&c()",
|
||||
);
|
||||
|
||||
test("while(true)while(a())continue;", "for(;;)for(;a();)continue;"); // for(;;)for(;a(););
|
||||
|
||||
@@ -88,7 +88,11 @@ fn test_minimize_if() {
|
||||
test("function f(){if(!a)b();else return c;}", "function f(){if(!a)b();else return c;}");
|
||||
test("function f(){if(a)return c;else b();}", "function f(){if(a)return c;b();}");
|
||||
test("function f(){if((a(),b)){}else c();}", "function f(){a(),b||c();}");
|
||||
test("function f(){if(a(),!(b||c)){}else d();}", "function f(){a(),!(b||c)||d();}");
|
||||
test("function f(){if(a(),b){}else c();}", "function f(){a(),b||c();}");
|
||||
test("function f(){if(a(),!b){}else c();}", "function f(){a(),b&&c();}");
|
||||
test("function f(){if(a(),!b)c();}", "function f(){a(),b||c();}");
|
||||
test("function f(){if(!a(),b)c();}", "function f(){a(),b&&c();}");
|
||||
test("function f(){if(a(),!(b||c)){}else d();}", "function f(){a(),(b||c)&&d();}");
|
||||
|
||||
test("function f(a){if(a){}}", "function f(a){}");
|
||||
test("function f(a){if(a);}", "function f(a){}");
|
||||
|
||||
@@ -5,7 +5,7 @@ Original | minified | minified | gzip | gzip | Iterations | Fi
|
||||
|
||||
173.90 kB | 55.49 kB | 59.82 kB | 18.78 kB | 19.33 kB | 2 | moment.js
|
||||
|
||||
287.63 kB | 88.94 kB | 90.07 kB | 30.84 kB | 31.95 kB | 2 | jquery.js
|
||||
287.63 kB | 88.94 kB | 90.07 kB | 30.83 kB | 31.95 kB | 2 | jquery.js
|
||||
|
||||
342.15 kB | 114.75 kB | 118.14 kB | 42.68 kB | 44.37 kB | 2 | vue.js
|
||||
|
||||
@@ -17,11 +17,11 @@ Original | minified | minified | gzip | gzip | Iterations | Fi
|
||||
|
||||
1.25 MB | 634.21 kB | 646.76 kB | 158.43 kB | 163.73 kB | 2 | three.js
|
||||
|
||||
2.14 MB | 707.58 kB | 724.14 kB | 160.05 kB | 181.07 kB | 2 | victory.js
|
||||
2.14 MB | 707.55 kB | 724.14 kB | 160.05 kB | 181.07 kB | 2 | victory.js
|
||||
|
||||
3.20 MB | 958.38 kB | 1.01 MB | 316.95 kB | 331.56 kB | 2 | echarts.js
|
||||
|
||||
6.69 MB | 2.12 MB | 2.31 MB | 453.41 kB | 488.28 kB | 4 | antd.js
|
||||
6.69 MB | 2.12 MB | 2.31 MB | 453.37 kB | 488.28 kB | 4 | antd.js
|
||||
|
||||
10.95 MB | 3.31 MB | 3.49 MB | 849.76 kB | 915.50 kB | 4 | typescript.js
|
||||
10.95 MB | 3.31 MB | 3.49 MB | 849.75 kB | 915.50 kB | 4 | typescript.js
|
||||
|
||||
@@ -3,22 +3,22 @@ checker.ts:
|
||||
sys allocs: 40
|
||||
sys reallocs: 5
|
||||
sys deallocs: 40
|
||||
sys alloc bytes: 14996287 # 15.00 MB
|
||||
sys alloc bytes: 14995460 # 15.00 MB
|
||||
sys peak growth: 10169560 # 10.17 MB
|
||||
arena allocs: 56228
|
||||
arena reallocs: 5084
|
||||
arena size: 16501168 # 16.50 MB
|
||||
arena size: 16501008 # 16.50 MB
|
||||
|
||||
App.tsx:
|
||||
file size: 415342 # 415.34 kB
|
||||
sys allocs: 35
|
||||
sys reallocs: 8
|
||||
sys deallocs: 35
|
||||
sys alloc bytes: 2128539 # 2.13 MB
|
||||
sys alloc bytes: 2126572 # 2.13 MB
|
||||
sys peak growth: 1612427 # 1.61 MB
|
||||
arena allocs: 7729
|
||||
arena reallocs: 920
|
||||
arena size: 2782336 # 2.78 MB
|
||||
arena size: 2782328 # 2.78 MB
|
||||
|
||||
RadixUIAdoptionSection.jsx:
|
||||
file size: 2520 # 2.52 kB
|
||||
@@ -36,40 +36,40 @@ pdf.mjs:
|
||||
sys allocs: 1933
|
||||
sys reallocs: 205
|
||||
sys deallocs: 1933
|
||||
sys alloc bytes: 5313795 # 5.31 MB
|
||||
sys alloc bytes: 5287933 # 5.29 MB
|
||||
sys peak growth: 3693355 # 3.69 MB
|
||||
arena allocs: 19581
|
||||
arena allocs: 19582
|
||||
arena reallocs: 2574
|
||||
arena size: 5727264 # 5.73 MB
|
||||
arena size: 5726904 # 5.73 MB
|
||||
|
||||
antd.js:
|
||||
file size: 6686316 # 6.69 MB
|
||||
sys allocs: 155
|
||||
sys reallocs: 52
|
||||
sys deallocs: 155
|
||||
sys alloc bytes: 29973448 # 29.97 MB
|
||||
sys alloc bytes: 29960368 # 29.96 MB
|
||||
sys peak growth: 19934725 # 19.93 MB
|
||||
arena allocs: 175847
|
||||
arena allocs: 175842
|
||||
arena reallocs: 34169
|
||||
arena size: 44039472 # 44.04 MB
|
||||
arena size: 44039296 # 44.04 MB
|
||||
|
||||
binder.ts:
|
||||
file size: 193077 # 193.08 kB
|
||||
sys allocs: 25
|
||||
sys reallocs: 1
|
||||
sys deallocs: 25
|
||||
sys alloc bytes: 963008 # 963.01 kB
|
||||
sys alloc bytes: 962926 # 962.93 kB
|
||||
sys peak growth: 657404 # 657.40 kB
|
||||
arena allocs: 2930
|
||||
arena reallocs: 244
|
||||
arena size: 1092424 # 1.09 MB
|
||||
arena size: 1092336 # 1.09 MB
|
||||
|
||||
kitchen-sink.tsx:
|
||||
file size: 732898 # 732.90 kB
|
||||
sys allocs: 354
|
||||
sys reallocs: 174
|
||||
sys deallocs: 354
|
||||
sys alloc bytes: 5304252 # 5.30 MB
|
||||
sys alloc bytes: 5284342 # 5.28 MB
|
||||
sys peak growth: 3707425 # 3.71 MB
|
||||
arena allocs: 31100
|
||||
arena reallocs: 3011
|
||||
|
||||
Reference in new issue
Block a user