refactor(ecmascript): use value_type in to_primitive (#9108)

so that it supports more cases automatically.
This commit is contained in:
sapphi-red committed 2025-02-14 10:54:31 +00:00
1 parent 8f79012517
commit d9513900ca
2 files changed
+77 -70

No files matched your search

@@ -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
+72 -67
View File
@@ -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`
///
/// <https://tc39.es/ecma262/multipage/abstract-operations.html#sec-toprimitive>
pub trait ToPrimitive<'a> {
fn to_primitive_returns_string(&self) -> Option<bool>;
fn to_primitive_returns_string(
&self,
is_global_reference: &impl IsGlobalReference,
) -> Option<bool>;
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<bool> {
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<bool> {
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<bool> {
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<bool> {
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,
}
}
}