compiler/CLAUDE.md MARKDOWN 277 lines View on github.com → Search inside
1# React Compiler Knowledge Base23This document contains knowledge about the React Compiler gathered during development sessions. It serves as a reference for understanding the codebase architecture and key concepts.45## Project Structure67When modifying the compiler, you MUST read the documentation about that pass in `compiler/packages/babel-plugin-react-compiler/docs/passes/` to learn more about the role of that pass within the compiler.89- `packages/babel-plugin-react-compiler/` - Main compiler package10  - `src/HIR/` - High-level Intermediate Representation types and utilities11  - `src/Inference/` - Effect inference passes (aliasing, mutation, etc.)12  - `src/Validation/` - Validation passes that check for errors13  - `src/Entrypoint/Pipeline.ts` - Main compilation pipeline with pass ordering14  - `src/__tests__/fixtures/compiler/` - Test fixtures15    - `error.todo-*.js` - Unsupported feature, correctly throws Todo error (graceful bailout)16    - `error.bug-*.js` - Known bug, throws wrong error type or incorrect behavior17    - `*.expect.md` - Expected output for each fixture1819## Running Tests2021```bash22# Run all tests23yarn snap2425# Run tests matching a pattern26# Example: yarn snap -p 'error.*'27yarn snap -p <pattern>2829# Run a single fixture in debug mode. Use the path relative to the __tests__/fixtures/compiler directory30# For each step of compilation, outputs the step name and state of the compiled program31# Example: yarn snap -p simple.js -d32yarn snap -p <file-basename> -d3334# Update fixture outputs (also works with -p)35yarn snap -u36```3738## Linting3940```bash41# Run lint on the compiler source42yarn workspace babel-plugin-react-compiler lint43```4445## Formatting4647```bash48# Run prettier on all files (from the react root directory, not compiler/)49yarn prettier-all50```5152## Compiling Arbitrary Files5354Use `yarn snap compile` to compile any file (not just fixtures) with the React Compiler:5556```bash57# Compile a file and see the output58yarn snap compile <path>5960# Compile with debug logging to see the state after each compiler pass61# This is an alternative to `yarn snap -d -p <pattern>` when you don't have a fixture file yet62yarn snap compile --debug <path>63```6465## Minimizing Test Cases6667Use `yarn snap minimize` to automatically reduce a failing test case to its minimal reproduction:6869```bash70# Minimize a file that causes a compiler error71yarn snap minimize <path>7273# Minimize and update the file in-place with the minimized version74yarn snap minimize --update <path>75```7677## Version Control7879This repository uses Sapling (`sl`) for version control. Sapling is similar to Mercurial: there is not staging area, but new/deleted files must be explicitly added/removed.8081```bash82# Check status83sl status8485# Add new files, remove deleted files86sl addremove8788# Commit all changes89sl commit -m "Your commit message"9091# Commit with multi-line message using heredoc92sl commit -m "$(cat <<'EOF'93Summary line9495Detailed description here96EOF97)"98```99100## Key Concepts101102### HIR (High-level Intermediate Representation)103104The compiler converts source code to HIR for analysis. Key types in `src/HIR/HIR.ts`:105106- **HIRFunction** - A function being compiled107  - `body.blocks` - Map of BasicBlocks108  - `context` - Captured variables from outer scope109  - `params` - Function parameters110  - `returns` - The function's return place111  - `aliasingEffects` - Effects that describe the function's behavior when called112113- **Instruction** - A single operation114  - `lvalue` - The place being assigned to115  - `value` - The instruction kind (CallExpression, FunctionExpression, LoadLocal, etc.)116  - `effects` - Array of AliasingEffects for this instruction117118- **Terminal** - Block terminators (return, branch, etc.)119  - `effects` - Array of AliasingEffects120121- **Place** - A reference to a value122  - `identifier.id` - Unique IdentifierId123124- **Phi nodes** - Join points for values from different control flow paths125  - Located at `block.phis`126  - `phi.place` - The result place127  - `phi.operands` - Map of predecessor block to source place128129### AliasingEffects System130131Effects describe data flow and operations. Defined in `src/Inference/AliasingEffects.ts`:132133**Data Flow Effects:**134- `Impure` - Marks a place as containing an impure value (e.g., Date.now() result, ref.current)135- `Capture a -> b` - Value from `a` is captured into `b` (mutable capture)136- `Alias a -> b` - `b` aliases `a`137- `ImmutableCapture a -> b` - Immutable capture (like Capture but read-only)138- `Assign a -> b` - Direct assignment139- `MaybeAlias a -> b` - Possible aliasing140- `CreateFrom a -> b` - Created from source141142**Mutation Effects:**143- `Mutate value` - Value is mutated144- `MutateTransitive value` - Value and transitive captures are mutated145- `MutateConditionally value` - May mutate146- `MutateTransitiveConditionally value` - May mutate transitively147148**Other Effects:**149- `Render place` - Place is used in render context (JSX props, component return)150- `Freeze place` - Place is frozen (made immutable)151- `Create place` - New value created152- `CreateFunction` - Function expression created, includes `captures` array153- `Apply` - Function application with receiver, function, args, and result154155### Hook Aliasing Signatures156157Located in `src/HIR/Globals.ts`, hooks can define custom aliasing signatures to control how data flows through them.158159**Structure:**160```typescript161aliasing: {162  receiver: '@receiver',    // The hook function itself163  params: ['@param0'],      // Named positional parameters164  rest: '@rest',            // Rest parameters (or null)165  returns: '@returns',      // Return value166  temporaries: [],          // Temporary values during execution167  effects: [                // Array of effects to apply when hook is called168    {kind: 'Freeze', value: '@param0', reason: ValueReason.HookCaptured},169    {kind: 'Assign', from: '@param0', into: '@returns'},170  ],171}172```173174**Common patterns:**1751761. **RenderHookAliasing** (useState, useContext, useMemo, useCallback):177   - Freezes arguments (`Freeze @rest`)178   - Marks arguments as render-time (`Render @rest`)179   - Creates frozen return value180   - Aliases arguments to return1811822. **EffectHookAliasing** (useEffect, useLayoutEffect, useInsertionEffect):183   - Freezes function and deps184   - Creates internal effect object185   - Captures function and deps into effect186   - Returns undefined1871883. **Event handler hooks** (useEffectEvent):189   - Freezes callback (`Freeze @fn`)190   - Aliases input to return (`Assign @fn -> @returns`)191   - NO Render effect (callback not called during render)192193**Example: useEffectEvent**194```typescript195const UseEffectEventHook = addHook(196  DEFAULT_SHAPES,197  {198    positionalParams: [Effect.Freeze],  // Takes one positional param199    restParam: null,200    returnType: {kind: 'Function', ...},201    calleeEffect: Effect.Read,202    hookKind: 'useEffectEvent',203    returnValueKind: ValueKind.Frozen,204    aliasing: {205      receiver: '@receiver',206      params: ['@fn'],              // Name for the callback parameter207      rest: null,208      returns: '@returns',209      temporaries: [],210      effects: [211        {kind: 'Freeze', value: '@fn', reason: ValueReason.HookCaptured},212        {kind: 'Assign', from: '@fn', into: '@returns'},213        // Note: NO Render effect - callback is not called during render214      ],215    },216  },217  BuiltInUseEffectEventId,218);219220// Add as both names for compatibility221['useEffectEvent', UseEffectEventHook],222['experimental_useEffectEvent', UseEffectEventHook],223```224225**Key insight:** If a hook is missing an `aliasing` config, it falls back to `DefaultNonmutatingHook` which includes a `Render` effect on all arguments. This can cause false positives for hooks like `useEffectEvent` whose callbacks are not called during render.226227## Feature Flags228229Feature flags are configured in `src/HIR/Environment.ts`, for example `enableJsxOutlining`. Test fixtures can override the active feature flags used for that fixture via a comment pragma on the first line of the fixture input, for example:230231```javascript232// enableJsxOutlining @enableNameAnonymousFunctions:false233234...code...235```236237Would enable the `enableJsxOutlining` feature and disable the `enableNameAnonymousFunctions` feature.238239## Rust Port (Active)240241Work is tracked in `compiler/docs/rust-port/` with numbered plan docs.242Rust crates live in `compiler/crates/`.243244### Before implementing from a plan:245- Run `git log --oneline --grep="<plan-name>"` to see what's already done246- Read the plan doc's Remaining Work / Status section247- Only implement what's actually remaining248249### After implementing:250- Update the plan doc's status251- Run `/compiler-verify`252- Ensure `compiler/scripts/test-babel-ast.sh` passes253254## Debugging Tips2552561. Run `yarn snap -p <fixture>` to see full HIR output with effects2572. Look for `@aliasingEffects=` on FunctionExpressions2583. Look for `Impure`, `Render`, `Capture` effects on instructions2594. Check the pass ordering in Pipeline.ts to understand when effects are populated vs validated260261## Error Handling and Fault Tolerance262263The compiler is fault-tolerant: it runs all passes and accumulates errors on the `Environment` rather than throwing on the first error. This lets users see all compilation errors at once.264265**Recording errors**  Passes record errors via `env.recordError(diagnostic)`. Errors are accumulated on `Environment.#errors` and checked at the end of the pipeline via `env.hasErrors()` / `env.aggregateErrors()`.266267**`tryRecord()` wrapper**  In Pipeline.ts, validation passes are wrapped in `env.tryRecord(() => pass(hir))` which catches thrown `CompilerError`s (non-invariant) and records them. Infrastructure/transformation passes are NOT wrapped in `tryRecord()` because later passes depend on their output being structurally valid.268269**Error categories:**270- `CompilerError.throwTodo()`  Unsupported but known pattern. Graceful bailout. Can be caught by `tryRecord()`.271- `CompilerError.invariant()`  Truly unexpected/invalid state. Always throws immediately, never caught by `tryRecord()`.272- Non-`CompilerError` exceptions  Always re-thrown.273274**Key files:** `Environment.ts` (`recordError`, `tryRecord`, `hasErrors`, `aggregateErrors`), `Pipeline.ts` (pass orchestration), `Program.ts` (`tryCompileFunction` handles the `Result`).275276**Test fixtures:** `__tests__/fixtures/compiler/fault-tolerance/` contains multi-error fixtures verifying all errors are reported.

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.