oxc/tasks
sapphi-red 814da55f81
feat(minifier): compress x = x || 1 to x ||= 1 (#8368)
The simplified version of the evaluation of `a = a || b` is:

> AssignmentExpression : LeftHandSideExpression = LogicalORExpression || LogicalANDExpression
> 1. Let lRef be ? Evaluation of LeftHandSideExpression.
> 2. Let llRef be ? Evaluation of LogicalORExpression.
> 3. Let llVal be ? GetValue(llRef).
> 4. If ToBoolean(llVal) is true
>   a. Perform ? PutValue(lRef, llVal).
>   b. return llVal.
> 5. Let lrRef be ? Evaluation of LogicalANDExpression.
> 6. Let rRef be ? GetValue(lrRef).
> 7. Let rVal be ? GetValue(rRef). [Note GetValue(rRef) returns rRef itself]
> 8. Perform ? PutValue(lRef, rVal).
> 9. Return rVal.

The simplified version of the evaluation of `a ||= b` is:

> AssignmentExpression : LeftHandSideExpression ||= AssignmentExpression
> 1. Let lRef be ? Evaluation of LeftHandSideExpression.
> 2. Let lVal be ? GetValue(lRef).
> 3. If ToBoolean(lVal) is true, return lVal.
> 4. Let rRef be ? Evaluation of AssignmentExpression.
> 5. Let rVal be ? GetValue(rRef).
> 6. Perform ? PutValue(lRef, rVal).
> 7. Return rVal.

The difference of these is that

- the evaluation of `a` is done twice for `a = a || b`, one with `1. Let lRef be ? Evaluation of LeftHandSideExpression` and one with `2. Let llRef be ? Evaluation of LogicalORExpression.`. This is same with #8366, #8367.
- `PutValue(lRef, llVal)` is performed when `ToBoolean(lVal)` is `true`.

So `x = x || 1` can be compressed to `x ||= 1` when the conditions written in #8366 are met and `PutValue(lRef, llVal)` does not have a side effect. When `a` is a non-global identifier (and not a reference created by a `with` statement), these conditions are met.

**References**
- [Spec of `||`](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-binary-logical-operators-runtime-semantics-evaluation)
- [Spec of `=` / `||=`](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-binary-logical-operators-runtime-semantics-evaluation)
2025-01-09 03:47:12 +00:00
..
ast_tools refactor(ast)!: no unneccesary trailing underscores on AstBuilder method names (#8283) 2025-01-06 15:09:05 +00:00
benchmark refactor(linter): refactor LintBuilder to prep for nested configs (#8034) 2025-01-05 04:08:26 +00:00
common chore(doc): replace main/master to tag/commit to make the url always accessible (#7298) 2024-11-16 21:00:30 +08:00
compat_data refactor(global): sort imports (#7883) 2024-12-14 15:07:21 +00:00
coverage fix(transformer/private-methods): create brand binding var in hoist scope (#8361) 2025-01-09 03:17:38 +00:00
javascript_globals feat(linter)!: sync sindresorhus/globals; removed Object.prototype properties from builtin and es* globals (#6991) 2024-10-29 04:13:20 +00:00
lint_rules fix(tasks/lint_rules): sync unicorn rules with eslint rules (#8224) 2025-01-03 11:39:51 +08:00
minsize feat(minifier): compress x = x || 1 to x ||= 1 (#8368) 2025-01-09 03:47:12 +00:00
prettier_conformance refactor(prettier): Update tasks/prettier to correctly handle snapshots (#8337) 2025-01-08 17:10:30 +08:00
rulegen test(linter): use plugin name instead of category for finding rule (#8353) 2025-01-09 10:48:11 +08:00
transform_checker perf(semantic): allocate UnresolvedReferences in allocator (#8046) 2024-12-20 15:18:16 +00:00
transform_conformance fix(transformer/private-methods): no temp var for class when unused private methods (#8360) 2025-01-09 03:17:37 +00:00
website docs(tasks/website): add legend for fixable column (#7945) 2024-12-17 10:25:11 +08:00