mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(minifier): rotate associative operators to make it more idempotent (#8424)
another **massive** pain to debug ~~https://github.com/oxc-project/monitor-oxc/actions/runs/12717213600~~ https://github.com/oxc-project/monitor-oxc/actions/runs/12717978983/job/35455601146
This commit is contained in:
parent
a80460c6fe
commit
52f88c0e9c
3 changed files with 46 additions and 2 deletions
|
|
@ -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 let Expression::LogicalExpression(logical_expr) = &mut expr.alternate {
|
||||||
if logical_expr.operator == LogicalOperator::And
|
if logical_expr.operator == LogicalOperator::And
|
||||||
&& logical_expr.right.content_eq(&expr.consequent)
|
&& logical_expr.right.content_eq(&expr.consequent)
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,8 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
||||||
Self::try_compress_assignment_to_update_expression(e, ctx)
|
Self::try_compress_assignment_to_update_expression(e, ctx)
|
||||||
}
|
}
|
||||||
Expression::LogicalExpression(e) => Self::try_compress_is_null_or_undefined(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::TemplateLiteral(t) => Self::try_fold_template_literal(t, ctx),
|
||||||
Expression::BinaryExpression(e) => Self::try_fold_loose_equals_undefined(e, ctx)
|
Expression::BinaryExpression(e) => Self::try_fold_loose_equals_undefined(e, ctx)
|
||||||
.or_else(|| Self::try_compress_typeof_undefined(e, ctx)),
|
.or_else(|| Self::try_compress_typeof_undefined(e, ctx)),
|
||||||
|
|
@ -503,6 +504,38 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax {
|
||||||
Some(ctx.ast.move_expression(&mut expr.right))
|
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.
|
/// 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.
|
/// Evaluation here means `Evaluation` in the spec.
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,17 @@ fn integration() {
|
||||||
return console.log(e || JSON.stringify(os));
|
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
|
#[test] // https://github.com/oxc-project/oxc/issues/4341
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue