From 5516f7fcb973bb92e8314ed2df14f2ccab7cf2ca Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Thu, 9 Jan 2025 05:47:35 +0000 Subject: [PATCH] fix(minifier): do not fold object comparisons (#8375) --- .../src/constant_evaluation/mod.rs | 65 +++++++++---------- .../src/ast_passes/peephole_fold_constants.rs | 8 +++ 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/crates/oxc_ecmascript/src/constant_evaluation/mod.rs b/crates/oxc_ecmascript/src/constant_evaluation/mod.rs index c2525061a44c0..d363c5419537d 100644 --- a/crates/oxc_ecmascript/src/constant_evaluation/mod.rs +++ b/crates/oxc_ecmascript/src/constant_evaluation/mod.rs @@ -266,20 +266,18 @@ pub trait ConstantEvaluation<'a> { _ => unreachable!(), })) } - BinaryOperator::LessThan => { - self.is_less_than(left, right, true).map(|value| match value { - ConstantValue::Undefined => ConstantValue::Boolean(false), - _ => value, - }) - } + BinaryOperator::LessThan => self.is_less_than(left, right).map(|value| match value { + ConstantValue::Undefined => ConstantValue::Boolean(false), + _ => value, + }), BinaryOperator::GreaterThan => { - self.is_less_than(right, left, false).map(|value| match value { + self.is_less_than(right, left).map(|value| match value { ConstantValue::Undefined => ConstantValue::Boolean(false), _ => value, }) } BinaryOperator::LessEqualThan => { - self.is_less_than(right, left, false).map(|value| match value { + self.is_less_than(right, left).map(|value| match value { ConstantValue::Boolean(true) | ConstantValue::Undefined => { ConstantValue::Boolean(false) } @@ -288,7 +286,7 @@ pub trait ConstantEvaluation<'a> { }) } BinaryOperator::GreaterEqualThan => { - self.is_less_than(left, right, true).map(|value| match value { + self.is_less_than(left, right).map(|value| match value { ConstantValue::Boolean(true) | ConstantValue::Undefined => { ConstantValue::Boolean(false) } @@ -444,42 +442,37 @@ pub trait ConstantEvaluation<'a> { } /// - fn is_less_than( - &self, - left_expr: &Expression<'a>, - right_expr: &Expression<'a>, - _left_first: bool, - ) -> Option> { - let left = ValueType::from(left_expr); - let right = ValueType::from(right_expr); + fn is_less_than(&self, x: &Expression<'a>, y: &Expression<'a>) -> Option> { + // a. Let px be ? ToPrimitive(x, number). + // b. Let py be ? ToPrimitive(y, number). + let px = ValueType::from(x); - if left.is_string() && right.is_string() { - let left_string = self.get_side_free_string_value(left_expr); - let right_string = self.get_side_free_string_value(right_expr); - if let (Some(left_string), Some(right_string)) = (left_string, right_string) { - // In JS, browsers parse \v differently. So do not compare strings if one contains \v. - if left_string.contains('\u{000B}') || right_string.contains('\u{000B}') { - return None; - } - return Some(ConstantValue::Boolean( - left_string.cmp(&right_string) == Ordering::Less, - )); - } + // `.toString()` method is called and compared. + // TODO: bigint is handled very differently in the spec + if px.is_object() || px.is_undetermined() || px.is_bigint() { + return None; } - // TODO: bigint is handled very differently in the spec - // See - if left.is_bigint() || right.is_bigint() { + let py = ValueType::from(y); + + if py.is_object() || py.is_undetermined() || py.is_bigint() { return None; } - let left_num = self.get_side_free_number_value(left_expr)?; - let right_num = self.get_side_free_number_value(right_expr)?; + if px.is_string() && py.is_string() { + let left_string = self.get_side_free_string_value(x)?; + let right_string = self.get_side_free_string_value(y)?; + return Some(ConstantValue::Boolean(left_string.cmp(&right_string) == Ordering::Less)); + } - if left_num.is_nan() || right_num.is_nan() { + let left_num = self.get_side_free_number_value(x)?; + if left_num.is_nan() { + return Some(ConstantValue::Undefined); + } + let right_num = self.get_side_free_number_value(y)?; + if right_num.is_nan() { return Some(ConstantValue::Undefined); } - Some(ConstantValue::Boolean(left_num < right_num)) } } 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 2959cfad5f7f2..5a0b1501d3c5c 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs @@ -715,6 +715,14 @@ mod test { #[test] fn test_comparison() { test("(1, 2) !== 2", "false"); + test_same("({} <= {})"); + test_same("({} >= {})"); + test_same("({} > {})"); + test_same("({} < {})"); + test_same("([] <= [])"); + test_same("([] >= [])"); + test_same("([] > [])"); + test_same("([] < [])"); } #[test]