typ

package
v1.5.6 Latest Latest
Warning

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

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

Documentation

Overview

Package typ defines the core Type interface and type implementations.

All types in the type system implement the Type interface, which provides kind classification, string representation, hashing, and equality. Types are designed to be immutable and structurally comparable.

Primitive Types

Nil, Boolean, Number, Integer, String are singleton types representing Lua primitives. Integer is a subtype of Number.

Special Types

Any: Explicit dynamic type (opt-out of type checking). Operations on Any are permissive but lose type safety.

Unknown: Unresolved type information. Forces narrowing/inference rather than silently permitting operations.

Never: Bottom type (empty set). Represents unreachable code or impossible values. Never is a subtype of all types.

Self: Placeholder for the receiver type in method signatures. Substituted with the actual type when methods are resolved.

Composite Types

See the respective type files for: Function, Record, Union, Optional, Intersection, Tuple, Array, Map, Generic, Alias, Interface, and others.

Index

Constants

View Source
const DeepRecursionDepth = internal.MaxDeepDepth

DeepRecursionDepth is used for deep structural expansions.

View Source
const DefaultRecursionDepth = internal.MaxMediumDepth

DefaultRecursionDepth is the canonical recursion depth for typ operations.

Variables

View Source
var (
	True  = &Literal{Base: kind.Boolean, Value: true, hash: trueHash}
	False = &Literal{Base: kind.Boolean, Value: false, hash: falseHash}
)

True and False are singleton boolean literals.

View Source
var DefaultFormatOptions = FormatOptions{
	MaxDepth:        6,
	MaxNodes:        200,
	MaxUnionMembers: 6,
	MaxRecordFields: 8,
	MaxTupleElems:   8,
	MaxTypeParams:   6,
	MaxParams:       8,
	MaxReturns:      6,
	MaxBytes:        800,
}

DefaultFormatOptions keeps diagnostics readable while avoiding huge output.

View Source
var SoftAnnotationPolicy = SoftPolicy{}

SoftAnnotationPolicy treats empty records as non-soft (annotation semantics).

View Source
var SoftPlaceholderPolicy = SoftPolicy{AllowEmptyRecord: true}

SoftPlaceholderPolicy treats empty records as soft (placeholder semantics).

Functions

func DepthExceeded

func DepthExceeded(depth int) bool

DepthExceeded reports whether depth exceeds the default recursion limit.

func Format

func Format(t Type, opts FormatOptions) string

Format renders a type using the provided options.

func FormatShort

func FormatShort(t Type) string

FormatShort renders a type for diagnostics with bounded output size.

func GuardForDepth

func GuardForDepth(maxDepth int) internal.RecursionGuard

GuardForDepth returns a recursion guard for a specific depth. If maxDepth is non-positive, the default depth is used.

func HasKnownType added in v1.5.6

func HasKnownType(types []Type) bool

HasKnownType reports whether the slice contains at least one concrete type. nil entries and unknown entries are treated as unresolved.

func IsAbsentOrUnknown added in v1.5.6

func IsAbsentOrUnknown(t Type) bool

IsAbsentOrUnknown reports whether t is missing (nil) or unknown.

This intentionally does not treat the explicit nil type as unknown.

func IsAny added in v1.5.6

func IsAny(t Type) bool

IsAny reports whether t is explicitly the any type.

func IsBinaryMetamethod

func IsBinaryMetamethod(m Metamethod) bool

IsBinaryMetamethod returns true if the metamethod is for binary operators.

func IsComparisonMetamethod

func IsComparisonMetamethod(m Metamethod) bool

IsComparisonMetamethod returns true if the metamethod is for comparisons.

func IsMetamethod

func IsMetamethod(name string) bool

IsMetamethod returns true if the name is a valid metamethod.

func IsNever added in v1.5.6

func IsNever(t Type) bool

IsNever reports whether t is explicitly the never type.

func IsRecursiveRef

func IsRecursiveRef(t Type, rec *Recursive) bool

IsRecursiveRef returns true if t is a reference to the given recursive type.

func IsRefinableAnnotation added in v1.5.6

func IsRefinableAnnotation(t Type) bool

IsRefinableAnnotation reports whether an explicit annotation should be treated as a soft placeholder that call-site/contextual hints may refine.

Canonical rule: explicit top types (`any`, `unknown`) are authoritative and must not be rewritten by hints. Structural soft placeholders like `{any}` or `any[]` remain refinable.

func IsSoft

func IsSoft(t Type, policy SoftPolicy) bool

IsSoft reports whether a type should be treated as a soft placeholder under policy.

func IsUnaryMetamethod

func IsUnaryMetamethod(m Metamethod) bool

IsUnaryMetamethod returns true if the metamethod is for unary operators.

func IsUnknown added in v1.5.6

func IsUnknown(t Type) bool

IsUnknown reports whether t is explicitly the unknown type.

func IsUnknownOnlyOrEmpty added in v1.5.6

func IsUnknownOnlyOrEmpty(types []Type) bool

IsUnknownOnlyOrEmpty reports whether the slice has no concrete types.

func IsUnknownOrNil added in v1.5.6

func IsUnknownOrNil(t Type) bool

IsUnknownOrNil reports whether t is missing (nil), unknown, or explicit nil type.

func LiteralEquals

func LiteralEquals(a, b *Literal) bool

LiteralEquals checks if two literals are equal.

func MinRequiredArgs added in v1.5.6

func MinRequiredArgs(f *Function) int

MinRequiredArgs returns the minimum positional argument count required to call f.

Lua arguments are positional, so a required parameter after an optional parameter still requires all earlier positions to be present.

func NewDeepGuard

func NewDeepGuard() internal.RecursionGuard

NewDeepGuard returns a recursion guard using the canonical deep depth.

func NewGuard

func NewGuard() internal.RecursionGuard

NewGuard returns a recursion guard using the canonical default depth.

func TypeEquals

func TypeEquals(a, b Type) bool

TypeEquals compares two types for structural equality with cycle detection.

Uses coinductive equality for recursive types: if the same type pair is encountered again during traversal, they are assumed equal. This handles infinite recursive structures correctly.

Aliases are transparent: compares through to their targets.

func TypeMatchesLiteral

func TypeMatchesLiteral(t Type, lit *Literal) bool

TypeMatchesLiteral checks if a type is compatible with a literal value.

func TypeString

func TypeString(t Type) string

TypeString returns string representation with depth limiting.

func Visit

func Visit[R any](t Type, v Visitor[R]) R

Visit applies the first matching handler in v to t.

func VisitWithGuard

func VisitWithGuard[R any](
	t Type,
	guard internal.RecursionGuard,
	onCycle R,
	build func(next internal.RecursionGuard) Visitor[R],
) R

VisitWithGuard applies a Visitor with recursion guarding. Returns onCycle when the guard disallows entry.

func WithGuard

func WithGuard[R any](
	t Type,
	guard internal.RecursionGuard,
	onCycle R,
	fn func(next internal.RecursionGuard) R,
) R

WithGuard runs fn with a recursion guard and returns onCycle on guard rejection.

Types

type Alias

type Alias struct {
	Name   string // Alias name
	Target Type   // Underlying type
	// contains filtered or unexported fields
}

Alias represents a named type alias.

Aliases provide alternative names for types without creating new types. An Alias is structurally equivalent to its Target for subtyping and equality, but preserves the name for error messages and documentation.

Example: type UserId = number creates Alias{Name: "UserId", Target: number}

func NewAlias

func NewAlias(name string, target Type) *Alias

NewAlias creates a type alias.

func (*Alias) Equals

func (a *Alias) Equals(other Type) bool

Equals compares structurally through the alias target.

func (*Alias) Hash

func (a *Alias) Hash() uint64

func (*Alias) Kind

func (a *Alias) Kind() kind.Kind

func (*Alias) String

func (a *Alias) String() string

type Annotated

type Annotated struct {
	Inner       Type
	Annotations []Annotation
	// contains filtered or unexported fields
}

Annotated wraps a type with runtime validation annotations. The underlying type determines structural typing while annotations add runtime constraints like @min(0), @max(100), @pattern("^.+$").

func (*Annotated) Equals

func (a *Annotated) Equals(other Type) bool

func (*Annotated) Hash

func (a *Annotated) Hash() uint64

func (*Annotated) Kind

func (a *Annotated) Kind() kind.Kind

func (*Annotated) String

func (a *Annotated) String() string

type Annotation

type Annotation struct {
	Name string
	Arg  any
}

Annotation represents a runtime validation constraint.

func GetAnnotations

func GetAnnotations(t Type) []Annotation

GetAnnotations returns annotations from a type, or nil if none.

type Array

type Array struct {
	Element Type
	// contains filtered or unexported fields
}

Array represents a homogeneous sequence type: T[].

Arrays are Lua tables with integer keys starting at 1. The Element type describes what each element contains. Arrays support ipairs iteration and length operator (#).

func NewArray

func NewArray(elem Type) *Array

NewArray creates an array type.

func (*Array) Equals

func (a *Array) Equals(o Type) bool

func (*Array) Hash

func (a *Array) Hash() uint64

func (*Array) Kind

func (a *Array) Kind() kind.Kind

func (*Array) String

func (a *Array) String() string

type CaptureInfo

type CaptureInfo struct {
	Name    string
	Type    Type
	Mode    CaptureMode
	Escapes bool
	Mutated bool
}

CaptureInfo describes a single captured variable.

func (CaptureInfo) NeedsUpvalue

func (c CaptureInfo) NeedsUpvalue() bool

NeedsUpvalue returns true if this capture requires a heap-allocated upvalue.

type CaptureMode

type CaptureMode int

CaptureMode indicates how a variable is captured by a closure.

const (
	CaptureUnknown CaptureMode = iota
	CaptureByValue             // immutable, safe to copy at closure creation
	CaptureByRef               // mutable or escapes, needs upvalue
)

func (CaptureMode) String

func (m CaptureMode) String() string

type EffectInfo

type EffectInfo interface {
	internal.Equaler
	IsEffectInfo()
}

EffectInfo describes function effects (e.g., io, throw). Implemented by effect.Row.

type Field

type Field struct {
	Name     string
	Type     Type
	Optional bool // True if field may be absent (nil access returns nil)
	Readonly bool // True if field cannot be reassigned
}

Field represents a record field with name, type, optionality, and mutability.

type FieldAccess

type FieldAccess struct {
	Base  Type   // Base type (usually a TypeParam)
	Field string // Field name to access
	// contains filtered or unexported fields
}

FieldAccess represents a projected field type from an unresolved base.

Used in generic contexts where we need T.field but T is a type parameter. When T is instantiated with a concrete type, FieldAccess resolves to the actual field type.

Example: In a generic function returning T.name, if T is unresolved, the return type is FieldAccess{Base: T, Field: "name"}.

func NewFieldAccess

func NewFieldAccess(base Type, field string) *FieldAccess

NewFieldAccess creates a deferred field access.

func (*FieldAccess) Equals

func (f *FieldAccess) Equals(other Type) bool

func (*FieldAccess) Hash

func (f *FieldAccess) Hash() uint64

func (*FieldAccess) Kind

func (f *FieldAccess) Kind() kind.Kind

func (*FieldAccess) String

func (f *FieldAccess) String() string

type FormatOptions

type FormatOptions struct {
	MaxDepth        int
	MaxNodes        int
	MaxUnionMembers int
	MaxRecordFields int
	MaxTupleElems   int
	MaxTypeParams   int
	MaxParams       int
	MaxReturns      int
	MaxBytes        int
}

FormatOptions controls budgeted type rendering for diagnostics. Limits are best-effort; rendering may truncate with "..." when exceeded.

type Function

type Function struct {
	TypeParams []*TypeParam   // Generic type parameters (empty for non-generic)
	Params     []Param        // Positional parameters
	Variadic   Type           // Variadic element type (nil if not variadic)
	Returns    []Type         // Return types (empty for void functions)
	Effects    EffectInfo     // Effect row (effect.Row) for mutation/throw/io tracking
	Spec       SpecInfo       // Contract specification (*contract.Spec)
	Refinement RefinementInfo // Type refinement effect (*constraint.FunctionEffect)
	// contains filtered or unexported fields
}

Function represents a function type with parameters, returns, and effects.

Functions support generics via TypeParams, variadic arguments via Variadic, multiple return values via Returns, and effect tracking via Effects.

The Spec field holds Hoare-style contracts (pre/post conditions). The Refinement field holds type narrowing constraints for predicate functions.

func (*Function) Equals

func (f *Function) Equals(other Type) bool

func (*Function) Hash

func (f *Function) Hash() uint64

func (*Function) Kind

func (f *Function) Kind() kind.Kind

func (*Function) String

func (f *Function) String() string

type FunctionBuilder

type FunctionBuilder struct {
	// contains filtered or unexported fields
}

FunctionBuilder provides a fluent API for constructing function types.

Example:

fn := typ.Func().
    Param("x", typ.Number).
    Param("y", typ.Number).
    Returns(typ.Number).
    Build()

func Func

func Func() *FunctionBuilder

Func starts building a function type.

func (*FunctionBuilder) Build

func (b *FunctionBuilder) Build() *Function

Build creates the function type.

func (*FunctionBuilder) Effects

Effects sets effect row.

func (*FunctionBuilder) OptParam

func (b *FunctionBuilder) OptParam(name string, t Type) *FunctionBuilder

OptParam adds an optional parameter.

func (*FunctionBuilder) Param

func (b *FunctionBuilder) Param(name string, t Type) *FunctionBuilder

Param adds a required parameter.

func (*FunctionBuilder) Returns

func (b *FunctionBuilder) Returns(types ...Type) *FunctionBuilder

Returns sets return types.

func (*FunctionBuilder) Spec

Spec sets contract specification.

func (*FunctionBuilder) TypeParam

func (b *FunctionBuilder) TypeParam(name string, constraint Type) *FunctionBuilder

TypeParam adds a type parameter for generic functions.

func (*FunctionBuilder) Variadic

func (b *FunctionBuilder) Variadic(t Type) *FunctionBuilder

Variadic sets variadic parameter type.

func (*FunctionBuilder) WithRefinement

func (b *FunctionBuilder) WithRefinement(r RefinementInfo) *FunctionBuilder

WithRefinement sets the function refinement effect.

type Generic

type Generic struct {
	Name       string       // Type name (empty for anonymous generics)
	TypeParams []*TypeParam // Type parameters to be substituted
	Body       Type         // Template type with TypeParam references
	// contains filtered or unexported fields
}

Generic represents a parameterized type definition awaiting instantiation.

Generics have type parameters that are substituted with concrete types when instantiated. The Body contains the type with TypeParam references.

Identity:

  • Named generics use nominal identity (name + params, ignoring body)
  • Anonymous generics use structural identity (includes body in hash)

func NewGeneric

func NewGeneric(name string, params []*TypeParam, body Type) *Generic

NewGeneric creates a generic type definition. Named generics use nominal identity, anonymous generics use structural identity.

func (*Generic) Equals

func (g *Generic) Equals(other Type) bool

func (*Generic) Hash

func (g *Generic) Hash() uint64

func (*Generic) Kind

func (g *Generic) Kind() kind.Kind

func (*Generic) String

func (g *Generic) String() string

type IndexAccess

type IndexAccess struct {
	Base  Type // Base type (usually contains a TypeParam)
	Index Type // Index type for the access
	// contains filtered or unexported fields
}

IndexAccess represents a projected index type from an unresolved base.

Used in generic contexts where we need T[K] but T is a type parameter. When T is instantiated with a concrete type, IndexAccess resolves to the actual indexed element type.

Example: For Array<T>[number], if T is unresolved, the result is IndexAccess{Base: Array<T>, Index: number}.

func NewIndexAccess

func NewIndexAccess(base, index Type) *IndexAccess

NewIndexAccess creates a deferred index access.

func (*IndexAccess) Equals

func (i *IndexAccess) Equals(other Type) bool

func (*IndexAccess) Hash

func (i *IndexAccess) Hash() uint64

func (*IndexAccess) Kind

func (i *IndexAccess) Kind() kind.Kind

func (*IndexAccess) String

func (i *IndexAccess) String() string

type Instantiated

type Instantiated struct {
	Generic  *Generic // The generic being instantiated
	TypeArgs []Type   // Concrete types for each type parameter
	// contains filtered or unexported fields
}

Instantiated represents a generic type with concrete type arguments applied.

When a generic like Array<T> is used as Array<number>, an Instantiated type is created with Generic=Array and TypeArgs=[number]. The body can be expanded by substituting type parameters with arguments.

func Instantiate

func Instantiate(g *Generic, args ...Type) *Instantiated

Instantiate creates an instantiated generic type with the given arguments.

func (*Instantiated) Equals

func (i *Instantiated) Equals(other Type) bool

func (*Instantiated) Hash

func (i *Instantiated) Hash() uint64

func (*Instantiated) Kind

func (i *Instantiated) Kind() kind.Kind

func (*Instantiated) String

func (i *Instantiated) String() string

type Interface

type Interface struct {
	Name    string   // Interface name (empty for anonymous)
	Methods []Method // Required methods
	// contains filtered or unexported fields
}

Interface represents a structural interface type (trait/protocol).

Interfaces define a set of methods that a type must implement. Unlike nominal interfaces, subtyping is structural: any type with matching methods satisfies the interface.

Named interfaces (Name != "") use nominal identity for marker interfaces (interfaces with no methods, like Channel<T>).

func NewInterface

func NewInterface(name string, methods []Method) *Interface

NewInterface creates an interface type.

func (*Interface) Equals

func (i *Interface) Equals(other Type) bool

func (*Interface) Hash

func (i *Interface) Hash() uint64

func (*Interface) Kind

func (i *Interface) Kind() kind.Kind

func (*Interface) String

func (i *Interface) String() string

type Intersection

type Intersection struct {
	Members []Type
	// contains filtered or unexported fields
}

Intersection represents a type satisfying all member constraints: T1 & T2 & ...

Intersections require a value to satisfy every member type simultaneously. They are normalized during construction:

  • Nested intersections are flattened
  • Duplicate members are removed
  • Any members are dropped (Any is identity for intersection)
  • Never absorbs all other members (intersection with Never = Never)

Members are sorted by hash for deterministic comparison.

func (*Intersection) Equals

func (i *Intersection) Equals(other Type) bool

func (*Intersection) Hash

func (i *Intersection) Hash() uint64

func (*Intersection) Kind

func (i *Intersection) Kind() kind.Kind

func (*Intersection) String

func (i *Intersection) String() string

type Literal

type Literal struct {
	Base  kind.Kind // Boolean, Number, Integer, or String
	Value any       // bool, float64, int64, or string
	// contains filtered or unexported fields
}

Literal represents a singleton type containing exactly one value.

Literal types enable precise type checking for constant values:

  • LiteralBool(true) is a subtype of boolean
  • LiteralString("foo") is a subtype of string
  • LiteralInt(42) is a subtype of integer (and number)

Base indicates the underlying primitive kind (Boolean, Number, Integer, String). Value holds the actual value with the appropriate Go type.

func LiteralBool

func LiteralBool(v bool) *Literal

LiteralBool returns the canonical boolean literal type.

func LiteralInt

func LiteralInt(v int64) *Literal

LiteralInt creates an integer literal type.

func LiteralNumber

func LiteralNumber(v float64) *Literal

LiteralNumber creates a number literal type.

func LiteralString

func LiteralString(v string) *Literal

LiteralString creates a string literal type.

func (*Literal) Equals

func (l *Literal) Equals(other Type) bool

func (*Literal) Hash

func (l *Literal) Hash() uint64

func (*Literal) Kind

func (l *Literal) Kind() kind.Kind

func (*Literal) String

func (l *Literal) String() string

type Map

type Map struct {
	Key   Type
	Value Type
	// contains filtered or unexported fields
}

Map represents a homogeneous key-value mapping: {[K]: V}.

Maps are Lua tables where all keys have type K and all values have type V. Unlike Records, Maps have uniform types for all entries rather than named fields with potentially different types.

func NewMap

func NewMap(key, value Type) *Map

NewMap creates a map type.

func (*Map) Equals

func (m *Map) Equals(o Type) bool

func (*Map) Hash

func (m *Map) Hash() uint64

func (*Map) Kind

func (m *Map) Kind() kind.Kind

func (*Map) String

func (m *Map) String() string

type Meta

type Meta struct {
	Of Type // The type being wrapped
	// contains filtered or unexported fields
}

Meta represents a metatype (the type of a type value).

Meta types are used when types themselves are values, such as in type predicates or reflection. Meta{Of: T} represents the type of a runtime value that carries type T.

Example: typeof(Point) has type Meta{Of: Point}

func NewMeta

func NewMeta(of Type) *Meta

NewMeta creates a metatype.

func (*Meta) Equals

func (m *Meta) Equals(other Type) bool

func (*Meta) Hash

func (m *Meta) Hash() uint64

func (*Meta) Kind

func (m *Meta) Kind() kind.Kind

func (*Meta) String

func (m *Meta) String() string

type Metamethod

type Metamethod string

Metamethod represents a Lua metamethod identifier.

const (
	MetaIndex    Metamethod = "__index"
	MetaNewIndex Metamethod = "__newindex"
	MetaCall     Metamethod = "__call"
	MetaAdd      Metamethod = "__add"
	MetaSub      Metamethod = "__sub"
	MetaMul      Metamethod = "__mul"
	MetaDiv      Metamethod = "__div"
	MetaMod      Metamethod = "__mod"
	MetaPow      Metamethod = "__pow"
	MetaUnm      Metamethod = "__unm"
	MetaIDiv     Metamethod = "__idiv"
	MetaBand     Metamethod = "__band"
	MetaBor      Metamethod = "__bor"
	MetaBxor     Metamethod = "__bxor"
	MetaBnot     Metamethod = "__bnot"
	MetaShl      Metamethod = "__shl"
	MetaShr      Metamethod = "__shr"
	MetaConcat   Metamethod = "__concat"
	MetaLen      Metamethod = "__len"
	MetaEq       Metamethod = "__eq"
	MetaLt       Metamethod = "__lt"
	MetaLe       Metamethod = "__le"
	MetaToString Metamethod = "__tostring"
	MetaPairs    Metamethod = "__pairs"
	MetaIPairs   Metamethod = "__ipairs"
	MetaGC       Metamethod = "__gc"
	MetaClose    Metamethod = "__close"
	MetaMode     Metamethod = "__mode"
	MetaName     Metamethod = "__name"
)

func OperatorToMetamethod

func OperatorToMetamethod(op string) (Metamethod, bool)

OperatorToMetamethod maps a binary operator to its metamethod.

func UnaryOperatorToMetamethod

func UnaryOperatorToMetamethod(op string) (Metamethod, bool)

UnaryOperatorToMetamethod maps a unary operator to its metamethod.

type Metatabled

type Metatabled interface {
	Type
	GetMetamethod(m Metamethod) *Function
	HasMetamethod(m Metamethod) bool
}

Metatabled is an interface for types that can have metamethods.

type Method

type Method struct {
	Name string    // Method name
	Type *Function // Method signature
}

Method represents a method in an interface type.

type Optional

type Optional struct {
	Inner Type
	// contains filtered or unexported fields
}

Optional represents a nullable type: T | nil.

Optional is syntactic sugar for a union with nil. It provides cleaner representation for the common case of a value that may be absent.

The Inner field holds the non-nil type. An Optional never contains another Optional (they are flattened during construction).

func (*Optional) Equals

func (o *Optional) Equals(other Type) bool

func (*Optional) Hash

func (o *Optional) Hash() uint64

func (*Optional) Kind

func (o *Optional) Kind() kind.Kind

func (*Optional) String

func (o *Optional) String() string

type Param

type Param struct {
	Name     string
	Type     Type
	Optional bool // True if parameter has a default value
}

Param represents a function parameter with name, type, and optionality.

type Platform

type Platform struct {
	Name string // Platform type name
	// contains filtered or unexported fields
}

Platform represents a platform-specific opaque type.

Platform types are provided by the runtime environment and have no structural representation in the type system. They are compared nominally by name.

Example: userdata types, file handles, coroutines.

func NewPlatform

func NewPlatform(name string) *Platform

NewPlatform creates a platform type.

func (*Platform) Equals

func (p *Platform) Equals(other Type) bool

func (*Platform) Hash

func (p *Platform) Hash() uint64

func (*Platform) Kind

func (p *Platform) Kind() kind.Kind

func (*Platform) String

func (p *Platform) String() string

type Record

type Record struct {
	Fields    []Field
	Metatable Type // Metatable type for metamethod lookup
	MapKey    Type // Map component key type (nil if no map component)
	MapValue  Type // Map component value type (nil if no map component)
	Open      bool // Allow access to undefined fields
	// contains filtered or unexported fields
}

Record represents a Lua table with named fields: {field1: T1, field2: T2, ...}.

Records support both structural typing (field presence/type matching) and optional map components for tables with dynamic indexing.

Features:

  • Open: When true, unknown field access returns Unknown instead of error
  • MapKey/MapValue: Optional map component for {foo: T, [K]: V} patterns
  • Metatable: Optional metatable type for metamethod resolution

Fields are sorted by name for deterministic hashing and comparison.

func (*Record) Equals

func (r *Record) Equals(other Type) bool

func (*Record) GetField

func (r *Record) GetField(name string) *Field

GetField returns the field with the given name, or nil.

func (*Record) HasMapComponent

func (r *Record) HasMapComponent() bool

HasMapComponent returns true if the record has a map component (MapKey and MapValue set).

func (*Record) Hash

func (r *Record) Hash() uint64

func (*Record) Kind

func (r *Record) Kind() kind.Kind

func (*Record) String

func (r *Record) String() string

type RecordBuilder

type RecordBuilder struct {
	// contains filtered or unexported fields
}

RecordBuilder provides a fluent API for constructing record types.

Example:

rec := typ.NewRecord().
    Field("name", typ.String).
    OptField("age", typ.Integer).
    Build()

func NewRecord

func NewRecord() *RecordBuilder

NewRecord starts building a record type.

func (*RecordBuilder) AnnotatedField

func (b *RecordBuilder) AnnotatedField(name string, t Type, optional bool, annotations []Annotation) *RecordBuilder

AnnotatedField adds a field with validation annotations.

func (*RecordBuilder) Build

func (b *RecordBuilder) Build() *Record

Build creates the record type.

func (*RecordBuilder) Field

func (b *RecordBuilder) Field(name string, t Type) *RecordBuilder

Field adds a required field.

func (*RecordBuilder) MapComponent

func (b *RecordBuilder) MapComponent(key, value Type) *RecordBuilder

MapComponent sets the map component key and value types.

func (*RecordBuilder) Metatable

func (b *RecordBuilder) Metatable(t Type) *RecordBuilder

Metatable sets the metatable type.

func (*RecordBuilder) OptField

func (b *RecordBuilder) OptField(name string, t Type) *RecordBuilder

OptField adds an optional field.

func (*RecordBuilder) OptReadonlyField

func (b *RecordBuilder) OptReadonlyField(name string, t Type) *RecordBuilder

OptReadonlyField adds an optional readonly field.

func (*RecordBuilder) ReadonlyField

func (b *RecordBuilder) ReadonlyField(name string, t Type) *RecordBuilder

ReadonlyField adds a readonly field.

func (*RecordBuilder) SetOpen

func (b *RecordBuilder) SetOpen(open bool) *RecordBuilder

SetOpen marks the record as open (unknown field access returns unknown).

type Recursive

type Recursive struct {
	ID   uint64
	Name string
	Body Type
}

Recursive represents a self-referential (mu) type. Recursive types are identified by a unique ID to allow cycle detection during equality comparison and hashing without infinite recursion.

Example: type Node = { next: Node? } is represented as:

Recursive{ID: 1, Name: "Node", Body: Record{Fields: [{name: "next", type: <self-ref>}]}}

func NewRecursive

func NewRecursive(name string, builder RecursiveBuilder) *Recursive

NewRecursive creates a new recursive type. The builder function receives a placeholder that represents self-references and should return the body type using that placeholder where needed.

func NewRecursivePlaceholder

func NewRecursivePlaceholder(name string) *Recursive

NewRecursivePlaceholder creates an empty recursive type for deferred body assignment. Use SetBody to assign the body after creation. This is useful for mutual recursion.

func NewRecursiveWithBody

func NewRecursiveWithBody(name string, body Type) *Recursive

NewRecursiveWithBody creates a recursive type with a pre-built body. Use this when the body is already constructed with proper self-references.

func (*Recursive) Equals

func (r *Recursive) Equals(other Type) bool

Equals compares two recursive types by their structural identity. Two recursive types are equal if they have the same structure when the self-references are treated as equivalent.

func (*Recursive) Hash

func (r *Recursive) Hash() uint64

func (*Recursive) Kind

func (r *Recursive) Kind() kind.Kind

func (*Recursive) SetBody

func (r *Recursive) SetBody(body Type)

SetBody assigns the body to a placeholder recursive type.

func (*Recursive) String

func (r *Recursive) String() string

type RecursiveBuilder

type RecursiveBuilder func(self Type) Type

RecursiveBuilder is used during construction to provide a self-reference.

type Ref

type Ref struct {
	Module string // Module path (empty for local references)
	Name   string // Type name
	// contains filtered or unexported fields
}

Ref represents an unresolved reference to a named type definition.

Refs are created during parsing when a type name is encountered before its definition. They are resolved to the actual type during semantic analysis using the Module path to locate the definition.

Local refs (Module == "") refer to types in the current module. Cross-module refs include the module path for import resolution.

func NewRef

func NewRef(module, name string) *Ref

NewRef creates a type reference.

func (*Ref) Equals

func (r *Ref) Equals(other Type) bool

func (*Ref) Hash

func (r *Ref) Hash() uint64

func (*Ref) Kind

func (r *Ref) Kind() kind.Kind

func (*Ref) String

func (r *Ref) String() string

type RefinementInfo

type RefinementInfo interface {
	internal.Equaler
	IsRefinementInfo()
}

RefinementInfo describes type refinements from function calls. Implemented by *constraint.FunctionEffect.

type SoftPolicy

type SoftPolicy struct {
	// AllowEmptyRecord treats {} as a soft placeholder when true.
	AllowEmptyRecord bool
}

SoftPolicy controls how soft-placeholder detection behaves.

type SpecInfo

type SpecInfo interface {
	internal.Equaler
	IsSpecInfo()
}

SpecInfo describes function specifications (pre/post conditions). Implemented by *contract.Spec.

type Sum

type Sum struct {
	Name     string    // Type name for display
	Variants []Variant // Possible cases
	// contains filtered or unexported fields
}

Sum represents a tagged union (sum type / discriminated union).

Sum types enable safe pattern matching over a closed set of variants. Each variant has a tag and optional associated data.

Example: Option<T> = Some(T) | None

func NewSum

func NewSum(name string, variants []Variant) *Sum

NewSum creates a sum type.

func (*Sum) Equals

func (s *Sum) Equals(other Type) bool

func (*Sum) Hash

func (s *Sum) Hash() uint64

func (*Sum) Kind

func (s *Sum) Kind() kind.Kind

func (*Sum) String

func (s *Sum) String() string

type Tuple

type Tuple struct {
	Elements []Type
	// contains filtered or unexported fields
}

Tuple represents a fixed-length heterogeneous sequence: (T1, T2, ...).

Tuples are used for multi-value returns and destructuring assignments. Unlike Arrays, each position can have a different type and the length is fixed at compile time.

func NewTuple

func NewTuple(elems ...Type) *Tuple

NewTuple creates a tuple type.

func (*Tuple) Equals

func (t *Tuple) Equals(o Type) bool

func (*Tuple) Hash

func (t *Tuple) Hash() uint64

func (*Tuple) Kind

func (t *Tuple) Kind() kind.Kind

func (*Tuple) String

func (t *Tuple) String() string

type Type

type Type interface {
	Kind() kind.Kind
	String() string
	Hash() uint64
	Equals(other Type) bool
}

Type is the interface implemented by all types in the type system. Types are immutable and support structural equality and hashing.

var (
	Nil     Type = nilType{}
	Boolean Type = booleanType{}
	Number  Type = numberType{}
	Integer Type = integerType{}
	String  Type = stringType{}
	Any     Type = anyType{}
	Unknown Type = unknownType{}
	Never   Type = neverType{}
	Self    Type = selfType{}
)

Primitives are singletons.

Any vs Unknown semantics:

  • Any: explicit dynamic type (opt-out). Use only when the source is explicitly "any" or a deliberate dynamic escape hatch. Operations on Any are permissive.
  • Unknown: missing or unresolved information. It should force narrowing/inference rather than silently permitting operations.
var LuaError Type = NewInterface("Error", []Method{
	{Name: "kind", Type: Func().Param("self", Self).Returns(String).Build()},
	{Name: "retryable", Type: Func().Param("self", Self).Returns(Boolean).Build()},
	{Name: "details", Type: Func().Param("self", Self).Returns(Any).Build()},
	{Name: "message", Type: Func().Param("self", Self).Returns(String).Build()},
	{Name: "stack", Type: Func().Param("self", Self).Returns(String).Build()},
})

LuaError is the standard error type for Lua functions. It represents structured errors with message, kind, retryable, etc.

func ExtendRecordWithField

func ExtendRecordWithField(base Type, field string, fieldType Type) Type

ExtendRecordWithField returns a record type extended with a field. If the base type is nil, any, unknown, or nil, creates a new record with just the field. If the base type is already a record, adds or updates the field.

func JoinBranchOutcome added in v1.5.6

func JoinBranchOutcome(a, b Type) Type

JoinBranchOutcome merges mutually-exclusive expression outcomes (for example, `a and b` / `a or b`) while preserving uncertainty.

Unlike JoinPreferNonSoft, this must not treat unknown as absent information: expression typing needs to preserve runtime uncertainty when one branch may still produce unknown-like values.

func JoinPreferNonSoft

func JoinPreferNonSoft(a, b Type) Type

JoinPreferNonSoft joins two types while preferring non-soft placeholders. This centralizes the "soft placeholder" policy used across inference and flow.

func JoinReturnSlot added in v1.5.6

func JoinReturnSlot(a, b Type) Type

JoinReturnSlot merges return slot types while preserving uncertainty.

Unknown in return inference means unresolved runtime behavior. When one branch is unknown and another is explicit nil, keep unknown so summaries do not collapse to nil-only.

func NewAnnotated

func NewAnnotated(inner Type, annotations []Annotation) Type

NewAnnotated creates an annotated type wrapper. Returns the inner type directly if no annotations are provided.

func NewIntersection

func NewIntersection(members ...Type) Type

NewIntersection creates a normalized intersection type. Returns Any for empty intersections, the single type for one member, or a normalized Intersection for multiple distinct members.

func NewOptional

func NewOptional(inner Type) Type

NewOptional creates an optional type (T | nil).

Normalization rules:

  • nil or Nil → Nil (already optional)
  • T? → T? (already optional)
  • Any → Any (Any already includes nil)
  • Union → adds nil and re-normalizes through NewUnion

func NewUnion

func NewUnion(members ...Type) Type

NewUnion creates a normalized union type from the given members. Returns Never for empty unions, the single type for one member, or a normalized Union for multiple distinct members.

func PruneSoftUnionMembers

func PruneSoftUnionMembers(t Type) Type

PruneSoftUnionMembers removes soft placeholder members from unions when any non-soft member is present. This helps inference avoid contaminating concrete types with placeholder unions.

func Rewrite

func Rewrite(t Type, fn func(Type) (Type, bool)) Type

Rewrite traverses a type tree and applies fn at each node (bottom-up transformation).

The function fn is called on each type node before recursing into children. If fn returns (replacement, true), the replacement is used and children are not visited (early termination). If fn returns (_, false), children are recursively rewritten first, then the result is reassembled.

Returns the original pointer when nothing changed (structural sharing). This is the foundation for type substitution, expansion, and other transforms.

func UnwrapAnnotated

func UnwrapAnnotated(t Type) Type

UnwrapAnnotated returns the inner type, stripping annotations.

type TypeParam

type TypeParam struct {
	Name       string
	Constraint Type // Upper bound (nil means any type)
	// contains filtered or unexported fields
}

TypeParam represents a type parameter in a generic type or function.

Type parameters enable parametric polymorphism: a single definition that works with multiple types. The Constraint field bounds what types can instantiate this parameter (nil means any type is allowed).

Example: In Array<T>, T is a TypeParam with Name="T" and Constraint=nil.

func NewTypeParam

func NewTypeParam(name string, constraint Type) *TypeParam

NewTypeParam creates a type parameter.

func (*TypeParam) Equals

func (t *TypeParam) Equals(other Type) bool

func (*TypeParam) Hash

func (t *TypeParam) Hash() uint64

func (*TypeParam) Kind

func (t *TypeParam) Kind() kind.Kind

func (*TypeParam) String

func (t *TypeParam) String() string

type TypeVar

type TypeVar struct {
	ID int
	// contains filtered or unexported fields
}

TypeVar represents an inference variable during type checking.

Type variables are placeholders created during generic instantiation and constraint solving. They are unified with concrete types as the checker gathers information. ID distinguishes different variables.

func NewTypeVar

func NewTypeVar(id int) *TypeVar

NewTypeVar creates a type variable with the given ID.

func (*TypeVar) Equals

func (t *TypeVar) Equals(other Type) bool

func (*TypeVar) Hash

func (t *TypeVar) Hash() uint64

func (*TypeVar) Kind

func (t *TypeVar) Kind() kind.Kind

func (*TypeVar) String

func (t *TypeVar) String() string

type Union

type Union struct {
	Members []Type
	// contains filtered or unexported fields
}

Union represents a type that can be any of its member types: T1 | T2 | ...

Unions are normalized during construction:

  • Nested unions are flattened
  • Duplicate members are removed
  • Never members are dropped (Never is identity for union)
  • Any absorbs all other members (union with Any = Any)
  • Literals are subsumed by their base types (string | "foo" = string)
  • Single non-nil member with nil becomes Optional

Members are sorted by hash for deterministic comparison and serialization.

func (*Union) Contains

func (u *Union) Contains(t Type) bool

Contains checks if the union contains a specific type.

func (*Union) Equals

func (u *Union) Equals(other Type) bool

func (*Union) Hash

func (u *Union) Hash() uint64

func (*Union) Kind

func (u *Union) Kind() kind.Kind

func (*Union) String

func (u *Union) String() string

type Variant

type Variant struct {
	Tag   string // Discriminant value (e.g., "Some", "None")
	Types []Type // Associated data types (empty for unit variant like None)
}

Variant represents a case in a sum type (tagged union). Tag is the discriminant, Types holds the associated data (empty for unit variants).

type Visitor

type Visitor[R any] struct {
	Optional     func(*Optional) R
	Union        func(*Union) R
	Intersection func(*Intersection) R
	Array        func(*Array) R
	Map          func(*Map) R
	Tuple        func(*Tuple) R
	Function     func(*Function) R
	Record       func(*Record) R
	Alias        func(*Alias) R
	Ref          func(*Ref) R
	Platform     func(*Platform) R
	Meta         func(*Meta) R
	Generic      func(*Generic) R
	Instantiated func(*Instantiated) R
	TypeParam    func(*TypeParam) R
	TypeVar      func(*TypeVar) R
	FieldAccess  func(*FieldAccess) R
	IndexAccess  func(*IndexAccess) R
	Sum          func(*Sum) R
	Interface    func(*Interface) R
	Recursive    func(*Recursive) R
	Literal      func(*Literal) R
	Default      func(Type) R
}

Visitor dispatches on concrete type implementations. Nil handlers fall back to Default when provided; otherwise return zero.

Directories

Path Synopsis
Package join provides type join operations for control flow merging.
Package join provides type join operations for control flow merging.
Package subst provides type substitution operations for generics.
Package subst provides type substitution operations for generics.
Package union provides union type analysis operations.
Package union provides union type analysis operations.
Package unwrap provides type unwrapping, extraction, and predicate operations.
Package unwrap provides type unwrapping, extraction, and predicate operations.

Jump to

Keyboard shortcuts

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