nested

package
v1.5.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 21, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package nested handles nested function analysis coordination.

This package manages the analysis of nested function definitions, coordinating between parent and child scopes to propagate types and ensure consistent analysis ordering.

Nested Function Processing

When a function contains nested definitions:

function outer()
    local x = 1
    local function inner()
        return x  -- captures x
    end
end

The package ensures:

  • Parent scope is analyzed first
  • Captured variable types flow to nested functions
  • Nested function results propagate back to parent

Constructor Analysis

For functions that construct objects with methods:

function newCounter()
    local count = 0
    return {
        inc = function() count = count + 1 end
    }
end

The package coordinates method analysis with constructor return type inference.

Sibling Enrichment

Nested functions in the same scope (siblings) may reference each other. The package ensures mutual visibility of sibling types.

Package nested provides pure helper functions for nested function discovery in Lua.

Lua allows functions to be defined anywhere: as local statements, inside table constructors, as method definitions, or as anonymous values. This package provides utilities for discovering and classifying these nested function definitions.

Data Types

This package exports data types that describe nested functions:

  • Child: A discovered nested function with its identity resolved
  • FuncInfo: A Child extended with its synthesized function type
  • ScopeGroup: A group of functions sharing the same parent scope

Pure Functions

All functions in this package are pure: they take inputs and produce outputs without side effects. The orchestration of nested function processing is handled by the check package, which uses these helpers.

Scope Groups

Functions defined at the same lexical level share a scope group. This enables mutual recursion: function A can call function B, and B can call A, even if B is defined after A in the source code.

Constructor Pattern

The package detects the Lua OOP constructor pattern (see constructor.go):

function T.new()
    local self = setmetatable({}, T)
    self.field = value  -- These become instance fields
    return self
end

Self Type Resolution

Helper functions support self-type resolution for methods:

  • FindTableLiteralOwner: For table literal methods
  • FindFieldAssignmentBase: For field assignment methods
  • EnrichSelfTypeWithConstructorFields: For constructor-enriched self

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CollectCapturedContainerMutations added in v1.5.2

func CollectCapturedContainerMutations(
	graph *cfg.Graph,
	capturedSyms map[cfg.SymbolID]bool,
	synth func(ast.Expr, cfg.Point) typ.Type,
) map[cfg.SymbolID][]api.ContainerMutation

CollectCapturedContainerMutations scans a nested function's graph for container mutations (e.g., channel.send) that target captured variables.

func CollectCapturedFieldAssignments

func CollectCapturedFieldAssignments(
	graph *cfg.Graph,
	capturedSyms map[cfg.SymbolID]bool,
	synth func(ast.Expr, cfg.Point) typ.Type,
) map[cfg.SymbolID]map[string]typ.Type

CollectCapturedFieldAssignments scans a nested function's graph for field assignments to captured variables.

When a nested function assigns fields to a captured variable (e.g., `parent.field = v`), those assignments affect the type visible in the parent scope. This function collects such assignments for propagation back to the parent.

func CollectConstructorFields

func CollectConstructorFields(graph *cfg.Graph, selfSym cfg.SymbolID, synth func(ast.Expr, cfg.Point) typ.Type) map[string]typ.Type

CollectConstructorFields collects field assignments to a self symbol in a constructor.

This scans the constructor's CFG for statements like `self.field = value` and builds a map of field names to their types. These fields become part of the class's instance type, enabling the type checker to validate field access on instances created by this constructor.

func DetectConstructorPattern

func DetectConstructorPattern(nestedGraph, parentGraph *cfg.Graph, fn *ast.FunctionExpr, funcDef *cfg.FuncDefInfo) (classSymbol, selfSymbol cfg.SymbolID)

DetectConstructorPattern checks if a function is a constructor that: 1. Is named T.new (assigned to a field named "new" on a table) 2. Creates self via setmetatable({}, T) or setmetatable({}, {__index = T}) 3. Returns the self variable

The nestedGraph is the CFG of the function being analyzed. The parentGraph is the CFG where the function is defined (needed for T.new = function() pattern).

func EnrichSelfTypeWithConstructorFields

func EnrichSelfTypeWithConstructorFields(selfType typ.Type, classSymbol cfg.SymbolID, store Store) typ.Type

EnrichSelfTypeWithConstructorFields merges constructor instance fields into a self-type.

When a method is defined on a class that has a constructor, the self-type should include fields assigned in the constructor. This function looks up constructor fields for the class and merges them into the self-type.

This enables the type checker to recognize instance fields in methods:

function T.new()
    local self = setmetatable({}, T)
    self.name = ""  -- Collected as constructor field
    return self
end
function T:greet()
    print(self.name)  -- self.name is recognized because of constructor fields
end

func EnrichTableTypeWithFuncTypes

func EnrichTableTypeWithFuncTypes(
	rec *typ.Record,
	tableExpr *ast.TableExpr,
	graph *cfg.Graph,
	funcTypes map[cfg.SymbolID]typ.Type,
) typ.Type

EnrichTableTypeWithFuncTypes replaces method function types in a record with canonical function types derived from the interproc queries.

For table literals with method fields, the initially synthesized record may have function types without inferred return types. After analyzing the methods, canonical function types are available per symbol. This function updates the record with those more precise signatures.

func FindFieldAssignmentBase

func FindFieldAssignmentBase(graph *cfg.Graph, fn *ast.FunctionExpr, point cfg.Point) (cfg.SymbolID, *ast.TableExpr, cfg.Point)

FindFieldAssignmentBase finds the base object symbol when a function is assigned via field assignment.

For patterns like `obj.method = function(self) ... end`, this function finds the base object (obj) so that self can be typed as the object's type. Also returns the table literal assigned to that symbol, if any.

func FindTableLiteralForSymbol

func FindTableLiteralForSymbol(graph *cfg.Graph, sym cfg.SymbolID) (*ast.TableExpr, cfg.Point)

FindTableLiteralForSymbol finds the TableExpr assigned to a symbol.

This is used to find the table literal that defines a class or object, enabling self-type resolution for methods defined on that table.

func FindTableLiteralOwner

func FindTableLiteralOwner(graph *cfg.Graph, fn *ast.FunctionExpr) (*ast.TableExpr, cfg.SymbolID)

FindTableLiteralOwner finds the table literal containing fn as a field value.

For patterns like `local obj = { method = function(self) ... }`, this function finds the containing table so that self can be typed as the table's type. Returns both the TableExpr and its assigned symbol.

func NormalizeMethodSelfType added in v1.5.8

func NormalizeMethodSelfType(selfType typ.Type) typ.Type

NormalizeMethodSelfType widens literal-heavy self shapes so method-local flow constraints do not treat mutable receiver state as compile-time constants.

func ResolveNestedFuncIdentity

func ResolveNestedFuncIdentity(graph *cfg.Graph, nf cfg.NestedFunc, funcDef *cfg.FuncDefInfo) (string, cfg.SymbolID, bool)

ResolveNestedFuncIdentity determines the name, symbol, and locality of a nested function.

The identity is resolved by checking (in order):

  1. FuncDefInfo: Named function definitions provide name, symbol, and locality
  2. Local assignment: `local f = function()` provides target name and symbol
  3. NestedFunc symbol: Anonymous functions may still have an assigned symbol

Returns the function name (may be empty), symbol ID (may be 0), and whether the function is locally scoped.

Types

type Child

type Child struct {
	NF       cfg.NestedFunc
	DefScope *scope.State
	FuncDef  *cfg.FuncDefInfo
	FuncName string
	FuncSym  cfg.SymbolID
	IsLocal  bool
}

Child holds the resolved identity of a nested function definition.

Each Child represents a function discovered in the parent function's CFG. The Child captures the function's definition point, enclosing scope, and identity (name, symbol, locality).

func GatherChildren

func GatherChildren(graph *cfg.Graph, scopes map[cfg.Point]*scope.State, fallback *scope.State) []Child

GatherChildren iterates the graph's nested functions and resolves each one's definition scope and identity.

For each nested function in the CFG, this function:

  • Looks up the definition scope at the function's point
  • Retrieves any FuncDefInfo (for named function definitions)
  • Resolves the function's name, symbol, and locality

The result is a slice of Child structs ready for grouping and processing.

type FuncInfo

type FuncInfo struct {
	Child
}

FuncInfo extends Child with data needed during scope group processing.

type ScopeGroup

type ScopeGroup struct {
	Hash     uint64
	Funcs    []*FuncInfo
	MinPoint cfg.Point
}

ScopeGroup holds a group of functions sharing the same parent scope.

Functions in a scope group can see each other's types during analysis, enabling mutual recursion. The group is processed as a unit: sibling types are computed, then each function is checked with that context.

type Store

type Store interface {
	LookupConstructorFields(classSym cfg.SymbolID) map[string]typ.Type
}

Store provides access to session storage for enrichment functions.

This interface abstracts the SessionStore, providing access to literal signatures and constructor fields without depending on the session package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL