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

Output Guarantees

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

Edge Cases

TODOs

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:

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.