main
md 318 lines 23 KB
Rendered Raw
1 # React Compiler Passes Documentation
2
3 This directory contains detailed documentation for each pass in the React Compiler pipeline. The compiler transforms React components and hooks to add automatic memoization.
4
5 ## High-Level Architecture
6
7 ```
8 ┌─────────────────────────────────────────────────────────────┐
9 │ COMPILATION PIPELINE │
10 └─────────────────────────────────────────────────────────────┘
11
12
13 ┌─────────────────────────────────────────────────────────────────────────────────────┐
14 │ PHASE 1: HIR CONSTRUCTION │
15 │ ┌─────────┐ │
16 │ │ Babel │──▶ lower ──▶ enterSSA ──▶ eliminateRedundantPhi │
17 │ │ AST │ │ │
18 │ └─────────┘ ▼ │
19 │ ┌──────────┐ │
20 │ │ HIR │ (Control Flow Graph in SSA Form) │
21 │ └──────────┘ │
22 └─────────────────────────────────────────────────────────────────────────────────────┘
23
24
25 ┌─────────────────────────────────────────────────────────────────────────────────────┐
26 │ PHASE 2: OPTIMIZATION │
27 │ │
28 │ constantPropagation ──▶ deadCodeElimination │
29 │ │
30 └─────────────────────────────────────────────────────────────────────────────────────┘
31
32
33 ┌─────────────────────────────────────────────────────────────────────────────────────┐
34 │ PHASE 3: TYPE & EFFECT INFERENCE │
35 │ │
36 │ inferTypes ──▶ analyseFunctions ──▶ inferMutationAliasingEffects │
37 │ │ │
38 │ ▼ │
39 │ inferMutationAliasingRanges ──▶ inferReactivePlaces │
40 │ │
41 └─────────────────────────────────────────────────────────────────────────────────────┘
42
43
44 ┌─────────────────────────────────────────────────────────────────────────────────────┐
45 │ PHASE 4: REACTIVE SCOPE CONSTRUCTION │
46 │ │
47 │ inferReactiveScopeVariables ──▶ alignMethodCallScopes ──▶ alignObjectMethodScopes │
48 │ │ │
49 │ ▼ │
50 │ alignReactiveScopesToBlockScopesHIR ──▶ mergeOverlappingReactiveScopesHIR │
51 │ │ │
52 │ ▼ │
53 │ buildReactiveScopeTerminalsHIR ──▶ flattenReactiveLoopsHIR │
54 │ │ │
55 │ ▼ │
56 │ flattenScopesWithHooksOrUseHIR ──▶ propagateScopeDependenciesHIR │
57 │ │
58 └─────────────────────────────────────────────────────────────────────────────────────┘
59
60
61 ┌─────────────────────────────────────────────────────────────────────────────────────┐
62 │ PHASE 5: HIR → REACTIVE FUNCTION │
63 │ │
64 │ buildReactiveFunction │
65 │ │ │
66 │ ▼ │
67 │ ┌───────────────────┐ │
68 │ │ ReactiveFunction │ (Tree Structure) │
69 │ └───────────────────┘ │
70 │ │
71 └─────────────────────────────────────────────────────────────────────────────────────┘
72
73
74 ┌─────────────────────────────────────────────────────────────────────────────────────┐
75 │ PHASE 6: REACTIVE FUNCTION OPTIMIZATION │
76 │ │
77 │ pruneUnusedLabels ──▶ pruneNonEscapingScopes ──▶ pruneNonReactiveDependencies │
78 │ │ │
79 │ ▼ │
80 │ pruneUnusedScopes ──▶ mergeReactiveScopesThatInvalidateTogether │
81 │ │ │
82 │ ▼ │
83 │ pruneAlwaysInvalidatingScopes ──▶ propagateEarlyReturns ──▶ promoteUsedTemporaries │
84 │ │
85 └─────────────────────────────────────────────────────────────────────────────────────┘
86
87
88 ┌─────────────────────────────────────────────────────────────────────────────────────┐
89 │ PHASE 7: CODE GENERATION │
90 │ │
91 │ renameVariables ──▶ codegenReactiveFunction │
92 │ │ │
93 │ ▼ │
94 │ ┌─────────────┐ │
95 │ │ Babel AST │ (With Memoization) │
96 │ └─────────────┘ │
97 │ │
98 └─────────────────────────────────────────────────────────────────────────────────────┘
99 ```
100
101 ## Pass Categories
102
103 ### HIR Construction & SSA (1-3)
104
105 | # | Pass | File | Description |
106 |---|------|------|-------------|
107 | 1 | [lower](01-lower.md) | `HIR/BuildHIR.ts` | Convert Babel AST to HIR control-flow graph |
108 | 2 | [enterSSA](02-enterSSA.md) | `SSA/EnterSSA.ts` | Convert to Static Single Assignment form |
109 | 3 | [eliminateRedundantPhi](03-eliminateRedundantPhi.md) | `SSA/EliminateRedundantPhi.ts` | Remove unnecessary phi nodes |
110
111 ### Optimization (4-5)
112
113 | # | Pass | File | Description |
114 |---|------|------|-------------|
115 | 4 | [constantPropagation](04-constantPropagation.md) | `Optimization/ConstantPropagation.ts` | Sparse conditional constant propagation |
116 | 5 | [deadCodeElimination](05-deadCodeElimination.md) | `Optimization/DeadCodeElimination.ts` | Remove unreferenced instructions |
117
118 ### Type Inference (6)
119
120 | # | Pass | File | Description |
121 |---|------|------|-------------|
122 | 6 | [inferTypes](06-inferTypes.md) | `TypeInference/InferTypes.ts` | Constraint-based type unification |
123
124 ### Mutation/Aliasing Inference (7-10)
125
126 | # | Pass | File | Description |
127 |---|------|------|-------------|
128 | 7 | [analyseFunctions](07-analyseFunctions.md) | `Inference/AnalyseFunctions.ts` | Analyze nested function effects |
129 | 8 | [inferMutationAliasingEffects](08-inferMutationAliasingEffects.md) | `Inference/InferMutationAliasingEffects.ts` | Infer mutation/aliasing via abstract interpretation |
130 | 9 | [inferMutationAliasingRanges](09-inferMutationAliasingRanges.md) | `Inference/InferMutationAliasingRanges.ts` | Compute mutable ranges from effects |
131 | 10 | [inferReactivePlaces](10-inferReactivePlaces.md) | `Inference/InferReactivePlaces.ts` | Mark reactive places (props, hooks, derived) |
132
133 ### Reactive Scope Variables (11-12)
134
135 | # | Pass | File | Description |
136 |---|------|------|-------------|
137 | 11 | [inferReactiveScopeVariables](11-inferReactiveScopeVariables.md) | `ReactiveScopes/InferReactiveScopeVariables.ts` | Group co-mutating variables into scopes |
138 | 12 | [rewriteInstructionKindsBasedOnReassignment](12-rewriteInstructionKindsBasedOnReassignment.md) | `SSA/RewriteInstructionKindsBasedOnReassignment.ts` | Convert SSA loads to context loads for reassigned vars |
139
140 ### Scope Alignment (13-15)
141
142 | # | Pass | File | Description |
143 |---|------|------|-------------|
144 | 13 | [alignMethodCallScopes](13-alignMethodCallScopes.md) | `ReactiveScopes/AlignMethodCallScopes.ts` | Align method call scopes with receivers |
145 | 14 | [alignObjectMethodScopes](14-alignObjectMethodScopes.md) | `ReactiveScopes/AlignObjectMethodScopes.ts` | Align object method scopes |
146 | 15 | [alignReactiveScopesToBlockScopesHIR](15-alignReactiveScopesToBlockScopesHIR.md) | `ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts` | Align to control-flow block boundaries |
147
148 ### Scope Construction (16-18)
149
150 | # | Pass | File | Description |
151 |---|------|------|-------------|
152 | 16 | [mergeOverlappingReactiveScopesHIR](16-mergeOverlappingReactiveScopesHIR.md) | `HIR/MergeOverlappingReactiveScopesHIR.ts` | Merge overlapping scopes |
153 | 17 | [buildReactiveScopeTerminalsHIR](17-buildReactiveScopeTerminalsHIR.md) | `HIR/BuildReactiveScopeTerminalsHIR.ts` | Insert scope terminals into CFG |
154 | 18 | [flattenReactiveLoopsHIR](18-flattenReactiveLoopsHIR.md) | `ReactiveScopes/FlattenReactiveLoopsHIR.ts` | Prune scopes inside loops |
155
156 ### Scope Flattening & Dependencies (19-20)
157
158 | # | Pass | File | Description |
159 |---|------|------|-------------|
160 | 19 | [flattenScopesWithHooksOrUseHIR](19-flattenScopesWithHooksOrUseHIR.md) | `ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts` | Prune scopes containing hooks |
161 | 20 | [propagateScopeDependenciesHIR](20-propagateScopeDependenciesHIR.md) | `HIR/PropagateScopeDependenciesHIR.ts` | Derive minimal scope dependencies |
162
163 ### HIR → Reactive Conversion (21)
164
165 | # | Pass | File | Description |
166 |---|------|------|-------------|
167 | 21 | [buildReactiveFunction](21-buildReactiveFunction.md) | `ReactiveScopes/BuildReactiveFunction.ts` | Convert CFG to tree structure |
168
169 ### Reactive Function Pruning (22-25)
170
171 | # | Pass | File | Description |
172 |---|------|------|-------------|
173 | 22 | [pruneUnusedLabels](22-pruneUnusedLabels.md) | `ReactiveScopes/PruneUnusedLabels.ts` | Remove unused labels |
174 | 23 | [pruneNonEscapingScopes](23-pruneNonEscapingScopes.md) | `ReactiveScopes/PruneNonEscapingScopes.ts` | Remove non-escaping scopes |
175 | 24 | [pruneNonReactiveDependencies](24-pruneNonReactiveDependencies.md) | `ReactiveScopes/PruneNonReactiveDependencies.ts` | Remove non-reactive dependencies |
176 | 25 | [pruneUnusedScopes](25-pruneUnusedScopes.md) | `ReactiveScopes/PruneUnusedScopes.ts` | Remove empty scopes |
177
178 ### Scope Optimization (26-28)
179
180 | # | Pass | File | Description |
181 |---|------|------|-------------|
182 | 26 | [mergeReactiveScopesThatInvalidateTogether](26-mergeReactiveScopesThatInvalidateTogether.md) | `ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts` | Merge co-invalidating scopes |
183 | 27 | [pruneAlwaysInvalidatingScopes](27-pruneAlwaysInvalidatingScopes.md) | `ReactiveScopes/PruneAlwaysInvalidatingScopes.ts` | Prune always-invalidating scopes |
184 | 28 | [propagateEarlyReturns](28-propagateEarlyReturns.md) | `ReactiveScopes/PropagateEarlyReturns.ts` | Handle early returns in scopes |
185
186 ### Codegen Preparation (29-31)
187
188 | # | Pass | File | Description |
189 |---|------|------|-------------|
190 | 29 | [promoteUsedTemporaries](29-promoteUsedTemporaries.md) | `ReactiveScopes/PromoteUsedTemporaries.ts` | Promote temps to named vars |
191 | 30 | [renameVariables](30-renameVariables.md) | `ReactiveScopes/RenameVariables.ts` | Ensure unique variable names |
192 | 31 | [codegenReactiveFunction](31-codegenReactiveFunction.md) | `ReactiveScopes/CodegenReactiveFunction.ts` | Generate final Babel AST |
193
194 ### Transformations (32-38)
195
196 | # | Pass | File | Description |
197 |---|------|------|-------------|
198 | 34 | [optimizePropsMethodCalls](34-optimizePropsMethodCalls.md) | `Optimization/OptimizePropsMethodCalls.ts` | Normalize props method calls |
199 | 35 | [optimizeForSSR](35-optimizeForSSR.md) | `Optimization/OptimizeForSSR.ts` | SSR-specific optimizations |
200 | 36 | [outlineJSX](36-outlineJSX.md) | `Optimization/OutlineJsx.ts` | Outline JSX to components |
201 | 37 | [outlineFunctions](37-outlineFunctions.md) | `Optimization/OutlineFunctions.ts` | Outline pure functions |
202 | 38 | [memoizeFbtAndMacroOperandsInSameScope](38-memoizeFbtAndMacroOperandsInSameScope.md) | `ReactiveScopes/MemoizeFbtAndMacroOperandsInSameScope.ts` | Keep FBT operands together |
203
204 ### Validation (39-55)
205
206 | # | Pass | File | Description |
207 |---|------|------|-------------|
208 | 39 | [validateContextVariableLValues](39-validateContextVariableLValues.md) | `Validation/ValidateContextVariableLValues.ts` | Variable reference consistency |
209 | 40 | [validateUseMemo](40-validateUseMemo.md) | `Validation/ValidateUseMemo.ts` | useMemo callback requirements |
210 | 41 | [validateHooksUsage](41-validateHooksUsage.md) | `Validation/ValidateHooksUsage.ts` | Rules of Hooks |
211 | 42 | [validateNoCapitalizedCalls](42-validateNoCapitalizedCalls.md) | `Validation/ValidateNoCapitalizedCalls.ts` | Component vs function calls |
212 | 43 | [validateLocalsNotReassignedAfterRender](43-validateLocalsNotReassignedAfterRender.md) | `Validation/ValidateLocalsNotReassignedAfterRender.ts` | Variable mutation safety |
213 | 44 | [validateNoSetStateInRender](44-validateNoSetStateInRender.md) | `Validation/ValidateNoSetStateInRender.ts` | No setState during render |
214 | 45 | [validateNoDerivedComputationsInEffects](45-validateNoDerivedComputationsInEffects.md) | `Validation/ValidateNoDerivedComputationsInEffects.ts` | Effect optimization hints |
215 | 46 | [validateNoSetStateInEffects](46-validateNoSetStateInEffects.md) | `Validation/ValidateNoSetStateInEffects.ts` | Effect performance |
216 | 47 | [validateNoJSXInTryStatement](47-validateNoJSXInTryStatement.md) | `Validation/ValidateNoJSXInTryStatement.ts` | Error boundary usage |
217 | 48 | [validateNoImpureValuesInRender](48-validateNoImpureValuesInRender.md) | `Validation/ValidateNoImpureValuesInRender.ts` | Impure value isolation |
218 | 49 | [validateNoRefAccessInRender](49-validateNoRefAccessInRender.md) | `Validation/ValidateNoRefAccessInRender.ts` | Ref access constraints |
219 | 50 | [validateNoFreezingKnownMutableFunctions](50-validateNoFreezingKnownMutableFunctions.md) | `Validation/ValidateNoFreezingKnownMutableFunctions.ts` | Mutable function isolation |
220 | 51 | [validateExhaustiveDependencies](51-validateExhaustiveDependencies.md) | `Validation/ValidateExhaustiveDependencies.ts` | Dependency array completeness |
221 | 53 | [validatePreservedManualMemoization](53-validatePreservedManualMemoization.md) | `Validation/ValidatePreservedManualMemoization.ts` | Manual memo preservation |
222 | 54 | [validateStaticComponents](54-validateStaticComponents.md) | `Validation/ValidateStaticComponents.ts` | Component identity stability |
223 | 55 | [validateSourceLocations](55-validateSourceLocations.md) | `Validation/ValidateSourceLocations.ts` | Source location preservation |
224
225 ## Key Data Structures
226
227 ### HIR (High-level Intermediate Representation)
228
229 The compiler converts source code to HIR for analysis. Key types:
230
231 - **HIRFunction**: A function being compiled
232 - `body.blocks`: Map of BasicBlocks (control flow graph)
233 - `context`: Captured variables from outer scope
234 - `params`: Function parameters
235 - `returns`: The function's return place
236
237 - **BasicBlock**: A sequence of instructions with a terminal
238 - `instructions`: Array of Instructions
239 - `terminal`: Control flow (return, branch, etc.)
240 - `phis`: Phi nodes for SSA
241
242 - **Instruction**: A single operation
243 - `lvalue`: The place being assigned to
244 - `value`: The instruction kind (CallExpression, FunctionExpression, etc.)
245 - `effects`: Array of AliasingEffects
246
247 - **Place**: A reference to a value
248 - `identifier.id`: Unique IdentifierId
249 - `effect`: How the place is used (read, mutate, etc.)
250
251 ### ReactiveFunction
252
253 After HIR is analyzed, it's converted to ReactiveFunction:
254
255 - Tree structure instead of CFG
256 - Contains ReactiveScopes that define memoization boundaries
257 - Each scope has dependencies and declarations
258
259 ### AliasingEffects
260
261 Effects describe data flow and operations:
262
263 - **Capture/Alias**: Value relationships
264 - **Mutate/MutateTransitive**: Mutation tracking
265 - **Freeze**: Immutability marking
266 - **Render**: JSX usage context
267 - **Create/CreateFunction**: Value creation
268
269 ## Feature Flags
270
271 Many passes are controlled by feature flags in `Environment.ts`:
272
273 | Flag | Enables Pass |
274 |------|--------------|
275 | `enableJsxOutlining` | outlineJSX |
276 | `enableFunctionOutlining` | outlineFunctions |
277 | `validateNoSetStateInRender` | validateNoSetStateInRender |
278 | `enableUseMemoCacheInterop` | Preserves manual memoization |
279
280 ## Running Tests
281
282 ```bash
283 # Run all tests
284 yarn snap
285
286 # Run specific fixture
287 yarn snap -p <fixture-name>
288
289 # Run with debug output (shows all passes)
290 yarn snap -p <fixture-name> -d
291
292 # Compile any file (not just fixtures) and see output
293 yarn snap compile <path>
294
295 # Compile any file with debug output (alternative to yarn snap -d -p when you don't have a fixture)
296 yarn snap compile --debug <path>
297
298 # Minimize a failing test case to its minimal reproduction
299 yarn snap minimize <path>
300
301 # Update expected outputs
302 yarn snap -u
303 ```
304
305 ## Fault Tolerance
306
307 The pipeline is fault-tolerant: all passes run to completion, accumulating errors on `Environment` rather than aborting on the first error.
308
309 - **Validation passes** are wrapped in `env.tryRecord()` in Pipeline.ts, which catches non-invariant `CompilerError`s and records them. If a validation pass throws, compilation continues.
310 - **Infrastructure/transformation passes** (enterSSA, eliminateRedundantPhi, inferMutationAliasingEffects, codegen, etc.) are NOT wrapped in `tryRecord()` because subsequent passes depend on their output being structurally valid. If they fail, compilation aborts.
311 - **`lower()` (BuildHIR)** always produces an `HIRFunction`, recording errors on `env` instead of returning `Err`. Unsupported constructs (e.g., `var`) are lowered best-effort.
312 - At the end of the pipeline, `env.hasErrors()` determines whether to return `Ok(codegen)` or `Err(aggregatedErrors)`.
313
314 ## Further Reading
315
316 - [MUTABILITY_ALIASING_MODEL.md](../../src/Inference/MUTABILITY_ALIASING_MODEL.md): Detailed aliasing model docs
317 - [Pipeline.ts](../../src/Entrypoint/Pipeline.ts): Pass ordering and orchestration
318 - [HIR.ts](../../src/HIR/HIR.ts): Core data structure definitions