Skip to content
La3 Docs
Browse docs

Compiler Phases

The phase map from frontend checks through HIR, MIR, runtime, codegen, and later stdlib work.

Phase map

The compiler is being built in phases on purpose so each stage stays reviewable.

The plan is not a promise that every phase is complete right now. It is a dependency map that says which invariants must be true before later work can land without becoming a pile of hidden assumptions.

  • Phase 1: full type checking and borrow checking.
  • Phase 2: HIR lowering and desugaring.
  • Phase 3: MIR construction and control-flow lowering.
  • Phase 4: runtime library.
  • Phase 5 and 6: LLVM codegen and runtime-backed values.
  • Phase 12: dynamic stdlib policy and resolution.

Frontend invariants

The frontend is the correctness boundary, not just a parser.

  • Names are resolved before later passes see them.
  • Types are concrete before codegen starts.
  • Borrow checking rejects invalid ownership uses early.
  • The interpreter stays alive as a behavioural reference.

HIR

HIR is the typed, desugared representation the compiler can reason about without surface sugar in the way.

HIR removes the forms that are convenient for readers but awkward for lowering. It keeps the program tree-shaped, carries concrete types, and makes closures and bindings explicit so later passes do not need to rediscover surface syntax.

  • F-strings become formatting primitives plus concatenation.
  • ??, ?., ?, and while let lower to explicit control flow.
  • Binding sites are assigned stable ids.
  • Captured variables are listed explicitly on closures.

MIR

MIR is where the hard lowering work happens and where the control-flow graph becomes explicit.

  • It is a CFG of basic blocks with explicit temporaries.
  • Match lowering turns into decision trees.
  • Closure conversion becomes an explicit environment value.
  • Ownership lowering inserts drops and turns moves into the right operands.

Backend and runtime

LLVM stays thin, and the runtime owns the native heap model, string representation, and exported helpers.

  • The backend should translate MIR instead of re-inventing semantics.
  • The runtime exists so native binaries can share a stable support layer.
  • Differential testing checks compiled behaviour against the interpreter.