//! Typed mid-level IR — the single artefact that crosses the //! `check` → `codegen` boundary. Produced by //! `ailang_check::lower_to_mir` from a monomorphised, typechecked //! `Workspace`; consumed by `ailang_codegen`. Every node carries the //! facts codegen used to re-derive: its type (`ty`), the resolved //! callee (`Callee`, filled mir.2), parameter modes / consume counts //! (`Mode` / `consume_count`, filled mir.3), and string representation //! (`StrRep`, filled mir.4). MIR is never authored, never hashed, //! never round-tripped — it is a compiler-internal derived form. use ailang_core::ast::{Literal, Module, Pattern, Type}; use std::collections::BTreeMap; /// A whole monomorphised program, lowered to MIR. #[derive(Debug, Clone)] pub struct MirWorkspace { pub entry: String, pub modules: BTreeMap, } #[derive(Debug, Clone)] pub struct MirModule { pub name: String, /// The post-mono AST module. codegen reads structural data /// (Def::Type / Def::Const / ctor layouts / intrinsic-fn markers / /// imports) from here; the typed fn bodies come from `defs`. This /// keeps `MirWorkspace` the single artefact codegen consumes — /// structural reads were never a re-derivation, so carrying the AST /// alongside the typed bodies does not reintroduce one. pub ast: Module, pub defs: Vec, /// Typed bodies of the module's non-literal `Def::Const`s. A const /// is inlined at every `Var` reference site (codegen reads the /// body from here, keyed by name); literal consts emit a global /// instead and are not carried. Same role as `defs` for fns — the /// body is the checker-typed `MTerm` so codegen re-derives no /// type to lower it. pub consts: Vec, } /// One lowered non-literal const. `body` is the typed `MTerm` codegen /// inlines at each reference site. #[derive(Debug, Clone)] pub struct MirConst { pub name: String, pub ty: Type, pub body: MTerm, } /// One lowered top-level fn. `sig` is the declared signature; `body` /// is the lowered fn body with `ty` on every node. #[derive(Debug, Clone)] pub struct MirDef { pub name: String, pub sig: Type, pub params: Vec, pub body: MTerm, /// Per-binder consume count for this def's body, keyed by binder /// name (let-binders, params, pattern-binders). `0` means the /// binder is exclusively borrowed/unused in its scope and codegen /// must emit the scope-close `dec` under `--alloc=rc`. Filled by /// `lower_to_mir` from `ailang_check::uniqueness::infer_module_with_cross` /// (mir.3a) — the single uniqueness engine, run once on the /// post-mono body. Codegen reads it instead of re-running the pass. pub consume: BTreeMap, } /// One MIR node — structural counterpart of `ast::Term`, plus the /// `Str` split. `ty` is the checker-proved type at this node. #[derive(Debug, Clone)] pub enum MTerm { Lit { lit: Literal, ty: Type }, /// String literal — the `Str`-representation carrier. `rep` is /// `Static` for every literal at mir.1; mir.4 flips loop-carried /// seeds to `Heap`. Split out of `Lit` so the rep annotation has a /// home (spec §"Str split"). Str { lit: String, rep: StrRep }, Var { name: String, ty: Type }, /// `callee` is `Indirect()` at mir.1; mir.2 /// resolves static targets to `Callee::Static`. App { callee: Callee, args: Vec, tail: bool, ty: Type }, Let { name: String, mode: Mode, init: Box, body: Box, ty: Type }, LetRec { name: String, sig: Type, params: Vec, body: Box, in_term: Box, ty: Type, }, If { cond: Box, then: Box, else_: Box, ty: Type }, Do { op: String, args: Vec, tail: bool, ty: Type }, Ctor { type_name: String, ctor: String, args: Vec, ty: Type }, Match { scrutinee: Box, arms: Vec, ty: Type }, Lam { params: Vec, param_tys: Vec, ret_ty: Type, effects: Vec, body: Box, ty: Type, }, Seq { lhs: Box, rhs: Box, ty: Type }, Clone { value: Box, ty: Type }, ReuseAs { source: Box, body: Box, ty: Type }, Loop { binders: Vec, body: Box, ty: Type }, Recur { args: Vec, ty: Type }, /// `elem` is `None` at mir.1; mir.5 carries the element type. New { type_name: String, elem: Option, args: Vec, ty: Type }, Intrinsic { ty: Type }, } /// A match arm. Patterns stay structural (`ast::Pattern`) — they carry /// no type annotation the boundary re-derives. #[derive(Debug, Clone)] pub struct MArm { pub pat: Pattern, pub body: MTerm, } #[derive(Debug, Clone)] pub struct MLoopBinder { pub name: String, pub ty: Type, pub init: MTerm, } #[derive(Debug, Clone)] pub enum MNewArg { Type(Type), Value(MTerm), } /// A call/ctor/recur argument with its mode and consume count. Both /// fields are mir.1 defaults (`Owned` / `1`); mir.3 fills them. #[derive(Debug, Clone)] pub struct MArg { pub term: MTerm, pub mode: Mode, pub consume_count: u32, } /// A resolved App callee. `Static`/`Builtin` are filled by mir.2's /// `lower_to_mir::classify_callee`, which mirrors check's `synth` /// `Term::Var` ladder; `Indirect` is a genuinely dynamic callee /// (fn-typed local/param, closure value, or a name shadowed by a /// local). `sig` is the callee's fn-type — the lossless replacement /// for the sub-term's `ty()` that codegen's drop path reads for the /// callee `ret_mode`. #[derive(Debug, Clone)] pub enum Callee { /// A statically-resolved user/prelude fn: codegen routes it to /// `emit_call(module, fn_name, …)` with `module` pre-resolved /// (replacing codegen's `type_home_module` ladder). Static { module: String, fn_name: String, sig: Type }, /// An operator / intrinsic builtin (`+`, `not`, `str_concat`, …): /// codegen lowers it inline by `name` (opcode selection), never /// via `emit_call`. Builtin { name: String, sig: Type }, /// A dynamic callee — lower the boxed term to a fn-pointer. Indirect(Box), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum StrRep { Heap, Static, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Mode { Owned, Borrow, } impl MTerm { /// The checker-proved type at this node. `Str` is always `Str`. pub fn ty(&self) -> Type { match self { MTerm::Lit { ty, .. } | MTerm::Var { ty, .. } | MTerm::App { ty, .. } | MTerm::Let { ty, .. } | MTerm::LetRec { ty, .. } | MTerm::If { ty, .. } | MTerm::Do { ty, .. } | MTerm::Ctor { ty, .. } | MTerm::Match { ty, .. } | MTerm::Lam { ty, .. } | MTerm::Seq { ty, .. } | MTerm::Clone { ty, .. } | MTerm::ReuseAs { ty, .. } | MTerm::Loop { ty, .. } | MTerm::Recur { ty, .. } | MTerm::New { ty, .. } | MTerm::Intrinsic { ty } => ty.clone(), MTerm::Str { .. } => Type::str_(), } } }