Skip to content

Commit cac0258

Browse files
committed
[compiler] Claude file/settings
Initializes CLAUDE.md and a settings file for the compiler/ directory to help use claude with the compiler. Note that some of the commands here depend on changes to snap from the next PR.
1 parent 2976f25 commit cac0258

File tree

2 files changed

+263
-1
lines changed

2 files changed

+263
-1
lines changed

compiler/.claude/settings.local.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
{
22
"permissions": {
33
"allow": [
4-
"Bash(node scripts/enable-feature-flag.js:*)"
4+
"Bash(node scripts/enable-feature-flag.js:*)",
5+
"Bash(yarn snap:*)",
6+
"Bash(for test in \"error.invalid-access-ref-during-render\" \"error.invalid-ref-in-callback-invoked-during-render\" \"error.invalid-impure-functions-in-render-via-render-helper\")",
7+
"Bash(do)",
8+
"Bash(echo:*)",
9+
"Bash(done)",
10+
"Bash(cat:*)",
11+
"Bash(sl revert:*)",
12+
"Bash(yarn workspace snap run build:*)",
13+
"Bash(yarn tsc:*)",
14+
"Bash(yarn snap:build)",
15+
"Bash(timeout 30 yarn snap:*)"
516
],
617
"deny": [],
718
"ask": []

compiler/CLAUDE.md

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# React Compiler Knowledge Base
2+
3+
This document contains knowledge about the React Compiler gathered during development sessions. It serves as a reference for understanding the codebase architecture and key concepts.
4+
5+
## Project Structure
6+
7+
- `packages/babel-plugin-react-compiler/` - Main compiler package
8+
- `src/HIR/` - High-level Intermediate Representation types and utilities
9+
- `src/Inference/` - Effect inference passes (aliasing, mutation, etc.)
10+
- `src/Validation/` - Validation passes that check for errors
11+
- `src/Entrypoint/Pipeline.ts` - Main compilation pipeline with pass ordering
12+
- `src/__tests__/fixtures/compiler/` - Test fixtures
13+
- `error.*.js` - Fixtures that should produce compilation errors
14+
- `*.expect.md` - Expected output for each fixture
15+
16+
## Running Tests
17+
18+
```bash
19+
# Run all tests
20+
yarn snap
21+
22+
# Run tests matching a pattern
23+
# Example: yarn snap -p 'error.*'
24+
yarn snap -p <pattern>
25+
26+
# Run a single fixture in debug mode. Use the path relative to the __tests__/fixtures/compiler directory
27+
# For each step of compilation, outputs the step name and state of the compiled program
28+
# Example: yarn snap -p simple.js -d
29+
yarn snap -p <file-basename> -d
30+
31+
# Update fixture outputs (also works with -p)
32+
yarn snap -u
33+
```
34+
35+
## Version Control
36+
37+
This repository uses Sapling (`sl`) for version control. Unlike git, Sapling does not require explicitly adding files to the staging area.
38+
39+
```bash
40+
# Check status
41+
sl status
42+
43+
# Commit all changes
44+
sl commit -m "Your commit message"
45+
46+
# Commit with multi-line message using heredoc
47+
sl commit -m "$(cat <<'EOF'
48+
Summary line
49+
50+
Detailed description here
51+
EOF
52+
)"
53+
```
54+
55+
## Key Concepts
56+
57+
### HIR (High-level Intermediate Representation)
58+
59+
The compiler converts source code to HIR for analysis. Key types in `src/HIR/HIR.ts`:
60+
61+
- **HIRFunction** - A function being compiled
62+
- `body.blocks` - Map of BasicBlocks
63+
- `context` - Captured variables from outer scope
64+
- `params` - Function parameters
65+
- `returns` - The function's return place
66+
- `aliasingEffects` - Effects that describe the function's behavior when called
67+
68+
- **Instruction** - A single operation
69+
- `lvalue` - The place being assigned to
70+
- `value` - The instruction kind (CallExpression, FunctionExpression, LoadLocal, etc.)
71+
- `effects` - Array of AliasingEffects for this instruction
72+
73+
- **Terminal** - Block terminators (return, branch, etc.)
74+
- `effects` - Array of AliasingEffects
75+
76+
- **Place** - A reference to a value
77+
- `identifier.id` - Unique IdentifierId
78+
79+
- **Phi nodes** - Join points for values from different control flow paths
80+
- Located at `block.phis`
81+
- `phi.place` - The result place
82+
- `phi.operands` - Map of predecessor block to source place
83+
84+
### AliasingEffects System
85+
86+
Effects describe data flow and operations. Defined in `src/Inference/AliasingEffects.ts`:
87+
88+
**Data Flow Effects:**
89+
- `Impure` - Marks a place as containing an impure value (e.g., Date.now() result, ref.current)
90+
- `Capture a -> b` - Value from `a` is captured into `b` (mutable capture)
91+
- `Alias a -> b` - `b` aliases `a`
92+
- `ImmutableCapture a -> b` - Immutable capture (like Capture but read-only)
93+
- `Assign a -> b` - Direct assignment
94+
- `MaybeAlias a -> b` - Possible aliasing
95+
- `CreateFrom a -> b` - Created from source
96+
97+
**Mutation Effects:**
98+
- `Mutate value` - Value is mutated
99+
- `MutateTransitive value` - Value and transitive captures are mutated
100+
- `MutateConditionally value` - May mutate
101+
- `MutateTransitiveConditionally value` - May mutate transitively
102+
103+
**Other Effects:**
104+
- `Render place` - Place is used in render context (JSX props, component return)
105+
- `Freeze place` - Place is frozen (made immutable)
106+
- `Create place` - New value created
107+
- `CreateFunction` - Function expression created, includes `captures` array
108+
- `Apply` - Function application with receiver, function, args, and result
109+
110+
### Hook Aliasing Signatures
111+
112+
Located in `src/HIR/Globals.ts`, hooks can define custom aliasing signatures to control how data flows through them.
113+
114+
**Structure:**
115+
```typescript
116+
aliasing: {
117+
receiver: '@receiver', // The hook function itself
118+
params: ['@param0'], // Named positional parameters
119+
rest: '@rest', // Rest parameters (or null)
120+
returns: '@returns', // Return value
121+
temporaries: [], // Temporary values during execution
122+
effects: [ // Array of effects to apply when hook is called
123+
{kind: 'Freeze', value: '@param0', reason: ValueReason.HookCaptured},
124+
{kind: 'Assign', from: '@param0', into: '@returns'},
125+
],
126+
}
127+
```
128+
129+
**Common patterns:**
130+
131+
1. **RenderHookAliasing** (useState, useContext, useMemo, useCallback):
132+
- Freezes arguments (`Freeze @rest`)
133+
- Marks arguments as render-time (`Render @rest`)
134+
- Creates frozen return value
135+
- Aliases arguments to return
136+
137+
2. **EffectHookAliasing** (useEffect, useLayoutEffect, useInsertionEffect):
138+
- Freezes function and deps
139+
- Creates internal effect object
140+
- Captures function and deps into effect
141+
- Returns undefined
142+
143+
3. **Event handler hooks** (useEffectEvent):
144+
- Freezes callback (`Freeze @fn`)
145+
- Aliases input to return (`Assign @fn -> @returns`)
146+
- NO Render effect (callback not called during render)
147+
148+
**Example: useEffectEvent**
149+
```typescript
150+
const UseEffectEventHook = addHook(
151+
DEFAULT_SHAPES,
152+
{
153+
positionalParams: [Effect.Freeze], // Takes one positional param
154+
restParam: null,
155+
returnType: {kind: 'Function', ...},
156+
calleeEffect: Effect.Read,
157+
hookKind: 'useEffectEvent',
158+
returnValueKind: ValueKind.Frozen,
159+
aliasing: {
160+
receiver: '@receiver',
161+
params: ['@fn'], // Name for the callback parameter
162+
rest: null,
163+
returns: '@returns',
164+
temporaries: [],
165+
effects: [
166+
{kind: 'Freeze', value: '@fn', reason: ValueReason.HookCaptured},
167+
{kind: 'Assign', from: '@fn', into: '@returns'},
168+
// Note: NO Render effect - callback is not called during render
169+
],
170+
},
171+
},
172+
BuiltInUseEffectEventId,
173+
);
174+
175+
// Add as both names for compatibility
176+
['useEffectEvent', UseEffectEventHook],
177+
['experimental_useEffectEvent', UseEffectEventHook],
178+
```
179+
180+
**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.
181+
182+
### Effect Inference Pipeline
183+
184+
Effects are populated by `InferMutationAliasingEffects` (runs before validation):
185+
186+
1. For `Date.now()`, `Math.random()` etc. - adds `Impure` effect (controlled by `validateNoImpureFunctionsInRender` config)
187+
2. For `ref.current` access - adds `Impure` effect (controlled by `validateRefAccessDuringRender` config)
188+
3. For return terminals - adds `Alias` from return value to `fn.returns`
189+
4. For component/JSX returns - adds `Render` effect
190+
5. For function expressions - adds `CreateFunction` effect with captures
191+
192+
### Validation: validateNoImpureValuesInRender
193+
194+
Located at `src/Validation/ValidateNoImpureValuesInRender.ts`
195+
196+
**Purpose:** Detect when impure values (refs, Date.now results, etc.) flow into render context.
197+
198+
**Algorithm:**
199+
1. Track impure values in a Map<IdentifierId, ImpureEffect>
200+
2. Track functions with impure returns separately (they're not impure values themselves)
201+
3. Fixed-point iteration over all blocks:
202+
- Process phi nodes (any impure operand makes result impure)
203+
- Process instruction effects
204+
- Process terminal effects
205+
- Backwards propagation for mutated LoadLocal values
206+
4. Validate: check all Render effects against impure values
207+
208+
**Key patterns:**
209+
- `Impure` effect marks the target as impure
210+
- `Capture/Alias/etc` propagates impurity from source to target
211+
- `Apply` propagates impurity from args/receiver to result
212+
- `CreateFunction` propagates impurity from captured values (but NOT from body effects)
213+
- If a value has both `Render` and `Capture` in same instruction, only error on Render (don't cascade)
214+
215+
**Tracking functions with impure returns:**
216+
- Separate from the `impure` map (function values aren't impure, just their returns)
217+
- Populated when analyzing FunctionExpression bodies
218+
- Used when:
219+
1. Calling the function - mark call result as impure
220+
2. Capturing the function - mark target as impure (for object.foo = impureFunc cases)
221+
222+
**Backwards propagation:**
223+
- When `$x = LoadLocal y` and `$x` is mutated with impure content, mark `y` as impure
224+
- This handles: `const arr = []; arr.push(impure); render(arr)`
225+
226+
## Known Issues / Edge Cases
227+
228+
### Function Outlining
229+
After `OutlineFunctions` pass, inner functions are replaced with `LoadGlobal(_temp)`. The validation runs BEFORE outlining, so it sees the original FunctionExpression. But be aware that test output shows post-outlining HIR.
230+
231+
### SSA and LoadLocal
232+
In SSA form, each `LoadLocal` creates a new identifier. When a loaded value is mutated:
233+
- `$x = LoadLocal y`
234+
- `mutate($x, impure)`
235+
- `$z = LoadLocal y` (different from $x!)
236+
- `render($z)`
237+
238+
The impurity in $x must propagate back to y, then forward to $z. This requires backwards propagation in the fixed-point loop.
239+
240+
## Configuration Flags
241+
242+
In `Environment.ts` / test directives:
243+
- `validateNoImpureFunctionsInRender` - Enable impure function validation (Date.now, Math.random, etc.)
244+
- `validateRefAccessDuringRender` - Enable ref access validation
245+
246+
## Debugging Tips
247+
248+
1. Run `yarn snap -p <fixture>` to see full HIR output with effects
249+
2. Look for `@aliasingEffects=` on FunctionExpressions
250+
3. Look for `Impure`, `Render`, `Capture` effects on instructions
251+
4. Check the pass ordering in Pipeline.ts to understand when effects are populated vs validated

0 commit comments

Comments
 (0)