Files
react/compiler/packages/babel-plugin-react-compiler/docs/passes/07-analyseFunctions.md
Joseph Savona 870cccd656 [compiler] Summaries of the compiler passes to assist agents in development (#35595)
Autogenerated summaries of each of the compiler passes which allow
agents to get the key ideas of a compiler pass, including key
input/output invariants, without having to reprocess the file each time.
In the subsequent diff this seemed to help.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35595).
* #35607
* #35298
* #35596
* #35573
* __->__ #35595
* #35539
2026-01-23 11:26:47 -08:00

4.6 KiB

analyseFunctions

File

src/Inference/AnalyseFunctions.ts

Purpose

Recursively analyzes all nested function expressions and object methods in a function to infer their aliasing effect signatures, which describe how the function affects its captured variables when invoked.

Input Invariants

  • The HIR has been through SSA conversion and type inference
  • FunctionExpression and ObjectMethod instructions have an empty aliasingEffects array (@aliasingEffects=[])
  • Context variables (captured variables from outer scope) exist on fn.context but do not have their effect populated

Output Guarantees

  • Every FunctionExpression and ObjectMethod has its aliasingEffects array populated with the effects the function performs when called (mutations, captures, aliasing to return value, etc.)
  • Each context variable's effect property is set to either Effect.Capture (if the variable is captured or mutated by the inner function) or Effect.Read (if only read)
  • Context variable mutable ranges are reset to {start: 0, end: 0} and scopes are set to null to prepare for the outer function's subsequent inferMutationAliasingRanges pass

Algorithm

  1. Recursive traversal: Iterates through all blocks and instructions looking for FunctionExpression or ObjectMethod instructions
  2. Depth-first processing: For each function expression found, calls lowerWithMutationAliasing() which:
    • Recursively calls analyseFunctions() on the inner function (handles nested functions)
    • Runs inferMutationAliasingEffects() on the inner function to determine effects
    • Runs deadCodeElimination() to clean up
    • Runs inferMutationAliasingRanges() to compute mutable ranges and extract externally-visible effects
    • Runs rewriteInstructionKindsBasedOnReassignment() and inferReactiveScopeVariables()
    • Stores the computed effects in fn.aliasingEffects
  3. Context variable effect classification: Scans the computed effects to determine which context variables are captured/mutated vs only read:
    • Effects like Capture, Alias, Assign, MaybeAlias, CreateFrom mark the source as captured
    • Mutation effects (Mutate, MutateTransitive, etc.) mark the target as captured
    • Sets operand.effect = Effect.Capture or Effect.Read accordingly
  4. Range reset: Resets mutable ranges and scopes on context variables to prepare for outer function analysis

Key Data Structures

  • HIRFunction.aliasingEffects: Array of AliasingEffect storing the externally-visible behavior of a function when called
  • Place.effect: Effect enum value (Capture or Read) describing how a context variable is used
  • AliasingEffect: Union type describing data flow (Capture, Alias, Assign, etc.) and mutations (Mutate, MutateTransitive, etc.)
  • FunctionExpression/ObjectMethod.loweredFunc.func: The inner HIRFunction to analyze

Edge Cases

  • Nested functions: Handled via recursive call to analyseFunctions() before processing the current function - innermost functions are analyzed first
  • ObjectMethod: Treated identically to FunctionExpression
  • Apply effects invariant: The pass asserts that no Apply effects remain in the function's signature - these should have been resolved to more precise effects by inferMutationAliasingRanges()
  • Conditional mutations: Effects like MutateTransitiveConditionally are tracked - a function that conditionally mutates a captured variable will have that effect in its signature
  • Immutable captures: ImmutableCapture, Freeze, Create, Impure, Render effects do not contribute to marking context variables as Capture

TODOs

  • No TODO comments in the pass itself

Example

Consider a function that captures and conditionally mutates a variable:

function useHook(a, b) {
  let z = {a};
  let y = b;
  let x = function () {
    if (y) {
      maybeMutate(z);  // Unknown function, may mutate z
    }
  };
  return x;
}

Before AnalyseFunctions:

Function @context[y$28, z$25] @aliasingEffects=[]

After AnalyseFunctions:

Function @context[read y$28, capture z$25] @aliasingEffects=[
  MutateTransitiveConditionally z$25,
  Create $14 = primitive
]

The pass infers:

  • y is only read (used in the condition)
  • z is captured into the function and conditionally mutated transitively (because maybeMutate() is unknown)
  • The inner function's signature includes MutateTransitiveConditionally z$25 to indicate this potential mutation

This signature is then used by InferMutationAliasingEffects on the outer function to understand that creating this function captures z, and calling the function may mutate z.