mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(minifier): do not fold object comparisons (#8375)
This commit is contained in:
parent
a1752a062c
commit
5516f7fcb9
2 changed files with 38 additions and 37 deletions
|
|
@ -266,20 +266,18 @@ pub trait ConstantEvaluation<'a> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
BinaryOperator::LessThan => {
|
BinaryOperator::LessThan => self.is_less_than(left, right).map(|value| match value {
|
||||||
self.is_less_than(left, right, true).map(|value| match value {
|
ConstantValue::Undefined => ConstantValue::Boolean(false),
|
||||||
ConstantValue::Undefined => ConstantValue::Boolean(false),
|
_ => value,
|
||||||
_ => value,
|
}),
|
||||||
})
|
|
||||||
}
|
|
||||||
BinaryOperator::GreaterThan => {
|
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),
|
ConstantValue::Undefined => ConstantValue::Boolean(false),
|
||||||
_ => value,
|
_ => value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
BinaryOperator::LessEqualThan => {
|
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(true) | ConstantValue::Undefined => {
|
||||||
ConstantValue::Boolean(false)
|
ConstantValue::Boolean(false)
|
||||||
}
|
}
|
||||||
|
|
@ -288,7 +286,7 @@ pub trait ConstantEvaluation<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
BinaryOperator::GreaterEqualThan => {
|
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(true) | ConstantValue::Undefined => {
|
||||||
ConstantValue::Boolean(false)
|
ConstantValue::Boolean(false)
|
||||||
}
|
}
|
||||||
|
|
@ -444,42 +442,37 @@ pub trait ConstantEvaluation<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://tc39.es/ecma262/#sec-abstract-relational-comparison>
|
/// <https://tc39.es/ecma262/#sec-abstract-relational-comparison>
|
||||||
fn is_less_than(
|
fn is_less_than(&self, x: &Expression<'a>, y: &Expression<'a>) -> Option<ConstantValue<'a>> {
|
||||||
&self,
|
// a. Let px be ? ToPrimitive(x, number).
|
||||||
left_expr: &Expression<'a>,
|
// b. Let py be ? ToPrimitive(y, number).
|
||||||
right_expr: &Expression<'a>,
|
let px = ValueType::from(x);
|
||||||
_left_first: bool,
|
|
||||||
) -> Option<ConstantValue<'a>> {
|
|
||||||
let left = ValueType::from(left_expr);
|
|
||||||
let right = ValueType::from(right_expr);
|
|
||||||
|
|
||||||
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
|
// TODO: bigint is handled very differently in the spec
|
||||||
// See <https://tc39.es/ecma262/#sec-islessthan>
|
if px.is_object() || px.is_undetermined() || px.is_bigint() {
|
||||||
if left.is_bigint() || right.is_bigint() {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let left_num = self.get_side_free_number_value(left_expr)?;
|
let py = ValueType::from(y);
|
||||||
let right_num = self.get_side_free_number_value(right_expr)?;
|
|
||||||
|
|
||||||
if left_num.is_nan() || right_num.is_nan() {
|
if py.is_object() || py.is_undetermined() || py.is_bigint() {
|
||||||
return Some(ConstantValue::Undefined);
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
Some(ConstantValue::Boolean(left_num < right_num))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -715,6 +715,14 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_comparison() {
|
fn test_comparison() {
|
||||||
test("(1, 2) !== 2", "false");
|
test("(1, 2) !== 2", "false");
|
||||||
|
test_same("({} <= {})");
|
||||||
|
test_same("({} >= {})");
|
||||||
|
test_same("({} > {})");
|
||||||
|
test_same("({} < {})");
|
||||||
|
test_same("([] <= [])");
|
||||||
|
test_same("([] >= [])");
|
||||||
|
test_same("([] > [])");
|
||||||
|
test_same("([] < [])");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue