mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(minifier): recognize object spread of object literals as side-effect-free (#20299)
## Summary - Add `ObjectExpression` handling in `ObjectPropertyKind::SpreadProperty`'s `may_have_side_effects` — spreading an object literal is side-effect-free when all its properties are - Fix `remove_unused_object_expr` to check side effects for all-spread objects instead of unconditionally bailing Closes rolldown/rolldown#8582
This commit is contained in:
4 files changed
+23
-4
No files matched your search
@@ -650,6 +650,10 @@ impl<'a> MayHaveSideEffects<'a> for ObjectPropertyKind<'a> {
|
||||
} else {
|
||||
match &e.argument {
|
||||
Expression::ArrayExpression(arr) => arr.may_have_side_effects(ctx),
|
||||
Expression::ObjectExpression(obj) => obj
|
||||
.properties
|
||||
.iter()
|
||||
.any(|property| property.may_have_side_effects(ctx)),
|
||||
Expression::StringLiteral(_) => false,
|
||||
Expression::TemplateLiteral(t) => t.may_have_side_effects(ctx),
|
||||
_ => true,
|
||||
|
||||
@@ -336,7 +336,12 @@ impl<'a> PeepholeOptimizations {
|
||||
return true;
|
||||
}
|
||||
if object_expr.properties.iter().all(ObjectPropertyKind::is_spread) {
|
||||
return false;
|
||||
// All-spread objects like `({...x})` can only be removed if
|
||||
// the spread arguments themselves have no side effects.
|
||||
return !object_expr
|
||||
.properties
|
||||
.iter()
|
||||
.any(|property| property.may_have_side_effects(ctx));
|
||||
}
|
||||
|
||||
let mut transformed_elements = ctx.ast.vec();
|
||||
|
||||
@@ -310,10 +310,11 @@ fn closure_compiler_tests() {
|
||||
test("new Object(...true)", true);
|
||||
|
||||
// OBJECT_SPREAD
|
||||
// These could all invoke getters.
|
||||
// Spreading unknown identifiers could invoke getters.
|
||||
test("({...x})", true);
|
||||
test("({...{}})", true);
|
||||
test("({...{a:1}})", true);
|
||||
// Spreading object literals is side-effect-free if the properties are.
|
||||
test("({...{}})", false);
|
||||
test("({...{a:1}})", false);
|
||||
test("({...{a:i++}})", true);
|
||||
test("({...{a:f()}})", true);
|
||||
test("({...f()})", true);
|
||||
@@ -711,6 +712,11 @@ fn test_object_expression() {
|
||||
test("({...`foo${foo}`})", true);
|
||||
test("({...`foo${foo()}`})", true);
|
||||
test("({...foo()})", true);
|
||||
// Spreading object literals
|
||||
test("({...{}})", false);
|
||||
test("({...{a: 1}})", false);
|
||||
test("({...{a: foo()}})", true);
|
||||
test("({...{[foo()]: 1}})", true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -176,6 +176,10 @@ fn test_object_literal() {
|
||||
// Object-spread may trigger getters.
|
||||
test_same("({...a})");
|
||||
test_same("({...foo()})");
|
||||
// Spreading object literals is safe if contents are safe.
|
||||
test("({...{}})", "");
|
||||
test("({...{a: 1}})", "");
|
||||
test("({...{a: foo()}})", "foo()");
|
||||
test("({ [{ foo: foo() }]: 0 })", "foo()");
|
||||
test("({ foo: { foo: foo() } })", "foo()");
|
||||
|
||||
|
||||
Reference in new issue
Block a user