compiler/packages/babel-plugin-react-compiler/docs/passes/08-inferMutationAliasingEffects.md MARKDOWN 145 lines View on github.com → Search inside
1# inferMutationAliasingEffects23## File4`src/Inference/InferMutationAliasingEffects.ts`56## Purpose7Infers the mutation and aliasing effects for all instructions and terminals in the HIR, making the effects of built-in instructions/functions as well as user-defined functions explicit. These effects form the basis for subsequent analysis to determine the mutable range of each value in the program and for validation against invalid code patterns like mutating frozen values.89## Input Invariants10- HIR must be in SSA form (run after SSA pass)11- Types must be inferred (run after InferTypes pass)12- Functions must be analyzed (run after AnalyseFunctions pass) - this provides `aliasingEffects` on FunctionExpressions13- Each instruction must have an lvalue (destination place)1415## Output Guarantees16- Every instruction has an `effects` array (or null if no effects) containing `AliasingEffect` objects17- Terminals that affect data flow (return, try/catch) have their `effects` populated18- Each instruction's lvalue is guaranteed to be defined in the inference state after visiting19- Effects describe: creation of values, data flow (Assign, Alias, Capture), mutations (Mutate, MutateTransitive), freezing, and errors (MutateFrozen, MutateGlobal, Impure)2021## Algorithm22The pass uses abstract interpretation with the following key phases:23241. **Initialization**:25   - Create initial `InferenceState` mapping identifiers to abstract values26   - Initialize context variables as `ValueKind.Context`27   - Initialize parameters as `ValueKind.Frozen` (for top-level components/hooks) or `ValueKind.Mutable` (for function expressions)28292. **Two-Phase Effect Processing**:30   - **Phase 1 - Signature Computation**: For each instruction, compute a "candidate signature" based purely on instruction semantics and types (cached per instruction via `computeSignatureForInstruction`)31   - **Phase 2 - Effect Application**: Apply the signature to the current abstract state via `applySignature`, which refines effects based on the actual runtime kinds of values32333. **Fixed-Point Iteration**:34   - Process blocks in a worklist, queuing successors after each block35   - Merge states at control flow join points using lattice operations36   - Iterate until no changes occur (max 100 iterations as safety limit)37   - Phi nodes are handled by unioning the abstract values from all predecessors38394. **Effect Refinement** (in `applyEffect`):40   - `MutateConditionally` effects are dropped if value is not mutable41   - `Capture` effects are downgraded to `ImmutableCapture` if source is frozen42   - `Mutate` on frozen values becomes `MutateFrozen` error43   - `Assign` from primitives/globals creates new values rather than aliasing4445## Key Data Structures4647### InferenceState48Maintains two maps:49- `#values: Map<InstructionValue, AbstractValue>` - Maps allocation sites to their abstract kind50- `#variables: Map<IdentifierId, Set<InstructionValue>>` - Maps identifiers to the set of values they may point to (set to handle phi joins)5152### AbstractValue53```typescript54type AbstractValue = {55  kind: ValueKind;56  reason: ReadonlySet<ValueReason>;57};58```5960### ValueKind (lattice)61```62MaybeFrozen    <- top (unknown if frozen or mutable)63    |64  Frozen       <- immutable, cannot be mutated65  Mutable      <- can be mutated locally66  Context      <- mutable box (context variables)67    |68  Global       <- global value69  Primitive    <- copy-on-write semantics70```7172The `mergeValueKinds` function implements the lattice join:73- `Frozen | Mutable -> MaybeFrozen`74- `Context | Mutable -> Context`75- `Context | Frozen -> MaybeFrozen`7677### AliasingEffect Types78Key effect kinds handled:79- **Create**: Creates a new value at a place80- **Assign**: Direct assignment (pointer copy)81- **Alias**: Mutation of destination implies mutation of source82- **Capture**: Information flow (MutateTransitive propagates through)83- **MaybeAlias**: Possible aliasing for unknown function returns84- **Mutate/MutateTransitive**: Direct/transitive mutation85- **MutateConditionally/MutateTransitiveConditionally**: Conditional versions86- **Freeze**: Marks value as immutable87- **Apply**: Function call with complex data flow8889## Edge Cases90911. **Spread Destructuring from Props**: The `findNonMutatedDestructureSpreads` pre-pass identifies spread patterns from frozen values that are never mutated, allowing them to be treated as frozen.92932. **Hoisted Context Declarations**: Special handling for variables declared with hoisting (`HoistedConst`, `HoistedFunction`, `HoistedLet`) to detect access before declaration.94953. **Try-Catch Aliasing**: When a `maybe-throw` terminal is reached, call return values are aliased into the catch binding since exceptions can throw return values.96974. **Function Expressions**: Functions are considered mutable only if they have mutable captures or tracked side effects (MutateFrozen, MutateGlobal, Impure).98995. **Iterator Mutation**: Non-builtin iterators may alias their collection and mutation of the iterator is conditional.1001016. **Array.push and Similar**: Uses legacy signature system with `Store` effect on receiver and `Capture` of arguments.102103## TODOs104- `// TODO: using InstructionValue as a bit of a hack, but it's pragmatic` - context variable initialization105- `// TODO: call applyEffect() instead` - try-catch aliasing106- `// TODO: make sure we're also validating against global mutations somewhere` - global mutation validation for effects/event handlers107- `// TODO; include "render" here?` - whether to track Render effects in function hasTrackedSideEffects108- `// TODO: consider using persistent data structures to make clone cheaper` - performance optimization for state cloning109- `// TODO check this` and `// TODO: what kind here???` - DeclareLocal value kinds110111## Example112113For the code:114```javascript115const arr = [];116arr.push({});117arr.push(x, y);118```119120After `InferMutationAliasingEffects`, the effects are:121122```123[10] $39 = Array []124    Create $39 = mutable           // Array literal creates mutable value125126[11] $41 = StoreLocal arr$40 = $39127    Assign arr$40 = $39            // arr points to the array value128    Assign $41 = $39129130[15] $45 = MethodCall $42.push($44)131    Apply $45 = $42.$43($44)       // Records the call132    Mutate $42                      // push mutates the array133    Capture $42 <- $44             // {} is captured into array134    Create $45 = primitive         // push returns number (length)135136[20] $50 = MethodCall $46.push($48, $49)137    Apply $50 = $46.$47($48, $49)138    Mutate $46                      // push mutates the array139    Capture $46 <- $48             // x captured into array140    Capture $46 <- $49             // y captured into array141    Create $50 = primitive142```143144The key insight is that `Mutate` effects extend the mutable range of the array, and `Capture` effects record data flow so that if the array is later frozen (e.g., returned from a component), the captured values are also considered frozen for validation purposes.

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.