Documentation
¶
Overview ¶
Package io provides binary serialization and deserialization for Lua types.
The package supports full round-trip encoding of all type system constructs including primitives, composites (records, functions, unions), generics, and flow-sensitive constraints. Serialized types are stored in manifests for cross-module type resolution.
Primary APIs:
- Encode/Decode: Serialize individual types to/from bytes
- Manifest: Cross-module type information container
- FunctionSummary: Interprocedural analysis data
The binary format uses little-endian encoding with length-prefixed strings and type-tagged values. Version numbers track format changes for backward compatibility checking.
Usage:
data, err := io.Encode(typ.String)
decoded, err := io.Decode(data)
manifest := io.NewManifest("mymodule")
manifest.SetExport(exportType)
data, err := manifest.Encode()
Index ¶
- Variables
- func ApplyFunctionSummary(fn *typ.Function, summary *FunctionSummary) *typ.Function
- func Decode(data []byte) (typ.Type, error)
- func Encode(t typ.Type) ([]byte, error)
- func EncodeManifest(m *Manifest) ([]byte, error)
- func LookupEnrichedExport(manifests ManifestQuerier, path string) typ.Type
- type FunctionSummary
- type Manifest
- func (m *Manifest) AddGlobal(name string, t typ.Type)
- func (m *Manifest) AllGlobals() map[string]typ.Type
- func (m *Manifest) AllSummaries() map[string]*FunctionSummary
- func (m *Manifest) AllTypes() map[string]typ.Type
- func (m *Manifest) DefineSummary(name string, s *FunctionSummary)
- func (m *Manifest) DefineType(name string, t typ.Type)
- func (m *Manifest) Encode() ([]byte, error)
- func (m *Manifest) EnrichedExport() typ.Type
- func (m *Manifest) LookupSummary(name string) (*FunctionSummary, bool)
- func (m *Manifest) LookupType(name string) (typ.Type, bool)
- func (m *Manifest) LookupValue(name string) (typ.Type, bool)
- func (m *Manifest) SetExport(t typ.Type)
- type ManifestQuerier
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidManifest indicates the file header does not contain the magic bytes. ErrInvalidManifest = errors.New("invalid manifest header") // ErrVersionMismatch indicates the manifest was created with an incompatible version. ErrVersionMismatch = errors.New("manifest version mismatch") )
Manifest decoding errors.
Functions ¶
func ApplyFunctionSummary ¶
func ApplyFunctionSummary(fn *typ.Function, summary *FunctionSummary) *typ.Function
ApplyFunctionSummary enriches a function type with behavioral data from a summary.
This function merges type-level function information with runtime behavioral specifications. It is used for cross-module constraint and effect propagation.
Merge strategy:
- Effects: Summary effects take precedence if non-empty
- Spec: Built from summary constraints if present
- Refinement: Built from summary ensures if present
- Falls back to existing fn values when summary doesn't provide data
The result is a new function type; the input fn is not modified.
func EncodeManifest ¶
EncodeManifest encodes a manifest to bytes.
func LookupEnrichedExport ¶ added in v1.5.6
func LookupEnrichedExport(manifests ManifestQuerier, path string) typ.Type
LookupEnrichedExport resolves the manifest by path and returns its enriched export type.
Types ¶
type FunctionSummary ¶
type FunctionSummary struct {
Params []typ.Type
Returns []typ.Type
Effects effect.Row
// Contract constraints
Requires constraint.Condition
Ensures constraint.Condition
ExprRequires []constraint.ExprCompare
ExprEnsures []constraint.ExprCompare
// Escape analysis
ParamEscapes []bool
ReturnsParam int // -1 if returns fresh value
}
FunctionSummary captures function behavior for cross-module flow analysis.
Summaries enable sophisticated type checking across module boundaries without re-analyzing source code. They encode:
Type information:
- Params: Parameter types for arity and type checking
- Returns: Return types for result type derivation
- Effects: Effect row for effect propagation
Contract information (Hoare-style pre/postconditions):
- Requires: Preconditions that must hold at call sites
- Ensures: Postconditions guaranteed after the call
- ExprRequires/ExprEnsures: Arithmetic constraints on lengths/indices
Escape analysis information:
- ParamEscapes: Which parameters escape (are stored, not just borrowed)
- ReturnsParam: If >= 0, indicates which param flows to return (passthrough)
The type checker uses summaries to:
- Check argument types against parameter types
- Derive return types from effects and argument types
- Propagate narrowing constraints through function calls
- Track value ownership for optimization
func NewSummary ¶
func NewSummary(params, returns []typ.Type) *FunctionSummary
NewSummary creates a function summary.
func (*FunctionSummary) Clone ¶
func (s *FunctionSummary) Clone() *FunctionSummary
Clone returns a deep copy of the FunctionSummary.
type Manifest ¶
type Manifest struct {
// Path is the module path used for require() resolution.
Path string
// Version is a monotonic counter for cache invalidation.
Version uint64
// Export is the type returned by require(). Usually a record of functions.
Export typ.Type
// Types maps type names to their definitions for cross-module type references.
Types map[string]typ.Type
// Summaries maps function names to their behavioral specifications.
// Enables interprocedural analysis without source code.
Summaries map[string]*FunctionSummary
// Globals records types assigned to _G for global namespace pollution tracking.
Globals map[string]typ.Type
// contains filtered or unexported fields
}
Manifest captures type information for cross-module resolution.
A manifest is the persistent representation of a module's type signature, enabling type checking across module boundaries without re-analyzing source. Manifests are serialized to binary and stored alongside compiled Lua chunks.
The manifest lifecycle:
- Analysis phase generates a manifest from source analysis
- Manifest is serialized and stored (cache or file)
- Dependent modules load the manifest via db.Connect()
- Type checker resolves cross-module references through ManifestQuerier
Thread safety: Manifest instances are immutable after creation. The db.DB handles concurrent access during Connect/Disconnect operations.
func DecodeManifest ¶
DecodeManifest deserializes binary to manifest.
func LookupManifest ¶ added in v1.5.6
func LookupManifest(manifests ManifestQuerier, path string) *Manifest
LookupManifest resolves a manifest by path.
Resolution policy is canonical across checker layers:
- Direct lookup via Manifest(path)
- Fallback lookup via Imports()path
func (*Manifest) AllGlobals ¶
AllGlobals returns a copy of all global definitions.
func (*Manifest) AllSummaries ¶
func (m *Manifest) AllSummaries() map[string]*FunctionSummary
AllSummaries returns a deep copy of all function summaries.
func (*Manifest) DefineSummary ¶
func (m *Manifest) DefineSummary(name string, s *FunctionSummary)
DefineSummary adds a function summary.
func (*Manifest) DefineType ¶
DefineType adds a type definition.
func (*Manifest) EnrichedExport ¶
EnrichedExport returns the Export type with function summaries applied.
This method combines the structural Export type with behavioral information from Summaries. For each function field in the export record, if a matching summary exists, the function type is enriched with:
- Effects from the summary's effect row
- Spec from the summary's contract constraints
- Refinement from the summary's ensures condition
This enables cross-module constraint propagation and effect tracking without storing redundant information in both Export and Summaries.
func (*Manifest) LookupSummary ¶
func (m *Manifest) LookupSummary(name string) (*FunctionSummary, bool)
LookupSummary finds a function summary.
func (*Manifest) LookupType ¶
LookupType finds a type by name.
func (*Manifest) LookupValue ¶ added in v1.5.6
LookupValue finds an exported value field by name from the enriched export type.
type ManifestQuerier ¶
type ManifestQuerier interface {
// Manifest returns the manifest for the given module path, or nil if not loaded.
Manifest(path string) *Manifest
// Imports returns all loaded manifests keyed by module path.
Imports() map[string]*Manifest
}
ManifestQuerier provides read-only access to module manifests.
This interface decouples manifest consumers from the storage implementation. It is implemented by db.DB for the analysis context.
Architecture:
- types/io defines Manifest structure and serialization
- types/db provides storage and caching via the DB type
- Analysis code accesses manifests through ManifestQuerier
This layering prevents import cycles and allows different storage backends.