Fixes#16647
Use `symbol_is_mutated()` to check if the member expression base object may be reassigned, preventing incorrect transformations like `x.y || (x = {}, x.y = 3)` to `x.y ||= (x = {}, 3)`.
🤖 generated with help from Claude Opus 4.5
Improve folding of iife
## details
- check all `CallExpression` if they can be collapsed
eg. passed as arguments or in assignment
- functions without arguments and body can be collapsed to to `void 0`
`(() => {})()` or `(function () { })()` to `void 0`
- with one statement and without return will be collapsed to `(c, void
0)`
`(() => { fn() })()` to `(fn(), void 0)`
- `FunctionExpression` is not supported
`(function () { ... })()`
## notes
- function with arguments could be handled by first in-lining them
- empty function with arguments could be also if all arguments do not
have defaults
- we should consider optimizing function definitions by removing not
used arguments
- initially i added support for `FunctionExpression` but there is no way
to track `this` usage, and thus we are unable to minify this
## change example
code
```js
{
let AOT = true;
const getAOT = /* @__NO_SIDE_EFFECTS__ */ () => AOT;
const fn = getAOT() ? () => console.log("Hi") : () => {};
fn();
}
```
currently is collapsed to
```js
(/* @__PURE__ */ /* @__NO_SIDE_EFFECTS__ */ (() => !0)() ? () => console.log("Hi") : () => {})();
```
and with this change
```js
console.log('Hi');
```
------------------
from what i can see @sapphi-red worked on this file
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
fixes https://github.com/rolldown/rolldown/issues/7093
```js
function wrapper() { let foo; const bar = (() => { foo = {} })(); foo.bar = bar; return foo }
```
cannot be compressed to
```js
function wrapper() { let foo; return foo.bar = (() => { foo = {} })(), foo }
```
because `foo` is read on left hand side.
fixes#13912
As long as we know the variable is not re-assigned, the value is same even if we reordered the expression.
By using that fact, we can compress
```js
function wrapper() { var x = foo, y = bar; return [x, y] }
```
to
```js
function wrapper() { return [foo, bar] }
```
.
```js
var a = function(exports) {
exports.foo = 'foo'
}
a(exports)
```
The `exports` parameter was not mangled. But it is fine to mangle this.
We need to keep the global `exports` variable as-is, but that is handled by keeping the global variable references.
refs #5965
```js
x = ''.concat('a', ' ').concat('b').split(/[\\s\\n]+/)
```
was not compressed to
```js
x = 'a b'.split(/[\\s\\n]+/)
```
. This PR changes the code to allow that.
Inline single use variables in for statements:
```js
function wrapper1() { var x = foo; for (var i = x; i < 10; i++) console.log(i) }
function wrapper2() { var i, x = foo; for (i = x; i < 10; i++) console.log(i) }
// to
function wrapper1() { for (var i = foo; i < 10; i++) console.log(i) }
function wrapper2() { var i; for (i = foo; i < 10; i++) console.log(i) }
```
```js
function wrapper() { var x = {}; for (var a in x) console.log(a) }
// to
function wrapper() { for (var a in {}) console.log(a) }
```
```js
function wrapper() { var x = []; for (var a of x) console.log(a) }
// to
function wrapper() { for (var a of []) console.log(a) }
```
refs #13277
Ported the basic parts of esbuild's `substituteSingleUseSymbolInStmt`.
This would allow compressing
```js
let x = fn();
return x;
```
into
```js
return fn();
```
Avoid generating `var r = [...arguments]` if `r` is not used to reduce the number of iterations.
This would also remove `[...arguments].slice()`, which would not be removed currently because we don't treat `Array::slice` as sideeffect free.
Reverse-transpile rest argument code generated by TypeScript and babel.
Example input:
```js
for (var e = arguments.length, r = Array(e), a = 0; a < e; a++)
r[a] = arguments[a];
```
output:
```js
var r = [...arguments];
```
It's a quite specific transform though.
Compress `Object(expr)(args)` to `(0, expr)(args)`.
This can be done because
- the function call throws an error if the callee is not a function.
- `Object(expr)` would output a function if and only if `expr` is a function.
---
**References**
- [spec of `Object()`](https://tc39.es/ecma262/2025/multipage/fundamental-objects.html#sec-object-value)
Made function expression PIFEs to be kept. Similar to #12353 but for function expressions.
The minsize for victory is bigger because webpack's output contains many PIFEs (some shouldn't be written as PIFEs though).
refs #12353
In script mode:
```js
var x;
```
must be preserved.
fixes#12341
I took the opportunity to refactor these test cases, and also apply "remove unused assignment expression" to all expressions instead of lone assignment expression.
```js
function foo() {
var x = 1;
return x = 2;
}
```
fixes https://github.com/rolldown/rolldown/issues/4118fixes#10626
At present, there is no option to keep legal comments when minification is turn on.
This PR allows Codegen to set legal comments with minfication turned on, with the following behavior:
* Inline: only if the attached code is not removed
* Eof: move all legal comments to the end of file, regardless of where they appear
* Linked and External: saved into `CodegenReturn::legal_comments` for the caller to use, regardless of where they appear
Code gets moved around or removed if minifier is turned on, so some legal comments may disappear from the final output.
The recommended legal comment option is Eof.
---
For Rolldown to keep legal comments, it should set `LegalComment::Inline` for chunk codegen and `LegalComment::Eof` for minification codegen.