Latest Results
fix(es/resolver): classify bodyless fns as instantiating and seed namespace ids into the merged type scope
Address the two Codex P2 review comments (round 4), plus three defects
that an adversarial self-review found in the same machinery.
P2-1: tsc classifies every function declaration as instantiating, with
or without a body. Remove the body check from decl_is_instantiating. A
namespace whose only member is an ambient function declaration now
counts as instantiated. The hoisting pre-pass seeds its value slot, so
an earlier sibling reopen binds the namespace instead of an outer
binding. Make ts_module_is_instantiated public and delegate
TsModuleDecl::is_concrete in the strip pass to it. The resolver and the
emitter now classify namespaces identically by construction. Statement
retention of overload signatures does not change.
P2-2: seed scan.namespace_ids into the merged type table during the
hoisting pre-pass. The seed only fills vacant slots, uses the instance
mark, and records namespace ownership. The declaring body later
overwrites the slot with its body mark through the existing ownership
mechanism. A type slot that a non-namespace type declaration already
claimed stays untouched. The seed applies to erased namespaces too,
because erasure removes the value meaning and keeps the type meaning.
Self-review fixes in the same machinery:
1. Value seed: the erased-name filter kept a name erased when any
occurrence of it was a non-instantiated namespace declaration, even
when a function, class, enum, or an instantiated namespace
occurrence in the same body gave the merged symbol value meaning. A
forward value reference then fell through to an outer binding or to
an unresolved identifier. The scan now tracks value meaning per
name, in either declaration order, and a namespace declaration no
longer overwrites the declaration kind that a merged function
recorded.
2. Type seed ownership: when a later re-open declared an interface or
a type alias with a seeded namespace name, the slot kept namespace
ownership, so the namespace registration clobbered the merged slot
with its body mark and references disagreed with the type
declaration. A non-namespace type declaration seen by any re-open
now revokes namespace ownership, in either seeding order, and every
reference agrees with the merged declaration on the instance mark.
3. Bare type references: the type seed made a bare type reference
resolve into a sibling namespace. tsc gives a namespace-only symbol
no type meaning (TS2709) and resolves the reference past it to an
outer type binding. Bare type references now skip merged type slots
that only a namespace owns; the left side of a qualified name still
resolves with namespace meaning and binds them.
Verified against tsc 5.9.3 for all changes, with positive and negative
controls. Two existing tsc reference baselines change and both now match
the tsc emit: parserFunctionDeclaration7 (module M with only an overload
signature gets its IIFE) and neverReturningFunctions1 (the Debug
namespace gets its IIFE; its references were already qualified).
New fixtures: ambient-fn-namespace, declare-namespace-member,
deep-ambient-fn, and fn-ns-value-merge (strip);
namespace_reopen_ambient_fn_instantiates,
namespace_reopen_forward_type_ref, namespace_reopen_fn_ns_value_merge,
namespace_reopen_ns_iface_type_merge, and
namespace_reopen_bare_type_ref_outer (resolver).
Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>MavenRain:fix/resolver-namespace-merge fix(react-compiler): make fast check conservative (#12105)
## Description
This fixes false negatives in the existing React Compiler
`fast_check::is_required` predicate and documents its conservative
skip-gate contract.
Before this PR, `is_required` was a low-false-positive heuristic, but it
was not safe for callers that skip React Compiler when it returns
`false`. On the real v0 corpus it missed anonymous `forwardRef`
callbacks and a module using member hook calls. This PR improves the
existing method rather than adding a second public predicate, following
maintainer feedback.
The new implementation allows false positives but not false negatives:
`false` means compilation cannot change the program. It scans every
function context for JSX, actual hook calls matching React Compiler
HIR's own hook-name rule, member hook calls, and opt-in/dynamic-gating
directives in real directive prologues.
The Node `isReactCompilerRequired{,Sync}` APIs continue to call
`is_required`. Fatal and recovered parse errors return `true`, because
an unsuccessful fixed-syntax parse cannot prove that compilation is
unnecessary.
The package test command enumerates both test files explicitly so it
remains compatible with the existing Windows + Node 18 CI job.
## v0 correctness corpus
I benchmarked a fixed v0 checkout
(`1ab042a47c053bf5ddad5ffb9c6af153ce8e5b56`) on a 16-vCPU / 32-GB Vercel
DevBox:
- 1,816 tracked JS/TS source files
- 10,464,109 source bytes
- zero parser failures
- 257 modules actually transformed by the Rust React Compiler
- 67 compiler diagnostics
The harness parses the corpus once, runs detectors repeatedly, and uses
the actual compiler result as ground truth. It asserts that gated and
ungated transformed paths are identical.
| Detector | Selected files | False negatives |
| --- | ---: | ---: |
| `is_required` before this PR | 279 | 10 / 257 (3.89%) |
| Current Next.js conservative visitor | 315 | 0 / 257 |
| This PR: improved `is_required` | **302** | **0 / 257** |
The old implementation missed nine real `React.forwardRef` UI modules
and one hook module using `React.useState` / `React.useEffect`. The
improved implementation retains all 257 transforms while rejecting 13
more false positives than the current Next.js visitor.
## End-to-end compiler effect
A fresh optimized release run after applying all review feedback used
five interleaved gated/ungated samples on the exact corpus:
| Pipeline | Median | Transformed modules |
| --- | ---: | ---: |
| No gate | 2,371.956 ms | 257 |
| Improved `is_required` gate | **1,906.180 ms** | 257 |
That removes **465.776 ms / 19.64%** from the React Compiler pipeline on
the real v0 corpus without changing compiler output. The detector itself
took 20.624 ms for the full 10.46-MB corpus (mean of 100 passes).
The temporary synthetic CodSpeed benchmark was removed at review
request. The performance evidence remains the real v0 corpus with actual
compiler output as the correctness oracle.
## Review feedback incorporated
- Improved the existing `is_required` API instead of introducing
`may_require`.
- Detect hooks only at call sites and reuse React Compiler's
`is_hook_name` rule (`use` plus uppercase ASCII or a digit).
- Restrict opt-in strings to leading directive prologues using
`Stmt::can_precede_directive`.
- Treat both fatal and recovered parser errors conservatively in the
Node binding.
- Added actual-compiler regressions proving name-only and JSX-free
`React.createElement` wrapper cases do not compile.
- Removed the synthetic benchmark and changed the changeset from a minor
feature to a patch fix.
## Validation
- `cargo fmt --all -- --check`
- `cargo test -p swc_ecma_react_compiler` (107 unit tests + 15 fixtures)
- `cargo test -p binding_react_compiler_node` (14 passed)
- `cargo clippy -p swc_ecma_react_compiler -p
binding_react_compiler_node --all-targets -- -D warnings`
- `pnpm --filter @swc/react-compiler build:dev`
- `pnpm --filter @swc/react-compiler test` (8/8)
- Earlier full-PR validation: `cargo clippy --all --all-targets -- -D
warnings`; `packages/core: pnpm build:dev && pnpm test` (117 passed, 3
skipped)
- Final GPT-5.6 Sol xhigh + Claude Opus 5 xhigh autoreview panel: zero
findings, “patch is correct” (0.99 confidence)
Follow-up to
[vercel/next.js#96820](https://github.com/vercel/next.js/pull/96820). Latest Branches
0%
SyMind:codex/fix-unused-var-init-cycle 0%
MavenRain:fix/resolver-namespace-merge 0%
fix/arguments-parameter-injection-size © 2026 CodSpeed Technology