Skip to content

Commit 35c6d48

Browse files
7086cmdBoshen
andauthored
feat(minifier): implement Number known methods (#12078)
My vacation is near, so I may have some time resuming my contributions. Here it is just implementing some functionalities that may never be used in actual usage :-) I'm not sure if the minsize result is accurate, since there may be a problem with my `minsize` locally. I'll check my local `minsize` later, and I'll use the CI as a test this time. --------- Co-authored-by: Boshen <boshenc@gmail.com>
1 parent 6ec0778 commit 35c6d48

File tree

1 file changed

+52
-20
lines changed

1 file changed

+52
-20
lines changed

crates/oxc_minifier/src/peephole/replace_known_methods.rs

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ impl<'a> PeepholeOptimizations {
7373
"fromCharCode" => Self::try_fold_string_from_char_code(*span, arguments, object, ctx),
7474
"toString" => Self::try_fold_to_string(*span, arguments, object, ctx),
7575
"pow" => self.try_fold_pow(*span, arguments, object, ctx),
76+
"isFinite" | "isNaN" | "isInteger" | "isSafeInteger" => {
77+
Self::try_fold_number_methods(*span, arguments, object, name, ctx)
78+
}
7679
"sqrt" | "cbrt" => Self::try_fold_roots(*span, arguments, name, object, ctx),
7780
"abs" | "ceil" | "floor" | "round" | "fround" | "trunc" | "sign" => {
7881
Self::try_fold_math_unary(*span, arguments, name, object, ctx)
@@ -1025,6 +1028,38 @@ impl<'a> PeepholeOptimizations {
10251028
_ => None,
10261029
}
10271030
}
1031+
1032+
fn try_fold_number_methods(
1033+
span: Span,
1034+
args: &mut Arguments<'a>,
1035+
object: &Expression<'a>,
1036+
name: &str,
1037+
ctx: &mut Ctx<'a, '_>,
1038+
) -> Option<Expression<'a>> {
1039+
if !Self::validate_global_reference(object, "Number", ctx) {
1040+
return None;
1041+
}
1042+
if args.len() != 1 {
1043+
return None;
1044+
}
1045+
let extracted_expr = args.first()?.as_expression()?;
1046+
if !extracted_expr.is_number_literal() {
1047+
return None;
1048+
}
1049+
let extracted = extracted_expr.get_side_free_number_value(ctx)?;
1050+
let result = match name {
1051+
"isFinite" => Some(extracted.is_finite()),
1052+
"isInteger" => Some(extracted.fract().abs() < f64::EPSILON),
1053+
"isNaN" => Some(extracted.is_nan()),
1054+
"isSafeInteger" => {
1055+
let integer = extracted.fract().abs() < f64::EPSILON;
1056+
let safe = extracted.abs() <= 2f64.powi(53) - 1.0;
1057+
Some(safe && integer)
1058+
}
1059+
_ => None,
1060+
};
1061+
result.map(|value| ctx.ast.expression_boolean_literal(span, value))
1062+
}
10281063
}
10291064

10301065
/// Port from: <https://github.com/google/closure-compiler/blob/v20240609/test/com/google/javascript/jscomp/PeepholeReplaceKnownMethodsTest.java>
@@ -1650,36 +1685,33 @@ mod test {
16501685
}
16511686

16521687
#[test]
1653-
#[ignore]
16541688
fn test_fold_number_functions_is_safe_integer() {
1655-
test("Number.isSafeInteger(1)", "true");
1656-
test("Number.isSafeInteger(1.5)", "false");
1657-
test("Number.isSafeInteger(9007199254740991)", "true");
1658-
test("Number.isSafeInteger(9007199254740992)", "false");
1659-
test("Number.isSafeInteger(-9007199254740991)", "true");
1660-
test("Number.isSafeInteger(-9007199254740992)", "false");
1689+
test_value("Number.isSafeInteger(1)", "!0");
1690+
test_value("Number.isSafeInteger(1.5)", "!1");
1691+
test_value("Number.isSafeInteger(9007199254740991)", "!0");
1692+
test_value("Number.isSafeInteger(9007199254740992)", "!1");
1693+
test_value("Number.isSafeInteger(-9007199254740991)", "!0");
1694+
test_value("Number.isSafeInteger(-9007199254740992)", "!1");
16611695
}
16621696

16631697
#[test]
1664-
#[ignore]
16651698
fn test_fold_number_functions_is_finite() {
1666-
test("Number.isFinite(1)", "true");
1667-
test("Number.isFinite(1.5)", "true");
1668-
test("Number.isFinite(NaN)", "false");
1669-
test("Number.isFinite(Infinity)", "false");
1670-
test("Number.isFinite(-Infinity)", "false");
1671-
test_same("Number.isFinite('a')");
1699+
test_value("Number.isFinite(1)", "!0");
1700+
test_value("Number.isFinite(1.5)", "!0");
1701+
test_value("Number.isFinite(NaN)", "!1");
1702+
test_value("Number.isFinite(Infinity)", "!1");
1703+
test_value("Number.isFinite(-Infinity)", "!1");
1704+
test_same_value("Number.isFinite('a')");
16721705
}
16731706

16741707
#[test]
1675-
#[ignore]
16761708
fn test_fold_number_functions_is_nan() {
1677-
test("Number.isNaN(1)", "false");
1678-
test("Number.isNaN(1.5)", "false");
1679-
test("Number.isNaN(NaN)", "true");
1680-
test_same("Number.isNaN('a')");
1709+
test_value("Number.isNaN(1)", "!1");
1710+
test_value("Number.isNaN(1.5)", "!1");
1711+
test_value("Number.isNaN(NaN)", "!0");
1712+
test_same_value("Number.isNaN('a')");
16811713
// unknown function may have side effects
1682-
test_same("Number.isNaN(+(void unknown()))");
1714+
test_same_value("Number.isNaN(+(void unknown()))");
16831715
}
16841716

16851717
#[test]

0 commit comments

Comments
 (0)