diff --git a/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs b/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs index dc42bed961..3795a3ee69 100644 --- a/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs +++ b/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs @@ -117,10 +117,12 @@ impl MayHaveSideEffects for BinaryExpression<'_> { true } BinaryOperator::Addition => { - if self.left.to_primitive_returns_string() == Some(true) - || self.right.to_primitive_returns_string() == Some(true) + if self.left.to_primitive_returns_string(is_global_reference) == Some(true) + || self.right.to_primitive_returns_string(is_global_reference) == Some(true) { - let other_side = if self.left.to_primitive_returns_string() == Some(true) { + let other_side = if self.left.to_primitive_returns_string(is_global_reference) + == Some(true) + { &self.right } else { &self.left diff --git a/crates/oxc_ecmascript/src/to_primitive.rs b/crates/oxc_ecmascript/src/to_primitive.rs index 7b828f28b1..f825bb4c89 100644 --- a/crates/oxc_ecmascript/src/to_primitive.rs +++ b/crates/oxc_ecmascript/src/to_primitive.rs @@ -1,12 +1,18 @@ use oxc_ast::ast::*; -use crate::is_global_reference::IsGlobalReference; +use crate::{ + constant_evaluation::{DetermineValueType, ValueType}, + is_global_reference::IsGlobalReference, +}; /// `ToPrimitive` /// /// pub trait ToPrimitive<'a> { - fn to_primitive_returns_string(&self) -> Option; + fn to_primitive_returns_string( + &self, + is_global_reference: &impl IsGlobalReference, + ) -> Option; fn to_primitive_returns_symbol( &self, is_global_reference: &impl IsGlobalReference, @@ -18,22 +24,32 @@ pub trait ToPrimitive<'a> { } impl ToPrimitive<'_> for Expression<'_> { - fn to_primitive_returns_string(&self) -> Option { - match self { - Expression::StringLiteral(_) - | Expression::TemplateLiteral(_) - | Expression::RegExpLiteral(_) - | Expression::ArrayExpression(_) => Some(true), - // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, - // ToPrimitive for an object returns `"[object Object]"` - Expression::ObjectExpression(obj) => { - if maybe_object_with_to_primitive_related_properties_overridden(obj) { - None - } else { - Some(true) + fn to_primitive_returns_string( + &self, + is_global_reference: &impl IsGlobalReference, + ) -> Option { + match self.value_type(is_global_reference) { + ValueType::String => Some(true), + ValueType::Number + | ValueType::BigInt + | ValueType::Boolean + | ValueType::Null + | ValueType::Undefined => Some(false), + ValueType::Object | ValueType::Undetermined => { + match self { + Expression::RegExpLiteral(_) | Expression::ArrayExpression(_) => Some(true), + // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, + // ToPrimitive for an object returns `"[object Object]"` + Expression::ObjectExpression(obj) => { + if maybe_object_with_to_primitive_related_properties_overridden(obj) { + None + } else { + Some(true) + } + } + _ => None, } } - _ => None, } } @@ -41,34 +57,28 @@ impl ToPrimitive<'_> for Expression<'_> { &self, is_global_reference: &impl IsGlobalReference, ) -> Option { - match self { - Expression::Identifier(ident) => { - if matches!(ident.name.as_str(), "Infinity" | "NaN" | "undefined") - && is_global_reference.is_global_reference(ident) == Some(true) - { - Some(false) - } else { - None + match self.value_type(is_global_reference) { + ValueType::String + | ValueType::Number + | ValueType::BigInt + | ValueType::Boolean + | ValueType::Null + | ValueType::Undefined => Some(false), + ValueType::Object | ValueType::Undetermined => { + match self { + Expression::RegExpLiteral(_) | Expression::ArrayExpression(_) => Some(false), + // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, + // ToPrimitive for an object returns `"[object Object]"` + Expression::ObjectExpression(obj) => { + if maybe_object_with_to_primitive_related_properties_overridden(obj) { + None + } else { + Some(false) + } + } + _ => None, } } - Expression::StringLiteral(_) - | Expression::TemplateLiteral(_) - | Expression::NullLiteral(_) - | Expression::NumericLiteral(_) - | Expression::BigIntLiteral(_) - | Expression::BooleanLiteral(_) - | Expression::RegExpLiteral(_) - | Expression::ArrayExpression(_) => Some(false), - // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, - // ToPrimitive for an object returns `"[object Object]"` - Expression::ObjectExpression(obj) => { - if maybe_object_with_to_primitive_related_properties_overridden(obj) { - None - } else { - Some(false) - } - } - _ => None, } } @@ -76,33 +86,28 @@ impl ToPrimitive<'_> for Expression<'_> { &self, is_global_reference: &impl IsGlobalReference, ) -> Option { - match self { - Expression::Identifier(ident) => { - if matches!(ident.name.as_str(), "Infinity" | "NaN" | "undefined") - && is_global_reference.is_global_reference(ident) == Some(true) - { - Some(false) - } else { - None + match self.value_type(is_global_reference) { + ValueType::String + | ValueType::Number + | ValueType::Boolean + | ValueType::Null + | ValueType::Undefined => Some(false), + ValueType::BigInt => Some(true), + ValueType::Object | ValueType::Undetermined => { + match self { + Expression::RegExpLiteral(_) | Expression::ArrayExpression(_) => Some(false), + // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, + // ToPrimitive for an object returns `"[object Object]"` + Expression::ObjectExpression(obj) => { + if maybe_object_with_to_primitive_related_properties_overridden(obj) { + None + } else { + Some(false) + } + } + _ => None, } } - Expression::StringLiteral(_) - | Expression::TemplateLiteral(_) - | Expression::NullLiteral(_) - | Expression::NumericLiteral(_) - | Expression::BooleanLiteral(_) - | Expression::RegExpLiteral(_) - | Expression::ArrayExpression(_) => Some(false), - // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, - // ToPrimitive for an object returns `"[object Object]"` - Expression::ObjectExpression(obj) => { - if maybe_object_with_to_primitive_related_properties_overridden(obj) { - None - } else { - Some(false) - } - } - _ => None, } } }