Documentation
¶
Overview ¶
Package siblings manages sibling function type coordination.
This package handles the coordination of function types for sibling functions - local functions defined in the same scope that may reference each other.
Sibling Functions ¶
Functions in the same scope can call each other:
local function isEven(n)
if n == 0 then return true end
return isOdd(n - 1)
end
local function isOdd(n)
if n == 0 then return false end
return isEven(n - 1)
end
The package ensures both functions see each other's types during analysis.
Overlay System ¶
[Overlay] provides a view that combines:
- Stable sibling types from previous iterations
- Pending updates from current iteration
This supports fixpoint iteration for mutually recursive siblings.
Integration ¶
Sibling coordination runs as part of nested function analysis, ensuring consistent types across sibling definitions.
Package siblings provides sibling type construction for nested function analysis.
Sibling types are function types visible to other functions in the same scope group, enabling mutual recursion and forward references within a scope block. When multiple functions are defined at the same scope level (e.g., in the same do block), they form a sibling group that can call each other.
Problem Statement ¶
Consider this Lua code:
local function even(n) return n == 0 or odd(n-1) end local function odd(n) return n ~= 0 and even(n-1) end
Without sibling type propagation, `even` cannot see `odd`'s type (not yet defined), and vice versa. This package enables both functions to see each other's types during type checking by computing a unified sibling type map for the group.
Build Algorithm ¶
The Build function constructs sibling types through four steps:
- Seed from previous iteration (monotonic accumulation across fixpoint iterations)
- Merge captured variable types from the parent scope
- Add sibling function types enriched with return summaries
- Overlay literal signatures for refined function types
The result is a SymbolID -> Type map that can be injected into the type environment when analyzing any function in the group.
Integration with Fixpoint ¶
Sibling types are recomputed on each fixpoint iteration as return summaries improve. The monotonic accumulation (step 1) ensures that types only grow more precise, guaranteeing convergence.
Index ¶
- func Build(c BuildConfig) map[cfg.SymbolID]typ.Type
- func BuildOverlay(c OverlayConfig) map[cfg.SymbolID]typ.Type
- func Compute(store map[uint64]map[cfg.SymbolID]typ.Type, groupHash uint64) map[cfg.SymbolID]typ.Type
- func Copy(m map[cfg.SymbolID]typ.Type) map[cfg.SymbolID]typ.Type
- type BuildConfig
- type BuildServices
- type BuildServicesFuncs
- type FuncEntry
- type OverlayConfig
- type OverlayEntry
- type OverlayServices
- type OverlayServicesFuncs
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Build ¶
func Build(c BuildConfig) map[cfg.SymbolID]typ.Type
Build constructs the sibling types map for a scope group.
The algorithm proceeds in four phases:
Phase 1 - Seed from Previous: Copy types from SiblingTypesPrev to preserve types accumulated in prior fixpoint iterations. This ensures monotonicity: types only grow more precise, never regress.
Phase 2 - Captured Variables: For each function, find captured variables from the parent scope and add their types. This enables nested functions to see types of variables defined in enclosing scopes.
Phase 3 - Sibling Functions: Add canonical function types for locally-defined siblings.
The result maps each symbol to its best-known type. Functions in the group use this map as an overlay during type checking to resolve sibling references.
func BuildOverlay ¶
func BuildOverlay(c OverlayConfig) map[cfg.SymbolID]typ.Type
BuildOverlay constructs an overlay map for return inference.
This overlay is used during SCC-based return type inference. It provides function types for sibling functions based on their current return summaries. The current function (CurrentSym) is excluded from the overlay to avoid circular dependence during its own analysis.
For siblings without summaries yet, placeholder function types are created using seed type services to preserve parameter arity. This enables the fixpoint to make progress even when not all return types are known.
func Compute ¶
func Compute(store map[uint64]map[cfg.SymbolID]typ.Type, groupHash uint64) map[cfg.SymbolID]typ.Type
Compute extracts sibling types for a function's scope group from the store.
The store is keyed by group hash (computed from the parent scope). This function looks up the sibling types for the given group and returns them. Returns nil if no sibling types exist for the group.
Types ¶
type BuildConfig ¶
type BuildConfig struct {
// Funcs are the function entries in this scope group.
Funcs []FuncEntry
// GroupHash identifies the scope group.
GroupHash uint64
// SiblingTypesPrev are sibling types from the previous iteration (monotonic accumulation).
SiblingTypesPrev map[cfg.SymbolID]typ.Type
// FuncTypes are canonical local function types for this scope group.
FuncTypes map[cfg.SymbolID]typ.Type
// Services provides required lookups for sibling construction.
Services BuildServices
}
BuildConfig holds inputs for sibling type construction.
This configuration bundles all dependencies needed by the Build function. The services (captured symbols, type lookup, record enrichment) are provided by the checker session to avoid tight coupling between packages.
type BuildServices ¶
type BuildServices interface {
CapturedSymbols(fn *ast.FunctionExpr) []cfg.SymbolID
TypeAtPoint(point cfg.Point, sym cfg.SymbolID) typ.Type
EnrichRecord(rec *typ.Record, sym cfg.SymbolID) typ.Type
}
BuildServices provides lookups for sibling construction.
type BuildServicesFuncs ¶
type BuildServicesFuncs struct {
CapturedSymbolsFn func(fn *ast.FunctionExpr) []cfg.SymbolID
TypeAtPointFn func(point cfg.Point, sym cfg.SymbolID) typ.Type
EnrichRecordFn func(rec *typ.Record, sym cfg.SymbolID) typ.Type
}
BuildServicesFuncs adapts functions to BuildServices.
func (BuildServicesFuncs) CapturedSymbols ¶
func (b BuildServicesFuncs) CapturedSymbols(fn *ast.FunctionExpr) []cfg.SymbolID
func (BuildServicesFuncs) EnrichRecord ¶
func (BuildServicesFuncs) TypeAtPoint ¶
type FuncEntry ¶
FuncEntry captures the minimum info needed for sibling type construction.
Each entry represents a function defined in the scope group. The entry includes the AST node, CFG location, symbol identity, locality flag, and synthesized function type. Non-local functions (e.g., module-level definitions) are included for captured variable resolution but do not contribute their types to siblings.
type OverlayConfig ¶
type OverlayConfig struct {
// Summaries maps symbols to their return type summaries.
Summaries map[cfg.SymbolID][]typ.Type
// Siblings are the sibling functions in this scope group.
Siblings []OverlayEntry
// CurrentSym is the symbol of the function being analyzed (excluded from overlay).
CurrentSym cfg.SymbolID
// Services provides seed type resolution for siblings without summaries.
Services OverlayServices
}
OverlayConfig holds inputs for return inference overlay construction.
This configuration is used by BuildOverlay to construct a type overlay for return inference within an SCC. The overlay provides types for sibling functions so that calls between them can be typed during fixpoint iteration.
type OverlayEntry ¶
type OverlayEntry struct {
Symbol cfg.SymbolID
Func *ast.FunctionExpr
}
OverlayEntry captures info for a sibling function in return overlay construction.
Used during SCC-based return inference to track which functions are in the same scope group and may be called as siblings.
type OverlayServices ¶
type OverlayServices interface {
SeedType(fn *ast.FunctionExpr) typ.Type
}
OverlayServices provides seed type resolution for overlay construction.
type OverlayServicesFuncs ¶
type OverlayServicesFuncs struct {
SeedTypeFn func(fn *ast.FunctionExpr) typ.Type
}
OverlayServicesFuncs adapts functions to OverlayServices.
func (OverlayServicesFuncs) SeedType ¶
func (o OverlayServicesFuncs) SeedType(fn *ast.FunctionExpr) typ.Type