mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(minifier): keep the default in shorthand assignment targets (#28183)
`try_compress_assignment_target_property` rewrites `{ a: a }` to `{ a }`
in assignment patterns. It found the target with
`AssignmentTargetMaybeDefault::identifier_mut()`, which also matches `a:
a = b`, and then built the shorthand without an initializer, so the
default was dropped:
```js
({ x: x = f() } = o);
// before: ({ x } = o);
// after: ({ x = f() } = o);
```
When `o.x` is `undefined`, `x` stayed `undefined` and `f()` was not
called. The rewrite now moves the initializer into the shorthand. Both
forms name an anonymous function default after the identifier, so
`.name` does not change.
This causes 9 of the 21 `obj-prop-elem-init-*` minify failures in
`runtime.snap` (the `evaluation`, `yield-expr` and `let` cases under
`expressions/assignment/dstr/`, `statements/for-of/dstr/` and
`statements/for-await-of/`). Their minified output now keeps the
default. The other 12 are `fn-name-*` cases with a different cause, and
their output is unchanged. `runtime.snap` is not regenerated here.
Tests cover literal, call, `yield` and `await` defaults, a default that
reads the target, nested and array patterns, `for...in`, `for...of` and
`for await...of` heads, a rest sibling and a computed string key, plus
forms that must stay unchanged. `cargo minsize` and `cargo allocs` show
no change.
AI-assisted (Claude Code).
This commit is contained in:
1 parent
def47b8093
commit
520a26edd6
2 files changed
+37
-5
No files matched your search
@@ -96,7 +96,7 @@ impl<'a> PeepholeOptimizations {
|
||||
prop: &mut AssignmentTargetProperty<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
// `a: a` -> `a`
|
||||
// `a: a` -> `a`, `a: a = b` -> `a = b`
|
||||
if let AssignmentTargetProperty::AssignmentTargetPropertyProperty(assign_target_prop_prop) =
|
||||
prop
|
||||
{
|
||||
@@ -105,11 +105,16 @@ impl<'a> PeepholeOptimizations {
|
||||
return;
|
||||
};
|
||||
if prop_name == ident.name {
|
||||
let ident = ident.take_in(ctx);
|
||||
// `identifier_mut` also matches `a: a = b`, so keep its default.
|
||||
let init = match &mut assign_target_prop_prop.binding {
|
||||
AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(target) => {
|
||||
Some(target.init.take_in(ctx))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let new_prop = AssignmentTargetProperty::new_assignment_target_property_identifier(
|
||||
ident.span,
|
||||
ident.take_in(ctx),
|
||||
None,
|
||||
ctx,
|
||||
ident.span, ident, init, ctx,
|
||||
);
|
||||
ctx.replace_assignment_target_property(prop, new_prop);
|
||||
}
|
||||
|
||||
@@ -939,6 +939,33 @@ fn test_compress_destructuring_assignment_target() {
|
||||
test("var {y: y} = x", "var {y} = x");
|
||||
test("var {y: z, 'z': y} = x", "var {y: z, z: y} = x");
|
||||
test("var {y: y, 'z': z} = x", "var {y, z} = x");
|
||||
test("var {y: y = f()} = x", "var {y = f()} = x");
|
||||
|
||||
test("({ y: y } = x)", "({ y } = x)");
|
||||
test("({ 'y': y } = x)", "({ y } = x)");
|
||||
test("({ y: y = 1 } = x)", "({ y = 1 } = x)");
|
||||
test("({ y: y = f() } = x)", "({ y = f() } = x)");
|
||||
test("({ y: y = y } = x)", "({ y = y } = x)");
|
||||
test("({ y: y = function() {} } = x)", "({ y = function() {} } = x)");
|
||||
test("({ y: y = f(), z: z } = x)", "({ y = f(), z } = x)");
|
||||
test("({ a: { y: y = f() } } = x)", "({ a: { y = f() } } = x)");
|
||||
test("[{ y: y = f() }] = x", "[{ y = f() }] = x");
|
||||
test("for ({ y: y = f() } of x);", "for ({ y = f() } of x);");
|
||||
test("for ({ y: y = f() } in x);", "for ({ y = f() } in x);");
|
||||
test(
|
||||
"async function g() { for await ({ y: y = f() } of x); }",
|
||||
"async function g() { for await ({ y = f() } of x); }",
|
||||
);
|
||||
test("function* g() { ({ y: y = yield } = x) }", "function* g() { ({ y = yield } = x) }");
|
||||
test(
|
||||
"async function g() { ({ y: y = await f() } = x) }",
|
||||
"async function g() { ({ y = await f() } = x) }",
|
||||
);
|
||||
test("({ y: y = 1, ...z } = x)", "({ y = 1, ...z } = x)");
|
||||
test("({ ['y']: y = 1 } = x)", "({ y = 1 } = x)");
|
||||
test_same("({ [y]: y = 1 } = x)");
|
||||
test_same("({ y: z = f() } = x)");
|
||||
test_same("({ y: a.y = f() } = x)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user