Commit Graph

43 Commits

Author SHA1 Message Date
Boshen 1645d93cfb fix(react_compiler): preserve source spans (#25462)
React Compiler rebuilt source-derived AST nodes with empty spans, so compiled function bodies had no useful source mappings. Preserve retained HIR and reactive spans during codegen while keeping synthetic memoization scaffolding unmapped.

AI-assisted: implementation used Codex; the author remains responsible for review.
2026-08-11 02:10:30 +00:00
Boshen 4a6542bfda chore(react_compiler): configure package publishing (#25389)
Prevents the internal `oxc_react_compiler` and
`oxc_transform_react_napi` Rust crates from being published while
including the `oxc-transform-react` npm package in workspace releases.

Validated with `taplo lint`, Cargo metadata, and `just ready`.

AI assistance was used for this change.
2026-08-08 08:05:28 +00:00
oxc-guard 45a17c25d1 release(crates): oxc v0.143.0 (#25250)
### 💥 BREAKING CHANGES

- 4120da0 semantic: [**BREAKING**] Return borrowed JSDoc so the parse cache works (#25186) (Connor Shea)
- f0a41c8 allocator: [**BREAKING**] Remove `ArenaBox::dangling` method (#25236) (overlookmotel)
- 067da8c ast: [**BREAKING**] Store single parameter in `TSIndexSignature::parameter` (#25154) (camc314)
- a0c7788 ast: [**BREAKING**] Change `TSIndexSignatureName::name` to `Ident` (#25150) (camc314)
- 1bdedd1 ast: [**BREAKING**] Introduce `ExportDeclaration`, `ExportFromDeclaration` (#25095) (camc314)
- c917f20 ast: [**BREAKING**] Introduce `ArrowFunctionBody` enum (#24987) (camc314)
- 7e1199c ast: [**BREAKING**] Remove conversion to `Box` from AST builder methods (#25038) (overlookmotel)

### 🚀 Features

- 3c8312e allocator: Make `Box` `Send` + `Sync` when the type it contains is (#25242) (overlookmotel)
- cb5bc08 ast: Derive `GetSpan` for `Comment` (#25147) (leaysgur)
- 8541e18 ast_tools: Generate minifier scope collector (#25088) (camc314)
- 5acdae2 ecmascript: Skip transparent TS expressions (#25072) (camc314)
- 85d0f4d napi: Add React Compiler transform binding (#24934) (Boshen)
- 70d6ece minifier: Fold safe integer exponentiation (#25009) (Dunqing)
- 73fc747 minifier: Enable termination statement optimization for do while (#24921) (Armano)
- 5eadfdb minifier: Fold safe integer division and remainder (#24981) (Dunqing)

### 🐛 Bug Fixes

- 6c9ee14 minifier: Preserve if-chain idempotency and correct side effects when alternate should not be moved (#25041) (Armano)
- 8a47ff3 ecmascript: Do not treat lone-surrogate strings as constants (#25084) (Dunqing)
- 468b970 isolated-declarations: Strip re-export attributes (#25090) (camc314)
- a70035d parser: Report export imports in namespaces (#25086) (camc314)
- 5d8ccf5 react_compiler: Preserve nonfatal diagnostics (#25066) (Boshen)
- d349e4a react_compiler: Match eslint suppression gating (#25068) (Boshen)
- 0dc16ba react_compiler: Track catch block declarations (#25067) (Boshen)
- e6734a5 minifier: Fold typeof comparisons with known object strings (#25017) (Dunqing)
- 3a9d5a5 minifier: Keep `typeof foo == ['object']` as-is (#24941) (sapphi-red)
- 10ec276 ast: Custom AST builder methods take `IntoIn<ArenaBox>` where child method does (#25033) (overlookmotel)
- fbe8d31 minifier: Respect targets when folding RegExp source (#24790) (Dunqing)

### ⚡ Performance

- fb402b0 minifier: Stop re-deriving printed numeric spellings (#25103) (Dunqing)
- 7251e52 react_compiler: Avoid large types on stack (#25037) (overlookmotel)
- e07718f isolated_declarations: Avoid large types on stack (#25036) (overlookmotel)
- 9fb1e3e transformer: Avoid large types on stack (#25035) (overlookmotel)
- 8b80f8b parser: Avoid large types on stack (#25034) (overlookmotel)

### 📚 Documentation

- 2ea0aa9 ast: Correct grammar in AST builder methods doc comments (#25173) (overlookmotel)
2026-08-03 11:07:37 +00:00
oxc-guard[bot] fc702c1fa9 release(crates): oxc v0.142.0 (#24977)
### 💥 BREAKING CHANGES

- 1ac5ac7 ast: [**BREAKING**] Tighten bound on `AstBuild` trait (#24925)
(overlookmotel)

### 🚀 Features

- c7c5696 minifier: Fold parenthesized boolean ternary tests (#24968)
(Dunqing)
- 82c5806 minifier: Fold sequence branches in boolean ternaries (#24943)
(Dunqing)
- cc623d9 ast_visit: Add VisitJsMut visitor (#24828) (Boshen)
- b31713a minifier: Add new IsTerminated trait and use it in exit-point
optimization (#24950) (Armano)
- e9e0f24 minifier: Shorten integer zero comparisons (#24933) (Dunqing)
- 34f5559 minifier: Convert switch with one case to if statement
(#24611) (Armano)
- 9107e74 str: Add `static_str!` macro (#24887) (overlookmotel)
- 4d6f623 parser: Emit error for type args in JS files (#24896)
(camc314)
- ec08afc ast: Re-export `Ident` from `oxc_ast` crate (#24861)
(overlookmotel)
- 73cfdfa oxc: Re-export `oxc_str` types from `oxc` crate (#24860)
(overlookmotel)
- 11f5d1f ast_visit: Add `Utf8ToUtf16::convert_program_and_comments`
(#24859) (overlookmotel)

### 🐛 Bug Fixes

- cb5acfb minifier: Optimize termination statements in labeled
statements (#24813) (Armano)
- 4618300 minifier: Avoid longer numeric constant folds (#24875)
(Dunqing)
- f7971f1 minifier: Keep side effects in typeof comparisons (#24940)
(sapphi-red)
- 4597d6f minifier: Keep side effects when compressing `== true` to `==
1` (#24939) (sapphi-red)
- c3a48df minifier: Keep side effects values in template literals
(#24938) (sapphi-red)
- e19f183 minifier: Keep side effects when folding `Number` call
(#24937) (sapphi-red)
- 9d7745a react-compiler: Preserve warning bailouts (#24935) (Boshen)
- 0126aba codegen: Preserve orphaned file coverage comments (#24815)
(Dunqing)
- 9fbbaf8 parser: Clarify return in class static blocks (#24899)
(camc314)
- e7d5c78 str: Fix hygiene of `format_ident!` and `format_str!` macros
(#24886) (overlookmotel)
- 07e9acc ecmascript: Keep side effects in parent of `toString` calls
(#24846) (sapphi-red)
- 16a40ad ecmascript: Detect side effects in unused arguments to
`charCodeAt` (#24845) (sapphi-red)
- 5b4ae54 parser: Use specific for-await diagnostic (#24856) (camc314)
- ffcc33a parser: Report for-await in non-async functions (#24855)
(camc314)
- df230d0 minifier: Avoid reordering this in nested class keys (#24785)
(Dunqing)
- d24b76b minifier: Isolate derived constructor this state (#24784)
(Dunqing)
- 582805d parser: Parse unary conditional after satisfies (#24807)
(Boshen)
- 23b904f minifier: Preserve default parameter side effects (#24791)
(Dunqing)
- 3048594 parser: Use correct diagnostic for `await using` in bare
switch case (#24798) (camc314)
- e80574f estree: Handle empty spans serializing `ImportMeta` and
`NewTarget` (#24775) (overlookmotel)
- 4b12840 minifier: Do not fold a `-0` ternary branch to `+a` (loses the
sign) (#23637) (Jerry Zhao)
- 133bb35 ecmascript: Detect side effects of `foo().#bar` correctly when
PropertyReadSideEffects::None (#24769) (sapphi-red)

### ⚡ Performance

- a086d91 ecmascript: Avoid number literal allocations (#24889)
(Dunqing)
- 98f2ecb react_compiler: Compare value set pointers before probing in
state merge (#24805) (Marius Schulz)
- b287f29 estree: Avoid ident hash calculations when serializing
(#24774) (overlookmotel)

### 📚 Documentation

- 4d2e2bf ast: Fix incorrect return value in `common_js_require` docs
(#24945) (connorshea)
- b539e74 estree: Document custom serializers for `ImportMeta` and
`NewTarget` (#24777) (overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
2026-07-27 23:07:40 +08:00
Jacob Asper 33a97da760 chore(oxc_react_compiler): exclude testonly files from published crate (#24932)
Adds explicit includes for `oxc_react_compiler` to omit 2.2MB of files
(49% of total) under `/tests` and `/fixtures` from the published
package. I included the examples directory, but that can also be
excluded if desired

[The full list of removed files are included in this text
file](https://github.com/user-attachments/files/30380492/oxc_react_removed.txt).
Today I learned there is a size limit in GitHub PR descriptions

For the record, I checked all other published crates in the workspace,
and none of them included any extraneous files 😃
2026-07-26 10:13:54 +08:00
Boshen baf022d74d refactor(ast)!: remove old AstBuilder methods (#24563)
Closes the migration tracked in #23043.

The new builder API (methods on the AST types themselves) has been in place for a while, all Oxc crates are migrated, and every crate which uses `AstBuilder` already enables `disable_old_builder` in its tests. The module docs said "after a few weeks, we will remove `AstBuilder`'s own methods entirely" — this does that.

## What's removed

- `crates/oxc_ast/src/generated/ast_builder.rs` and `builder/methods.rs` — `AstBuilder`'s own node and primitive constructors.
- `AstBuilderGenerator`, which produced the former.
- The `disable_old_builder` Cargo feature, plus the dev-dependency hacks it required across 33 manifests. Eight crates depended on `oxc_ast` *purely* to turn the feature on; those deps and their `cargo-shear` ignore entries are gone too.

## One thing worth reviewing

`AstBuilderGenerator` owned the `#[builder(default)]` / `#[builder(skip)]` attr registration that `BuilderMethodsGenerator` only *reads* — its doc comment said as much. Deleting it naively would have silently dropped `skip`/`default` handling for the 12 AST types using those attrs, so `attrs()` and `parse_attr()` move to `BuilderMethodsGenerator`.

The evidence this was faithful: after regenerating, `builder_methods.rs` and every other generated file are **byte-identical**. The only generated change in the diff is the deletion.

## Breaking changes

- `AstBuilder`'s own methods are gone. Use the AST type methods: `Statement::new_expression_statement(span, expr, &builder)` instead of `builder.statement_expression(span, expr)`.
- `AstBuilder` is no longer `Copy`/`Clone`, and its `allocator` field is private — use the `allocator` method from `GetAllocator`.
- `AstBuilder` and `NONE` are no longer re-exported from the crate root; import them from `oxc_ast::builder`. (The `disable_old_builder` feature already gated these off, so nothing in-tree used the root path.)
- The `disable_old_builder` feature no longer exists — remove it from any manifest that sets it.

A migration note covering all of the above is in `crates/oxc_ast/src/builder/mod.rs`.

---

Implemented with AI assistance (Claude Code); design, review, and verification driven by the author per the repo AI-usage policy.
2026-07-21 15:22:46 +00:00
oxc-guard[bot] 14533a3dc1 release(crates): oxc v0.141.0 (#24714)
### 💥 BREAKING CHANGES

- 54cc121 ast: [**BREAKING**] Split `MetaProperty` into `ImportMeta` and
`NewTarget` (#24557) (camc314)

### 🚀 Features

- 4c71560 parser: More friendly error for spread element in dynamic
imports (#24705) (sapphi-red)
- 7b045cd minfier: Drop last break from last switch case (#24673)
(Armano)
- 7d3c178 minifier: Remove unreachable recursive functions (#24125)
(Dunqing)
- 94f99b3 ast: Allow `NONE` to be passed to AST builder methods where
`Option<ArenaVec>` is expected (#24629) (overlookmotel)
- 77230c5 ast: Accept arrays for `ArenaVec` params of AST builder
methods (#24621) (overlookmotel)
- f08b152 allocator: Implement `FromIn` for array to `Vec` conversion
(#24620) (overlookmotel)
- 2338c13 track-memory-allocations: Track heap deallocs, alloc bytes,
and peak growth (#24619) (Boshen)
- 7aa4739 syntax,transformer: Move JSX entity decoder to `oxc_syntax`
(#24617) (camc314)
- 2b097c4 str: Export `Str` as `ArenaStr` (#24604) (overlookmotel)
- 3acf4c1 minifier: Expand switch optimiation to remove empty cases
(#24520) (Armano)
- 129b759 parser: Improve diagnostics for unparenthesized LHS on
exponential expr (#24569) (camc314)
- 4d0c601 minifier: Fold arithmetic over undefined and null operands
(#24485) (Dunqing)
- 91541dd minifier: Drop empty switch statements  (#24527) (Armano)
- d05224d ast_visit: Generate VisitJs visitor that skips TypeScript
type-space (#24499) (Boshen)
- 3d22307 parser: Add `ParseOptions::enable_ident_hashes` (#24491)
(Boshen)

### 🐛 Bug Fixes

- 64c2241 minifier: Align class heritage removal with assumptions
(#24533) (Dunqing)
- 48b59f4 parser: Span ambient generator diagnostics (#24711) (camc314)
- e750a82 ecmascript: Fix false negative for may_have_side_effects on
dynamic property access (#24709) (sapphi-red)
- f145d73 minifier: Guard reordered identifier reads (#24698) (Dunqing)
- a2ef382 isolated-declarations: Reject `window.Symbol` as global symbol
reference (#24689) (camc314)
- b1bcf72 minifier: Invalidate facts for redeclared bindings (#24658)
(Dunqing)
- 921b834 minifier: Don't treat a conditionally-assigned var as
write-once (#24650) (Dunqing)
- 061af1f minifier: Avoid stale pure function summaries (#24636)
(Dunqing)
- 40c2f43 allocator: `Vec::from_array_in` do not allocate zero-length
array (#24628) (overlookmotel)
- 70994ae codegen: Preserve comments before expression operands (#24510)
(Dunqing)
- 7b4baff parser: Reject new import member access (#23459) (camc314)
- 128b385 minifier: Clippy warning with no-debug-assertions (#24547)
(camc314)
- 8421feb parser: Use first `as` span for imported name (#24537)
(leaysgur)
- c517aa0 parser: Reject invalid accessor assertions (#24504) (camc314)

### ⚡ Performance

- 884d9eb parser: Pre-size cover-grammar assignment target buffers
(#24683) (Boshen)
- d3f07a0 diagnostics: Box OxcDiagnosticInner to reduce binary size
(#24665) (Boshen)
- bcc9de0 parser: Defer diagnostic creation until parse exit (#24663)
(Boshen)
- c35d8ab allocator: Mark `ReplaceWith` panic path cold (#24515)
(camc314)
- ba65790 semantic, allocator: Branchless `clone_in` for semantic IDs
(#24564) (overlookmotel)
- 747feec parser: Build AST nodes with the AST builder instead of
cloning (#24540) (Boshen)
- ba35a0d react_compiler: Use IndexVec for dense id-keyed maps (#24549)
(Boshen)
- b685062 react_compiler: Keep small hot-path collections inline
(#24514) (Marius Schulz)
- a149e95 transformer: Outline rare expression exits (#24512) (camc314)
- 7808a6e react_compiler: Make aliasing effects cheap to intern and
clone (#24506) (Marius Schulz)
- 3a36f2a react_compiler: Store AbstractValue reasons as a u16 bitmask
(#24480) (Boshen)
- 1c96753 react_compiler: Use FxHashMap for the lookup-only aliasing
node map (#24490) (Boshen)

Co-authored-by: Cameron <cameron.clark@hey.com>
2026-07-21 16:09:41 +01:00
Boshen bfecb1a3f8 refactor(react_compiler): back HIR ordered maps with Vec + FxHashMap (#24666)
The HIR's insertion-ordered CFG containers were `indexmap`-based:

- `HIR.blocks: FxIndexMap<BlockId, BasicBlock>` — iteration order is
reverse-postorder, which is load-bearing (forward dataflow visits each
block after its predecessors).
- `BasicBlock.preds: FxIndexSet<BlockId>` — predecessor order sets
phi-operand order.
- `Phi.operands: FxIndexMap<BlockId, Place>` — one operand per
predecessor, in that order.

`indexmap` has no arena-allocator variant, which blocks moving the HIR
into an arena. `Vec` and hash maps do (`oxc_allocator::Vec` /
`oxc_allocator::HashMap`), so this replaces those three fields with
`OrderedMap` / `OrderedSet` — ordered containers backed by `Vec<(K, V)>`
plus an `FxHashMap<K, usize>` index. They mirror the subset of the
`IndexMap` / `IndexSet` API the HIR uses
(`get`/`get_mut`/`insert`/`shift_remove`/`retain`/`drain`/`keys`/`values`/`iter[_mut]`/`get_index_of`,
`IntoIterator`, `Index`, `DoubleEndedIterator`), preserving insertion
order and O(1) lookup, so call sites are unchanged.

This is a preparatory step: the three fields are now composed of
arena-convertible primitives, so the eventual arena move is a mechanical
`Vec` -> `Vec<'a>` / `FxHashMap` -> arena `HashMap` swap rather than an
impossible `indexmap` port.

The `SymbolId`-keyed builder maps and `StabilizeBlockIds`' scratch set
stay `FxIndexMap` / `FxIndexSet` — they are pass-local working data, not
HIR CFG structures.

Pure internal change: the fixtures snapshot is byte-identical; new unit
tests cover the `shift_remove` / `retain` / `drain` reindexing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-21 09:49:23 +08:00
Marius Schulz b6850625af perf(react_compiler): keep small hot-path collections inline (#24514)
## What

Two kinds of small, hot collections in the react-compiler pass get
heap-allocated on every use:

- The HIR operand/lvalue visitors (`each_instruction_value_operand`,
`each_terminal_operand`, and friends) build a fresh `Vec<Place>` for
every instruction they're called on, and nearly every pass calls them in
a loop. The lists almost always hold one to four entries.
- The aliasing fixpoint allocates a successor list per block visit
(`terminal_successors`) and an args/captures list per interned effect
(`EffectKey`).

## Change

- The visitors now return `PlaceList = SmallVec<[Place; 4]>`; element
order and contents are unchanged.
- `terminal_successors` returns a `SmallVec<[BlockId; 2]>`, and
`EffectKey::Apply` args / `CreateFunction` captures are inline small
vectors, so building a typical key no longer allocates.
- Adds `smallvec` to the crate (already a workspace dependency).

Numbers from the stock release profile (fat LTO), linting cal.com with
`react/react-compiler` as the only enabled rule, `--threads=1`:

|              |         before |          after |               delta |
| ------------ | -------------: | -------------: | ------------------: |
| instructions | 18,085,644,607 | 17,200,052,223 |               −4.9% |
| wall time    |        2.787 s |        2.754 s | −1.2% |

## Verification

- Lint output is byte-identical to main on cal.com and excalidraw, with
`reportAllBailouts` both on and off (full stdout/stderr and exit codes,
single-threaded).
- Transform output is identical on all 1,438 tsx/jsx files across the
two corpora, with no exit-code changes.
- `cargo test -p oxc_react_compiler` (including the fixture snapshot
suite), clippy, and rustfmt are all clean.

This PR was assisted by Claude Code.
2026-07-15 00:14:01 +08:00
Boshen 3a36f2a67c perf(react_compiler): store AbstractValue reasons as a u16 bitmask (#24480)
Follow-up to #24476. Profiling the mutation-aliasing pass after that PR showed the `SmallVec<[ValueReason; 4]>` I introduced for `AbstractValue.reason` at **~7% of compile self-time** — it no longer allocates, but it's still copied on every `AbstractValue` clone, which happens once per entry on every `InferenceState` clone in the fixpoint.

There are only 12 `ValueReason` variants, so the whole set fits in a `u16` bitmask. `ReasonSet` — and therefore `AbstractValue` — becomes `Copy`, so copying it is a register move instead of a memcpy, and membership / union / superset collapse to single bitwise ops.

The one behavioral wrinkle is `primary_reason`, which returns the first non-`Other` reason: it now iterates in `ValueReason` declaration order rather than insertion order. The full snapshot suite (`tests/snapshot.rs`, the ~1288 upstream fixtures) is **unchanged**, confirming the ordering difference is not observable in output.

### Results

Real-world React component files (from `bluesky-social/social-app`), compile pass only:

| File | before | after |
| --- | ---: | ---: |
| Explore.tsx (35 KB) | 23.1 ms | **21.2 ms** (−8%) |
| MessageItem.tsx (30 KB) | 21.3 ms | **20.5 ms** (−4%) |
| Drawer.tsx (21 KB) | 8.6 ms | 8.7 ms (noise; few reasons) |

Allocation count is unchanged — the `SmallVec` was already inline, so this is purely a copy/`memcpy` win.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-14 07:56:22 +00:00
oxc-guard[bot] 8e0ed2ebb9 release(crates): oxc v0.140.0 (#24453)
### 🚀 Features

- 616bfa2 minifier: Remove unreachable code after terminating statements
(#24441) (Dunqing)
- ddab89a data_structures: Add `likely` and `unlikely` functions
(#24368) (overlookmotel)
- a3a39f9 react_compiler: Implement enableEmitHookGuards codegen
(#24329) (Boshen)
- b79eef7 minifier: Apply De Morgan's law to negated comparison chains
in jump guards and loop tests (#24279) (Dunqing)
- 34ff7b4 minifier: Drop write-only property assignments to unused local
bindings by default (#24112) (Dunqing)
- 1b829d8 semantic: Record const enums in EnumData (#24268) (Dunqing)
- ba0944c semantic: Add `Scoping::set_symbol_span` (#24221) (camc314)

### 🐛 Bug Fixes

- 7d33363 minifier: Preserve guaranteed throws from class heritage
evaluation (#24349) (Dunqing)
- 058a62f semantic: Track ambient contexts in `SemanticBuilder` (#24327)
(camc314)
- 721eb0b transformer/decorator: Scope accessor class binding (#24330)
(camc314)
- 1ebdce3 semantic: Allow reserved keywords in ambient declaration types
(#24325) (camc314)
- 460176a track-memory-allocations: Exclude arena chunks from Sys allocs
(#24292) (Dunqing)
- af4922b transformer: Clear lowered namespace redeclarations (#24300)
(camc314)
- ffd2765 semantic: Mark declared computed `MethodDefinition`s as type
references (#24296) (camc314)
- f17514b isolated-declarations: Emit const readonly fields as types
(#24288) (camc314)
- 40f769d minifier: Make `__proto__` write tracking execution-order
independent (#24280) (Dunqing)
- 6371fed transformer: Remove stale enum member bindings (#24272)
(camc314)
- f05dfab transformer: Correct symbol flags for lowered namespaces
(#24271) (Dunqing)
- 84eeb55 transformer: Correct symbol flags for lowered enums (#24269)
(Dunqing)
- c3057da transformer: Preserve generated class binding spans (#24220)
(camc314)
- 8260096 transformer: Correct span for lowered namespace symbol
(#24222) (camc314)
- 42d00d3 semantic: Mark declared class heritage as type references
(#24237) (camc314)
- 588d997 semantic: Mark TS `PropertyDefinition`s computed fields as
type references (#24233) (camc314)
- 9b95632 semantic: Mark computed method keys in `TSMethodSignature`s as
type references (#24232) (camc314)

### ⚡ Performance

- 5b26643 transformer_plugins: Dispatch global defines by trailing name
(#23666) (Boshen)
- dce0f29 react_compiler: Replace all compiled functions in a single AST
walk (#24403) (Boshen)
- f85f0d8 ast: Delegate inherited enum variants in clone_in and estree
derives (#23555) (Boshen)
- 3ff0234 allocator: Remove `unwrap` from `ReplaceWith` (#24365)
(overlookmotel)
- ab22e80 transformer: Fix Rust 1.97 performance regression (#24354)
(camc314)
- b47585c parser: Use `ReplaceWith` instead of `TakeIn` (#24018)
(overlookmotel)
- b227a06 minifier: Use `ReplaceWith` instead of `TakeIn` (#24017)
(overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
2026-07-14 15:02:22 +08:00
Boshen 1e3e626831 perf(react_compiler): reduce allocations in reactive-places and mutation-aliasing passes (#24476)
Two allocation-focused optimizations to the React Compiler's two hottest passes. Both are behavior-preserving — the full snapshot suite (`tests/snapshot.rs`, the ~1288 upstream fixtures) is unchanged, and no snapshots were regenerated.

Profiling the compiler on real component files showed ~99% of compile time is the compiler core (parse/semantic/codegen are <1% combined), and the core is allocation-bound: compiling a 35 KB file did ~1.2M heap allocations. These two changes remove most of that.

### 1. Memoize post-dominator frontiers (`infer_reactive_places`)

`is_reactive_controlled_block` recomputed each block's post-dominator frontier — a reverse-CFG walk that allocates several sets — on every call, which happens once per block and once per phi operand on every fixpoint iteration. The frontier depends only on the CFG, which is invariant across the fixpoint, so it is now computed once per block up front and looked up.

### 2. Inline `SmallVec` for `AbstractValue.reason` (`infer_mutation_aliasing_effects`)

`AbstractValue.reason` was an `FxIndexSet<ValueReason>`, which heap-allocates on every clone. During inference these values are cloned constantly (once per entry on every `InferenceState` clone), so the reason sets dominated allocation in the pass. The sets are tiny — usually a single element, never more than one per `ValueReason` variant — so they are now backed by an inline, insertion-ordered `SmallVec`: clones no longer allocate, and `primary_reason` (first non-`Other` reason) keeps its ordering.

### Results

Measured on real-world React component files (from `bluesky-social/social-app`), compile pass only, system allocator:

| File | before | after | allocations |
| --- | ---: | ---: | ---: |
| Explore.tsx (35 KB) | 49.6 ms | 23.5 ms (**2.1×**) | 1.24M → 220K (**−82%**) |
| MessageItem.tsx (30 KB) | 28.4 ms | 20.9 ms (**1.36×**) | 542K → 297K (**−45%**) |
| Drawer.tsx (21 KB) | 9.7 ms | 8.7 ms (1.11×) | 183K → 155K (−15%) |

\#2 is the larger lever — the reason-set clones dominated allocation in the pass. \#1 is a complementary ~6–10% CPU win from avoiding the redundant frontier recomputation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-14 03:53:33 +00:00
Boshen b80d351d5c refactor(react_compiler): drop lint allows and fix clippy warnings (#24449)
Follow-up to #24442 / #24448 (now merged). Removes clippy `"allow"`s from `crates/oxc_react_compiler` and fixes the warnings they were hiding.

## Crate-wide allows removed (`[lints.clippy]`)

Only `result_large_err` (the whole-crate `Result<T, OxcDiagnostic>` trade-off) remains.

| lint | warnings | fix |
| --- | --- | --- |
| `collapsible_if` | 197 | `cargo clippy --fix` (nested `if` → `&&` / `if let` chains) |
| `unnecessary_unwrap` | 4 | rewritten as `if let Some(..)` |
| `disallowed_types` | 0 | allow was dead — no `std::HashMap`/`HashSet` in the crate (the `ScopeInfo`/`ScopeData` comment was stale) |
| `needless_return` | 0 | allow was dead — no trailing `return`s |

## Inline allows removed

| lint | fix |
| --- | --- |
| `only_used_in_recursion` (3) | drop the recursion-only params: `func` (`apply_effect` → `apply_signature`), `types` (`get_context_reassignment`), `is_first_pass` (`record_instruction_derivations`) |
| `large_enum_variant` (3) | box `ReactiveStatement::Terminal` and `CompileResult`'s `output` (unboxed at the `lib.rs` boundary, so the public `compile` API is unchanged); `AliasingEffect`'s allow was already dead |
| `enum_variant_names` (1) | rename `Type::TypeVar` → `Type::Var` |

## Notes

- Behavior-preserving: the insta snapshot corpus and all 15 transform tests are byte-identical; `clippy` is clean.
- Deliberately left in place (would need bigger refactors, out of scope): `result_large_err` (whole-crate), `too_many_arguments` (×15 — arg-bundling structs), and `HIR`'s `upper_case_acronyms`.
- This diverges the vendored `src/` modules a bit further from upstream `react_compiler_oxc` (the `collapsible_if` collapses especially) — worth a note for whoever re-syncs.
- One thing the lint surfaced: `is_first_pass` in `record_instruction_derivations` was passed a real value by its fixpoint-loop caller but never read, so both passes were already identical — removing it is behavior-preserving but flags a latent gap if the passes were meant to differ.
2026-07-13 08:58:25 +00:00
Boshen 53342c91e9 refactor(react_compiler): define IDs with oxc_index nonmax index types (#24442)
## What

Migrate the React Compiler's HIR ID newtypes from hand-rolled `pub struct X(pub u32)` / `type X = u32` to oxc's `oxc_index::define_nonmax_u32_index_type!` — the same index-type idiom used by `SymbolId`, `ScopeId`, `NodeId`, `ReferenceId`, `BasicBlockId`, etc.

Migrated: `BlockId`, `IdentifierId`, `InstructionId`, `EvaluationOrder`, `DeclarationId`, `ScopeId`, `TypeId`, `FunctionId`, `MutableRangeId`, and the validation-pass `RefId`.

## Why

`NonMaxU32` backing adds a niche, so `Option<Id>` is **4 bytes instead of 8**. The crate has 48 `Option<Id>` fields — many on hot HIR structs (`Identifier`, `Place`, `MutableRange`, `ReactiveScope`, `Instruction`) — which shrink for free, plus `RefId`'s `Option<RefId>` fields. It also aligns the crate with the rest of oxc, and the macro's `Add`/`PartialOrd<usize>` impls let the pervasive `id.0 + 1` / `a.0 > b.0 + 1` arithmetic collapse to `id + 1` / `a > b + 1`.

## Notes

- `ValueId` is intentionally **not** migrated. It overlays two id-spaces by OR-ing bit 31 (`| 0x80000000`), whose value space includes `u32::MAX` and would panic under `NonMaxU32`; it is also only ever a hashmap/set key (never a `Vec` index or inside `Option<ValueId>`), so a nonmax index buys nothing. It stays a plain `u32` newtype, with the bit-tag now behind a named `ValueId::from_identifier` constructor.
- Named sentinels replace repeated magic zeros: `EvaluationOrder::UNSET` (the "not-yet-numbered" order, ~106 sites) and `BlockId::PLACEHOLDER` (the never-read block installed by the final `terminate()`; uses `MAX_INDEX` so it can't alias the real entry block, which is `0`).
- The old `u32::MAX` sentinels: the two never-read placeholders now use the named consts above; the `infer_types` one is a plain `u32` function-key and is unchanged.
- Behavior-preserving: the insta snapshot corpus and all 15 transform tests are byte-identical.
- These `src/` modules track upstream closely; this deliberately diverges, consistent with the recent oxc-integration work on this crate.
2026-07-13 07:02:13 +00:00
Boshen cc820cb2c7 refactor(react_compiler): use oxc utilities instead of reimplementations (#24430)
Replaces hand-rolled JavaScript utilities in `oxc_react_compiler` with oxc's canonical implementations, each of which is also strictly more spec-correct than the local version.

## Replaced

- **`is_valid_identifier`** (two copies) → `oxc_syntax::identifier::is_identifier_name` + `oxc_syntax::keyword::is_reserved_keyword`. Removes duplicated 46-word reserved-word lists and approximate `is_alphabetic`/`is_alphanumeric` char checks (oxc uses exact ECMAScript `ID_Start`/`ID_Continue`). Also fixes one copy that silently allowed `await` as an identifier.
- **`js_to_number`** → `oxc_ecmascript::StringToNumber`. The local version accepted `"inf"`/`"nan"` and used Rust's Unicode `.trim()` instead of JS whitespace.
- **`js_to_int32` / `js_to_uint32`** → `oxc_ecmascript::{ToInt32, ToUint32}`. The local `(n.trunc() as i64) & 0xFFFFFFFF` saturated for large magnitudes (e.g. `1e300` produced `-1` instead of `0`).
- **`format_js_number`** → `oxc_syntax::number::ToJsString`. Replaces a documented `Number.prototype.toString()` approximation (which fell back to Rust's `Display`) with the dragonbox-based, spec-correct formatter.
- **`ox_parse_regexp_flags`** → `oxc::RegExpFlags::try_from(char)`. Removes a duplicated 8-arm flag `match`.

Adds the `oxc_ecmascript` dependency and enables the `to_js_string` feature on `oxc_syntax`. The single-call numeric conversions are inlined at their call sites; `is_valid_identifier` (composes two calls, used as a fn-pointer), `format_js_number` (pub, cross-file `Display` helper), and `ox_parse_regexp_flags` (a per-char loop) remain thin helpers.

Snapshot conformance (over the upstream fixture corpus) and the transform integration tests pass unchanged.
2026-07-13 01:54:16 +00:00
Boshen cadbfee9a5 refactor(react_compiler): remove dead code (#24426)
Removes all compiler-flagged dead code from `oxc_react_compiler`.

## Removed

- **Superseded functions** (`propagate_scope_dependencies_hir`): `collect_hoistable_property_loads`, `collect_hoistable_property_loads_impl`, `key_by_scope_id` — the live pipeline uses the restructured `collect_hoistable_and_propagate` instead.
- **Unused methods/wrappers**: `kind_opt`, `mutate`, `define_context`.
- **Unused fields** (removed with their construction sites): `PropertyPathNode::{parent, root}`, `DependencyCollectionContext::temporaries_used_outside_scope` (cascaded cleanly through `collect_dependencies`), `JsxInstrInfo::instr_id`, `ControlFlowTarget::Loop::owns_block`, `OxcContext::fn_name`, `StartMemoInfo::span`, `Callbacks::memo_locals`.
- **Unused enum variant**: `MutationKind::None` (the `Ord` ordering of the remaining variants is preserved).
- **Dormant scaffolding**: `TransformedValue::Replace` — collapsed the base traversal's replace path down to direct `visit_value` calls (the 11 transform passes are unaffected) — and `LvalueRef::Spread` plus its codegen match arm.
- **`hmac-sha256` dependency** — orphaned once `source_file_hash` was removed; dropped from the crate and workspace manifests.

Pre-existing `#[allow(dead_code)]` markers on live-but-unread code were left intact, so the diff is purely dead-code removal. Snapshot conformance (over the upstream fixture corpus) and the transform integration tests pass unchanged.
2026-07-13 00:43:16 +00:00
Boshen 7ae9257187 refactor(react_compiler): replace String with arena Ident/Str in HIR (#24393)
Converts `oxc_react_compiler` HIR strings from owned `String` to arena types from `oxc_str`, mirroring the `oxc_ast` conventions. Output is byte-identical over the 1806-fixture snapshot corpus, and the public `transform`/`lint` API is unchanged.

## Type mapping

- Identifier-ish names → `Ident<'a>` (Copy, precomputed hash): `IdentifierName`, `PropertyLiteral`, `ObjectPropertyKey`, `NonLocalBinding`/`VariableBinding` names, JSX attribute/tag names, `StoreGlobal`, `MetaProperty`, function ids/name-hints, `Type::shape_id`/`object_name`
- Text values → `Str<'a>`: directives, `JSXText`, template quasis, regex pattern/flags, import module specifiers
- `JsString` is now Copy with `Utf8(Str<'a>) | Wtf16(&'a [u16])` — string literals borrow AST arena text directly; constant-folding results allocate once into the arena
- Name-keyed maps → `IdentHashMap`/`IdentHashSet`/`IdentIndexMap` (str lookups keep working via `Equivalent` with the precomputed hash)
- `type_annotation_kind` → `Option<&'static str>` (`"as"`/`"satisfies"`)

## Where names come from

- AST names are copied out of node fields as `Ident<'a>` values (free); binding names resolved through `Scoping` are arena-copied once by `ScopeResolver::symbol_ident()` (the `Scoping` name storage lives in the `Semantic` borrow, not the arena)
- `Environment<'a>` now carries `allocator: &'a Allocator`; synthesized names (`#t{n}` temporaries, `name_{i}` collision suffixes, `_temp{i}` uids, `$` cache vars, outlined-component names) build with `format_ident!`
- `BUILT_IN_*` shape ids are `Ident<'static>` consts (`static_ident!`), so shape-id comparisons take the len+hash fast path; the static globals/shapes base tables are `IdentHashMap<'static, _>` built with zero startup `String` allocations (the handful of `<generated_N>` anon ids minted during the once-per-process static build are leaked as static data; per-compilation ids go in the arena)

## Structural payoff

Codegen previously kept the HIR at a separate lifetime `'h` and re-allocated every identifier into the output arena via `ox_str`. Input AST, HIR, and output AST share one allocator, so the lifetimes are unified: a name flows from source text through lowering, SSA versioning, and renaming into the output AST without a single copy. Per-operand `Constant` clones in constant propagation and per-version name clones in `enter_ssa` are now 16-byte copies.

To keep the public API borrow-free (`&Program<'a>`, `&Semantic<'_>`, unchanged from before), the HIR holds no references into the input `Program`: the two AST nodes it used to keep verbatim — `TypeCastExpression` type annotations and `UnsupportedNode` statements (inline TS `enum`) — are cloned into the arena at lowering with `clone_in_with_semantic_ids` (preserving the semantic id cells codegen's rename-by-reference-identity relies on). `FunctionNode` and the discovery/lowering paths carry the node borrow and the arena lifetime separately.

## Deliberately still `String`

- Config API (`options.rs`, `environment_config.rs`, `type_config.rs`) — created before the arena exists; converted at the `with_config` boundary
- `Cow<'static, str>` where values are static-or-config-owned: `FunctionSignature::canonical_name`/`known_incompatible`, `get_react_compiler_runtime_module`
- Suppression comment values are now `&'a str` source subslices; `decode_jsx_entities` returns `Cow` (borrows when no entity)
- Diagnostics/debug text (`format_place`, dependency printers, sort keys, `format_js_number`) and aliasing-config placeholder names (`"@rest"`, …)

## Verification

- `cargo test -p oxc_react_compiler`: 1806-fixture snapshot suite unchanged, 15 integration tests pass (tests/example untouched from main)
- `oxc_linter` / `oxc_transformer` (+tests) / benchmark build clean; transformer integration tests pass
- clippy (CI profile), typos, shear, fmt clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-12 08:28:02 +00:00
Boshen 0e8ecbe16d refactor(react_compiler): remove for_kv_map, question_mark, unneeded_wildcard_pattern clippy allows (#24342)
Remove three clippy lint allows from `oxc_react_compiler` and fix the six spots that triggered them:

- `unneeded_wildcard_pattern` (3): drop redundant `children: _` / `span: _` fields next to `..` in match patterns
- `for_kv_map` (1): iterate `temporaries.values()` instead of discarding the key from `iter()`
- `question_mark` (2): replace `match`-with-`return None` arms with `?` in `constant_propagation.rs` (same early-return semantics)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-10 07:10:31 +00:00
renovate[bot] 0e00b91b5a chore(deps): update dependency rust to v1.97.0 (#24328)
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [rust](https://redirect.github.com/rust-lang/rust) | minor | `1.96.1`
→ `1.97.0` |

---

### Release Notes

<details>
<summary>rust-lang/rust (rust)</summary>

###
[`v1.97.0`](https://redirect.github.com/rust-lang/rust/blob/HEAD/RELEASES.md#Version-1970-2026-07-09)

[Compare
Source](https://redirect.github.com/rust-lang/rust/compare/1.96.1...1.97.0)

\==========================

<a id="1.97.0-Language"></a>

## Language

- [Consider `Result<T, Uninhabited>` and `ControlFlow<Uninhabited, T>`
to be equivalent to `T` for must use
lint](https://redirect.github.com/rust-lang/rust/pull/148214)
- [Add allow-by-default `dead_code_pub_in_binary` lint for unused pub
items in binary
crates](https://redirect.github.com/rust-lang/rust/pull/149509)
- [Stabilize the `div32`, `lam-bh`, `lamcas`, `ld-seq-sa` and `scq`
target features](https://redirect.github.com/rust-lang/rust/pull/154510)
- [Stabilize
`cfg(target_has_atomic_primitive_alignment)`](https://redirect.github.com/rust-lang/rust/pull/155006)
- [Allow trailing `self` in imports in more
cases](https://redirect.github.com/rust-lang/rust/pull/155137)

<a id="1.97.0-Platform-Support"></a>

## Platform Support

- [nvptx64-nvidia-cuda: drop support for old architectures and old
ISAs](https://redirect.github.com/rust-lang/rust/pull/152443)

Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.

[platform-support-doc]:
https://doc.rust-lang.org/rustc/platform-support.html

<a id="1.97.0-Stabilized-APIs"></a>

## Stabilized APIs

- [`Default for
RepeatN`](https://doc.rust-lang.org/stable/std/iter/struct.RepeatN.html#impl-Default-for-RepeatN%3CA%3E)
- [`Copy for
ffi::FromBytesUntilNulError`](https://doc.rust-lang.org/stable/std/ffi/struct.FromBytesUntilNulError.html#impl-Copy-for-FromBytesUntilNulError)
- [`Send for std::fs::File` on
UEFI](https://redirect.github.com/rust-lang/rust/pull/154003)
-
[`<{integer}>::isolate_highest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.isolate_highest_one)
-
[`<{integer}>::isolate_lowest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.isolate_lowest_one)
-
[`<{integer}>::highest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.highest_one)
-
[`<{integer}>::lowest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.lowest_one)
-
[`<{integer}>::bit_width`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.bit_width)
-
[`NonZero<{integer}>::isolate_highest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.isolate_highest_one)
-
[`NonZero<{integer}>::isolate_lowest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.isolate_lowest_one)
-
[`NonZero<{integer}>::highest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.highest_one)
-
[`NonZero<{integer}>::lowest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.lowest_one)
-
[`NonZero<{integer}>::bit_width`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.bit_width)

These previously stable APIs are now stable in const contexts:

-
[`char::is_control`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_control)

<a id="1.97.0-Cargo"></a>

## Cargo

- [Stabilize `build.warnings`
config.](https://redirect.github.com/rust-lang/cargo/pull/16796) This
controls how lint warnings from local packages are treated. Useful for
enforcing a warning-free build in CI, replacing `-Dwarnings`.
[docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#buildwarnings)
- [Stabilize `resolver.lockfile-path`
config.](https://redirect.github.com/rust-lang/cargo/pull/16694) This
allows specifying the path to the lockfile to use when resolving
dependencies. Useful when working with read-only source directories.
[docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#resolverlockfile-path)
- [cargo-clean: Error when `--target-dir` doesn't look like a Cargo
target
directory.](https://redirect.github.com/rust-lang/cargo/pull/16712) This
prevents accidental deletion of non-target directories.
- [Add `-m` shorthand for
`--manifest-path`](https://redirect.github.com/rust-lang/cargo/pull/16858)
- [Remove `curl` dependency from `crates-io`
crate](https://redirect.github.com/rust-lang/cargo/pull/16936)

<a id="1.97.0-Rustdoc"></a>

## Rustdoc

- [Stabilize `--emit`
flag](https://redirect.github.com/rust-lang/rust/pull/146220)
- [Stabilize
`--remap-path-prefix`](https://redirect.github.com/rust-lang/rust/pull/155307)

<a id="1.97.0-Compatibility-Notes"></a>

## Compatibility Notes

- [Emit a future-compatibility warning when relying on `f32:
From<{float}>` to constrain
`{float}`](https://redirect.github.com/rust-lang/rust/pull/139087)
- [Rust will use the v0 symbol mangling scheme by
default.](https://redirect.github.com/rust-lang/rust/pull/151994) This
may cause some tools (such as debuggers or profilers, especially with
old versions) to fail to demangle symbols emitted by Rust. It may also
cause the formatting of text in backtraces to change.
- [Prevent deref coercions in `pin!`, in order to prevent
unsoundness.](https://redirect.github.com/rust-lang/rust/pull/153457)
The most likely case where this might impact users is: writing `pin!(x)`
where `x` has type `&mut T` will now always correctly produce a value of
type `Pin<&mut &mut T>`, instead of sometimes allowing a coercion that
produces a value of type `Pin<&mut T>`. This coercion was previously
incorrectly allowed since Rust 1.88.0.
- [Deprecate `std::char` constants and
functions](https://redirect.github.com/rust-lang/rust/pull/153873)
- [Warn on linker output by
default](https://redirect.github.com/rust-lang/rust/pull/153968)
- [Remove hidden `f64` methods which have been deprecated since
1.0](https://redirect.github.com/rust-lang/rust/pull/153975)
- [report the `varargs_without_pattern` lint in
deps](https://redirect.github.com/rust-lang/rust/pull/154599)
- [Forbid passing generic arguments to module path segments even if the
module reexports a generic enum
variant](https://redirect.github.com/rust-lang/rust/pull/154971)
- [Error on invalid macho `link_section`
specifier](https://redirect.github.com/rust-lang/rust/pull/155065)
- The encoding of certain `enum`s [have
changed](https://redirect.github.com/rust-lang/rust/pull/155473). This
is not a breaking change, as it only applies to `enum`s without layout
guarantees, but is noted here as we've seen people impacted from having
made assumptions about the layout algorithm.
- [Error on `#[export_name = "..."]` where the name is
empty](https://redirect.github.com/rust-lang/rust/pull/155515)
- [Syntactically reject tuple index shorthands in struct
patterns](https://redirect.github.com/rust-lang/rust/pull/155698)
- [validate `#[link_name = "..."]` & `#[link(name = "...")]`
parameters](https://redirect.github.com/rust-lang/rust/pull/155817)
- On Windows, after calling `shutdown` on a socket to shut down the
write side, attempting to write to the socket will now produce a
`BrokenPipe` error rather than `Other`. [Map `WSAESHUTDOWN` to
`io::ErrorKind::BrokenPipe`](https://redirect.github.com/rust-lang/rust/pull/156063)

</details>

---

### Configuration

📅 **Schedule**: (in timezone Asia/Shanghai)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/oxc-project/oxc).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
2026-07-09 18:34:23 +01:00
Boshen 5a9721aa8f refactor(react_compiler): use oxc_diagnostics directly, delete react_compiler_diagnostics (#24322)
The crate-private diagnostics data model (`react_compiler_diagnostics`: `CompilerDiagnostic`, `CompilerDiagnosticDetail`, `CompilerErrorDetail`, `CompilerErrorOrDiagnostic`, `ErrorSeverity`) duplicated what `OxcDiagnostic` already models and was converted to it at the program boundary anyway. This deletes the module and has passes construct `OxcDiagnostic` eagerly.

### What survives, and where the category went

- `ErrorCategory` stays (it drives TS-parity semantics). The aggregate `CompilerError` recovers it from the deterministic `[ReactCompiler] <Category>: ` message prefix that `ErrorCategory::diagnostic` writes — no field on the diagnostic changes, so consumers see exactly the same `OxcDiagnostic`s as before. Category-driven control flow is preserved: `Invariant` throws from `record_error`, `Config` always trips the panic threshold, and `PreserveManualMemo` displays as an error while staying internally a warning for `panicThreshold: critical_errors`.
- `CompilerError` slims to `Vec<OxcDiagnostic>` plus the two control-flow flags (`is_thrown`, `unimplemented`); pass signatures use `Result<T, OxcDiagnostic>` with `From` conversions keeping `?` working.
- `js_string.rs` was never diagnostics code (WTF-16 string values) — moved to `react_compiler_utils`. `GENERATED_SOURCE`/`Span` moved to `react_compiler_hir`.

### Output parity

Zero output change. The two legacy carrier types rendered labels differently (plain underline vs `span.label(text)`), and thrown Todo/`enter_ssa` errors were flattened to span-only form; each converted site preserves its path's rendering. The 1736-fixture snapshot corpus and the oxlint `react/react-compiler` rule snapshot pass **unchanged** — no snapshot files are touched in this PR.

Net −784 lines. `cargo lint` needed a crate-local `result_large_err = "allow"` (the crate defines its own `[lints.clippy]` and doesn't inherit the workspace allow; same rationale — `OxcDiagnostic` is deliberately inlined).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-09 12:19:19 +00:00
Boshen 06db0c21ef refactor(react_compiler): remove no-op debug logging and HIR printers (#24252)
## What

`ProgramContext::log_debug` had an **empty body** — so every
`DebugLogEntry` built behind the ~57 `if context.debug_enabled { … }`
gates in the pipeline (and the 16 `log_reactive_debug!` calls) was
computed and immediately discarded. The `debug` cargo feature gated
~2500 lines of HIR/reactive printers (`print.rs`, `debug_print.rs`,
`print_reactive_function.rs`) that fed only those discarded entries.

`PluginOptions::debug` (public, default `false`) had no consumer other
than toggling that no-op.

## Changes

- Remove the no-op sink: `DebugLogEntry`, `log_debug`,
`ProgramContext::debug_enabled`, `PluginOptions::debug`, the ~57 gated
blocks, and the `log_reactive_debug!` macro.
- Delete the three printers and the `debug` cargo feature.
- Prune the HIR / reactive-IR metadata fields that only the printers
read — reactive terminal/value `span`s (keeping the ones codegen
actually reads, e.g. `ForOf`/`ForIn`), type-annotation metadata — plus
the helpers that became unreachable.

## Notes

- Behavior-preserving: the 1806-fixture snapshot corpus and integration
tests are **byte-identical**, and `oxc_transformer`/`oxc_linter` compile
unchanged.
- Net ~−3000 lines.

Follow-up to #24248.
2026-07-07 15:48:18 +08:00
oxc-guard[bot] 69b2dfc181 release(crates): oxc v0.139.0 (#24218)
### 🚀 Features

- 260425f semantic/examples: Include unresolved references (#24214)
(camc314)
- 2d9b0b3 minifier: Fold boolean-literal ternary branches in value
contexts (#24110) (Dunqing)
- 61fbf10 ast: Implement `ReplaceWith` on all AST types (#24013)
(overlookmotel)
- 7db7a29 allocator: Add `ReplaceWith` trait (#24012) (overlookmotel)
- 4eb074e mangler: Add `reserved` option for names that must not be
mangled (#24041) (Dunqing)
- 2e62012 data_structures: Add `StringExt` trait (#24006)
(overlookmotel)
- 60e7160 minifier: Drop side-effect-free IIFEs whose result is unused
(#23967) (Dunqing)
- 26dd9e2 ast: Add method to widen inherited enum ref to parent ref
(#23961) (overlookmotel)

### 🐛 Bug Fixes

- e8b50ee transformer: Clean up semantics for stripped TypeScript syntax
(#24180) (camc314)
- d966d0b react_compiler: Remove clippy allows (#24168) (Boshen)
- 854ef8d react_compiler: Compile generic functions instead of
over-bailing on type-param hoisting (#24158) (Boshen)
- 093586c react_compiler: Align memoization cache-slot allocation with
Babel (#24157) (Boshen)
- 09c8f59 react_compiler: Normalize snapshot fixture paths (#24142)
(camc314)
- f13df97 react_compiler: Drop stray empty statement from catch bindings
(#24133) (Boshen)
- cb2a505 react_compiler: Codegen destructuring reassignment targets
(#24131) (Boshen)
- b82c394 react_compiler: Propagate codegen invariants instead of
emitting empty bodies (#24128) (Boshen)
- 5771982 react_compiler: Render unchanged programs as source in fixture
snapshots (#24129) (Boshen)
- 4b16e1a transformer/async-to-generator: Preserve direct eval scope
flags (#24136) (camc314)
- 4e9194f react_compiler: Lower `delete obj.prop` to
Property/ComputedDelete (#24123) (Boshen)
- 0b25582 ast: Type binding node `typeAnnotation` as `TSTypeAnnotation |
null` (#23113) (Boshen)
- 018c0e5 transformer: Hoist lowered async declarations (#22770)
(camc314)
- 652fbaf mangler: Keep names of destructured exported bindings (#24036)
(Dunqing)
- e274415 minifier: Don't drop global calls that throw despite pure
arguments (#23917) (Dunqing)
- 59abb30 minifier: Only merge string literals in `try_fold_add` when
the inner operator is `+` (#23622) (Jerry Zhao)

### ⚡ Performance

- c5ca77b transformer: Avoid cloning refresh options (#24191) (camc314)
- bf1a151 react_compiler: Compile out debug printers (#24184) (Boshen)
- abb44a0 transformer: Build fixed object-rest arguments (#24190)
(camc314)
- a4db731 isolated_declarations: Use `ReplaceWith` instead of `TakeIn`
(#24016) (overlookmotel)
- ff10855 transformer: Use `ReplaceWith` instead of `TakeIn` (#24015)
(overlookmotel)
- bd49aff ecmascript: Avoid heap-allocating Math.min/max/imul operands
(#23941) (Lawrence Lin)
- e4b708b react_compiler: Skip compiled files before prefilters (#24171)
(Boshen)
- c59f2fe rust: Return impl ExactSizeIterator from slice-backed
accessors (#24144) (Boshen)
- 5d6d04a codegen: SWAR-skip boring byte runs in sourcemap line/column
scan (#24023) (Boshen)
- a55e0be traverse: Reduce string operations in `get_var_name_from_node`
(#24007) (overlookmotel)
- e6d48e1 transformer/nullish_coalescing: Move cold path into separate
function (#23989) (overlookmotel)
- c4e35b5 transformer/object_rest_spread: Pre-allocate capacity in `Vec`
(#23988) (overlookmotel)
- 527b8e5 transformer/decorators: Narrow type earlier (#23987)
(overlookmotel)

### 📚 Documentation

- 30d17f5 allocator: Clarify docs for `TakeIn::take_in_box` (#24093)
(overlookmotel)
- 675e6a8 ast: Correct doc comment for `PrivateFieldExpression` (#24008)
(overlookmotel)
- e4c30e6 minifier: Explain what `dce` mode means (#23994) (Dunqing)
- 37cbf88 ast_macros: Document fields of `StructDetails` (#23959)
(overlookmotel)
- 4de3e54 ast: Correct doc comment (#23948) (overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
2026-07-06 23:26:26 +08:00
Boshen d966d0bfd3 fix(react_compiler): remove clippy allows (#24168)
Removes the blanket `clippy::all` module allowances from `oxc_react_compiler` and fixes the resulting diagnostics with mechanical cleanups, targeted item-level allowances, and normal dependency access to `cow-utils`.

Validated with `just fmt`, `cargo clippy -p oxc_react_compiler --lib --all-targets -- -D warnings`, and `cargo test -p oxc_react_compiler`.

AI-assisted.
2026-07-05 02:11:52 +00:00
camc314 09c8f59654 fix(react_compiler): normalize snapshot fixture paths (#24142)
## Summary

- Normalize React compiler snapshot names using path components instead of splitting on `/fixtures/`.
- Normalize fixture source newlines before parsing so diagnostic byte offsets are stable across Windows and Unix checkouts.
- Allow manually dispatched CI runs to execute the Windows cargo test job, without enabling it for normal pull requests.

## Root Cause

Windows `insta::glob!` passes fixture paths like `\?\E:\oxc\crates\oxc_react_compiler\fixtures\...`. The old string split only handled Unix `/fixtures/`, so Windows generated absolute-path snapshot names and treated every fixture as a new snapshot. After fixing that, Windows still differed because CRLF fixture checkout shifted diagnostic source offsets relative to LF snapshots.
2026-07-04 08:33:28 +00:00
Boshen 6efce65746 test(react_compiler): snapshot the upstream fixture corpus (#24101)
## Summary

`oxc_react_compiler` had no committed test over the upstream React
Compiler fixture corpus — the fixtures lived only in the
`oxc-project/forked-react-compiler` checkout, exercised out-of-tree.
That gap let real regressions slip past the 15 in-crate integration
tests. This PR closes it.

- **`crates/oxc_react_compiler/fixtures/`** — 1734 fixture *input* files
(`.js`/`.ts`/`.tsx`/`.jsx`/`.mjs`), copied from the fork's
`babel-plugin-react-compiler/src/__tests__/fixtures/compiler` tree with
subdirectories preserved. Flow fixtures (the `@flow`-pragma ones) are
excluded — oxc has no Flow parser. The upstream `.expect.md` goldens are
also not copied; insta is the golden here.
- **`crates/oxc_react_compiler/tests/snapshot.rs`** — an `insta::glob!`
test that, per fixture, derives `PluginOptions`/`EnvironmentConfig` from
the first-line `// @directive` pragmas (base `compilationMode=all` /
`panicThreshold=all_errors`, matching the upstream `snap` runner),
parses → builds semantic → runs `transform`, and snapshots the compiled
output plus diagnostics. Unrecognised directives are ignored, as
upstream does; camelCase flag directives map to `EnvironmentConfig`
fields via `convert_case`.
- **`crates/oxc_react_compiler/tests/snapshots/`** — 1734 committed
`.snap` goldens (oxc's own output).
- **`.typos.toml`** — excludes the fixtures dir (the upstream fixtures
contain intentional typos; `**/*.snap` was already excluded).

These snapshots are oxc's own golden output, so `cargo test` (and CI)
now catches any change in compiler behaviour across the corpus.
Regenerate after an intended change with `cargo insta accept`.

## Verification

- `cargo test -p oxc_react_compiler` passes — the 1734-fixture snapshot
test plus the existing 15 integration tests; also green under
`--all-features` (matches the cross-target CI job).
- clippy `-D warnings`, `cargo fmt`, and `typos` clean.
- No fixture panics; 1336 compiled / 398 unchanged / 335 with
diagnostics.
- The `error.*` fixtures capture the exact diagnostics — including the
"Cannot reassign variable after render" error that a recent scoping
change had silently suppressed, confirming the suite catches real
regressions.

---

AI usage disclosure: authored with Claude Code and reviewed before
submission.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-03 16:49:53 +08:00
Boshen 3cad48d67b refactor(react_compiler): gate HIR debug printing behind a debug feature (#24048)
Puts the HIR debug printer (`react_compiler::debug_print`, ~600 lines)
behind a new off-by-default `debug` cargo feature, so it isn't compiled
into normal builds.

### How
- `Cargo.toml`: add `[features]` with `debug = []`.
- `react_compiler/mod.rs`: `#[cfg(feature = "debug")]` on `pub mod
debug_print;`, plus a `#[cfg(not(feature = "debug"))]` no-op stub module
exposing the two entry points the pipeline calls (`debug_hir`,
`format_hir_function_into`).

The printer is threaded through the vendored `pipeline.rs` at ~70 `if
context.debug_enabled { … }` sites (plus a closure capture and a local
formatter fn that are required pass arguments). Gating each site would
scatter ~75 `#[cfg]` attributes through vendored code and fight
re-syncability, so gating the module with a stub keeps
`pipeline.rs`/`imports.rs` untouched while still compiling the printer
out by default.

### Behavior
No change to default builds: nothing in the workspace sets
`PluginOptions::debug`, so the printer was never triggered. To get HIR
dumps, build with `--features oxc_react_compiler/debug` and set
`PluginOptions::debug = true`.

### Verified
- Default build (stub) and `--features debug` (real printer) both
compile clean.
- `oxc_react_compiler` tests pass in both modes (15/15); clippy clean in
both.
- `oxc`, `oxc_linter`, `oxc_transformer` build with default features.
2026-07-02 15:31:40 +08:00
Boshen 64683a7784 refactor(react_compiler): drop the oxc_parser dependency (#24038)
Removes `oxc_parser` from `oxc_react_compiler`'s library dependencies. The compiler is handed an already-parsed `Program` (via `transform`/`lint`), so the library itself no longer needs to parse anything.

The only remaining `src/` use was in `codegen_reactive_function.rs`, when re-emitting a stored TS type annotation (on an `as`/`satisfies` cast) whose inner identifiers had binding renames applied. The old code sliced the original source, applied the renames as text edits, wrapped the result in `let __oxc_t = null as …;`, and **re-parsed** it.

That path is replaced with a `clone_in` of the stored `TSType` followed by an in-place identifier rename via `VisitMut`. `clone_in` preserves spans, so the renames stay keyed by source offset — the exact same reference set that drove the text edits before. Both approaches rename the same identifiers (both are driven by the `visit_ts_type` walk plus the `reference_node_ids`/`renames` filter) and yield structurally identical ASTs, so codegen output is unchanged. It's also cheaper (no source slicing, no re-parse) and can no longer fail, so the helper's return type drops from `Option<TSType>` to `TSType` and the dead `None` fallback at the two call sites is removed.

`oxc_parser` moves to `[dev-dependencies]` (the example and integration tests still parse source).

Depends on the API in #24028 (already merged).
2026-07-02 05:14:53 +00:00
Boshen 3c2a0f0e39 refactor(react_compiler): drop the old AstBuilder compat shim (#24027)
## Summary

Follow-up cleanup after the de-Babel (#24009). The ported codegen called deprecated inherent `AstBuilder` methods (`vec` / `alloc` / `expression_*` / `statement_*` / …), which the crate's `disable_old_builder` dev-dep flags for migration; a compat trait `OldBuilderExt` (`old_builder_ext.rs`) mirrored them on the new API to ease the port.

This removes that shim: all ~300 call sites (`codegen_reactive_function.rs` + `program.rs`) now use the new `AstBuilder` API directly (`ArenaVec::*_in` / `ArenaBox::new_in` / `Type::new_*`), and `old_builder_ext.rs` (~1.7k lines) is deleted. The now-unused `oxc_str` dependency is dropped.

## Verification

- No deprecated builder methods remain (`cargo check` reports 0 `use of deprecated`).
- clippy `--all-features --all-targets -D warnings`: clean.
- Differential over the 1,805 upstream React Compiler fixtures: byte-identical (`same=1805 diff=0`).
- 15 integration tests pass; `cargo shear` / `cargo fmt --check` / `typos` clean.

---

Produced with AI assistance (Claude Code); verified byte-identical against the 1,805-fixture differential and the crate's tests.
2026-07-02 01:13:03 +00:00
Boshen 269ce46cdb test(react_compiler): move end-to-end tests to tests/, drop internal unit tests (#24022)
## Summary

Follow-up to #24009 (de-Babel). Now that `oxc_react_compiler` speaks the
oxc AST natively, this tidies its test + dependency layout:

- **Move the 15 end-to-end tests to `tests/transform.rs` as integration
tests** — they exercise the crate through its public `transform_source`
API instead of `#[cfg(test)]` modules inside `lib.rs`.
- **Remove the internal unit tests** (function discovery, `JsString`,
HIR `Environment`, codegen hashing, prefilter) — the crate is covered
through its public API.
- **Move `oxc_codegen` to `[dev-dependencies]`** — the library builds
the oxc AST but never codegens it; only the example and integration
tests print the program.

Net −397 lines.

## Verification

- `cargo test -p oxc_react_compiler`: 15 integration tests pass, 0 unit.
- Differential over the 1,805 upstream React Compiler fixtures:
byte-identical (`same=1805 diff=0`).
- clippy `-D warnings`, `cargo fmt --check`, `typos`, `cargo shear`:
clean. Example builds.

---

Produced with AI assistance (Claude Code); verified byte-identical
against the 1,805-fixture differential and the crate's tests.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-02 08:12:43 +08:00
Boshen 36088087f8 refactor(react_compiler): replace the vendored Babel AST with the oxc AST (#24009)
## Summary

`oxc_react_compiler` (the Rust port of the React Compiler) worked internally on a **vendored Babel-shaped AST**: the pipeline converted the oxc `Program` into that AST, compiled against it, then converted back to oxc for codegen. That cost ~6k lines of conversion glue plus a whole Babel-AST module, and it couldn't carry TypeScript type nodes through the IR (type annotations were serialized to JSON and re-parsed from source).

This PR removes the Babel AST entirely. The compiler now consumes the **oxc AST natively**: it lowers the oxc AST directly to the HIR, and codegen builds oxc via `AstBuilder` and splices the compiled functions into the `&mut Program` in place. Since oxc already models every TS type-annotation node, the HIR carries borrowed `&'a TSType<'a>` nodes directly instead of re-parsing.

```
oxc Program → convert_scope → discovery (oxc_ast_visit::Visit)
            → build_hir (oxc AST → HIR) → passes
            → codegen (oxc AstBuilder) → splice into &mut Program
```

## Commits

1. `RawNode` JSON blob → structured metadata; drop serde / serde_json
2. Front-end: lower the oxc AST → HIR directly (transitional span-bridge)
3. Back-end: codegen emits oxc via `AstBuilder` + splices in place; delete `convert_ast_reverse`
4. Delete the vendored `react_compiler_ast` + `convert_ast`; discovery walks the oxc `Program`
5. Thread `'a` through the HIR to carry `&'a TSType` / `&'a Statement` (no source-reparse)

Net **−13k lines** (71 files).

## Verification

Every commit is **byte-identical** to the pre-change compiler over the 1,805 upstream React Compiler fixtures (`same=1805 diff=0`), and `cargo test -p oxc_react_compiler` (38 tests) passes throughout. The public API (`transform(&mut Program)` / `lint` / `TransformResult`) is unchanged.

## Follow-ups (not in this PR)

- The codegen still calls deprecated `AstBuilder` methods (surfaced by `disable_old_builder`); they need migrating to the new builder interface (#23043) and the transitional `old_builder_ext.rs` shim removed. **CI `-D warnings` will flag these until then.**
- Optional ecosystem-fidelity fixes not covered by the fixture suite.

---

Produced with AI assistance (Claude Code); all output verified byte-identical against the 1,805-fixture differential and the crate's tests.
2026-07-01 15:31:00 +00:00
Boshen 74fb16871f refactor(react_compiler): vendor forked-react-compiler crates as in-crate modules (#23993)
## Summary

Vendors the React Compiler *core* — the 12 `react_compiler*` crates from
the MIT fork
[oxc-project/forked-react-compiler](https://github.com/oxc-project/forked-react-compiler)
@ `58d13c6` — directly into `crates/oxc_react_compiler`, one module per
upstream crate, **replacing the three crates.io `forked_react_compiler*`
dependencies**.

This lets us edit and re-sync the compiler core in-tree instead of
consuming it as published crates. The oxc↔Babel conversion boundary
(`convert_ast`, `convert_ast_reverse`, `convert_scope`, `prefilter`, …)
is unchanged.

## How

Two commits, kept separate for reviewability:

1. **Verbatim copy** — the 12 crates' `src/` trees copied unmodified
(114 files, `lib.rs` → `mod.rs`). Diff this commit against upstream to
confirm fidelity.
2. **Wire-up** — a scripted, compiler-verified path rewrite:
- each module's own `crate::` → `crate::<module>::`; sibling refs
`react_compiler_x::` → `crate::react_compiler_x::`
- `lib.rs` declares the 12 modules — `pub` (so the public API can name
types that originate in them) and `#[allow(clippy::all, dead_code,
unused)]` (kept near byte-for-byte with upstream)
- `Cargo.toml`: drop the 3 fork deps; add the externals they need
(`serde`, `serde-transcode`, `hmac-sha256`) and extend `serde_json`
features
- add `hmac-sha256` + `serde-transcode` to the workspace dependencies;
allowlist 4 vendored local-variable abbreviations in `.typos.toml`

## Verification

- `cargo test -p oxc_react_compiler`: **38 pass** (boundary smoke tests
+ vendored inline tests); codegen output byte-identical
- `cargo ck` (workspace, all-features/targets, `--locked`), clippy
(default + `dev-no-debug-assertions`), `cargo doc -D warnings`, `fmt`,
`typos`, `cargo shear`, `cargo deny` — all clean
- dependents build: `oxc_transformer --features react_compiler`,
`oxc_linter`

Behavior is unchanged — same compiler code, only module paths differ.

---
🤖 Generated with [Claude Code](https://claude.com/claude-code) —
AI-assisted, reviewed before submission (per the repo AI usage policy).
2026-07-01 12:53:57 +08:00
oxc-guard[bot] 8bf69a3076 release(crates): oxc v0.138.0 (#23934)
### 💥 BREAKING CHANGES

- 94fbacb ast: [**BREAKING**] Only export `AstBuilder` and `NONE` in
`builder` module (#23876) (overlookmotel)
- 8de5122 ecmascript: [**BREAKING**] Switch to new `AstBuilder` (#23834)
(overlookmotel)
- dc0ef38 transformer: [**BREAKING**] Switch to new `AstBuilder`
(#23831) (overlookmotel)
- 88f4455 str: [**BREAKING**] `Str` and `Ident` methods take
`&GetAllocator` (#23781) (overlookmotel)
- 36009dd allocator: [**BREAKING**] `GetAllocator::allocator` take
`&self` (#23676) (overlookmotel)
- bd74f9d allocator: [**BREAKING**] Rename `AllocatorAccessor` trait to
`GetAllocator` (#23675) (overlookmotel)

### 🚀 Features

- 326fe25 transformer_plugins: Support `typeof` `define` keys (#23605)
(Alexander Lichter)
- f2091b3 ast: Unify old and new `AstBuilder`s (#23875) (overlookmotel)
- cd1fd12 codegen: Expose `Codegen::print_string` API (#23785) (camc314)
- 785461b ast: Add custom builder methods to AST types (#23651)
(overlookmotel)
- 05d1357 ast: Add AST creation methods to AST types (#23650)
(overlookmotel)
- 2580eda str: Add `Str::from_str_in` and `Ident::from_str_in` methods
(#23767) (overlookmotel)
- 6883fcf minifier: Fold write-once falsy var to false in boolean
context (#23540) (Dunqing)
- fcbf993 allocator: Add `Vec::from_value_in` method (#23718)
(overlookmotel)
- 989ddb7 allocator: Add `Vec::from_box_in` method (#23717)
(overlookmotel)
- 9d1aa7f allocator: Improve `PartialEq` for `Vec` (#23716)
(overlookmotel)

### 🐛 Bug Fixes

- da0e5bf minifier: Don't reorder a closed-over TDZ read when inlining a
var (#23771) (Dunqing)
- 0b3021f allocator: Remove `Vec::from_box_in` (#23873) (overlookmotel)
- 0ab64ec ast: Silence deprecation warnings within files defining
deprecated `AstBuilder` methods (#23889) (overlookmotel)
- 8c07cad all: Enable `disable_old_builder` Cargo feature for `oxc_ast`
crate in tests (#23888) (overlookmotel)
- 3800f01 ast: Legacy `AstBuilder` methods take `self` not `&self`
(#23891) (overlookmotel)
- 869ac20 semantic/cfg: Connect for update exit to loop test (#23791)
(camc314)
- d3e92d5 semantic/cfg: Connect while branches from condition exit
(#23790) (camc314)
- 025045d ast: `ExportNamedDeclaration` plain builder methods return
boxed nodes (#23783) (overlookmotel)
- 7537c58 ast: Fix name of `AstBuilder` method for
`Expression::V8IntrinsicExpression` (#23766) (overlookmotel)
- 3f574f5 traverse: Fix unsoundness in `Traverse` walk functions
(#23745) (overlookmotel)
- 585760f parser: String in AST reference arena (#23721) (overlookmotel)
- 7231d55 allocator: Fix unsound lifetime extension in `Box::new_in`
(#23685) (overlookmotel)

### ⚡ Performance

- d5c916a semantic: Flatten hoisting_variables to avoid per-scope map
allocation (#23927) (Lawrence Lin)
- e71609d minifier: Bail member-expr folding before the side-effect walk
(#23924) (Lawrence Lin)
- e1f89ab minifier: Reduce string allocations folding addition (#23846)
(overlookmotel)
- 9f6ee3b isolated-declarations: Pool scope maps to avoid per-scope
alloc/rehash (#23761) (Boshen)
- 0b07c4c semantic: Avoid heap alloc for catch-clause binding ids
(#23911) (Lawrence Lin)
- c5eef8b regular_expression: Skip capturing-group pre-parse when
pattern has no `(` (#23908) (Lawrence Lin)
- b4f5b4b isolated_declarations: Remove redundant clone of formal
parameter pattern (#23912) (Lawrence Lin)
- 53d083f isolated_declarations: Use `TakeIn` not `CloneIn` (#23847)
(overlookmotel)
- 3ea9304 react_compiler: Use faster API to arena allocate strings
(#23849) (overlookmotel)
- a6d8e45 parser: Avoid span lookup for arrow expression body (#23788)
(camc314)
- e1886a0 transformer, minifier: Use `static_ident!` macro to create
static `Ident`s (#23727) (overlookmotel)
- 5527bef transformer/object-rest-spread: Reduce iteration (#23720)
(overlookmotel)
- 680ffbc transformer: Allocate AST nodes in arena directly (#23711)
(overlookmotel)
- 1c63c66 parser: Allocate AST nodes in arena directly (#23712)
(overlookmotel)
- 3855f0c minifier: Allocate AST nodes in arena directly (#23710)
(overlookmotel)
- d025887 isolated_declarations: Allocate AST nodes in arena directly
(#23709) (overlookmotel)
- 10b96c6 parser: Remove string search from parsing JSX element name
(#23713) (overlookmotel)

### 📚 Documentation

- 3d61dea all: Correct capitalization in comments (#23887)
(overlookmotel)
- aa1ad74 ast: Add `#[deprecated]` to legacy `AstBuilder` methods
(#23877) (overlookmotel)
- a4676db ast: Correct doc comment for `NONE` (#23765) (overlookmotel)
- 419ec80 syntax: Fix typo in doc comment (#23674) (overlookmotel)

### 🛡️ Security

- 3cdd18f deps: Update npm packages (#23690) (renovate[bot])

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
2026-06-29 20:11:00 +01:00
overlookmotel 3d61dea7e2 docs(all): correct capitalization in comments (#23887)
Just fix capitalization in comments.
2026-06-28 12:13:18 +00:00
overlookmotel f2091b3846 feat(ast): unify old and new AstBuilders (#23875)
Part of #23043.

Recent PRs have introduced a new `AstBuilder` type, and migrated all Oxc's crates over to it.

To allow downstream consumers to incrementally migrate from old `AstBuilder` to new one, unify the two implementations into a single `AstBuilder` type.

Remove the `builder_new` Cargo feature and instead add a new feature `disable_old_builder`. When enabled, this feature removes all the methods from `AstBuilder`, and makes `AstBuilder` non-`Copy`. Consumers should migrate, and then enable this feature to ensure later changes don't use the methods which are slated for removal.

Enable the `disable_old_builder` feature in all Oxc crates which use `AstBuilder` _in tests_. This ensures we don't go back to using the deprecated methods, while not forcing the feature on consumers (e.g. Rolldown) who use e.g. `oxc_transformer` but also use `AstBuilder` directly.
2026-06-27 20:37:38 +00:00
overlookmotel 3ea9304bd4 perf(react_compiler): use faster API to arena allocate strings (#23849)
Small perf optimization to React Compiler.

Replace `ArenaStringBuilder::from_str_in(s, self.allocator).into_str()` with `Str::from_str_in(s, self)`.

The latter is faster - `ArenaStringBuilder` is designed for building up a string from multiple parts. Here we just want to allocate a single string, so `Str::from_str_in` is faster, and simpler. Using `ArenaStringBuilder` was a weird choice. 🚨 Slop alert! 🚨

Also, return a `Str<'a>`. There's no advantage to coverting to a `&str`, and this removes having to convert _back_ to a `Str` elsewhere.
2026-06-26 19:24:28 +00:00
overlookmotel 8e31977907 refactor(react_compiler): switch to new AstBuilder (#23838)
Part of #23043. Migrate `oxc_react_compiler` over to new `AstBuilder`.
2026-06-26 18:17:32 +00:00
oxc-guard[bot] 6d56d57535 release(crates): oxc v0.137.0 (#23591)
### 💥 BREAKING CHANGES

- 7a76cd3 estree: [**BREAKING**] Make whether to include TS fields a
runtime option (#23574) (overlookmotel)
- e7b6b68 estree: [**BREAKING**] `ESTree` config use methods not consts
(#23573) (overlookmotel)

### 🚀 Features

- 556cc6d data_structures: Add `CodeBuffer::as_str` method (#23571)
(overlookmotel)
- 38c4b06 parser: Add friendly error for adjacent JSX elements (#23378)
(sapphi-red)
- 53509a8 minifier: Treeshake pure typed arrays and Set/Map array
literals (#23469) (Dunqing)
- 09762d9 minifier: Inline const value for read-only vars (#22593)
(Dunqing)

### 🐛 Bug Fixes

- 20375f9 react_compiler: Keep imports referenced only by a computed key
(#23586) (Boshen)
- 31bfd9b minifier: Keep Object introspection calls on a possible Proxy
(#23483) (Dunqing)
- 837a395 parser: Treat a line comment after ':' as leading, not
trailing (#23515) (Dunqing)
- e409fe0 minifier: Keep `new Map`/`WeakSet`/`WeakMap` with a string
argument (#23470) (Dunqing)
- ae02b4e ci/parser: Use `minimal` for vitest reporter (#23457)
(camc314)

### ⚡ Performance

- cf24329 mangler: Compile slot sort once instead of per CAPACITY
(#23577) (Boshen)
- 4058a6a parser: Reduce code bloat from verify_modifiers
monomorphization (#23576) (Boshen)
- 053b0c1 estree: Remove pointless `mem::take` (#23572) (overlookmotel)
- dfb52b6 transformer: Pre-size statement vecs in TS enum & namespace
lowering (#23516) (Yunfei He)
- 970e09a minifier: Compute template-literal inline checks in a single
pass (#23467) (Yunfei He)
- 3170c0e semantic,mangler,minifier: Fix `Semantic::stats` node count
and reuse stats in mangler builds (#23352) (Boshen)
- d1fa6e0 minifier: Evaluate ternary branches once in
minimize_conditional_expression (#23479) (Yunfei He)
- 3fa8051 transformer: Pre-size JSX props vec to attribute count
(#23466) (Yunfei He)
- 488b382 react_compiler: Borrow binding names in prefilter instead of
allocating (#23471) (Yunfei He)
- bcb3894 minifier: Incremental scoping refresh, delete
LiveUsageCollector (#23197) (Dunqing)

### 📚 Documentation

- f68641e data_structures: Improve docs on safety contract (#23575)
(overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
2026-06-18 17:31:57 +08:00
Boshen 2bac45ecc7 chore(react_compiler): bump forked_react_compiler to 0.2.0 (#23581)
Bumps `forked_react_compiler`, `forked_react_compiler_ast`, and
`forked_react_compiler_hir` from `0.1.4` to the published `0.2.0` and
adapts the OXC ↔ React Compiler AST bridge to the new API.

## API changes adapted

- **`RawNode`** — type-annotation and TS passthrough fields moved from
`Box<serde_json::Value>` to the lazily-parsed `RawNode`. Construct via
`RawNode::from_value` / `RawNode::null`; read back via `parse_value()`.
- **`StringLiteral.value`** is now a JS string type — write with
`.into()`, read with `.to_string_lossy()`.
- **`ScopeInfo`** maps now use the deterministic Fx hasher (`FxHashMap`
/ `FxIndexMap`) to match the upstream field types.
- **`PluginOptions`** no longer derives `Deserialize`; the test
constructs it typed via `default_plugin_options()`.

## Binary size (`napi/transform`)

Net **−533 KiB (−7.2%)** on the shipped binary, despite 0.2.0 pulling in
new transitive deps. Measured as the release cdylib (fat-LTO,
`--features allocator`, `aarch64-apple-darwin`, stripped); only the bump
differs between the two builds.

| Segment | Before (`main`) | After (this PR) | Δ |
|---|--:|--:|--:|
| **Total file** | 7,554,352 B | 7,008,592 B | **−545,760 B (−7.2%)** |
| `__TEXT` (code) | 7,274,496 B | 6,750,208 B | −524,288 B |
| `__DATA_CONST` | 163,840 B | 147,456 B | −16,384 B |
| `__LINKEDIT` | 98,304 B | 81,920 B | −16,384 B |

Almost all of it is `__TEXT` — likely the eager `serde_json::Value`
machinery dropped in favor of `RawNode`'s lazily-parsed raw JSON.

## Verification

- `cargo test -p oxc_react_compiler` — 17 passed
- `cargo check -p oxc_linter` and `cargo check -p oxc_transformer
--features react_compiler` — both clean

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-18 13:43:31 +08:00
oxc-guard[bot] 827248a7fb release(crates): oxc v0.136.0 (#23443)
### 💥 BREAKING CHANGES

- 7a24911 codegen: [**BREAKING**] Borrow sourcemaps from codegen
(#23422) (Boshen)
- bb0ed44 transformer: [**BREAKING**] Disable styled-components
transpileTemplateLiterals by default (#23171) (Boshen)

### 🚀 Features

- 1490a0a linter/react: Implement react-compiler rule (#23202) (Boshen)
- 6c0bdf0 transformer/react-refresh: Support `module.property.useHook()`
(#23190) (Dunqing)
- 47991bd semantic: Report TS1228 for invalid type predicates (#23174)
(camc314)
- 1d3af58 parser: Add TS2398 parameter property diagnostic (#23216)
(camc314)
- 44313da semantic: Add `scope_is_descendant_of` api (#22313) (camc314)
- e5050c0 parser: Improve diagnostic for rest initializer (#23205)
(camc314)
- ec266bb transformer: Run React Compiler as a feature-gated transform
pass (#23201) (Boshen)
- e7374fe parser: Report error for `const` modifier on interface type
parameter (#23173) (camc314)
- a7c1c9b parser: Report ambient definite variable assertions (#23165)
(camc314)
- d169fcd parser: Report invalid class definite assertions (#23164)
(camc314)
- 00244d8 parser: Report definite property initializer errors (#23160)
(camc314)

### 🐛 Bug Fixes

- 52d0c31 transformer: Replace ambient dot defines (#23231) (camc314)
- 2c28748 transformer/class: Parent generated constructors to class
scope (#23222) (camc314)
- 8edd234 parser: Report accessor definite assertion on token (#23203)
(camc314)
- de38a3f react_compiler: Keep imports referenced only by a local
re-export (#23176) (Boshen)
- f5721c2 codegen: Preserve parentheses around `intrinsic` type
reference (#23156) (Boshen)
- e89f81d parser: Don't emit TS1477 for parenthesized instantiation
expression (#23147) (Boshen)
- 8a04149 parser: Reject module-referencing imports/exports in a
namespace body (#22829) (Boshen)

### ⚡ Performance

- 2783295 parser: Table-driven operator precedence lookup (#23346)
(Boshen)
- 231d5de parser: Single-match member expression dispatch (#23347)
(Boshen)
- e89729b codegen: Accept one-shot wrap closures (#23265) (camc314)
- a6c11fa parser: Force-inline read_non_decimal to fold per-digit number
dispatch (#23157) (Boshen)
- d74964c parser: Store class definite assertion offset (#23170)
(camc314)
- f0fda4d parser: Shrink-wrap cold diagnostic tails out of hot frames
(#23159) (Boshen)
- a082180 parser: Store definite assertion offset (#23167) (camc314)
- 534f9c6 oxc: Conditionally rebuild semantic in compiler pipeline
(#23153) (Boshen)
- b435c6a parser: Skip checkpoint for `infer T extends U` constraint in
disallow context (#23128) (Boshen)
- 7464dce parser: Peek instead of checkpoint/rewind for `export default`
modifier (#23124) (Boshen)
- 80a9a32 parser: Fast-path single-keyword TS declarations (#23083)
(Boshen)
- da1a6c6 diagnostics: Migrate to allocation-optimized oxc-miette
(#23094) (Boshen)
- b7b08ce parser: Peek once for the static modifier disambiguation
(#23079) (Boshen)
- e7e07a3 parser: Fold unary dispatch into a single match (#23076)
(Boshen)

### 📚 Documentation

- d241add semantic: Add `AGENTS.md` test guidance for agents (#23441)
(camc314)
- 026f1ae parser: Add `AGENTS.md` test guidance for agents (#23440)
(camc314)
- 09755ac transformer: Add `AGENTS.md` test guidance for agents (#23439)
(camc314)
- e6bdfd4 lexer: Correct reference link for `byte_handlers!` (#23313)
(Dunqing)
- 65b6d7a allocator: Fix memory leaks in `Arena` examples (#23257)
(overlookmotel)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
2026-06-15 20:05:34 +08:00
Boshen ec266bb733 feat(transformer): run React Compiler as a feature-gated transform pass (#23201)
## Summary

Exposes the React Compiler from `oxc_transformer` behind a Cargo feature so callers no longer need a separate `oxc_react_compiler::transform` + scoping-rebuild step before transforming.

- **`oxc_transformer`**: new `react_compiler` Cargo feature (off by default) + `TransformOptions::react_compiler` field. When set, `Transformer::build_with_scoping` runs the React Compiler first (via a private `run_react_compiler` method), replacing the program and rebuilding scoping for the downstream transforms.
- **Opt-in**: the feature is **not** enabled by `oxc_transformer`'s defaults, nor by `oxc`'s `transformer`/`full` features — enabling the transformer does not pull the heavy `oxc_react_compiler` dependency. It is a separate `react_compiler` feature on `oxc` (which implies `transformer`); the napi transform binding opts in explicitly.
- **Dedupe**: removes the inline React-Compiler orchestration (and the `react_compiler_options()` hook) from `oxc`'s `CompilerInterface` and the napi transform binding; both now drive it through `TransformOptions::react_compiler`.
- **Diagnostics**: the compiler's errors and warnings are merged into `TransformerReturn::errors` (each keeps its severity; downstream filters). `compile()` reports them but no longer aborts codegen — the transformer always leaves a valid program, matching the documented "code may still be available even if there are errors" behaviour.
- **Links**: updates the React Compiler references to the merged upstream location (`react/react/tree/main/compiler`).

## Notes

Transform/codegen output is unchanged when the feature is off (the field defaults to `None` everywhere). The diagnostics behaviour change (no codegen abort) is conformance-safe — the transform-conformance harness keys off reported diagnostics, not printed output.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-10 08:03:07 +00:00
Boshen 48c6f28c4a refactor(react_compiler): split diagnostics into errors/warnings and simplify transform API (#23168)
## What

Reworks the `oxc_react_compiler` public API:

- Renames the standalone `run` entrypoint to `transform`. It now returns a `TransformResult` instead of taking a `&mut errors` vec and rebuilding `Scoping` internally. Callers use `result.program` (`Some`/`None`) to decide whether to rebuild scoping — the `oxc::Compiler` callsite does exactly this.
- Splits `TransformResult`/`LintResult` diagnostics into separate `errors` and `warnings` (partitioned by `Severity`), and documents `errors` / `warnings` / `events`.
- Adds `#[derive(Default)]` to `TransformResult` for the bail-out paths.
- Inlines the former `transform_impl`; semantic is now built internally, after the cheap prefilter bail-outs (so non-React files skip semantic construction).
- Bumps the `forked_react_compiler` family `0.1.3` → `0.1.4`.

Example and benchmark updated to the new `transform(&program, &allocator, options)` signature.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-10 00:17:36 +08:00
oxc-guard[bot] e9b8fd595c release(crates): oxc v0.135.0 (#23117)
### 💥 BREAKING CHANGES

- ee4dc73 ast: [**BREAKING**] Add `#[non_exhaustive]` to AST nodes
(#23046) (overlookmotel)
- 4c35362 ast: [**BREAKING**] Add
`AstBuilder::template_element_escape_raw` and
`template_element_escape_raw_with_lone_surrogates` methods (#23047)
(overlookmotel)

### 🚀 Features

- b846ab2 react_compiler: Integrate the Rust port of the React Compiler
(#22942) (Boshen)
- 5b8dd68 parser: Report TS1255 for invalid class definite assertions
(#22917) (camc314)
- 85efabf semantic: Make building the class table optional, off by
default (#22862) (Boshen)

### 🐛 Bug Fixes

- 556acdc codegen: Parenthesize TS-cast assignment targets (#23112)
(Boshen)
- 37169ff codegen: Don't emit space between postfix `--` and `>` when
minifying (#23036) (Boshen)
- a4b1bf7 codegen: Drop redundant whitespace in minified TypeScript
output (#23038) (Boshen)
- cf53285 parser: Report reserved type-declaration names in the parser
(#23035) (Boshen)
- 4e44969 ast: Fix UB in `escape_template_element_raw` (#23052)
(overlookmotel)
- c543154 parser: Report comma operator in JSX expression in the parser
(#23030) (Boshen)
- 325c94f codegen: Tighten conditional-type and constructor-type
whitespace when minifying (#23033) (Boshen)
- 95dd3a2 parser: Report `import type` alias to a non-external reference
in the parser (#23032) (Boshen)
- 90180b8 codegen: Drop space after `:` in function return type when
minifying (#23028) (Boshen)
- 6da876e parser: Report `abstract` private class field in the parser
(#23029) (Boshen)
- 28467ce codegen: Don't emit space before a postfix update operand when
minifying (#23027) (Boshen)
- cb29926 codegen: Drop redundant space after `export default` when
minifying (#23024) (Boshen)
- 62965ae codegen: Drop redundant space after `else` when minifying
(#23025) (Boshen)
- 989230a parser: Report compound assignment to non-simple target in the
parser (#23022) (Boshen)
- 06f367c parser: Report `super.#field` private access in the parser
(#23014) (Boshen)
- 184edef codegen: Print space before `const`/`declare` enum modifier
(#23013) (Boshen)
- 4d722e0 parser: Report duplicate switch `default` clause in the parser
(#23012) (Boshen)
- 597ed85 codegen: Parenthesize `let`/`async` for-of head target
(#23008) (Boshen)
- 8b631bf codegen: Remove stray space before mapped type value colon
(#23010) (Boshen)
- c08407e codegen: Don't over-parenthesize `in` inside an arrow in a
for-init (#23009) (Boshen)
- 600cd6f codegen: Parenthesize lower-precedence
`TSInstantiationExpression` operand (#23007) (Boshen)
- 187e1a5 codegen: Don't leak space after comment-only JSX expression
container (#23006) (Boshen)
- 294c473 codegen: Don't over-parenthesize `TSTypeAssertion` operand
(#23004) (Boshen)
- 786d96f codegen: Give `TSTypeAssertion` unary precedence (#23002)
(Boshen)
- 1295882 parser: Report `new.target` and `import.meta` syntax errors in
the parser (#23003) (Boshen)
- d727b6b codegen: Parenthesize `await` expression as base of `**`
(#23001) (Boshen)
- 67dfa08 codegen: Keep parentheses around `new` callees containing a
call (#22997) (Boshen)
- 17e7cf3 parser: Disallow unerasable `as`/`satisfies` assertions
(#22986) (Boshen)
- beb46d3 parser: Commit to module goal on decorated exports (#22941)
(Boshen)
- 49e63f7 isolated-declarations: Require annotations for satisfies
initializers (#22898) (camc314)
- 8c93601 isolated-declarations: Allow unknown enum initializer in
non-const enum (#22900) (camc314)

### ⚡ Performance

- 7d89909 parser: Peek instead of lookahead for yield disambiguation
(#23071) (Boshen)
- bf872f0 parser: Skip arrow lookahead for a parenthesized literal
(#23070) (Boshen)
- d19fc54 parser: Guard type-argument speculation behind an angle-token
check (#23069) (Boshen)
- 8eb5507 parser: Skip redundant member-rest re-scan on call entry
(#23068) (Boshen)
- 883dfc1 parser: Skip parse_call_expression_rest when no call follows
(#23063) (Boshen)
- b171153 parser: Peek before the await-using lookahead (#23059)
(Boshen)
- 56f21bd parser: Use peek_token for the TS `asserts` type predicate
(#23058) (Boshen)
- 68805ac parser: Use peek_token instead of checkpoint/rewind for
single-token decisions (#23056) (Boshen)
- 1f9d8eb ast: `AstBuilder::template_element_escape_raw` avoid
allocation if no escape required (#23053) (overlookmotel)
- 502b04d semantic: Move cold function redeclaration handling into
`#[cold]` function (#22973) (overlookmotel)

### 📚 Documentation

- 275d318 napi/minifier: Point `target` to oxc docs (#23102) (camc314)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
2026-06-08 22:17:46 +08:00
Boshen b846ab2d9a feat(react_compiler): integrate the Rust port of the React Compiler (#22942)
Closes https://github.com/oxc-project/oxc/issues/10048

Integrates the Rust port of the React Compiler ([facebook/react#36173](https://github.com/facebook/react/pull/36173)) into oxc.

## Notes (resolved)

- Published crates can't reference Git URLs, so using this from Rolldown needs the React Compiler crates on crates.io. ✅ Published as a fork at https://crates.io/crates/forked_react_compiler; this PR depends on those `forked_react_compiler*` crates so people can get earlier access.
- The React Compiler crates had no license field. ✅ The published fork carries `license = "MIT"` (per the React repo's MIT license), so Cargo Deny and Security Analysis pass.

## Benchmark

**Wall-clock overhead vs plain transform** (release `transformSync`, same `jsx: automatic`, toggling only `reactCompiler`):

| fixture | without | with | overhead |
| --- | --- | --- | --- |
| RadixUIAdoptionSection.jsx (2.5 KiB) | 0.03 ms | 1.81 ms | +1.8 ms |
| excalidraw `App.tsx` (406 KiB) | 4.09 ms | 14.49 ms | +10.4 ms (3.5×) |

So roughly a fixed ~1.8 ms floor per file plus a per-size cost — about **3.5× the transform time** on a large real-world component.

## Binary size

Linking the React Compiler pulls the whole compiler pipeline (HIR, lowering, inference, SSA, optimization, reactive scopes, validation) plus the oxc⇄Babel AST conversion into the binding. Release build of the napi transform addon (`transform.darwin-arm64.node`, `--release`, stripped), darwin-arm64:

| build | size |
| --- | --- |
| baseline (`main`) | 3.51 MiB |
| with React Compiler | 8.66 MiB |
| **delta** | **+5.14 MiB (+146%, 2.46×)** |
2026-06-08 13:32:56 +00:00