Commit Graph

10 Commits

Author SHA1 Message Date
Boshen 5d8ccf510b fix(react_compiler): preserve nonfatal diagnostics (#25066)
Preserves nonfatal React Compiler diagnostics and covers warning bailouts through the N-API binding.

AI-assisted.
2026-07-29 13:09:20 +00:00
Boshen 6427542c8d refactor(react_compiler): split public API into compile + in-place CompileOutput::transform (#24401)
Splits `oxc_react_compiler`'s public API into two phases so the transform rewrites the caller's program in place instead of returning a whole-program clone:

- `compile(&Program, &Semantic, &Allocator, PluginOptions) -> (Option<CompileOutput>, Diagnostics)` — read-only; `None` means no changes (or error / lint output mode).
- `CompileOutput::transform(self, &mut Program, &Allocator)` — substitutes the compiled functions into the program in place. `CompileOutput` owns only arena data (replacements + `ProgramContext`), so the caller drops its `Semantic` between the two calls, releasing the shared borrow that previously forced `ox_splice_program` to `clone_in_with_semantic_ids` the entire program.
- `lint` is unchanged and structurally never runs the transform phase; the oxlint rule needed no changes.

The old `transform` free function and `TransformResult` are removed; `oxc_transformer` no longer does the `*program = result.program.take()` swap and just applies the output to its `&mut Program`.

The 1806-fixture snapshot corpus is byte-identical, and the transform path drops one whole-program clone per compiled file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-12 14:35:19 +00:00
Boshen 1fff15c499 refactor(react_compiler): borrow semantic in compile pipeline (#24063)
Borrow existing semantic data and caller allocator in React Compiler transform/lint paths to avoid hidden rebuild/allocation work.

Transform now returns the compiled program so callers can install it after the semantic borrow ends.

AI-assisted.
2026-07-02 10:17:42 +00:00
Boshen 579f025c7c refactor(react_compiler): trim PluginOptions and remove timing instrumentation (#24042)
Slims down `oxc_react_compiler`'s `PluginOptions` and removes the now-dead timing infrastructure. Four related cleanups:

### Remove `source_code` from `PluginOptions`
It was redundant — `compile` in `lib.rs` always overwrote it with `program.source_text`, and no caller set it. The one consumer (`ProgramContext::new` in `program.rs`) now reads `program.source_text` directly (the oxc `Program` is already in scope there), and the threading block in `lib.rs` is gone.

### `default_plugin_options()` → `impl Default for PluginOptions`
Converted the free function into a manual `Default` impl (the defaults are non-trivial: `should_compile: true`, `target: "19"`, `flow_suppressions: true`, …). All callers now use `PluginOptions::default()`.

### Remove `profiling`
The field was always `false` in practice (no caller set it). Its sole consumer now passes `TimingData::new(false)` — which leads into…

### Remove the timing instrumentation entirely
With `profiling` gone, timing was pure, always-disabled instrumentation: every `context.timing.start/stop` was a no-op and the collected `Vec<TimingEntry>` was always empty and never read (`lib.rs` destructures `CompileResult` with `..`). Removed:
- `timing.rs` (the `TimingData`/`TimingEntry` module) and its `mod` declaration
- ~218 `context.timing.start/stop(...)` calls across `pipeline.rs`
- the `timing` field on `ProgramContext` and on both `CompileResult` variants, plus all initializers

### Verification
- `oxc_react_compiler`: builds, 15/15 tests pass.
- `oxc_linter`: `react_compiler` rule snapshot test passes — **snapshot unchanged** (diagnostics identical).
- `oxc_transformer` react_compiler integration: 2/2 pass; `oxc_benchmark` bench compiles.
- rustc warnings, clippy (`dev-no-debug-assertions`), and `cargo shear` all clean.
2026-07-02 06:21:54 +00:00
Boshen 81101e7749 refactor(react_compiler): transform takes &mut Program, lint takes &Program (#23995)
## Summary

`transform` now rewrites the program **in place** instead of returning a
new one, and `lint` stays **read-only** — aligning with how the rest of
the oxc transform pipeline mutates the AST.

- `transform(program: &mut Program, allocator, options)` writes the
memoized AST back into `program`. `TransformResult` drops its `program:
Option<Program>` field (and lifetime) and gains `changed: bool`.
- `lint(program: &Program, options)` is unchanged — borrowed, read-only.
- Both share a private `compile(&Program) -> (Option<Program>,
Diagnostics, Vec<LoggerEvent>)` pipeline. Keeping the semantic borrow
contained in that call is what lets `transform` do `*program = compiled`
afterwards — `SemanticBuilder::build` takes `&'a Program<'a>`, so an
inlined build would pin the borrow for the whole arena and block the
write.
- `transform_source` now returns `(Program, TransformResult)`.

## Callers updated

- `oxc_transformer::run_react_compiler` — the `*program = compiled` it
used to do now lives inside `transform`; it just checks `result.changed`
before rebuilding scoping.
- `examples/react_compiler.rs`,
`tasks/benchmark/benches/react_compiler.rs` — pass `&mut program`, gate
output on `result.changed`.
- lib.rs smoke tests — `transform_source(...).program.expect(...)` →
destructure `(program, result)` + `assert!(result.changed, ...)`.

## Verification

- `cargo test -p oxc_react_compiler` (38) and `oxc_transformer
--features react_compiler` (9) pass
- `cargo ck` (workspace, all-features/all-targets, `--locked`), clippy
(`dev-no-debug-assertions`), `cargo fmt --check` — clean
- `oxc_linter` (uses `lint`), benchmark target, and example all build

---
🤖 Generated with [Claude Code](https://claude.com/claude-code) —
AI-assisted, reviewed before submission (per the repo AI usage policy).
2026-07-01 13:44:21 +08:00
Boshen 777f02ae10 refactor(diagnostics)!: return a Diagnostics type instead of Vec<OxcDiagnostic> (#23217)
## Summary

Introduces `oxc_diagnostics::Diagnostics` — a `Vec<OxcDiagnostic>` newtype that knows the difference between errors and warnings — and makes it the standard diagnostics return value across oxc.

- **New type**: `Diagnostics` with `has_errors()`, `has_warnings()`, `errors()`, `warnings()`, plus `Vec`-like ergonomics (Deref, `IntoIterator`, `Extend`, `From`/`Into<Vec>`) so most call sites are unchanged.
- **Return types**: `ParserReturn`, `SemanticBuilderReturn`, `IsolatedDeclarationsReturn`, the React Compiler `TransformResult`/`LintResult`, and `TransformerReturn` now expose `diagnostics: Diagnostics` instead of `errors: Vec<OxcDiagnostic>` (the React Compiler's separate `errors`/`warnings` are merged into one severity-tagged list).
- **Behaviour**: a React Compiler **error** now stops the transform (no output), while **warnings** flow through and the transform continues. `compile()` aborts codegen only when `diagnostics.has_errors()` — warnings alone no longer abort (previously any diagnostic did).

## Breaking change

Consumers reading `*.errors` on these return values must read `*.diagnostics`. React Compiler consumers that read `.errors`/`.warnings` separately should use `diagnostics.has_errors()` / `diagnostics.errors()` / `diagnostics.warnings()`.

Parser/semantic/isolated-declarations fatality is otherwise unchanged. Builds on the React Compiler transform feature (#23201).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-10 14:46:52 +00: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
Boshen 1260f03b4f refactor(semantic): don't build the AstNodes store by default (#23005)
## What

Make the full `AstNodes` store **opt-in**, so the compiler pipeline (transformer / codegen / minifier) can run semantic analysis without building it at all.

Previously every `SemanticBuilder` run allocated and populated the full `AstNodes` store, even for consumers that only need scoping + the syntax checker. This separates the node-related builder state into three independent pieces:

- a standalone `NodeId` counter — the source of truth for node ids, valid in either mode;
- an **ancestry stack** — an upward-walk-only stack of the current node's ancestors, the only ancestry the syntax checker and binder actually read;
- the full **`AstNodes`** store — random access to every node, needed by the linter and mangler.

## How

- A new `AstNodeStore` (in `crates/oxc_semantic/src/node/store.rs`) bundles the node-id counter, the current-node cursor/flags, and the storage. The storage is an enum (`AstNodeStoreKind`) with two variants — `Full(AstNodes)` and `Ancestry(AncestryStack)` — so the full store and the ancestry stack are **mutually exclusive by construction**; they can never both be maintained at once.
- The checker and binder read ancestry through an `Ancestry` view (`node/ancestry.rs`) that dispatches between the full store (linter / mangler) and the stack (compiler pipeline). They no longer do random `NodeId` access into the store — all ancestry access is upward-walk-only.
- `SemanticBuilder` gains `with_build_nodes(bool)`. The default is **off** (ancestry stack only). `new_linter()` turns it on (the linter needs the full store); `new_compiler()` leaves it off.
- `CompilerInterface::build_semantic_nodes()` lets `oxc::Compiler` consumers opt back in if their `after_semantic` hook reads `Semantic::nodes`.

## Notes

- Behaviour-neutral: semantic conformance snapshots are unchanged.
- Allocation snapshots updated — the default (ancestry) path allocates slightly less (the growing `Stack` trades a couple of fixed allocations for a few reallocs).
- Builds on the already-merged `SymbolFlags`-based redeclaration checks (#23060) and the `new_linter`/`new_compiler` preset adoption (#23057), which removed the last random node reads from the redeclaration path so the checker works without the store.
2026-06-08 16:13:56 +00: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