`ParserReturn` contains a property `panicked`.
The name `panicked` is misleading. The parser did _not_ panic. When `true`, it means that the parser encountered a fatal error and is unable to parse the source, because it contains an unrecoverable syntax error.
Rename this property to `fatal_error`, to better describe what it means.
This is a breaking change, but one that's trivial to fix in downstream code - the property doesn't change its meaning or behavior, just its name.
All the changes in this PR in other crates are just reacting to this change and making everywhere use the term "fatal error" instead of "panicked", so the codebase is consistent.
> **PR stack (3 of 3)**
> 1. #24739
> 2. #24742
> 3. **#24712 (this PR)**
>
> Review #24739 and #24742 first. This PR is based on #24742, so GitHub shows only the RegExp behavior change.
Stacked on #24742, which exposes strict engine-target capabilities to side-effect analysis.
RegExp constructor calls used for engine feature detection were removed by DCE when their pattern was valid according to the current Oxc RegExp parser. A pattern can be valid at build time but still throw a `SyntaxError` on the configured runtime, so removing the call changes the result of surrounding `try`/`catch` checks.
RegExp purity now requires both syntactic validity and support from every configured target. Consumers without concrete targets remain conservative, while an explicit target allows the minifier to remove constructors known to be safe for those engines.
Target-independent flag validation and pattern compatibility checks now live in `oxc_regular_expression`; side-effect analysis only maps target support to unsupported flags and patterns. String patterns, modern flags, named groups, property escapes, lookbehind, modifiers, invalid flags, and lone-surrogate strings are covered. A RegExp literal with replacement flags is removable only when the target supports both those flags and the dedicated `ES2015RegExpConstructorCanAlterFlags` compatibility feature. Explicitly targeting `esnext` opts into current features.
## Example
Input:
```js
export function supportsUnicodeRegExp() {
try {
new RegExp("\\p{Ll}", "u");
return true;
} catch {
return false;
}
}
```
Before:
```js
export function supportsUnicodeRegExp() {
try {
return true;
} catch {
return false;
}
}
```
After:
```js
export function supportsUnicodeRegExp() {
try {
new RegExp("\\p{Ll}", "u");
return true;
} catch {
return false;
}
}
```
Verified with all `oxc_regular_expression`, `oxc_compat`, `oxc_ecmascript`, and `oxc_minifier` tests; the no-feature/`side_effects`/`constant_evaluation` `oxc_ecmascript` matrix; affected-crate clippy; formatting; and diff checks.
Fixesrolldown/rolldown#10279.
Implemented with AI assistance (OpenAI Codex and Claude). The contributor remains responsible for reviewing, understanding, and submitting these changes under the repository AI usage policy.
Pure refactor. Just shorten code.
Replace pattern of creating a `Vec` and pushing to it repeatedly with just passing an array to the AST builder method.
This is shorter and more performant - though perf doesn't matter, because it's just in a test.
Pure refactor. Just shorten code.
#24621 made AST builder methods take arrays as params.
Replace `ArenaVec::from_value_in(v, alloc)` with `[v]` where the `ArenaVec` is passed to an AST builder method.
```rs
let block = Statement::new_block_statement(
SPAN,
ArenaVec::from_value_in(return_stmt, ctx),
ctx,
);
```
\->
```rs
let block = Statement::new_block_statement(SPAN, [return_stmt], ctx);
```
Pure refactor. Just shorten code.
#24621 made AST builder methods take arrays as params.
Replace `ArenaVec::new_in(...)` arguments written inline at AST builder method call sites with the empty array literal `[]`.
```rs
let block = Statement::new_block_statement(SPAN, ArenaVec::new_in(ctx), ctx);
```
\->
```rs
let block = Statement::new_block_statement(SPAN, [], ctx);
```
Migrate the transform-pipeline `Visit` implementors to `VisitJs` (#24499): `oxc_transformer` (3), `oxc_minifier` (4), `oxc_react_compiler` (1), plus the parser regex example and the coverage driver. Part of #24317; linter half in #24530. Behavior is unchanged.
Together with #24530: `oxlint` −129.4 KiB (−0.94%) stripped, `oxc_transform` napi −16.2 KiB (−0.46%).
## Why each visitor can switch
A visitor is safe on `VisitJs` when its hooks cannot observe anything inside the pruned type grammar — either the hooked node kinds are value-space-only, or the AST it walks cannot contain type nodes at that pipeline stage.
| Visitor | File | Why equivalent |
|---|---|---|
| `PrivateInExpressionDetector` | `crates/oxc_transformer/src/decorator/legacy/mod.rs` | Hooks `visit_private_in_expression` (+`visit_decorators`); `#x in y` is runtime-only and cannot occur in type grammar, even inside decorator expressions carrying casts. |
| `BindingMover` | `crates/oxc_transformer/src/es2017/async_to_generator.rs` | Its formal-parameter overrides visit only pattern + initializer (`BindingPattern` carries no type field — annotations are sibling fields it never touches); runs in the exit phase after TS strip. |
| `UsedInJSXBindingsCollector` | `crates/oxc_transformer/src/jsx/refresh.rs` | Runs on un-stripped TSX, but its hooks (JSX-shaped calls, `visit_jsx_opening_element`, declarations/imports) cannot fire inside type grammar; its hand-written `visit_ts_type_annotation` skip-stub is deleted — `VisitJs` prunes that natively. |
| `Finder` | `crates/oxc_react_compiler/src/react_compiler/entrypoint/program.rs` | Matches functions by `scope_id`; real JS function scopes never live in pure type grammar, and `VisitJs` still walks the places one could hide (enum initializers, namespace bodies, cast inner expressions). |
| `KeepVar` | `crates/oxc_minifier/src/keep_var.rs` | Hooks `visit_statement`/`visit_variable_declaration`; statements and `var` declarations don't exist in type space, and namespace/enum bodies (which can contain them) are still walked by `VisitJs`. |
| `DirectEvalFlagCheck` | `crates/oxc_minifier/src/peephole/mod.rs` | Debug-only; hooks `visit_call_expression` only — call expressions cannot occur in valid type grammar. |
| `LiveDirectEvalCollector` | `crates/oxc_minifier/src/peephole/mod.rs` | Same single call-expression hook; type-space-immune regardless of input. |
| `TestVisitor` | `crates/oxc_minifier/tests/ecmascript/prop_name.rs` | Test helper parsing `SourceType::default()` (plain JS); single non-recursing `visit_object_expression` hook. |
| `RegularExpressionVisitor` | `crates/oxc_parser/examples/regular_expression.rs` | Finds `RegExpLiteral` / `new RegExp(...)`; neither node kind can occur in type grammar. |
| `CheckASTNodes` | `tasks/coverage/src/driver.rs` | Its only active override is `visit_reg_exp_literal` (regex print idempotency); `RegExpLiteral` cannot occur in type space. (The commented-out `visit_span` full-AST check would need `Visit` if ever revived.) |
Left on `Visit`: the minifier's incremental-scoping bookkeeping (`DropDiff`, `OverPruneCheck`, `LiveRefCollector`) — dropping `let x: Foo = …` must unmark the type-space `Foo` reference, which the `peephole::remove_unused_declaration` tests verify (they fail under `VisitJs`; confirmed and reverted during this work). `ChildScopeCollector` also stays: TS type nodes (mapped/conditional/function types) carry real `scope_id`s it must collect.
---
🤖 This PR was written with the assistance of Claude Code (Claude Fable 5).
## What
`is_pure_global_method_call` (and the bare-global path) in `CallExpression::may_have_side_effects` treated a call as side-effect-free whenever its arguments were, ignoring that several of these functions **throw** at runtime. Unused calls that throw were therefore dropped as dead code. terser and esbuild both keep them.
Guard the cases oxc can prove:
| Call | Throws | Before | After |
| --- | --- | --- | --- |
| `String.raw()`, `Symbol.keyFor()`, `Symbol.keyFor(42)` | `TypeError` (missing/invalid required arg) | dropped | kept |
| `URL.canParse()` | `TypeError` (required first arg) | dropped | kept |
| `String.fromCodePoint(-1 / 1.5 / 0x110000)` | `RangeError` (code point outside `[0, 0x10FFFF]`) | dropped | kept |
| `Math.abs(10n)`, `Date.UTC(10n)`, `String.fromCharCode(10n)`, `isNaN(10n)`, … | `TypeError` (`ToNumber(BigInt)`) | dropped | kept |
Safe optimizations are preserved — `URL.canParse("x")`, `String.fromCodePoint(65)`, `String.fromCharCode(65)`, `Math.abs(1)` still drop. `String.raw` / `Symbol.keyFor` are removed from the pure-method list (never provably safe); the rest get argument guards.
### A Symbol argument is left droppable, on purpose
A Symbol argument also throws (`ToString` / `ToNumber` on a Symbol), but oxc has no `ValueType::Symbol` and `to_primitive` never resolves a pure expression to `Symbol`, so a Symbol throw is **never provable**. Guarding it would mean keeping every `Math.abs(x)` / `parseInt(x)` on an undetermined argument — a large minification regression. esbuild makes the same trade-off (it drops `Math.abs(Symbol.iterator)` too), so only the provable cases are guarded.
oxc already guards exactly this for the `Number` / `Symbol` / `BigInt` / `Error` constructors; this brings the method-call path in line. The assumption (including the non-provable-Symbol carve-out) is documented in `crates/oxc_minifier/docs/ASSUMPTIONS.md`.
Covered by `test_throwing_global_calls` in `crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs`; cross-checked against terser and esbuild; `minsize` unchanged.
---
Stacked on #23916.
## What
`Object.isExtensible`, `Object.isFrozen`, and `Object.isSealed` were grouped with the throwing introspection methods (`Object.keys`, `getOwnPropertyDescriptor`, …) in `CallExpression::may_have_side_effects`, so a call with a missing / `null` / `undefined` argument was conservatively kept.
Unlike those methods, the three `is*` methods never `ToObject` their target — per [spec](https://tc39.es/ecma262/#sec-object.isextensible) a non-object receiver returns a primitive (`false` / `true`) instead of throwing, so the call is side-effect-free and an unused one can be dropped.
```js
// in
Object.isExtensible();
Object.isFrozen(x);
Object.isSealed();
Object.keys();
// out
Object.isFrozen(x), Object.keys();
```
`isExtensible()` / `isSealed()` drop (pure); `isFrozen(x)` stays — an undetermined target could be a `Proxy`, whose `[[IsExtensible]]` / `[[OwnPropertyKeys]]` traps are observable — and `keys()` stays (it throws on the `undefined` receiver).
Covered by new cases in `crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs`; `minsize` unchanged.
Closes#23779
Same as #23709.
Small perf optimizations around AST builder calls.
- AST nodes which end up in `Box`es, allocate into the `Box` as early as possible, to increase chance compiler sees the type can be built directly in arena, rather than built on the stack, and then copied from stack into arena.
- Functions return `Box<T>` rather than `T` where the value needs to be boxed anyway. If function is not inlined, this avoids stack allocation + copy.
Also, shorten code where possible by using more specific `AstBuilder` methods.
## Summary
Closes#17157.
`Object.keys`, `getOwnPropertyDescriptor(s)`, `getOwnPropertyNames`, `getOwnPropertySymbols`, `getPrototypeOf`, `hasOwn`, `isExtensible`, `isFrozen`, and `isSealed` introspect their target through internal methods a `Proxy` can trap (`[[OwnPropertyKeys]]`, `[[GetOwnProperty]]`, …), so they have observable side effects when the target is a Proxy. They were treated as unconditionally pure and dropped when unused — so `Object.getOwnPropertyDescriptor(proxy, "foo")` / `Object.keys(proxy)` were silently removed, skipping the trap.
They are now treated as side-effect-free only when the target is provably not a Proxy (a determined, non-null value type — i.e. a literal), unless the bundler opts out of property-read side effects. A `null`/`undefined`/missing target is also kept (it throws a `TypeError`).
- `Object.create(proto)` is pure only with an object/`null` prototype and no `properties` argument (read via `[[OwnPropertyKeys]]`/`[[Get]]`).
- `Object.values`/`entries` are no longer treated as pure at all — they invoke `[[Get]]` and run getters even on a plain object.
- `Object.is` stays unconditionally pure.
## Credit
Adapted from #21056 by @gthb. Their `proxy_sensitive_arg_index` approach is preserved; this version adds corrections for the getter-invoking methods (`values`/`entries`, and `create` with properties) and the throw-on-`null`/`undefined` cases that the original treated as droppable.
Verified by `cargo test -p oxc_minifier` / `-p oxc_ecmascript`; `minsize` unchanged.
cloese https://github.com/oxc-project/oxc/pull/21056
## Summary
Introduces `oxc_diagnostics::Diagnostics` — a `Vec<OxcDiagnostic>` newtype that knows the difference between errors and warnings — and makes it the standard diagnostics return value across oxc.
- **New type**: `Diagnostics` with `has_errors()`, `has_warnings()`, `errors()`, `warnings()`, plus `Vec`-like ergonomics (Deref, `IntoIterator`, `Extend`, `From`/`Into<Vec>`) so most call sites are unchanged.
- **Return types**: `ParserReturn`, `SemanticBuilderReturn`, `IsolatedDeclarationsReturn`, the React Compiler `TransformResult`/`LintResult`, and `TransformerReturn` now expose `diagnostics: Diagnostics` instead of `errors: Vec<OxcDiagnostic>` (the React Compiler's separate `errors`/`warnings` are merged into one severity-tagged list).
- **Behaviour**: a React Compiler **error** now stops the transform (no output), while **warnings** flow through and the transform continues. `compile()` aborts codegen only when `diagnostics.has_errors()` — warnings alone no longer abort (previously any diagnostic did).
## Breaking change
Consumers reading `*.errors` on these return values must read `*.diagnostics`. React Compiler consumers that read `.errors`/`.warnings` separately should use `diagnostics.has_errors()` / `diagnostics.errors()` / `diagnostics.warnings()`.
Parser/semantic/isolated-declarations fatality is otherwise unchanged. Builds on the React Compiler transform feature (#23201).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
`obj.prop++` performs an implicit `GetValue` + `ToNumeric` + `PutValue`. The `ToNumeric` coercion alone can invoke `valueOf`/`Symbol.toPrimitive` on the old value, and the read/write may trigger getters, setters, or Proxy traps.
Previously `UpdateExpression::may_have_side_effects` only checked `property_write_side_effects()` and treated the update as free when disabled — letting the minifier drop `counter.value++` even when `counter` is externally observable.
## Fix
Return `true` unconditionally for `UpdateExpression`. Terser, esbuild, Rollup, and SWC all hardcode `++`/`--` as unconditionally side-effectful — this matches their behavior, and mirrors how compound assignments like `a.b += 1` are already handled one impl above (`AssignmentExpression`).
## Impact
Under rolldown's tree-shake config (`propertyWriteSideEffects: false`), these are now correctly preserved instead of being dropped:
```js
counter.value++;
(class { static { ++counter.count; } });
class A { [counter.another++] = 123; }
```
## Reported
rolldown/rolldown#9094 ([comment](https://github.com/rolldown/rolldown/pull/9094#discussion_r3083594834))
fixes https://github.com/oxc-project/oxc/issues/21296 by treating `this` as potentially having side effects.
We can reduce the case that is bailed out by checking whether `this` is written inside `constructor` or not in the future.
Pure refactor.
Rename `Atom` to `Str`. The name "Atom" is a leftover from when we used to intern strings (years ago), and is misleading now.
Just call it `Str`. This follows the naming convention we have for arena-allocated versions of other types e.g. `Box`, `Vec`, `HashMap` - which we name the same as the native equivalents but with a lifetime (`Box<'a>` not `ArenaBox<'a>`, so `Str<'a>` not `ArenaStr<'a>`).
Rename all variables that contained "atom", and methods which relate to `Str`s to match the new type name.
Rename `as_atom` methods to `as_arena_str`. The longer name is required here to disambiguate from `as_str` methods which return a `&str`.
Some variables called "atom" still exist in `oxc_regular_expression` crate - that's a different meaning of "atom" - the meaning defined in regexp spec.
The diff of this PR is large but it's 100% renaming. No substantive or unrelated changes whatsoever.
## Summary
- Upgrade `javascript-globals` from 1.4.1 to 1.5.0
- Use direct exports (`GLOBALS_BUILTIN`, `GLOBALS_ES2026`) instead of indexing into `GLOBALS["builtin"]` / `GLOBALS["es2026"]`, avoiding repeated hashmap lookups
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Extract all global lookup tables (~430 lines) into a new `known_globals.rs` module, keeping `expressions.rs` focused on `MayHaveSideEffects` trait implementations
- Extract `is_pure_math_method` to deduplicate 36 Math method names shared between read-safety (`is_known_global_property`) and call-safety (`is_pure_global_method_call`) checks
- Extract inline call-safe match into a named `is_pure_global_method_call` function with clear doc comments
- Rename `is_pure_call` → `is_pure_callable_constructor`, removing 4 dead entries (`String`, `Number`, `BigInt`, `Symbol`) already handled by earlier special-case logic
- Redefine `is_unconditionally_pure_constructor` in terms of `is_pure_callable_constructor` to keep error-type lists in sync
- **Fix**: use `is_typed_array_constructor` for the TypedArray `.of()` arm, adding previously missing `BigInt64Array` and `BigUint64Array`
## Test plan
- [x] Added tests for `BigInt64Array.of()` and `BigUint64Array.of()`
- [x] All existing `side_effects` tests pass
- [x] `cargo clippy` clean
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
`new Map(x)`, `new Set(x)`, `new WeakMap(x)`, `new WeakSet(x)` were incorrectly considered side-effect-free when the argument is a variable reference. These constructors iterate their argument via `Symbol.iterator`, which can execute arbitrary user code (custom iterators, proxies, etc.).
**Before:** `is_pure_constructor` unconditionally included `Map`/`Set`/`WeakMap`/`WeakSet`, so `new Map(variable)` was treated as pure.
**After:** Collection constructors are only pure with provably safe arguments:
- No arguments: `new Set()`
- `null` or `undefined`: `new Set(null)`
- Array literals: `new Set([1, 2, 3])`, `new Map([[k, v]])`
- Variable references or other expressions: **NOT pure**
This matches the behavior of **esbuild** and **Rollup**:
- esbuild: only marks pure with no args, null, undefined, or array literals ([test cases](https://github.com/evanw/esbuild/blob/main/internal/js_parser/js_parser_test.go))
- Rollup: uses `PURE_WITH_ARRAY` — only array literals are trusted ([knownGlobals.ts](https://github.com/rollup/rollup/blob/master/src/ast/nodes/shared/knownGlobals.ts))
**Found via:** Rolldown's `tree-shake-iterable` test failing after delegating `NewExpression` side-effect analysis to Oxc.
## Test plan
- [x] Added tests for all cases: null, undefined, array literals, variable refs, Map with non-array entries
- [x] All existing `oxc_minifier` tests pass (473 passed)
- [x] Verified against Rolldown's `tree-shake-iterable` and `manual-pure-functions` test suites
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Object spread (`...{ get prop() {} }`) invokes getters at runtime, so
it has side effects
- The previous code only checked key/value AST nodes and missed the
getter invocation
- Setters are **not** invoked by spread, so they remain side-effect-free
- Fixes the Rolldown test `rollup@function@object-spread-side-effect`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## 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
Closesrolldown/rolldown#8582
## Summary
Part of https://github.com/oxc-project/oxc/issues/19673
Several side-effect detection improvements:
- **Computed member expressions**: When `property_read_side_effects` is `None`, non-literal keys (e.g. `obj[identRef]`) now check the key expression and object for their own side effects instead of always returning `true`
- **ObjectExpression spread**: When `property_read_side_effects` is `None`, `{...expr}` delegates to the argument's own side effects
- **Class MethodDefinition**: Now checks for parameter decorators (TypeScript `@foo` on params)
- **Class AccessorProperty**: Now checks accessor property values for side effects
- **TypedArray constructors**: Added `Int8Array`, `Uint8Array`, `Uint8ClampedArray`, `Int16Array`, `Uint16Array`, `Int32Array`, `Uint32Array`, `Float32Array`, `Float64Array`, `BigInt64Array`, `BigUint64Array` to pure constructors (`DataView` excluded as it requires an `ArrayBuffer` argument)
## Test plan
- [x] Added tests for computed member non-literal keys with `property_read_side_effects`
- [x] Added tests for ObjectExpression spread with `property_read_side_effects`
- [x] Added tests for class method parameter decorators
- [x] Added tests for class accessor property values
- [x] Added tests for TypedArray constructors
- [x] All existing tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
close: #13067
Part of https://github.com/oxc-project/oxc/issues/19673
Depends on #20217.
Port known-globals lists from Rolldown to Oxc's side-effect detection:
- **Global identifiers** (Math, Array, console, DOM classes, etc.) are now considered side-effect-free to access via `is_known_global_identifier`, matching Rolldown's `GLOBAL_IDENT` set
- **Property reads** like `Math.PI`, `console.log`, `Object.keys` are considered side-effect-free via `is_known_global_property`
- **3-level chains** like `Object.prototype.hasOwnProperty` are supported via `is_known_global_property_deep`
## Test plan
- [x] Added tests for known global identifiers (Math, Array, Object, console, etc.)
- [x] Added tests for known global property reads (Math.PI, Object.keys, etc.)
- [x] Added tests for 3-level chains (Object.prototype.hasOwnProperty, etc.)
- [x] Existing minifier test expectations updated for improved side-effect detection
- [x] All existing tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Part of https://github.com/oxc-project/oxc/issues/19673
## Summary
- Add `property_write_side_effects()` to `MayHaveSideEffectsContext` trait with default `true` (conservative)
- Implement `MayHaveSideEffects` for `AssignmentExpression` and `UpdateExpression` (previously fell through to `_ => true`)
- When `property_write_side_effects` is `false`, member expression writes are side-effect-free
- Compound assignments (`+=`) and updates (`++`) still respect `property_read_side_effects` for their implicit reads
- Reference: https://rolldown.rs/reference/InputOptions.treeshake#propertywritesideeffects
## Test plan
- [x] Added `test_property_write_side_effects_support` covering all combinations of write/read side-effect settings
- [x] Existing tests pass unchanged
## Summary
- remove the `MetaProperty.url` side-effect-free special-case from property read analysis
- treat `import.meta.url` reads as side-effectful in side-effect tests
- add regression coverage for both `import.meta.url` and `new.target.url` getter side effects
Closes#19466Closes#19467
## Testing
- `just fmt`
- `cargo test -p oxc_minifier test_property_access`
- `cargo test -p oxc_minifier test_esm_minification_edge_cases`
- `cargo test -p oxc_minifier test_meta_property_url_getter_side_effects`
## AI Disclosure
This PR was prepared with AI assistance (OpenAI Codex) and reviewed by the contributor.
## Summary
- align side-effect detection for conversion-heavy global calls with spec behavior
- add explicit handling for `PrivateInExpression` throw behavior on non-object RHS
- treat `import.meta.url` property reads as side-effect free
- expand minifier may-have-side-effects tests for String/Number/Boolean/BigInt/Symbol coercion cases
## Testing
- cargo test -p oxc_minifier may_have_side_effects -- --nocapture
- cargo test -p oxc_ecmascript
## AI Usage
- Drafted with AI assistance (Codex) and reviewed/tested by the author.
## Fix minifier incorrectly handling `+[false]` and `+[true]`
- [x] Explore repository structure and locate the bug
- [x] Identify the root cause in `to_number` implementation for arrays
- [x] Add test case for the bug in minifier fold_constants tests
- [x] Add test case in to_number unit tests
- [x] Fix the bug in `to_number.rs` to properly convert arrays to strings first
- [x] Run tests to verify the fix - all tests passing
- [x] Manual verification with minifier example - outputs NaN correctly
- [x] Run code review - no issues found
- [x] Run security check - no vulnerabilities found
- [x] Comprehensive testing of all array conversion cases - all correct
- [x] Apply cargo fmt to fix formatting
- [x] Address PR feedback: hoist use statements, simplify comments and code
- [x] Address bot feedback: optimize count, remove redundant import, add test coverage
**Summary:**
Fixed a bug where `+[false]` and `+[true]` were incorrectly minified to `0` and `1` instead of `NaN`. The issue was in the `to_number` implementation for arrays in `oxc_ecmascript`, which was bypassing the proper ECMAScript conversion chain (array → string → number). Now correctly converts arrays to strings first via `to_js_string`, then converts the string to a number.
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>minifier: `+[false]` and `+[true]` are incorrectly minified</issue_title>
> <issue_description><!--
> ⚠️ IMPORTANT ⚠️
> Please use the appropriate template for each!
>
> - If you are reporting a bug for Oxlint or the Oxc VS Code extension:
> - https://github.com/oxc-project/oxc/issues/new?template=linter_bug_report.yaml
> - If you are reporting a bug for Oxfmt, especially difference with Prettier:
> - https://github.com/oxc-project/oxc/issues/new?template=formatter_diff_report.yaml
>
> Other than that, feel free to enter whatever information you like.
>
> Please include as much detail as possible, such as version information.
> Also, if you have steps to reproduce the issue, that would be very helpful.
> -->
> I was messing around with [jsfuck](https://jsfuck.com/) and found out that oxc_minifier doesn't minify `+[false]` or `+[true]` correctly. It is supposed to evalutate to `NaN`, but Oxc just grabs the boolean and uses that. This makes the 'minified' jsfuck code invalid (not that I'm using jsfuck on a day to day basis)
>
> Original:
> ```ts
> const a = +[false]
> const b = +[true]
> ```
>
> Oxc minified:
> ```ts
> const a = 0
> const b = 1;
> ```
>
> Expected:
> ```ts
> const a = NaN
> const b = NaN;
> ```
>
> [Playground](https://playground.oxc.rs/?code=const+a+%3D+%2B%5Bfalse%5D%0Aconst+b+%3D+%2B%5Btrue%5D) (enable minify syntax)
>
> </issue_description>
>
> <agent_instructions>probably there a bug in the constant evaluator in oxc_ecmascript that handles `UnaryExpression`</agent_instructions>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
<!-- START COPILOT CODING AGENT SUFFIX -->
- Fixesoxc-project/oxc#19084
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
In #10129, I introduced `PropertyReadSideEffects`. In that, I added `PropertyReadSideEffects::OnlyMemberPropertyAccess`. This was because I thought this was the default behavior of Rollup at that time.
But after re-reading the Rollup's code and checking the behavior in REPL while reviewing https://github.com/rolldown/rolldown/pull/5945, I noticed that I was wrong. Since this was added solely for Rolldown to add support for `treeshake.propertyReadSideEffects` and it's not useful for that usecase, I removed the value.
cc @IWANABETHATGUY
Do not remove empty function calls if the function is async or generator or args can cause type error.
From test262:
```js
function fn({}) {}
assert.throws(TypeError, function() {
fn(null);
});
```
Add `value` field to `BigIntLiteral`, same as the other literal types.
Once upon a time, we stored the value as a `BigInt` which normalized the representation (removing `_`s, and converting e.g. `0xFF` to `255`). But we had to remove it because `BigInt` owns a heap allocation, and this caused a memory leak.
https://github.com/oxc-project/oxc/commit/50fe0fef73027f10740e68a65a78216933b5d8a0
This PR brings back the `value` field, but avoids memory leak by storing the normalized value as a string (`Atom`).
This has effects in various places in the codebase:
* Brings our JS-side AST into line with ESTree (fixing the test cases broken by #11563).
* Fixes edge cases in a couple of lint rules.
* Codegen now prints bigints in normalized form e.g. `0xFFn` is printed as `255n`.
* Changes behavior of 1 function in `oxc_ecmascript`.
I've made comments below on the parts I'm not so sure about. Review would be very welcome!