Atoll narrows a checked program through three intermediate representations. Each one has a different authority:
| Representation | Owns | Deliberately leaves out |
|---|---|---|
| HIR | Resolved source meaning, types, dispatch, effects, patterns, and origins | Physical frames and WebAssembly values |
| MIR | Monomorphic control flow, suspension, storage, ABI plans, and ownership operations | Surface syntax and unresolved types |
| WasmIR | Primitive WebAssembly value flow, explicit storage boundaries, effects, and encodable control | Language-level inference and layout decisions |
These are not three spellings of the same tree. Information is intentionally removed or made explicit at every transition. HIR preserves source-shaped constructs such as patterns and type matches. MIR replaces those constructs with blocks, values, and transfers. WasmIR accepts only operations whose WebAssembly behavior is already determined.
Handoff rule
A producer must establish every invariant its consumer relies on. A consumer may validate that contract, but it must not silently reconstruct an omitted decision.
checked HIR
-- specialize types and calls -->
monomorphic HIR
-- lower control, suspension, ownership, and layout -->
MIR
-- canonicalize ABI and runtime operations -->
canonical MIR
-- lower primitive values and effects -->
WasmIR
-- structure, allocate, and encode -->
WebAssemblyFor example, semantic analysis chooses which method or trait witness a call uses. MIR may choose a direct or frame calling convention for that resolved target. WasmIR records the selected call kind and operand types. The encoder does not repeat overload resolution, inspect a semantic type registry, or guess whether a call can suspend.
Identity
Identifiers are representation-local. A HirExprId, MIR LocalId, and
WasmIR VReg can have the same numeric spelling without identifying the same
thing. Cross-layer tools use explicit provenance maps:
AST origin
↓
HIR node + Origin
↓
MIR op/terminator → HIR node and source range
↓
WasmIR instruction → MIR block/op
↓
encoded offset → source/debug recordIDs are dense handles into arenas or vectors. They are not stable public file formats, hashes, or addresses. Moving a node between a local and merged arena requires relocation; changing a block or instruction sequence requires updating its side tables.
Error policy
Recovery nodes are allowed while the front end is collecting diagnostics. They prevent one source error from cascading into dozens of unrelated messages. They do not authorize code generation.
An error-severity front-end diagnostic closes the backend gate. Likewise, a MIR or WasmIR verifier failure is a compiler defect or a backend diagnostic, not a request to emit a placeholder value. No successful artifact may contain an unresolved HIR type, an unfinished MIR terminator, or an invalid WasmIR use.
Normative scope
The chapters specify:
- node and function shapes that passes may rely on;
- identity, ordering, and range rules;
- control-flow and suspension semantics;
- storage, ownership, and ABI attachment points;
- provenance and synthetic-node classification;
- verifier obligations and legal form transitions.
They do not promise a stable serialization format for compiler internals. Rust enum layout, debug-print syntax, pass-private facts, and numeric IDs may change without changing the Atoll language or runtime ABI. Stable external formats—the source language, runtime ABI, module metadata, and debugger protocol—are documented in their own sections.
Use the Compiler Pipeline for stage orchestration and Provenance for the end-to-end source mapping.