I now have a thorough understanding of the React Compiler source. Here is the comprehensive report.
React Compiler Source Code: Comprehensive Exploration Report
Location Status
The React Compiler source is NOT available locally. The working directory (/home/jm/data/ai/cloudlang-trees/react) is a git worktree of a CloudLang OCaml project, not the facebook/react repository. All data below was retrieved via the GitHub API (gh api repos/facebook/react/...).
To clone locally, run:
git clone --depth=1 --filter=blob:none --sparse https://github.com/facebook/react.git
cd react && git sparse-checkout set compiler
1. Full Directory Listing of the Compiler Source
Top-level compiler packages (compiler/packages/):
babel-plugin-react-compiler/ (THE core compiler)
eslint-plugin-react-compiler/
make-read-only-util/
react-compiler-healthcheck/
react-compiler-runtime/
react-forgive/
react-mcp-server/
snap/
Core source tree (compiler/packages/babel-plugin-react-compiler/src/):
index.ts # Package entry point
Babel/
BabelPlugin.ts # Babel plugin wrapper (visitor pattern)
RunReactCompilerBabelPlugin.ts
CompilerError.ts # (standalone file, not a directory)
Entrypoint/
Gating.ts # Feature flag gating support
Imports.ts # Import management
Options.ts # Plugin configuration/options parsing
Pipeline.ts # THE COMPILATION PIPELINE ORCHESTRATOR
Program.ts # Program-level traversal (find components/hooks)
Reanimated.ts # Reanimated integration support
Suppression.ts # Suppression comment handling
ValidateNoUntransformedReferences.ts
index.ts
Flood/
FlowTypes.ts
TypeErrors.ts
TypeUtils.ts
Types.ts
HIR/
AssertConsistentIdentifiers.ts
AssertTerminalBlocksExist.ts
AssertValidBlockNesting.ts
AssertValidMutableRanges.ts
BuildHIR.ts # AST -> HIR lowering
BuildReactiveScopeTerminalsHIR.ts
CollectHoistablePropertyLoads.ts
CollectOptionalChainDependencies.ts
ComputeUnconditionalBlocks.ts
DefaultModuleTypeProvider.ts
DeriveMinimalDependenciesHIR.ts
Dominator.ts # Dominator tree computation
Environment.ts # Compiler environment/config state
FindContextIdentifiers.ts
Globals.ts # Built-in type/shape definitions
HIR.ts # CORE TYPE DEFINITIONS (1700+ lines)
HIRBuilder.ts # HIR construction helpers
MergeConsecutiveBlocks.ts
MergeOverlappingReactiveScopesHIR.ts
ObjectShape.ts # Function signature / shape system
PrintHIR.ts # Debug printing
PropagateScopeDependenciesHIR.ts
PruneUnusedLabelsHIR.ts
ScopeDependencyUtils.ts
TypeSchema.ts
Types.ts # Type system types (Type, FunctionType, ObjectType, etc.)
index.ts
visitors.ts # HIR traversal utilities
Inference/
AliasingEffects.ts # AliasingEffect type definitions
AnalyseFunctions.ts # Nested function analysis
ControlDominators.ts
DropManualMemoization.ts
InferEffectDependencies.ts
InferMutationAliasingEffects.ts # Abstract interpretation for effects
InferMutationAliasingRanges.ts # Mutable range computation
InferReactivePlaces.ts # Reactivity inference
InlineImmediatelyInvokedFunctionExpressions.ts
MUTABILITY_ALIASING_MODEL.md # Design doc for the aliasing model
index.ts
Optimization/
ConstantPropagation.ts
DeadCodeElimination.ts
InlineJsxTransform.ts
InstructionReordering.ts
LowerContextAccess.ts
OptimizeForSSR.ts
OptimizePropsMethodCalls.ts
OutlineFunctions.ts
OutlineJsx.ts
PruneMaybeThrows.ts
index.ts
ReactiveScopes/
AlignMethodCallScopes.ts
AlignObjectMethodScopes.ts
AlignReactiveScopesToBlockScopesHIR.ts
AssertScopeInstructionsWithinScope.ts
AssertWellFormedBreakTargets.ts
BuildReactiveFunction.ts # HIR CFG -> Reactive tree conversion
CodegenReactiveFunction.ts # FINAL CODE GENERATION (reactive -> Babel AST)
CollectReactiveIdentifiers.ts
CollectReferencedGlobals.ts
ExtractScopeDeclarationsFromDestructuring.ts
FlattenReactiveLoopsHIR.ts
FlattenScopesWithHooksOrUseHIR.ts
InferReactiveScopeVariables.ts # Group mutating-together values into scopes
MemoizeFbtAndMacroOperandsInSameScope.ts
MergeReactiveScopesThatInvalidateTogether.ts
PrintReactiveFunction.ts
PromoteUsedTemporaries.ts
PropagateEarlyReturns.ts
PruneAllReactiveScopes.ts
PruneAlwaysInvalidatingScopes.ts
PruneHoistedContexts.ts
PruneInitializationDependencies.ts
PruneNonEscapingScopes.ts
PruneNonReactiveDependencies.ts
PruneTemporaryLValues.ts
PruneUnusedLabels.ts
PruneUnusedScopes.ts
RenameVariables.ts
StabilizeBlockIds.ts
index.ts
visitors.ts
SSA/
EliminateRedundantPhi.ts
EnterSSA.ts
RewriteInstructionKindsBasedOnReassignment.ts
index.ts
Transform/
NameAnonymousFunctions.ts
TransformFire.ts
index.ts
TypeInference/
InferTypes.ts
index.ts
Utils/
ComponentDeclaration.ts
DisjointSet.ts
HookDeclaration.ts
Keyword.ts
Result.ts
RuntimeDiagnosticConstants.ts
Stack.ts
TestUtils.ts
todo.ts
types.d.ts
utils.ts
Validation/
ValidateContextVariableLValues.ts
ValidateExhaustiveDependencies.ts
ValidateHooksUsage.ts
ValidateLocalsNotReassignedAfterRender.ts
ValidateMemoizedEffectDependencies.ts
ValidateNoCapitalizedCalls.ts
ValidateNoDerivedComputationsInEffects.ts
ValidateNoDerivedComputationsInEffects_exp.ts
ValidateNoFreezingKnownMutableFunctions.ts
ValidateNoImpureFunctionsInRender.ts
ValidateNoJSXInTryStatement.ts
ValidateNoRefAccessInRender.ts
ValidateNoSetStateInEffects.ts
ValidateNoSetStateInRender.ts
ValidatePreservedManualMemoization.ts
ValidateSourceLocations.ts
ValidateStaticComponents.ts
ValidateUseMemo.ts
index.ts
__tests__/
DisjointSet-test.ts
Logger-test.ts
Result-test.ts
e2e/
envConfig-test.ts
fixtures/
parseConfigPragma-test.ts
test-utils/
2. Main Entry Point and Pipeline Orchestration
Entry chain:
index.ts -- Package root. Default export is BabelPluginReactCompiler from Babel/BabelPlugin.ts. Also re-exports compileFn as compile and compileProgram from Entrypoint/.
Babel/BabelPlugin.ts -- Babel plugin object with Program.enter visitor. Calls compileProgram().
Entrypoint/Program.ts -- Traverses the Babel AST to find React components and hooks, then calls compileFn() for each.
Entrypoint/Pipeline.ts -- THE core pipeline orchestrator. Contains compileFn() which calls run() then runWithEnvironment(). This is a ~400-line function that calls every compilation pass in sequence.
3. Complete List of Compilation Passes (in exact pipeline order)
The runWithEnvironment() function in Pipeline.ts executes these passes sequentially. The pipeline operates in three major phases:
Phase 1: HIR Construction & Analysis
| # |
Pass |
Module |
Description |
| 1 |
lower() |
HIR/BuildHIR.ts |
Babel AST -> HIR CFG lowering |
| 2 |
pruneMaybeThrows() |
Optimization/PruneMaybeThrows.ts |
Remove unnecessary try/catch |
| 3 |
validateContextVariableLValues() |
Validation/ |
Validate context variable assignments |
| 4 |
validateUseMemo() |
Validation/ |
Validate useMemo usage |
| 5 |
dropManualMemoization() |
Inference/ |
(conditional) Remove useMemo/useCallback markers |
| 6 |
inlineImmediatelyInvokedFunctionExpressions() |
Inference/ |
Inline IIFEs |
| 7 |
mergeConsecutiveBlocks() |
HIR/ |
Simplify CFG by merging straight-line blocks |
Phase 2: SSA, Type Inference & Mutation/Aliasing Analysis
| # |
Pass |
Module |
Description |
| 8 |
enterSSA() |
SSA/EnterSSA.ts |
Convert to SSA form |
| 9 |
eliminateRedundantPhi() |
SSA/EliminateRedundantPhi.ts |
Remove trivial phi nodes |
| 10 |
constantPropagation() |
Optimization/ |
Forward-propagate constants |
| 11 |
inferTypes() |
TypeInference/InferTypes.ts |
Infer types for identifiers |
| 12 |
validateHooksUsage() |
Validation/ |
(conditional) Validate Rules of Hooks |
| 13 |
validateNoCapitalizedCalls() |
Validation/ |
(conditional) |
| 14 |
transformFire() |
Transform/TransformFire.ts |
(conditional) Fire transform |
| 15 |
lowerContextAccess() |
Optimization/ |
(conditional) Lower context access |
| 16 |
optimizePropsMethodCalls() |
Optimization/ |
Optimize props method calls |
| 17 |
analyseFunctions() |
Inference/AnalyseFunctions.ts |
Recursively analyze nested function expressions |
| 18 |
inferMutationAliasingEffects() |
Inference/InferMutationAliasingEffects.ts |
Core pass: abstract interpretation to determine mutation/aliasing effects |
| 19 |
optimizeForSSR() |
Optimization/ |
(conditional) SSR optimizations |
| 20 |
deadCodeElimination() |
Optimization/ |
Remove unreachable/unused code |
| 21 |
instructionReordering() |
Optimization/ |
(conditional) Reorder instructions |
| 22 |
pruneMaybeThrows() |
Optimization/ |
Second pass of MaybeThrow pruning |
| 23 |
inferMutationAliasingRanges() |
Inference/InferMutationAliasingRanges.ts |
Core pass: compute mutable ranges for each value |
Phase 3: Validations (post-analysis)
| # |
Pass |
Module |
Description |
| 24 |
validateLocalsNotReassignedAfterRender() |
Validation/ |
|
| 25 |
assertValidMutableRanges() |
HIR/ |
(conditional) |
| 26 |
validateNoRefAccessInRender() |
Validation/ |
(conditional) |
| 27 |
validateNoSetStateInRender() |
Validation/ |
(conditional) |
| 28 |
validateNoDerivedComputationsInEffects() |
Validation/ |
(conditional, two variants) |
| 29 |
validateNoSetStateInEffects() |
Validation/ |
(conditional, lint mode) |
| 30 |
validateNoJSXInTryStatement() |
Validation/ |
(conditional, lint mode) |
| 31 |
validateNoImpureFunctionsInRender() |
Validation/ |
(conditional) |
| 32 |
validateNoFreezingKnownMutableFunctions() |
Validation/ |
|
Phase 4: Reactivity & Scope Inference
| # |
Pass |
Module |
Description |
| 33 |
inferReactivePlaces() |
Inference/InferReactivePlaces.ts |
Mark places as reactive based on effects |
| 34 |
validateExhaustiveDependencies() |
Validation/ |
(conditional) |
| 35 |
rewriteInstructionKindsBasedOnReassignment() |
SSA/ |
Fix instruction kinds post-SSA |
| 36 |
validateStaticComponents() |
Validation/ |
(conditional, lint mode) |
| 37 |
inferReactiveScopeVariables() |
ReactiveScopes/InferReactiveScopeVariables.ts |
Group co-mutating values into reactive scopes |
| 38 |
memoizeFbtAndMacroOperandsInSameScope() |
ReactiveScopes/ |
Fbt/macro handling |
| 39 |
outlineJSX() |
Optimization/OutlineJsx.ts |
(conditional) Outline JSX |
| 40 |
nameAnonymousFunctions() |
Transform/ |
(conditional) |
| 41 |
outlineFunctions() |
Optimization/OutlineFunctions.ts |
(conditional) |
Phase 5: Scope Alignment & Dependency Propagation (still on HIR)
| # |
Pass |
Module |
Description |
| 42 |
alignMethodCallScopes() |
ReactiveScopes/ |
Align scopes for method calls |
| 43 |
alignObjectMethodScopes() |
ReactiveScopes/ |
Align scopes for object methods |
| 44 |
pruneUnusedLabelsHIR() |
HIR/ |
Remove unused labels |
| 45 |
alignReactiveScopesToBlockScopesHIR() |
ReactiveScopes/ |
Align reactive scopes to JS block scopes |
| 46 |
mergeOverlappingReactiveScopesHIR() |
HIR/ |
Merge overlapping scopes |
| 47 |
buildReactiveScopeTerminalsHIR() |
HIR/ |
Create scope terminal nodes |
| 48 |
flattenReactiveLoopsHIR() |
ReactiveScopes/ |
Flatten scopes in loops |
| 49 |
flattenScopesWithHooksOrUseHIR() |
ReactiveScopes/ |
Flatten scopes containing hooks |
| 50 |
propagateScopeDependenciesHIR() |
HIR/PropagateScopeDependenciesHIR.ts |
Compute scope dependencies |
| 51 |
inferEffectDependencies() |
Inference/ |
(conditional) Infer useEffect deps |
| 52 |
inlineJsxTransform() |
Optimization/ |
(conditional) |
Phase 6: HIR -> Reactive Function (tree form)
| # |
Pass |
Module |
Description |
| 53 |
buildReactiveFunction() |
ReactiveScopes/BuildReactiveFunction.ts |
Convert CFG to tree-shaped ReactiveFunction |
Phase 7: Reactive Function Optimization & Pruning
| # |
Pass |
Module |
Description |
| 54 |
pruneUnusedLabels() |
ReactiveScopes/ |
|
| 55 |
pruneNonEscapingScopes() |
ReactiveScopes/ |
Remove scopes for non-escaping values |
| 56 |
pruneNonReactiveDependencies() |
ReactiveScopes/ |
|
| 57 |
pruneUnusedScopes() |
ReactiveScopes/ |
|
| 58 |
mergeReactiveScopesThatInvalidateTogether() |
ReactiveScopes/ |
|
| 59 |
pruneAlwaysInvalidatingScopes() |
ReactiveScopes/ |
|
| 60 |
pruneInitializationDependencies() |
ReactiveScopes/ |
(conditional) |
| 61 |
propagateEarlyReturns() |
ReactiveScopes/ |
Handle early returns in scopes |
| 62 |
pruneUnusedLValues() |
ReactiveScopes/ |
|
| 63 |
promoteUsedTemporaries() |
ReactiveScopes/ |
Promote temps to named variables |
| 64 |
extractScopeDeclarationsFromDestructuring() |
ReactiveScopes/ |
|
| 65 |
stabilizeBlockIds() |
ReactiveScopes/ |
|
| 66 |
renameVariables() |
ReactiveScopes/ |
|
| 67 |
pruneHoistedContexts() |
ReactiveScopes/ |
|
Phase 8: Final Validation & Code Generation
| # |
Pass |
Module |
Description |
| 68 |
validateMemoizedEffectDependencies() |
Validation/ |
(conditional) |
| 69 |
validatePreservedManualMemoization() |
Validation/ |
(conditional) |
| 70 |
codegenFunction() |
ReactiveScopes/CodegenReactiveFunction.ts |
Final codegen: ReactiveFunction -> Babel AST with useMemoCache |
| 71 |
validateSourceLocations() |
Validation/ |
(conditional) |
4. HIR Type Definitions (from HIR/HIR.ts)
The HIR is the central data model. Key comment from source: AST -> (lowering) -> HIR -> (analysis) -> Reactive Scopes -> (codegen) -> AST
Core Graph Structure
HIR: { entry: BlockId, blocks: Map<BlockId, BasicBlock> } -- CFG in reverse postorder
BasicBlock: { kind: BlockKind, id: BlockId, instructions: Instruction[], terminal: Terminal, preds: Set<BlockId>, phis: Set<Phi> }
BlockKind: 'block' | 'value' | 'loop' | 'sequence' | 'catch'
Instructions
Instruction: { id: InstructionId, lvalue: Place, value: InstructionValue, effects: AliasingEffect[] | null, loc: SourceLocation }
InstructionValue: Large discriminated union (~40 variants) including LoadLocal, StoreLocal, DeclareLocal, Primitive, BinaryExpression, CallExpression, MethodCall, NewExpression, PropertyLoad, PropertyStore, ComputedLoad, ComputedStore, ObjectExpression, ArrayExpression, JsxExpression, FunctionExpression, Destructure, LoadGlobal, StoreGlobal, Await, GetIterator, IteratorNext, TemplateLiteral, TaggedTemplateExpression, StartMemoize, FinishMemoize, etc.
InstructionKind: Const | Let | Reassign | Catch | HoistedConst | HoistedLet | HoistedFunction | Function
Places & Identifiers
Place: { kind: 'Identifier', identifier: Identifier, effect: Effect, reactive: boolean, loc: SourceLocation } -- a reference to a storage location
Identifier: { id: IdentifierId, declarationId: DeclarationId, name: IdentifierName | null, mutableRange: MutableRange, scope: ReactiveScope | null, type: Type, loc: SourceLocation }
MutableRange: { start: InstructionId, end: InstructionId } -- range where a value is being created/mutated
Terminals (Control Flow)
Terminal: Discriminated union of 20 variants including goto, if, branch, switch, for, for-of, for-in, do-while, while, logical, ternary, optional, label, sequence, try, maybe-throw, return, throw, unreachable, scope (reactive scope), pruned-scope
Effects & Values
Effect enum: Unknown | Freeze | Read | Capture | ConditionallyMutateIterator | ConditionallyMutate | Mutate | Store
ValueKind enum: MaybeFrozen | Frozen | Primitive | Global | Mutable | Context
ValueReason enum: Global | JsxCaptured | HookCaptured | HookReturn | Effect | KnownReturnSignature | Context | State | ReducerState | ReactiveFunctionArgument | Other
Reactive Scopes
ReactiveScope: { id: ScopeId, range: MutableRange, dependencies: ReactiveScopeDependencies, declarations: Map<IdentifierId, ReactiveScopeDeclaration>, reassignments: Set<Identifier>, earlyReturnValue: ... | null, merged: Set<ScopeId>, loc }
ReactiveScopeDependency: { identifier: Identifier, reactive: boolean, path: DependencyPath }
Reactive Function (Tree Form)
ReactiveFunction: { loc, id, params, body: ReactiveBlock, env, directives, ... }
ReactiveBlock: Array<ReactiveStatement> (tree-shaped, not CFG)
ReactiveStatement: ReactiveInstructionStatement | ReactiveTerminalStatement | ReactiveScopeBlock | PrunedReactiveScopeBlock
Function Representation
HIRFunction: { loc, id, fnType, env, params, returns, context, body: HIR, generator, async, directives, aliasingEffects }
LoweredFunction: { func: HIRFunction } -- wrapper for nested functions
Type System (from HIR/Types.ts)
Type: BuiltInType | PhiType | TypeVar | PolyType | PropType | ObjectMethod
BuiltInType: PrimitiveType | FunctionType | ObjectType
FunctionType: { kind: 'Function', shapeId: string | null, return: Type, isConstructor: boolean }
ObjectType: { kind: 'Object', shapeId: string | null }
Opaque ID Types (simulated branded types)
BlockId, ScopeId, IdentifierId, DeclarationId, InstructionId -- all number & { [symbol]: brand }
5. Inference Passes: Aliasing, Effects, and Mutation
The inference system was redesigned in June 2025 (per MUTABILITY_ALIASING_MODEL.md).
AliasingEffects.ts -- Effect Type Definitions
AliasingEffect is a discriminated union with 17 variants:
| Effect |
Purpose |
Freeze |
Mark value as frozen (immutable from this reference) |
Mutate |
Direct mutation, errors if immutable |
MutateConditionally |
Mutation only if value is mutable |
MutateTransitive |
Deep/transitive mutation |
MutateTransitiveConditionally |
Deep mutation only if mutable (default for unknown functions) |
Capture |
Data flow where local mutation of dest does NOT mutate source |
Alias |
Data flow where local mutation of dest DOES mutate source |
MaybeAlias |
Potential aliasing (for unknown function returns) |
Assign |
Direct assignment into = from |
Create |
Create new value of given kind |
CreateFrom |
Create value derived from another (property load, index) |
CreateFunction |
Create function value with captured variables |
ImmutableCapture |
Immutable data flow (for escape analysis) |
Apply |
Function call with receiver, args, signature |
MutateFrozen |
Error: mutation of frozen value |
MutateGlobal |
Error: mutation of global (ok in effects/handlers) |
Impure |
Side-effect not safe during render |
Render |
Value accessed during render |
Also defines AliasingSignature: { receiver, params, rest, returns, effects, temporaries } for encoding function aliasing behavior.
InferMutationAliasingEffects.ts -- Abstract Interpretation
This is the most complex pass in the compiler. Its approach:
Candidate effects: For each instruction, compute a signature of candidate effects based purely on instruction semantics and operand types. These are cached per instruction.
Abstract interpretation: Iterate over the HIR CFG until fixpoint. Track:
AbstractValue per value: { kind: ValueKind, reason: Set<ValueReason>, context: Set<Place> }
InferenceState: maps InstructionValue -> AbstractValue and IdentifierId -> Set<InstructionValue> (pointer set for phi nodes)
Effect application (applyEffect()): Each candidate effect is resolved against current abstract state:
MutateConditionally x: dropped if x is not mutable
Mutate y on frozen value: converted to MutateFrozen error
Capture a -> b: pruned if source is primitive/global or destination is not mutable
Apply: resolves to locally-known function signature, known aliasing signature, legacy signature, or generic fallback
CreateFunction: determines if function is mutable based on whether it captures mutable/context values or has tracked side effects
Key state operations:
state.freeze(place, reason): Transitively freeze a reference
state.mutate(variant, place): Returns 'none' | 'mutate' | 'mutate-frozen' | 'mutate-global' | 'mutate-ref'
state.assign(place, value): Direct aliasing
state.merge(other): Lattice join for fixpoint iteration
state.kind(place): Lookup abstract value kind
Special handling:
- Props spreading (
findNonMutatedDestructureSpreads): treats {...otherProps} as frozen when source is frozen and spread is never mutated
- Hoisted context declarations
- Catch handler bindings (aliased to call results in try blocks)
- Return terminals get
Freeze effect for non-function-expression functions
InferMutationAliasingRanges.ts -- Mutable Range Computation
Builds on the effects computed by the previous pass:
- Constructs a data flow graph with ordered edges and mutations
- Tracks "when" each effect occurs relative to others
- Walks each mutation effect against the graph, updating the
MutableRange (start:end instruction IDs) of each reachable node
- Populates legacy
Effect on each Place
- Validates against invalid effects (mutations of globals/frozen values) for render-reachable code
- Computes externally-visible effects for function expressions (mutations of params/context-vars)
AnalyseFunctions.ts -- Nested Function Analysis
Recursively processes nested FunctionExpression and ObjectMethod values by running a mini-pipeline on each:
analyseFunctions() (recursive)
inferMutationAliasingEffects() (as function expression)
deadCodeElimination()
inferMutationAliasingRanges() (as function expression)
rewriteInstructionKindsBasedOnReassignment()
inferReactiveScopeVariables()
- Stores computed
aliasingEffects on the function node
Then populates Effect on each context variable for the outer function's analysis.
InferReactivePlaces.ts -- Reactivity Inference
Uses a StableSidemap to track sources of stability (hook calls like useRef(), useState(), etc.) and propagates stability through assignments and destructuring. Marks Place.reactive based on whether values change between renders, using ControlDominators for conditional reactivity analysis.
Key Design Insight from MUTABILITY_ALIASING_MODEL.md
The model distinguishes between:
- Alias (local mutation propagates):
const a = identity(b) -- mutating a might mutate b
- Capture (local mutation does NOT propagate):
array.push(item) -- mutating array does not mutate item
- CreateFrom (inverse of Capture):
const a = obj.prop -- mutating a transitively mutates obj
- Assign (direct assignment):
const a = b -- a IS b
- Freeze freezes the reference, not the underlying value. Other aliases to the same value can still mutate it.
- MaybeAlias represents uncertain aliasing from unknown functions, making downstream mutations conditional.
The transitivity rules between these effects are carefully defined to preserve mutation semantics when computing function signatures (e.g., Capture then CreateFrom = Alias, but CreateFrom then Capture = Capture).