Skip to content

Commit

Permalink
fix(minifier): rotate associative operators to make it more idempotent (
Browse files Browse the repository at this point in the history
  • Loading branch information
camc314 committed Jan 11, 2025
1 parent a80460c commit 52f88c0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ impl<'a> PeepholeMinimizeConditions {
}
}

// `a ? c : b && c` -> `(a || b) && c``
// `a ? c : b && c` -> `(a || b) && c`
if let Expression::LogicalExpression(logical_expr) = &mut expr.alternate {
if logical_expr.operator == LogicalOperator::And
&& logical_expr.right.content_eq(&expr.consequent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
Self::try_compress_assignment_to_update_expression(e, ctx)
}
Expression::LogicalExpression(e) => Self::try_compress_is_null_or_undefined(e, ctx)
.or_else(|| self.try_compress_logical_expression_to_assignment_expression(e, ctx)),
.or_else(|| self.try_compress_logical_expression_to_assignment_expression(e, ctx))
.or_else(|| Self::try_rotate_logical_expression(e, ctx)),
Expression::TemplateLiteral(t) => Self::try_fold_template_literal(t, ctx),
Expression::BinaryExpression(e) => Self::try_fold_loose_equals_undefined(e, ctx)
.or_else(|| Self::try_compress_typeof_undefined(e, ctx)),
Expand Down Expand Up @@ -503,6 +504,38 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
Some(ctx.ast.move_expression(&mut expr.right))
}

/// `a || (b || c);` -> `(a || b) || c;`
fn try_rotate_logical_expression(
expr: &mut LogicalExpression<'a>,
ctx: Ctx<'a, 'b>,
) -> Option<Expression<'a>> {
let Expression::LogicalExpression(right) = &mut expr.right else { return None };
if right.operator != expr.operator {
return None;
}

let mut new_left = ctx.ast.expression_logical(
expr.span,
ctx.ast.move_expression(&mut expr.left),
expr.operator,
ctx.ast.move_expression(&mut right.left),
);

{
let Expression::LogicalExpression(new_left2) = &mut new_left else { unreachable!() };
if let Some(expr) = Self::try_rotate_logical_expression(new_left2, ctx) {
new_left = expr;
}
}

Some(ctx.ast.expression_logical(
expr.span,
new_left,
expr.operator,
ctx.ast.move_expression(&mut right.right),
))
}

/// Returns `true` if the assignment target and expression have no side effect for *evaluation* and points to the same reference.
///
/// Evaluation here means `Evaluation` in the spec.
Expand Down
11 changes: 11 additions & 0 deletions crates/oxc_minifier/tests/ast_passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ fn integration() {
return console.log(e || JSON.stringify(os));
});"#,
);

test_idempotent(
"if (!(foo instanceof Var) || open) {
arg0 = null;
} else if (que || !(foo && bar)) {
if (baz()) arg0 = null;
}",
"(!(foo instanceof Var) || open || (que || !(foo && bar)) && baz()) && (arg0 = null);",
);

test_same("a && (b && (c && (d && (e && (f && (g && (h && i && j && k && l && m && n && o && p && q && r && s && t && u && v && w && x && y && z)))))))");
}

#[test] // https://github.com/oxc-project/oxc/issues/4341
Expand Down

0 comments on commit 52f88c0

Please sign in to comment.