From 2a10a99444eb59fa44ce730baff5323ec3b418b7 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Mon, 10 Feb 2025 05:36:13 +0000 Subject: [PATCH] feat(ecmascript): support arrays and objects for unary expression may_have_side_effects (#8990) Detect `+[]` / `+{}` as side effect free. --- .../src/side_effects/may_have_side_effects.rs | 12 ++++++++++++ .../tests/ecmascript/may_have_side_effects.rs | 6 ++++++ 2 files changed, 18 insertions(+) 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 a26c1db78a198..82b6a89071576 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 @@ -82,6 +82,12 @@ pub trait MayHaveSideEffects { !(matches!(ident.name.as_str(), "Infinity" | "NaN" | "undefined") && self.is_global_reference(ident)) } + Expression::ArrayExpression(arr) => { + self.array_expression_may_have_side_effects(arr) + } + // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, + // ToPrimitive for an object returns `"[object Object]"` + Expression::ObjectExpression(obj) => !obj.properties.is_empty(), // ToNumber throws an error when the argument is Symbol / BigInt / an object that // returns Symbol or BigInt from ToPrimitive _ => true, @@ -98,6 +104,12 @@ pub trait MayHaveSideEffects { !(matches!(ident.name.as_str(), "Infinity" | "NaN" | "undefined") && self.is_global_reference(ident)) } + Expression::ArrayExpression(arr) => { + self.array_expression_may_have_side_effects(arr) + } + // unless `Symbol.toPrimitive`, `valueOf`, `toString` is overridden, + // ToPrimitive for an object returns `"[object Object]"` + Expression::ObjectExpression(obj) => !obj.properties.is_empty(), // ToNumber throws an error when the argument is Symbol an object that // returns Symbol from ToPrimitive _ => true, diff --git a/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs b/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs index 895cd346d75d7..2e22929a55c3c 100644 --- a/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs +++ b/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs @@ -364,9 +364,12 @@ fn test_unary_expressions() { test_with_global_variables("+Infinity", vec!["Infinity".to_string()], false); test_with_global_variables("+NaN", vec!["NaN".to_string()], false); test_with_global_variables("+undefined", vec!["undefined".to_string()], false); // NaN + test("+[]", false); // 0 + test("+[foo()]", true); test("+foo()", true); test("+foo", true); // foo can be Symbol or BigInt test("+Symbol()", true); + test("+{}", false); // NaN test("+{ valueOf() { return Symbol() } }", true); test("-0", false); @@ -377,9 +380,12 @@ fn test_unary_expressions() { test_with_global_variables("-Infinity", vec!["Infinity".to_string()], false); test_with_global_variables("-NaN", vec!["NaN".to_string()], false); test_with_global_variables("-undefined", vec!["undefined".to_string()], false); // NaN + test("-[]", false); // -0 + test("-[foo()]", true); test("-foo()", true); test("-foo", true); // foo can be Symbol test("-Symbol()", true); + test("-{}", false); // NaN test("-{ valueOf() { return Symbol() } }", true); test("~0", false);