From fd7c7b7c574f2df17818016f58d6eef6deb07f79 Mon Sep 17 00:00:00 2001 From: Cameron Clark Date: Tue, 31 Dec 2024 02:16:25 +0000 Subject: [PATCH] feat(minifier): try collapse conditional to logical or expr --- .../peephole_minimize_conditions.rs | 40 ++++++++++++++----- tasks/minsize/minsize.snap | 4 +- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs b/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs index f3b4e8593bd3a..088de64dddbbf 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_minimize_conditions.rs @@ -57,6 +57,9 @@ impl<'a> Traverse<'a> for PeepholeMinimizeConditions { fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { if let Some(folded_expr) = match expr { Expression::UnaryExpression(e) => Self::try_minimize_not(e, ctx), + Expression::ConditionalExpression(conditional_expr) => { + Self::try_minimize_conditional(conditional_expr, ctx) + } _ => None, } { *expr = folded_expr; @@ -253,6 +256,28 @@ impl<'a> PeepholeMinimizeConditions { None => ctx.ast.void_0(return_stmt.span), } } + + /// `a ? a : b` -> `a || b` + fn try_minimize_conditional( + expr: &mut ConditionalExpression<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Option> { + let Expression::Identifier(test_ident) = &expr.test else { return None }; + let Expression::Identifier(consequent_ident) = &expr.consequent else { return None }; + + if test_ident.name != consequent_ident.name { + return None; + } + + let ident = ctx.ast.move_expression(&mut expr.test); + + Some(ctx.ast.expression_logical( + expr.span, + ident, + LogicalOperator::Or, + ctx.ast.move_expression(&mut expr.alternate), + )) + } } /// @@ -662,21 +687,18 @@ mod test { } #[test] - #[ignore] fn test_minimize_hook() { fold("x ? x : y", "x || y"); - // We assume GETPROPs don't have side effects. - fold("x.y ? x.y : x.z", "x.y || x.z"); - fold("x?.y ? x?.y : x.z", "x?.y || x.z"); - fold("x?.y ? x?.y : x?.z", "x?.y || x?.z"); + fold_same("x.y ? x.y : x.z"); + fold_same("x?.y ? x?.y : x.z"); + fold_same("x?.y ? x?.y : x?.z"); - // This can be folded if x() does not have side effects. fold_same("x() ? x() : y()"); fold_same("x?.() ? x?.() : y()"); - fold("!x ? foo() : bar()", "x ? bar() : foo()"); - fold("while(!(x ? y : z)) foo();", "while(x ? !y : !z) foo();"); - fold("(x ? !y : !z) ? foo() : bar()", "(x ? y : z) ? bar() : foo()"); + // fold("!x ? foo() : bar()", "x ? bar() : foo()"); + // fold("while(!(x ? y : z)) foo();", "while(x ? !y : !z) foo();"); + // fold("(x ? !y : !z) ? foo() : bar()", "(x ? y : z) ? bar() : foo()"); } #[test] diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 93dc7f191d799..934fbc3765a1a 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -21,7 +21,7 @@ Original | minified | minified | gzip | gzip | Fixture 3.20 MB | 1.01 MB | 1.01 MB | 332.21 kB | 331.56 kB | echarts.js -6.69 MB | 2.32 MB | 2.31 MB | 493.08 kB | 488.28 kB | antd.js +6.69 MB | 2.32 MB | 2.31 MB | 493.07 kB | 488.28 kB | antd.js -10.95 MB | 3.51 MB | 3.49 MB | 910.42 kB | 915.50 kB | typescript.js +10.95 MB | 3.51 MB | 3.49 MB | 910.37 kB | 915.50 kB | typescript.js