Commit Graph

220 Commits

Author SHA1 Message Date
Boshen e74de61886 fix(transform-react): match Babel diagnostic reporting (#26128)
Match Babel’s default React Compiler diagnostic reporting and severity.

AI-assisted.
2026-08-27 05:27:21 +00:00
Boshen a565a37d1d fix(react_compiler): bail out on missing identifier nodes (#26112)
Match upstream's catchable missing-identifier invariant in `PruneNonEscapingScopes`, preventing a later misleading `PreserveManualMemo` diagnostic. Adds the original-shaped named function expression regression.

AI-assisted and reviewed by the contributor.
2026-08-26 14:47:42 +00:00
Boshen a237666359 perf(react-compiler): optimize non-null propagation (#26016)
Replace tree-based property-path sets with sorted inline sets and reuse scratch storage across fixpoint passes while preserving sorted block traversal.

Fixture benchmark: React Compiler time 10.30s → 9.26s.

AI assistance was used to investigate, implement, and benchmark this change.
2026-08-24 02:15:33 +00:00
Boshen fd61cd860f perf(react-compiler): compute post-dominator frontiers together (#26010)
Compute all post-dominator frontiers in one Cytron-style pass, avoiding a reverse CFG walk for every block. Reuse the result in reactive-place inference and set-state validation.

AI usage: Codex was used to implement and validate this change; the contributor remains responsible for review before merge.
2026-08-23 10:24:35 +00:00
Boshen 88f7f587df perf(react-compiler): avoid cloning aliasing effects (#26009)
Avoid repeatedly interning and deep-cloning aliasing effects during mutation inference. Cached effects are now interpreted by reference and cloned only when persisted.

Benchmarks improve by 8–14% on representative React Compiler workloads.

AI-assisted.
2026-08-23 06:12:06 +00:00
Boshen 4b6ea23be1 perf(react-compiler): use dense identifier state (#25999)
## Summary

- replace hot function-wide `IdentifierId` hash state in reactive-place inference with dense `IndexVec` storage

AI assistance was used to implement and review these changes. The contributor remains responsible for reviewing and understanding the submitted code.
2026-08-23 03:03:24 +00:00
Boshen b1201f1c8f fix(react-compiler): support for loops without test expressions (#25990)
Support for (;;) by lowering the omitted test to true and omitting the synthetic HIR initializer during codegen.

AI assistance was used to implement and verify this change.
2026-08-22 06:24:33 +00:00
Boshen a8325ec39a perf(react-compiler): reuse instruction operands (#25991)
Reuse operand visitor results in reactive-place inference to avoid repeated traversals and temporary `Vec` allocations.
2026-08-22 06:18:50 +00:00
Boshen f2e4ab0921 perf(react-compiler): omit codegen from oxlint (#25935)
Separate React Compiler emission from lint analysis so oxlint can dead-strip compiler codegen.

This reduces the stripped oxlint binary by 145 KiB (1.21%).

AI-assisted with Codex.
2026-08-22 05:53:45 +00:00
renovate[bot] d5d575c1de chore(deps): update rust to v1.98.0 (#25945)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [rust](https://rust-lang.org/)
([source](https://redirect.github.com/rust-lang/rust),
[changelog](https://redirect.github.com/rust-lang/rust/blob/main/RELEASES.md))
| toolchain | minor | `1.97.1` → `1.98.0` |

---

### Configuration

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

- Branch creation
  - "before 10am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, 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:eyJjcmVhdGVkSW5WZXIiOiI0NC4zNS40IiwidXBkYXRlZEluVmVyIjoiNDQuMzUuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
2026-08-20 18:04:07 +00:00
Boshen 975181512c fix(react-compiler): preserve computed property access (#25933)
Closes #25918.

Supersedes #25919.
References react/react#37234.

AI-assisted.
2026-08-20 07:19:24 +00:00
Boshen 691a1f0135 refactor(react_compiler): remove unreachable JSX colon check (#25810)
Remove an unreachable React Compiler diagnostic for colons in JSX attribute identifiers. Oxc's parser represents namespaced attributes with `JSXNamespacedName`, so parser-produced identifiers cannot contain colons.

Validated with `cargo test -p oxc_react_compiler`. `just ready` passed formatting and workspace checks, but its full suite hit environment-sensitive ANSI snapshot mismatches in unrelated Oxlint CLI tests.

AI-assisted; reviewed and validated by the contributor.
2026-08-18 07:48:12 +00:00
Boshen b831ca8af9 fix(react-compiler): improve derived state diagnostic (#25804)
Improve `react/no-deriving-state-in-effects` diagnostics with labeled state updates, named reactive dependencies, and actionable render guidance. Adds fixture coverage for single and multiple dependencies.

AI assistance was used for this change.
2026-08-17 14:33:28 +00:00
Boshen 2dacf7a9b6 perf(oxlint): reduce debug formatting code size (#25797)
Use compact `Display` formatting for React Compiler terminals and reuse `ConfigBuilderError`'s existing `Display` implementation for `Debug`.

This reduces the release `oxlint` binary from 12,773,552 to 12,740,432 bytes: **-33,120 bytes (-0.26%)**, with `__text` reduced by 24,452 bytes.

Validated with the affected crate tests, workspace checks, and oxlint snapshot tests.

AI assistance was used for implementation and measurement.
2026-08-17 13:04:51 +00:00
Boshen 28c0493682 fix(react-compiler): support typed assignment targets (#25758)
Support TypeScript-wrapped assignment targets in context analysis and
HIR lowering.

AI-assisted; reviewed and validated by the contributor.
2026-08-17 17:22:29 +08:00
Boshen c41d2a569e fix(react-compiler): support bigint object keys (#25749)
BigInt object keys fell through generic unsupported-key handling. Lower
them through the exact parser-provided decimal string, preserving
alternate bases and values beyond Number precision.

Validated with `just ready`.

AI-assisted.

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
2026-08-17 17:22:28 +08:00
Boshen fd3980e91b fix(react-compiler): support escaped tagged templates (#25748)
React Compiler HIR already preserves both raw and cooked tagged-template
values, but lowering rejected templates whenever they differed. Remove
the stale bailout and cover escaped and invalid escape sequences.

Validated with `just ready`.

AI-assisted.

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
2026-08-17 17:22:28 +08:00
Boshen 885c78bb8c fix(react-compiler): validate block nesting (#25745)
Port `assertValidBlockNesting` to reject partially overlapping
program-block and reactive-scope ranges before and after scope-terminal
rewriting. Reuse the traversal when constructing scope terminals.

Validated with `just ready`.

AI-assisted.

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
2026-08-17 17:22:27 +08:00
Boshen a469a928d5 fix(react-compiler): cover incompatible aliasing signatures (#25744)
`known_incompatible` is already checked before both aliasing and legacy
signature handling, making the legacy-path TODO stale. Add
aliasing-signature coverage to guard the shared behavior.

Validated with `just ready`.

AI-assisted.

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
2026-08-17 17:22:27 +08:00
Boshen c108d5c45e fix(linter): improve React Compiler diagnostics (#25742)
Improve React Compiler diagnostics with actionable help and cause-oriented labels. Preserve-memoization and recursive-initialization diagnostics previously spanned entire callbacks; they now keep codeframes compact while refs and `try`/`finally` show related locations.

Validated with React Compiler and React linter suites, Clippy, `just ready`, and the 24-rule VS Code ecosystem audit.

AI-assisted: Codex was used to implement and validate this change. I reviewed and take responsibility for the result.
2026-08-16 14:08:22 +00:00
Boshen daf03ff25d fix(react-compiler): bail out on JSX ref property loads (#25739)
Bail out when JSX `ref` values are loaded through properties, matching React Compiler and preserving getter and live-binding evaluation semantics.

The validator previously stopped temporary tracking for every property result inferred as ref-like instead of only stopping for `ref.current`.

Validation: `cargo test -p oxc_react_compiler` and `just ready`.

AI assistance: Codex was used to investigate and prepare this change; the contributor remains responsible for reviewing it before merge.
2026-08-16 13:25:12 +00:00
Boshen 066b31bdc6 fix(react-compiler): recompile outlined JSX components (#25737)
Queue JSX-outlined components back through the normal `process_fn` pipeline, matching Babel's `Program.ts`. Oxc rebuilds immutable semantics once per FIFO generation and preserves Babel's outlined declaration order.

Validated against the React Compiler fixture suite, Babel output, and `just ready`.

AI-assisted; reviewed and validated by the contributor.
2026-08-16 13:18:57 +00:00
Boshen 28125febdb feat(react-compiler): validate identifier consistency (#25735)
Ports Babel's identifier consistency invariant using Oxc's canonical identifier arena and runs it at every equivalent pipeline point.

Validated with the React compiler fixture corpus and clippy.

AI-assisted: Codex was used to implement and verify this change.
2026-08-16 11:12:30 +00:00
Boshen fd0aeb256c feat(react-compiler): validate terminal predecessors (#25734)
Ports Babel's terminal-predecessor invariant and runs it before HIR scope dependency propagation. Keeps terminal successor traversal inline to avoid per-edge heap allocations.

AI-assisted: Codex was used to implement and verify this change.
2026-08-16 07:10:07 +00:00
Boshen 67cf673a7c feat(react-compiler): validate terminal successors (#25732)
Ports React Compiler's terminal-successor invariant and runs it after CFG-rewriting passes. Uses the existing upstream `for-return.js` fixture for regression coverage.

AI-assisted: Codex was used to implement and verify this change.
2026-08-16 06:22:41 +00:00
Boshen 33d4ed9dec fix(react-compiler): preserve unreferenced function expression names (#25733)
Preserve named function expression names when the private name is unreferenced. This matches React Compiler lowering and avoids changing observable `Function.name` values.

Validated with `just ready`.

AI-assisted.
2026-08-16 05:27:34 +00:00
Boshen c9ec55e635 fix(react-compiler): improve diagnostic spans (#25731)
Improve React Compiler diagnostics with focused primary spans and related labels for declarations, dependencies, effects, nested functions, dynamic Hooks, and transitive ref access. This avoids full-function highlights and fixes zero-width arrow labels when lowered parameter spans are missing.

Validation: `env -u NO_COLOR just ready`.

AI-generated with Codex; reviewed and validated by the contributor.
2026-08-16 03:22:59 +00:00
Boshen 4e591ed4ed fix(react_compiler): support destructured context parameters (#25724)
Fix destructured function and rest parameters that become context variables by lowering them through temporaries before `StoreContext`. This avoids inconsistent `Destructure`/context HIR and compiles supported components correctly.

Validated with `just ready` and runtime equivalence checks against React 19.2.1's compiler runtime.

AI usage: Implemented with assistance from OpenAI Codex.
2026-08-16 03:04:17 +00:00
Boshen 8c4552dfa6 feat(linter)!: split react/react-compiler into per-category rules (#25500)
Splits the experimental `react/react-compiler` rule into 24 category-specific rules matching `eslint-plugin-react-hooks` v7.

- Runs React Compiler once per file and routes structured diagnostics to each enabled rule.
- Removes `react/react-compiler` and `reportAllBailouts`, with rules categorized by user-facing lint intent.
- Adds per-rule documentation and deduplicates shared React lint URLs.
- Preserves standardized compiler diagnostics while reporting each finding under its Oxlint rule name.

Breaking change: configurations using `react/react-compiler` must migrate to the category-specific rules.

Written with Claude Code and Codex.
2026-08-15 14:56:58 +00:00
Boshen dec0a86412 fix(react-compiler): standardize diagnostics (#25702)
Standardize React Compiler diagnostics with concise titles, primary labels, actionable help, notes, structured categories, and official guidance links.

Preserve React guidance when diagnostics are surfaced through Oxlint, and refresh affected snapshots.

AI-assisted; reviewed and validated by the contributor.
2026-08-15 13:31:34 +00:00
Boshen ad963b689d refactor(react_compiler): centralize diagnostics (#25699)
Centralizes React compiler diagnostics in explicit `#[cold]` functions and removes the `[ReactCompiler]` prefix, keeping diagnostic formatting off hot paths. Updates related NAPI expectations.

AI assistance was used.
2026-08-15 05:57:29 +00:00
Boshen 48e917fcba fix(react-compiler): preserve tagged template runtime semantics (#25678)
Preserve tagged-template call, aliasing, and mutation effects instead of assuming no-substitution tags are primitive or pure.

Execute opaque or effectful tags unconditionally while retaining memoization only when a configured signature proves a read-only pure call and safe return.

AI-assisted investigation and implementation; reviewed and understood by the contributor.
2026-08-15 05:12:06 +00:00
Boshen b0e6c2574c fix(react-compiler): match upstream inline enum handling (#25672)
Preserve inline TypeScript enums as opaque pass-through HIR nodes, matching upstream React Compiler behavior. Apply Oxc-specific raw AST reference renaming, and skip compilation when passthrough would hide nested captures or flatten block-local bindings.

AI-assisted: Codex was used to implement and validate this change.
2026-08-15 03:45:50 +00:00
Boshen c5f188a608 fix(react-compiler): use Babel v1 validation defaults (#25676)
Match the public validation defaults from babel-plugin-react-compiler 1.0 while retaining explicit opt-in for newer validations.

Validated with fixture snapshots and `just ready`.

AI-assisted investigation and implementation; reviewed and understood by the contributor.
2026-08-15 01:52:58 +00:00
Boshen e76632d9a0 fix(react_compiler): lower lowercase JSX tags as strings (#25667)
React Compiler's JSX reconstruction preserved the HIR identifier expression kind, causing compiler-generated lowercase aliases such as `navTitle` to lower as variable references. Classify reconstructed tags by their emitted JSX spelling while preserving underscore-prefixed component references.

Validation: `cargo test -p oxc_react_compiler`, `cargo clippy -p oxc_react_compiler --all-targets -- -D warnings`, and the transform-react NAPI suite.

AI assistance: OpenAI Codex was used to investigate, implement, and validate this change.
2026-08-14 13:53:59 +00:00
Boshen ce35d47499 fix(react_compiler): preserve JSX import source pragmas (#25592)
Anchor React Compiler-generated imports before the first source statement so downstream JSX transforms continue to read leading `@jsxImportSource` pragmas.

Validated with `just ready` and the transform-react binding suite. AI-assisted; the author remains responsible for review.
2026-08-14 05:37:11 +00:00
Boshen ecab5f7d2b fix(react-compiler): remove redundant compound assignment expressions (#25642)
Removes synthetic expression statements emitted after captured compound assignments when their value is unused. The lowering-created context load is tagged so analysis retains it, while codegen can omit it after the lvalue is pruned. Consumed assignment results are preserved.

Validated with `env -u NO_COLOR just ready`.

AI assistance: Codex was used to investigate, implement, and validate this change.
2026-08-14 05:25:06 +00:00
Boshen d68059a2d8 fix(react_compiler): retry after caught throws (#25641)
Retain exception-handler edges for value-block stores so caught throws do not commit the input/result memo entry. This preserves retries for identical inputs after a transient throw.

Adds a sequential-render evaluator fixture covering throw-once behavior.

Validated with `env -u NO_COLOR just ready` and a Sprout runtime comparison.

AI assistance was used to investigate and implement this change.
2026-08-14 05:02:31 +00:00
Boshen 0eac5a0373 fix(react_compiler): preserve caught throw semantics (#25593)
Preserve potentially throwing operations inside try/catch when dead-code elimination would otherwise remove their unused results. Share the throw classifier with try-edge pruning, retain caught destructuring, and use safe root dependencies without hoisting throwing operations outside their handlers.

This preserves source runtime behavior for property and computed reads, coercions, destructuring, computed keys, and spreads. Latest React Compiler currently has the same DCE divergence, so this follows JavaScript semantics rather than its incorrect output.

Validated with `just ready` and React Compiler’s Sprout evaluator.

AI assistance was used to investigate and implement this change.
2026-08-13 15:54:06 +00:00
Boshen 721a8eaced fix(react_compiler): preserve Symbol identity (#25597)
Model `Symbol()` as identity-bearing so escaping symbols are memoized, matching Babel. The regression came from registering `Symbol` with copy-like primitive globals while allowing capitalized built-in calls.

Validation: `cargo test -p oxc_react_compiler`; Babel output comparison; runtime identity check. `just ready` is blocked by three unrelated ANSI-sensitive Oxlint snapshot mismatches in this environment.

AI-assisted: Codex was used to investigate, implement, verify, and prepare this PR.
2026-08-13 13:44:56 +00:00
Boshen a2259b8e75 fix(react-compiler): scope forwardRef discovery context (#25591)
Scopes `forwardRef`/`memo` discovery context to the direct callback so nested helpers are not incorrectly compiled with stale caches. Adds regression coverage for arrow and function callbacks.

Validated with `just ready`.

AI-assisted.
2026-08-13 13:26:28 +00:00
Boshen 78bf14f4f8 fix(react_compiler): insert outlined functions as siblings at any nesting depth (#25548)
Closes #25536

## Problem

With `enableFunctionOutlining` (default on), the compiler outlines function expressions whose lowered **context** is empty. Context only counts variables captured from scopes inside the function being compiled — a free variable of the whole compiled function (e.g. a binding of an *enclosing* function) is modeled as a plain global load/store in HIR, so a callback referencing one still gets outlined. Correctness then depends entirely on where the outlined declaration is inserted: upstream uses Babel `originalFn.insertAfter(...)`, which splices into the statement list containing the original at **any nesting depth**, preserving the invariant that every name visible to the original is visible at its sibling position.

`ox_insert_outlined_after` searched only `program.body`. For a component declared inside another function, the search missed and the fallback appended the outlined declaration at module scope:

```js
export function makeProbe() {
  let mounts = 0;
  function MountCounter() {
    useEffect(() => { mounts += 1; }, []);
    return null;
  }
  return { MountCounter, read: () => mounts };
}
```

compiled to

```js
export function makeProbe() { /* ... useEffect(_temp, t0) ... */ }
function _temp() {
  mounts = mounts + 1; // ReferenceError: mounts is not defined
}
```

with no diagnostic — a silent miscompilation that only fails when the effect fires.

A second instance of the same shape: gating ran before outlined insertion. The gating rewrite replaces the declaration statement with a `const`, destroying the scope-id anchor, so gated components' outlined functions always fell to the end-of-program fallback (upstream inserts them during the compile-queue loop, before any replacement, so they land right after the gated `const`).

## Fix

- `ox_insert_outlined_after` locates the declaring statement through a new `InsertOutlinedAfter` mode on the shared `OxcVisitor`, scanning each statement list before descending into it. Top-level originals (the common case) cost the same as before — the target is found in the first list scanned with no descent — and the walk prunes itself once insertion happens. Matching by `scope_id` cell stays sound because `ox_replace_function` mutates originals in place and discovery skips compiled bodies, so the anchor statement is always original AST. The top-level append survives only as a fallback for sloppy-mode annex-B positions (`if (c) function F() {}`).
- Outlined insertion now runs before `ox_apply_gated_conditional`, restoring upstream's sequencing.

Arrow/function-expression originals still append at module scope: upstream does the same (`program.pushContainer('body', ...)`) — including for nested originals, where upstream's own output breaks the same way — and the port reproduces upstream behavior rather than diverging (now documented in the placement comment).

Placement in all three added fixtures (nested declaration = the issue repro, nested block, gating + outlining) is byte-identical to `babel-plugin-react-compiler` built from react @ 22e4f993c7 with matching options; the existing 1310 fixture snapshots are unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-12 14:31:36 +00:00
Boshen e3c6c4e739 fix(react-compiler): initialize named function expression bindings (#25515)
Treat a named function expression’s private name as a function-entry binding through HIR, SSA, and alias analysis. This prevents self-references from reaching mutation inference uninitialized and adds fixture coverage.

Closes #23752.

Validated with targeted compiler and linter checks, workspace checking, and linting.

AI-assisted.
2026-08-12 07:38:16 +00:00
Marius Schulz 60eb24062a perf(react_compiler): share codegen temporaries by reference (#24806)
## Context

The reactive-function codegen keeps a map of compiler temporaries and
snapshots that map whenever it enters a block, a memoization scope or a
nested function, restoring it on the way out. Each snapshot deep-cloned
every value collected so far into the arena, so the cost grew with the
number of blocks times the size of the accumulated trees. That's cheap
on small components and expensive on large ones with a lot of JSX.

## This PR

Store the temporaries as arena-allocated `&OxValue` references instead
of owned values. Entries are only ever replaced, never mutated in place,
and the one place that reads a temporary (`ox_codegen_place`) already
clones the node into the arena. So a snapshot is now just a copy of the
map's references, `ox_clone_temporaries` goes away, and the emitted
program is unchanged.

### Performance

The effect scales with component size, so it barely shows on typical
open-source apps (their largest components compile in tens of
milliseconds) and grows on very large components. Two views:

**Size-scaling probe** (reproducible): one function component with N
repeated JSX sections, compiled on `main` vs this branch:

| Sections | Source size | main | this branch | Ratio |
| ---: | ---: | ---: | ---: | ---: |
| 25 | 17 KB | 26 ms | 17 ms | 1.51x |
| 50 | 33 KB | 83 ms | 50 ms | 1.66x |
| 100 | 66 KB | 327 ms | 188 ms | 1.74x |
| 200 | 133 KB | 1,663 ms | 1,096 ms | 1.52x |
| 400 | 267 KB | 7,952 ms | 5,692 ms | 1.40x |

Compile time still grows super-linearly with size on both sides: on
`main` the remaining hot pass for large components is
`infer_reactive_scope_variables`, which this change does not touch.

<details><summary>Probe generator (Node)</summary>

```js
// node gen_scaling.mjs <N> > Big.tsx
const N = Number(process.argv[2]);
const header = `import { useState } from "react";
declare const Child: any;
declare const Footer: any;
declare function cx(...args: any[]): string;
declare function format(v: number): string;

export default function Big({ data, flag, onSelect, onDone }: any) {
  const [count, setCount] = useState(0);
  return (
    <div className="root" onClick={() => setCount(count + 1)}>
`;
const section = (i) => `      <section key="s${i}" className={cx("s${i}", flag ? "on" : "off")} onClick={() => onSelect(${i}, data.items[${i}])}>
        <h2 title={data.titles[${i}]}>
          {data.titles[${i}]} - {count + ${i}}
        </h2>
        {flag && <p className="note">{data.notes[${i}]}</p>}
        <ul>
          {data.items.map((it: any) => (
            <li key={it.id} data-idx={${i}}>
              {it.label} {format(it.value * ${i})}
            </li>
          ))}
        </ul>
        <Child a={data.a} b={{ x: ${i}, y: data.y, nested: { k: "k${i}" } }} onDone={() => onDone(${i}, data.a)} />
        <Footer id={${i}} label={\`row-${i}\`} total={data.total + ${i}} />
      </section>
`;
const footer = `    </div>
  );
}
`;
let body = "";
for (let i = 0; i < N; i++) body += section(i);
process.stdout.write(header + body + footer);
```
</details>

This PR was assisted by Claude Code.
2026-08-12 14:54:34 +08:00
Boshen 9f63f86f6a fix(react-compiler): handle tagged template hooks (#25525)
Fix tagged template hooks so they are validated and treated like hook calls, including unconditional execution across renders.

Closes #24473.

AI-assisted: Codex was used to investigate and implement this change. I reviewed and take responsibility for it.
2026-08-12 05:03:16 +00:00
Boshen 0bd116abe9 fix(react_compiler): handle local self-references in memo deps (#25524)
Fixes #25049.

Register `DeclareContext` bindings as locals before analyzing nested functions so local self-references are not treated as missing memo dependencies. Skip exhaustive dependency validation when both modes are disabled.

Validation: `just ready`

AI assistance was used to investigate and implement this change.
2026-08-12 04:41:18 +00:00
Boshen 4df5835fc3 fix(linter): allow capitalized built-in calls (#25516)
Fixes #24405.

The React Compiler global registry omitted `BigInt` and `Symbol`, causing `CapitalizedCalls` false positives. Register both primitives and expose the upstream-compatible `environment.validateNoCapitalizedCalls` option.

Validated with `just ready`.

AI-assisted: Codex was used to investigate and implement this change.
2026-08-12 03:51:52 +00:00
Boshen f76aad4b59 fix(react_compiler): allow callback ref member expressions (#25517)
Prevent JSX callback-ref member expressions from marking their receiver as a React ref. Add a compiler fixture covering the regression.

Fixes #23753.

Validated with `just ready`.

AI assistance was used to prepare this change.
2026-08-12 03:45:30 +00:00
Boshen d5140f192e fix(react_compiler): support computed string destructuring keys (#25513)
Normalize computed string-literal destructuring keys before React Compiler HIR lowering so aliased bindings are initialized correctly.

Fixes #23750.

AI assistance: Codex was used to investigate, implement, and validate this change.
2026-08-12 02:53:19 +00:00
Boshen 9d49d279fd fix(react_compiler): bail out instead of panicking on "Expected a node for all scopes" (#25506)
## Summary

`oxlint` with `react/react-compiler` enabled aborted the whole process with

```
panicked at .../prune_non_escaping_scopes.rs:
Expected a node for all scopes
```

on inputs like:

```ts
export const Component = () => {
  const raw = useValue();
  return (() => {
    try {
      return check(raw) ? raw : null;
    } catch {
      return null;
    }
  })();
};
```

## Root cause

Running the same input through the version-matched `babel-plugin-react-compiler` fails the **identical invariant** (still present at facebook/react HEAD), so the analysis inconsistency is an upstream bug the port reproduces faithfully:

- IIFE inlining turns both inner `return`s into reassignments of a temporary, and scope alignment widens the `check(raw)` scope over the try/catch, so `visit_scope` associates the temporary with that scope;
- the scope's only own declarations sit in the ternary *test*, which `computeMemoizationInputs` deliberately never descends into ("Conditionals do not alias their test value"), so `visit_operand` — the only place scope nodes are registered — never fires for it;
- when the escaping temporary is memoized, `force_memoize_scope_dependencies` looks up the unregistered scope and fails the invariant.

The port's actual defect is the error channel: upstream raises a *catchable* `CompilerError`, so with `panicThreshold: 'none'` (what linting uses) the function is silently skipped and the rest of the file proceeds. The port had written this invariant as `.expect()`, turning the per-function bail-out into a process abort.

## Fix

- `compute_memoized_identifiers` and its recursive helpers now return `Result`; the invariant becomes `Err(ErrorCategory::Invariant.diagnostic(...))` and flows through the existing per-function `handle_error` / `panic_threshold` path — the same observable behavior as Babel (function skipped, everything else still compiles/lints).
- The `react/react-compiler` rule now drops `Invariant`-category diagnostics unless `reportAllBailouts` is enabled, matching the eslint plugin where the `invariant` rule is `preset: Off` ("only meant for the compiler team's consumption"); without this, the fix would have replaced the crash with a spurious error-level report on valid code. `ErrorCategory` is now exported from `oxc_react_compiler` for this check.
- New fixture `error.bug-prune-non-escaping-scopes-iife-try-catch-ternary.js` (upstream's `error.bug-*` convention for known compiler bugs) plus rule tests covering both configs.

With the rule enabled, `oxlint` on the repro now exits cleanly with no report — identical to ESLint on the same input.

## Also fixes #24842

The rule-side filter resolves #24842 as well: `react/react-compiler` reported `Invariant: Expected a variable declaration` on a `for` loop without a variable-declaration initializer (`for (; i < 3; i++)`). Same pattern, different stage: that invariant fires in `codegenForInit` and already flowed through the catchable `Err` channel, so it surfaced as a spurious error report rather than a panic. It too reproduces upstream faithfully — the version-matched `babel-plugin-react-compiler` fails the identical invariant (`Got ExpressionStatement`) and upstream's own `error.todo-kitchensink` fixture expects it; by default Babel silently skips the function and ESLint reports nothing. The #24842 repro is added to the rule tests (clean by default, surfaced under `reportAllBailouts`).

## Relation to #25347

#25347 diagnosed this accurately (thanks @controversial!) but fixes it by registering scope nodes eagerly so compilation succeeds and emits memoized output. That would make oxc compile an input every upstream compiler version refuses to compile, producing memoization decisions with no upstream validation, exactly where upstream's invariant declares its internal model inconsistent — a wrong scope association would then surface as a missed invalidation (stale UI) instead of a crash, and the pass would permanently diverge from upstream for future syncs. The behavioral fix belongs upstream in facebook/react; this PR restores upstream's bail-out semantics so oxlint no longer crashes, and the port will inherit the upstream fix when it lands.

Closes #24710
Closes #24842
Closes #25347

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-11 16:40:36 +00:00