Latest Results
fix(es/minifier): keep directive prologue when merging if returns (#12580)
The `if_return` pass merged the directive prologue of a function body
into a sequence expression. A directive such as `"use strict"` then
became a discarded `void` operand and stopped being a directive. The
function lost strict mode. For example, `this` in a strict function
became the global object, and `arguments` aliased its parameters.
This change keeps the leading string-literal statements of a function
body out of the `if_return` merge. The pass still merges the statements
after them. This applies to ordinary functions and to block-bodied arrow
functions.
Tests:
- Add the fixtures `issues/9238`, `issues/9238-arrow` and
`issues/9238-prologue`. They check `arguments` aliasing, `this` in a
strict function, a returned function in a strict arrow, multiple
directives, and safe merging of ordinary statements. Each fixture also
has a `expected.repeat-stdout` check for two minification rounds. All
new fixtures fail without the fix.
- Update the `next/swc-4559` snapshot. It now keeps `"use strict"`,
which the old output wrongly dropped.
- Update the antd gzipped size in `libs-size.snapshot.md` (+0.01 KiB)
for the same reason.
Local validation (on the final revision): `cargo fmt --all`, `cargo
clippy --all --all-targets -- -D warnings`, `cargo test -p
swc_ecma_minifier` and `crates/swc_ecma_minifier/scripts/exec.sh`
passed. CI was not run locally.
Closes #9238
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> fix(es/fixer): wrap function declarations in sloppy-mode loop bodies (#12567)
**Description:**
With the default options, a script with a function declaration alone in
a loop body is minified to code that does not parse:
```js
var n = 0;
while (n++ < 2) {
function g() {
return n;
}
}
console.log(typeof g, g());
```
`minifySync(code, { compress: {}, mangle: {} })` gives `for(var
n=0;n++<2;)function g(){return n}console.log(typeof g,g());`, a
SyntaxError, so the whole file fails to load; the original prints
`function 3`.
The minifier unwraps the block, and since #12416 the fixer's
`wrap_single_function` puts it back around a function declaration used
as a loop body or an `if` clause, but only in strict mode code. Skipping
it in sloppy mode is right only for a plain function declaration as an
`if` clause, which Annex B allows. A loop body can never be a function
declaration, and Annex B does not cover async functions or generators
either: `if (c) { async function g() {} }` becomes `if(c)async function
g(){}`, also a SyntaxError.
`wrap_single_function` now takes `is_if_clause` and skips the block only
for a plain function declaration as an `if` clause in sloppy mode. Loop
bodies (all five loops) are always wrapped, and so are async and
generator declarations in an `if`. `if (c) function f() {}` in a script
is still printed without braces. A `with` body has the same problem, but
the fixer has no handler for `with` statements, so it is not part of
this change.
The fixer runs after the minifier, so on valid input no minifier pass
sees the change. Performance: one more boolean argument per loop and
`if` statement.
**Tests:**
- `tests/fixture/issues/12565/` in `swc_ecma_minifier` (`defaults:
true`, script), with `expected.stdout`. The five loops, an async `if`
clause and a generator `else` fail without the change: node cannot parse
the output. The control, a plain function as an `if` clause, keeps its
unwrapped output.
- No existing fixture or snapshot changes. Minifying every `input.js`
under `swc_ecma_minifier/tests` and the test262-parser `pass` files with
the default options, as a script and as a module, the only outputs that
change are the new fixtures and `terser/compress/blocks/issue_1672_for`
as a script; none of them parsed before.
Checks: `cargo test -p swc_ecma_transforms_base` (7847 passed), `cargo
test -p swc_ecma_minifier` (8041 passed), `cargo test -p swc` (same
results as on `main`), `./scripts/exec.sh`, `cargo clippy --all-targets
-- -D warnings` on both crates and `cargo fmt --all -- --check`.
**Related issue (if exists):**
Closes #12565
---
Found with a differential fuzzer. Drafted with AI assistance; I
confirmed locally that the new fixtures (except the control) fail
without the fix and that all of them pass with it, and that @swc/core
1.16.18 gives the output above. Latest Branches
+6%
fix/ts-namespace-enum-bindings 0%
0%
© 2026 CodSpeed Technology