diff --git a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs index 7c916ca7c8d8f2..b6d43d5dd8ff03 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs @@ -74,11 +74,18 @@ impl<'a> PeepholeFoldConstants { fn try_get_number_literal_value(&self, expr: &mut Expression<'a>) -> Option { match expr { Expression::NumericLiteral(n) => Some(n.value), + Expression::Identifier(id) if id.name.as_str() == "Infinity" => Some(f64::INFINITY), Expression::UnaryExpression(unary) if unary.operator == UnaryOperator::UnaryNegation => { - let Expression::NumericLiteral(arg) = &mut unary.argument else { return None }; - Some(-arg.value) + // let Expression::NumericLiteral(arg) = &mut unary.argument else { return None }; + match &mut unary.argument { + Expression::NumericLiteral(arg) => Some(-arg.value), + Expression::Identifier(id) if id.name.as_str() == "Infinity" => { + Some(f64::NEG_INFINITY) + } + _ => None, + } } _ => None, } @@ -517,7 +524,7 @@ impl<'a> PeepholeFoldConstants { let left = self.try_get_number_literal_value(&mut operation.left)?; let right = self.try_get_number_literal_value(&mut operation.right)?; if !left.is_finite() || !right.is_finite() { - return None; + return self.try_fold_infinity_arithmetic(left, operation.operator, right, ctx); } let result = match operation.operator { BinaryOperator::Addition => left + right, @@ -562,6 +569,52 @@ impl<'a> PeepholeFoldConstants { )) } + fn try_fold_infinity_arithmetic( + &self, + left: f64, + operator: BinaryOperator, + right: f64, + ctx: &mut TraverseCtx<'a>, + ) -> Option> { + if left.is_finite() && right.is_finite() || !operator.is_arithmetic() { + return None; + } + let result = match operator { + BinaryOperator::Addition => left + right, + BinaryOperator::Subtraction => left - right, + BinaryOperator::Multiplication => left * right, + BinaryOperator::Division => { + if right == 0.0 { + return None; + } + left / right + } + BinaryOperator::Remainder => { + if right == 0.0 { + return None; + } + left % right + } + BinaryOperator::Exponential => left.powf(right), + _ => unreachable!(), + }; + Some(match result { + f64::INFINITY => ctx.ast.expression_identifier_reference(SPAN, "Infinity"), + f64::NEG_INFINITY => ctx.ast.expression_unary( + SPAN, + UnaryOperator::UnaryNegation, + ctx.ast.expression_identifier_reference(SPAN, "Infinity"), + ), + _ if result.is_nan() => ctx.ast.expression_identifier_reference(SPAN, "NaN"), + _ => ctx.ast.expression_numeric_literal( + SPAN, + result, + result.to_string(), + if is_exact_int64(result) { NumberBase::Decimal } else { NumberBase::Float }, + ), + }) + } + fn try_fold_instanceof<'b>( &self, _span: Span, @@ -1699,12 +1752,16 @@ mod test { } #[test] - #[ignore] fn test_fold_arithmetic_infinity() { test("x=-Infinity-2", "x=-Infinity"); test("x=Infinity-2", "x=Infinity"); test("x=Infinity*5", "x=Infinity"); test("x = Infinity ** 2", "x = Infinity"); test("x = Infinity ** -2", "x = 0"); + + test("x = Infinity / Infinity", "x = NaN"); + test_same("x = Infinity % 0"); + test_same("x = Infinity / 0"); + test("x = Infinity % Infinity", "x = NaN"); } }