Skip to content

Commit 249895f

Browse files
authored
feat(minifier): implement variadic Math methods in known methods (#8783)
1 parent 4f30a17 commit 249895f

File tree

1 file changed

+63
-14
lines changed

1 file changed

+63
-14
lines changed

crates/oxc_minifier/src/peephole/replace_known_methods.rs

+63-14
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ impl<'a> PeepholeOptimizations {
6868
"abs" | "ceil" | "floor" | "round" | "fround" | "trunc" | "sign" => {
6969
Self::try_fold_math_unary(*span, arguments, name, object, ctx)
7070
}
71+
"min" | "max" => Self::try_fold_math_variadic(*span, arguments, name, object, ctx),
7172
_ => None,
7273
};
7374
if let Some(replacement) = replacement {
@@ -357,7 +358,7 @@ impl<'a> PeepholeOptimizations {
357358
}
358359

359360
fn validate_arguments(args: &Arguments, expected_len: usize) -> bool {
360-
args.len() == expected_len && args.iter().all(Argument::is_expression)
361+
(args.len() == expected_len) && args.iter().all(Argument::is_expression)
361362
}
362363

363364
/// `Math.pow(a, b)` -> `+(a) ** +b`
@@ -490,6 +491,46 @@ impl<'a> PeepholeOptimizations {
490491
Some(ctx.ast.expression_numeric_literal(span, result, None, NumberBase::Decimal))
491492
}
492493

494+
fn try_fold_math_variadic(
495+
span: Span,
496+
arguments: &Arguments,
497+
name: &str,
498+
object: &Expression<'a>,
499+
ctx: Ctx<'a, '_>,
500+
) -> Option<Expression<'a>> {
501+
if !Self::validate_global_reference(object, "Math", ctx) {
502+
return None;
503+
}
504+
let numbers = arguments
505+
.iter()
506+
.map(|arg| arg.as_expression().map(|e| ctx.get_side_free_number_value(e))?)
507+
.collect::<Option<Vec<_>>>()?;
508+
let result = if numbers.iter().any(|n| n.is_nan()) {
509+
f64::NAN
510+
} else {
511+
match name {
512+
// TODO
513+
// see <https://github.com/rust-lang/rust/issues/83984>, we can't use `min` and `max` here due to inconsistency
514+
"min" => numbers.iter().copied().fold(f64::INFINITY, |a, b| {
515+
if a < b || ((a == 0f64) && (b == 0f64) && (a.to_bits() > b.to_bits())) {
516+
a
517+
} else {
518+
b
519+
}
520+
}),
521+
"max" => numbers.iter().copied().fold(f64::NEG_INFINITY, |a, b| {
522+
if a > b || ((a == 0f64) && (b == 0f64) && (a.to_bits() < b.to_bits())) {
523+
a
524+
} else {
525+
b
526+
}
527+
}),
528+
_ => return None,
529+
}
530+
};
531+
Some(ctx.ast.expression_numeric_literal(span, result, None, NumberBase::Decimal))
532+
}
533+
493534
/// `[].concat(a).concat(b)` -> `[].concat(a, b)`
494535
/// `"".concat(a).concat(b)` -> `"".concat(a, b)`
495536
fn try_fold_concat_chain(&mut self, node: &mut Expression<'a>, ctx: Ctx<'a, '_>) {
@@ -1289,25 +1330,33 @@ mod test {
12891330
}
12901331

12911332
#[test]
1292-
#[ignore]
12931333
fn test_fold_math_functions_max() {
1294-
test_same("Math.max(Math.random(), 1)");
1334+
test_same_value("Math.max(Math.random(), 1)");
12951335

1296-
test("Math.max()", "-Infinity");
1297-
test("Math.max(0)", "0");
1298-
test("Math.max(0, 1)", "1");
1299-
test("Math.max(0, 1, -1, 200)", "200");
1336+
test_value("Math.max()", "-Infinity");
1337+
test_value("Math.max(0)", "0");
1338+
test_value("Math.max(0, 1)", "1");
1339+
test_value("Math.max(0, 1, -1, 200)", "200");
1340+
test_value("Math.max(0, -1, -Infinity)", "0");
1341+
test_value("Math.max(0, -1, -Infinity, NaN)", "NaN");
1342+
test_value("Math.max(0, -0)", "0");
1343+
test_value("Math.max(-0, 0)", "0");
1344+
test_same_value("Math.max(...a, 1)");
13001345
}
13011346

13021347
#[test]
1303-
#[ignore]
13041348
fn test_fold_math_functions_min() {
1305-
test_same("Math.min(Math.random(), 1)");
1306-
1307-
test("Math.min()", "Infinity");
1308-
test("Math.min(3)", "3");
1309-
test("Math.min(0, 1)", "0");
1310-
test("Math.min(0, 1, -1, 200)", "-1");
1349+
test_same_value("Math.min(Math.random(), 1)");
1350+
1351+
test_value("Math.min()", "Infinity");
1352+
test_value("Math.min(3)", "3");
1353+
test_value("Math.min(0, 1)", "0");
1354+
test_value("Math.min(0, 1, -1, 200)", "-1");
1355+
test_value("Math.min(0, -1, -Infinity)", "-Infinity");
1356+
test_value("Math.min(0, -1, -Infinity, NaN)", "NaN");
1357+
test_value("Math.min(0, -0)", "-0");
1358+
test_value("Math.min(-0, 0)", "-0");
1359+
test_same_value("Math.min(...a, 1)");
13111360
}
13121361

13131362
#[test]

0 commit comments

Comments
 (0)