Type System Architecture
AILANG uses a Hindley-Milner type system with row polymorphism and effect tracking.
Type Inference Pipeline
Key Phases
- Parsing: Surface syntax → Surface AST
- Elaboration: Surface AST → Core AST (ANF normalization)
- Type Inference: Core AST → Typed AST + CoreTypeInfo
- Validation: Verify CoreTypeInfo completeness (M-DX4)
- Lowering: Type-directed operator specialization
- Evaluation: Execute lowered Core AST
CoreTypeInfo: Type Information Storage
Purpose: Maps Core NodeIDs to their inferred types for use during lowering and later passes.
Definition (internal/types/typeinfo.go):
// CoreTypeInfo maps Core expression NodeIDs to their inferred types
type CoreTypeInfo map[uint64]Type
Population: During type inference, every Core expression gets an entry:
// After successful type inference (internal/types/typechecker_core.go:442)
tc.CoreTI.Set(expr.ID(), inferredType)
// After defaulting (lines 207-210, 340-342)
tc.CoreTI.ApplySubstitution(sub) // Resolve type variables to concrete types
CoreTypeInfo Invariant
CRITICAL COMPILER INVARIANT: Every Core node must have an entry in CoreTypeInfo before lowering.
Enforcement: Validation runs before lowering in all pipeline paths:
- File pipeline
- Module pipeline
- REPL
Validator: internal/pipeline/validate_coretypeinfo.go
The validator:
- Walks all Core node types (Var, Lit, Lambda, Let, LetRec, App, If, Match, BinOp, UnOp, Intrinsic, Record, List, Tuple, DictAbs, DictApp, etc.)
- Checks
CoreTypeInfo.Has(node.ID())for every node - Reports missing entries with: NodeID, ExprKind, Position, Hint
- Performance: O(n) linear, zero allocations
Properties:
- Presence required (every node must have a type)
- Polymorphic types accepted (type variables α, β, etc. are OK)
- Monomorphization-ready (validation checks presence, not concreteness)
Error Example:
CoreTypeInfo validation failed: missing type information for Core nodes
Missing Lit(Float) types (1 nodes):
• NodeID 42 at line 5, col 12
Hint: This usually means defaulting/substitution wasn't applied to CoreTI.
Debug with: ailang debug ast <file> --show-types --compact
Type Checking Algorithm
Constraint-Based Inference
AILANG uses Algorithm W (Hindley-Milner) with constraints:
- Generate constraints: Walk Surface AST, emit equality constraints
- Unify: Solve constraints to find principal types
- Defaulting: Resolve ambiguous numeric types (Int/Float)
- Generalization: Abstract free type variables to
forallquantifiers - Instantiation: Specialize polymorphic types at use sites
Row Polymorphism
Records and effects use row polymorphism for extensibility:
type Person = { name: string, age: int | r } -- Open row type
type Employee = { name: string, age: int, id: int } -- Extends Person
Effect rows track side effects:
readFile : string -> ! {IO | e} string
The effect row {IO | e} means:
- Requires
IOcapability - May have additional effects
e(polymorphic)
Effect System
Capability-Based Effects
Effects are tracked in function types and enforced at runtime:
-- Pure function (no effects)
add : int -> int -> int
-- Effectful function (requires IO capability)
println : string -> ! {IO} unit
Effect Checking
- Effect inference: Infer effect rows during type checking
- Effect subsumption: Check effect compatibility (subset relation)
- Capability checking: Verify runtime capabilities at evaluation
See internal/effects/ for effect runtime implementation.
Type Classes (Builtin)
Current implementation has hardcoded type class instances (Num, Eq, Ord, Show).
Planned: Structural reflection for user-defined type classes.
Dictionary Passing
Type class constraints are resolved via dictionary-passing transformation:
-- Surface syntax
add : forall a. Num a => a -> a -> a
-- Core (after elaboration)
add : forall a. NumDict a -> a -> a -> a
Dictionaries are constructed during elaboration and passed explicitly in Core AST.
Monomorphization
Transformation: Specialize polymorphic functions to concrete types before final codegen.
After monomorphization:
- All type variables resolved to concrete types
- Polymorphic functions duplicated per instantiation
- CoreTypeInfo updated with specialized types
The validator continues to work because it checks presence, not concreteness.
Implementation Files
Type System Core
internal/types/- Type representations and inferenceinternal/types/typechecker_core.go- Core AST type checkerinternal/types/typeinfo.go- CoreTypeInfo storage
Validation
internal/pipeline/validate_coretypeinfo.go- Validatorinternal/pipeline/validate_coretypeinfo_test.go- Testsinternal/pipeline/validate_coretypeinfo_bench_test.go- Benchmarks
Type-Directed Lowering
internal/pipeline/op_lowering.go- Operator specialization using CoreTypeInfo
Effects
internal/effects/- Effect runtime (capabilities, execution)