Skip to main content

logicaffeine_compile/
monomorphize.rs

1//! Monomorphization: a generic program rewritten into the concrete program it stands for, for the
2//! tiers with no generics of their own.
3//!
4//! Every call of a generic function becomes a call of one INSTANCE — a copy of the function with
5//! its type parameters replaced by the call's type arguments — and every applied generic type
6//! (`Box of Int`, `Maybe of Text`, core `Result of Int and Text`) becomes one registered concrete
7//! type. The type arguments come from the checker ([`crate::analysis::infer_instantiations`]),
8//! which solved each site once; a site inside a generic body names that function's own type
9//! variables, substituted per instance. When the backend has no `Option` of its own, `some x` /
10//! `none` and `Option of T` lower to the core `Option` enum's instances. An empty sequence literal
11//! whose element type the context fixes (and is not `Int`, the reading every backend already
12//! gives `[]`) becomes `a new Seq of X`.
13//!
14//! A program with no generic site is returned unchanged, statement for statement.
15
16use std::collections::{HashMap, HashSet};
17
18use crate::analysis::unify::{InferType, TyVar, TypeScope};
19use crate::analysis::{
20    infer_instantiations, FieldDef, FieldType, Instantiations, Site, TypeDef, TypeRegistry,
21    VariantDef,
22};
23use crate::ast::stmt::{Expr, MatchArm, Stmt, TypeExpr};
24use crate::ast_map::{self, Arenas, AstMap};
25use crate::intern::{Interner, Symbol};
26
27/// How far instantiation may go before a program is judged to need infinitely many instances
28/// (polymorphic recursion: `f of [T]` calling `f` at `Seq of T`).
29const INSTANCE_BUDGET: usize = 4096;
30
31/// What the backend lacks natively and monomorphization must lower.
32#[derive(Clone, Copy, Debug)]
33pub struct Options {
34    /// Lower `some` / `none` / `Option of T` to instances of the core `Option` enum.
35    pub lower_option: bool,
36}
37
38/// One registered concrete type: the generic type it applies, and to what.
39#[derive(Clone, Debug)]
40pub struct TypeInstance {
41    pub generic: Symbol,
42    pub args: Vec<InferType>,
43}
44
45/// A monomorphic program: its statements, the registry with every instance type added, and each
46/// instance type's origin (so a backend shows `Box of Int`'s instance as a `Box`).
47pub struct Monomorphized<'a> {
48    pub stmts: Vec<Stmt<'a>>,
49    pub registry: TypeRegistry,
50    pub instances: HashMap<Symbol, TypeInstance>,
51}
52
53/// Rewrite `stmts` into a program with no generic function, no applied generic type, and (under
54/// `options.lower_option`) no built-in `Option`.
55pub fn monomorphize<'a>(
56    stmts: &[Stmt<'a>],
57    registry: &TypeRegistry,
58    interner: &mut Interner,
59    arenas: Arenas<'a>,
60    options: Options,
61) -> Result<Monomorphized<'a>, String> {
62    let inst = infer_instantiations(stmts, interner, registry);
63    let generic_fns: HashMap<Symbol, &Stmt<'a>> = stmts
64        .iter()
65        .filter_map(|s| match s {
66            Stmt::FunctionDef { name, generics, .. } if !generics.is_empty() => Some((*name, s)),
67            _ => None,
68        })
69        .collect();
70    if !needs_monomorphization(stmts, registry, interner, &inst, options) {
71        return Ok(Monomorphized {
72            stmts: stmts.to_vec(),
73            registry: registry.clone(),
74            instances: HashMap::new(),
75        });
76    }
77
78    let mut taken: HashSet<String> = registry
79        .iter_types()
80        .map(|(s, _)| interner.resolve(*s).to_string())
81        .collect();
82    for s in stmts {
83        if let Stmt::FunctionDef { name, .. } = s {
84            taken.insert(interner.resolve(*name).to_string());
85        }
86    }
87    let twins = registry.namespaced_twins(interner);
88    let mut mono = Mono {
89        arenas,
90        registry,
91        inst: &inst,
92        options,
93        twins,
94        interner,
95        generic_fns,
96        taken,
97        fn_instances: HashMap::new(),
98        pending: std::collections::VecDeque::new(),
99        instances_of: HashMap::new(),
100        type_instances: HashMap::new(),
101        out_registry: registry.clone(),
102        instance_info: HashMap::new(),
103        subst: HashMap::new(),
104        param_types: HashMap::new(),
105        error: None,
106    };
107
108    enum Segment<'a> {
109        Stmt(Stmt<'a>),
110        InstancesOf(Symbol),
111    }
112    let mut segments = Vec::with_capacity(stmts.len());
113    for s in stmts {
114        match s {
115            Stmt::FunctionDef { name, generics, .. } if !generics.is_empty() => {
116                segments.push(Segment::InstancesOf(*name))
117            }
118            _ => segments.push(Segment::Stmt(mono.map_stmt(s))),
119        }
120    }
121    while let Some((generic, args, name)) = mono.pending.pop_front() {
122        let def = mono.instantiate_function(generic, &args, name);
123        mono.instances_of.entry(generic).or_default().push(def);
124    }
125    if let Some(e) = mono.error.take() {
126        return Err(e);
127    }
128
129    let mut out = Vec::with_capacity(segments.len());
130    for seg in segments {
131        match seg {
132            Segment::Stmt(s) => out.push(s),
133            Segment::InstancesOf(f) => out.extend(mono.instances_of.remove(&f).unwrap_or_default()),
134        }
135    }
136    Ok(Monomorphized {
137        stmts: out,
138        registry: mono.out_registry,
139        instances: mono.instance_info,
140    })
141}
142
143/// Whether anything in the program is generic enough to need rewriting: a call of a generic
144/// function, a construction or inspection of an applied generic type (or, lowered, an `Option`),
145/// an empty literal whose element the context fixes, or a signature naming an applied generic.
146fn needs_monomorphization(
147    stmts: &[Stmt],
148    registry: &TypeRegistry,
149    interner: &Interner,
150    inst: &Instantiations,
151    options: Options,
152) -> bool {
153    let generic_type = |t: &InferType| mentions_generic(t, options);
154    if !inst.calls.is_empty() {
155        return true;
156    }
157    if inst.constructed.values().any(generic_type)
158        || inst.empty_lists.values().any(is_retyped_empty_list)
159    {
160        return true;
161    }
162    if inst.scrutinees.values().any(generic_type) {
163        return true;
164    }
165    let empty = HashMap::new();
166    let twins = registry.namespaced_twins(interner);
167    let scope = TypeScope {
168        interner,
169        registry: Some(registry),
170        params: &empty,
171        twins: Some(&twins),
172    };
173    stmts.iter().any(|s| match s {
174        Stmt::FunctionDef {
175            params,
176            return_type,
177            ..
178        } => params
179            .iter()
180            .map(|(_, t)| *t)
181            .chain(return_type.iter().copied())
182            .any(|t| generic_type(&InferType::from_type_expr_in(t, &scope))),
183        _ => false,
184    })
185}
186
187fn mentions_generic(t: &InferType, options: Options) -> bool {
188    let rec = |x: &InferType| mentions_generic(x, options);
189    match t {
190        InferType::UserDefined(_, args) => !args.is_empty() || args.iter().any(rec),
191        InferType::Option(inner) => options.lower_option || rec(inner),
192        InferType::Seq(i) | InferType::Set(i) => rec(i),
193        InferType::Map(k, v) => rec(k) || rec(v),
194        InferType::Function(ps, r) => ps.iter().any(rec) || rec(r),
195        _ => false,
196    }
197}
198
199/// An empty literal (`[]`) the context types as a sequence of something other than `Int` — the
200/// element every backend already reads `[]` as.
201fn is_retyped_empty_list(t: &InferType) -> bool {
202    matches!(t, InferType::Seq(elem) if !matches!(**elem, InferType::Int | InferType::Var(_) | InferType::Unknown))
203}
204
205struct Mono<'a, 'r> {
206    arenas: Arenas<'a>,
207    registry: &'r TypeRegistry,
208    inst: &'r Instantiations,
209    options: Options,
210    interner: &'r mut Interner,
211    generic_fns: HashMap<Symbol, &'r Stmt<'a>>,
212    /// Every name a type or function already has, so a minted instance name never collides.
213    taken: HashSet<String>,
214    fn_instances: HashMap<(Symbol, String), Symbol>,
215    pending: std::collections::VecDeque<(Symbol, Vec<InferType>, Symbol)>,
216    instances_of: HashMap<Symbol, Vec<Stmt<'a>>>,
217    type_instances: HashMap<(Symbol, String), Symbol>,
218    out_registry: TypeRegistry,
219    instance_info: HashMap<Symbol, TypeInstance>,
220    /// The generic function being instantiated: its type variables, and its written type
221    /// parameters, each to the ground type this instance gives it.
222    subst: HashMap<TyVar, InferType>,
223    param_types: HashMap<Symbol, InferType>,
224    error: Option<String>,
225    /// Each bare type name that IS a namespaced type, so both spellings are one type.
226    twins: HashMap<Symbol, Symbol>,
227}
228
229/// A canonical key for a ground type (its structure, with symbols by identity).
230fn key_of(types: &[InferType]) -> String {
231    format!("{types:?}")
232}
233
234impl<'a, 'r> Mono<'a, 'r> {
235    fn fail(&mut self, message: String) {
236        if self.error.is_none() {
237            self.error = Some(message);
238        }
239    }
240
241    fn sym(&mut self, name: &str) -> Symbol {
242        self.interner.intern(name)
243    }
244
245    /// A fresh name built from `parts`, unused by any type or function.
246    fn mint(&mut self, parts: &str) -> Symbol {
247        let base: String = parts
248            .chars()
249            .map(|c| {
250                if c.is_ascii_alphanumeric() || c == '_' {
251                    c
252                } else {
253                    '_'
254                }
255            })
256            .collect();
257        let mut name = base.clone();
258        let mut n = 2;
259        while self.taken.contains(&name) {
260            name = format!("{base}_{n}");
261            n += 1;
262        }
263        self.taken.insert(name.clone());
264        self.interner.intern(&name)
265    }
266
267    /// `t` with this instance's type variables replaced by their ground types. A variable the
268    /// program never constrains (a phantom `E` in `Result of Int and E`) carries no value, so
269    /// any type represents it; it becomes `Int`, the one every backend represents.
270    fn ground(&self, t: &InferType) -> Result<InferType, String> {
271        Ok(match t {
272            InferType::Var(tv) => self.subst.get(tv).cloned().unwrap_or(InferType::Int),
273            InferType::Unknown => return Err("a type the checker could not determine".to_string()),
274            InferType::Seq(i) => InferType::Seq(Box::new(self.ground(i)?)),
275            InferType::Set(i) => InferType::Set(Box::new(self.ground(i)?)),
276            InferType::Option(i) => InferType::Option(Box::new(self.ground(i)?)),
277            InferType::Map(k, v) => {
278                InferType::Map(Box::new(self.ground(k)?), Box::new(self.ground(v)?))
279            }
280            InferType::UserDefined(s, args) => InferType::UserDefined(
281                *s,
282                args.iter()
283                    .map(|a| self.ground(a))
284                    .collect::<Result<_, _>>()?,
285            ),
286            InferType::Function(ps, r) => InferType::Function(
287                ps.iter()
288                    .map(|p| self.ground(p))
289                    .collect::<Result<_, _>>()?,
290                Box::new(self.ground(r)?),
291            ),
292            ground => ground.clone(),
293        })
294    }
295
296    /// Whether `t` still has a variable no instance binds — a type argument left open.
297    fn leaves_open(&self, t: &InferType) -> bool {
298        match t {
299            InferType::Var(tv) => !self.subst.contains_key(tv),
300            InferType::Seq(i) | InferType::Set(i) | InferType::Option(i) => self.leaves_open(i),
301            InferType::Map(k, v) => self.leaves_open(k) || self.leaves_open(v),
302            InferType::UserDefined(_, args) => args.iter().any(|a| self.leaves_open(a)),
303            InferType::Function(ps, r) => {
304                ps.iter().any(|p| self.leaves_open(p)) || self.leaves_open(r)
305            }
306            _ => false,
307        }
308    }
309
310    fn name_part(&mut self, t: &InferType) -> String {
311        match t {
312            InferType::Int => "Int".into(),
313            InferType::Float => "Real".into(),
314            InferType::String => "Text".into(),
315            InferType::Bool => "Bool".into(),
316            InferType::Seq(i) => format!("Seq_{}", self.name_part(i)),
317            InferType::Set(i) => format!("Set_{}", self.name_part(i)),
318            InferType::Option(i) => format!("Option_{}", self.name_part(i)),
319            InferType::Map(k, v) => format!("Map_{}_{}", self.name_part(k), self.name_part(v)),
320            InferType::UserDefined(s, args) if args.is_empty() => {
321                self.interner.resolve(*s).to_string()
322            }
323            InferType::UserDefined(s, args) => {
324                let parts: Vec<String> = args.iter().map(|a| self.name_part(a)).collect();
325                format!("{}_{}", self.interner.resolve(*s), parts.join("_"))
326            }
327            InferType::Function(ps, r) => {
328                let parts: Vec<String> = ps.iter().map(|p| self.name_part(p)).collect();
329                format!("Fn_{}_to_{}", parts.join("_"), self.name_part(r))
330            }
331            other => other.to_logos_name(),
332        }
333    }
334
335    /// The instance of generic function `f` a call at `site` needs, queued for instantiation the
336    /// first time it is asked for.
337    fn call_instance(&mut self, f: Symbol, site: Site) -> Option<Symbol> {
338        let fname = self.interner.resolve(f).to_string();
339        let Some(call) = self.inst.calls.get(&site).cloned() else {
340            self.fail(format!("the call of the generic function `{fname}` could not be type-checked, so its type arguments are unknown"));
341            return None;
342        };
343        if !call.precise && call.type_args.iter().any(|t| self.leaves_open(t)) {
344            self.fail(format!(
345                "cannot determine the type arguments of this call of `{fname}`: an argument's type is not known before running the program"
346            ));
347            return None;
348        }
349        let mut args = Vec::with_capacity(call.type_args.len());
350        for t in &call.type_args {
351            match self.ground(t) {
352                Ok(g) => args.push(g),
353                Err(why) => {
354                    self.fail(format!("cannot instantiate `{fname}`: {why}"));
355                    return None;
356                }
357            }
358        }
359        let key = (f, key_of(&args));
360        if let Some(name) = self.fn_instances.get(&key) {
361            return Some(*name);
362        }
363        if self.fn_instances.len() + self.type_instances.len() >= INSTANCE_BUDGET {
364            self.fail(format!(
365                "`{fname}` needs more than {INSTANCE_BUDGET} concrete copies — it calls itself at an ever-larger type, which a tier without generics cannot compile"
366            ));
367            return None;
368        }
369        let parts: Vec<String> = args.iter().map(|a| self.name_part(a)).collect();
370        let name = self.mint(&format!("{fname}__{}", parts.join("__")));
371        self.fn_instances.insert(key, name);
372        self.pending.push_back((f, args, name));
373        Some(name)
374    }
375
376    /// The generic definition an applied type instantiates. `Option` is the one generic the
377    /// prelude never declares — `some`/`none` are built in, so core's declaration is dropped
378    /// before prepending and the registry holds only its built-in arity — and lowers from core's
379    /// own definition,
380    /// `An Option of [T] is either: A Some (value: T). A None.`, unless the program declares its
381    /// own.
382    fn template(&mut self, generic: Symbol) -> Option<TypeDef> {
383        if let Some(def @ (TypeDef::Struct { .. } | TypeDef::Enum { .. })) =
384            self.registry.get(generic)
385        {
386            return Some(def.clone());
387        }
388        if self.interner.resolve(generic) != "Option" {
389            return None;
390        }
391        let t = self.sym("T");
392        let (some, none, value) = (self.sym("Some"), self.sym("None"), self.sym("value"));
393        Some(TypeDef::Enum {
394            variants: vec![
395                VariantDef {
396                    name: some,
397                    fields: vec![FieldDef {
398                        name: value,
399                        ty: FieldType::TypeParam(t),
400                        is_public: true,
401                    }],
402                },
403                VariantDef {
404                    name: none,
405                    fields: Vec::new(),
406                },
407            ],
408            generics: vec![t],
409            is_portable: false,
410            is_shared: false,
411        })
412    }
413
414    /// The concrete type an applied generic type (or, lowered, an `Option`) becomes, registered
415    /// the first time it is asked for. `None` for a type that stays as it is.
416    fn type_instance(&mut self, t: &InferType) -> Option<Symbol> {
417        let (generic, args) = match t {
418            InferType::UserDefined(g, args) if !args.is_empty() => (*g, args.clone()),
419            InferType::Option(inner) if self.options.lower_option => {
420                (self.sym("Option"), vec![(**inner).clone()])
421            }
422            _ => return None,
423        };
424        let key = (generic, key_of(&args));
425        if let Some(name) = self.type_instances.get(&key) {
426            return Some(*name);
427        }
428        if self.fn_instances.len() + self.type_instances.len() >= INSTANCE_BUDGET {
429            let gname = self.interner.resolve(generic).to_string();
430            self.fail(format!(
431                "`{gname}` needs more than {INSTANCE_BUDGET} concrete types"
432            ));
433            return None;
434        }
435        let parts: Vec<String> = args.iter().map(|a| self.name_part(a)).collect();
436        let gname = self.interner.resolve(generic).to_string();
437        let name = self.mint(&format!("{gname}__{}", parts.join("__")));
438        self.type_instances.insert(key, name);
439        self.instance_info.insert(
440            name,
441            TypeInstance {
442                generic,
443                args: args.clone(),
444            },
445        );
446        let def = match self.template(generic) {
447            Some(TypeDef::Struct {
448                fields,
449                generics,
450                is_portable,
451                is_shared,
452            }) => {
453                let params: HashMap<Symbol, InferType> =
454                    generics.iter().copied().zip(args.iter().cloned()).collect();
455                let fields = fields
456                    .iter()
457                    .map(|f| FieldDef {
458                        name: f.name,
459                        ty: self.field_type(&f.ty, &params),
460                        is_public: f.is_public,
461                    })
462                    .collect();
463                TypeDef::Struct {
464                    fields,
465                    generics: Vec::new(),
466                    is_portable,
467                    is_shared,
468                }
469            }
470            Some(TypeDef::Enum {
471                variants,
472                generics,
473                is_portable,
474                is_shared,
475            }) => {
476                let params: HashMap<Symbol, InferType> =
477                    generics.iter().copied().zip(args.iter().cloned()).collect();
478                let variants = variants
479                    .iter()
480                    .map(|v| VariantDef {
481                        name: v.name,
482                        fields: v
483                            .fields
484                            .iter()
485                            .map(|f| FieldDef {
486                                name: f.name,
487                                ty: self.field_type(&f.ty, &params),
488                                is_public: f.is_public,
489                            })
490                            .collect(),
491                    })
492                    .collect();
493                TypeDef::Enum {
494                    variants,
495                    generics: Vec::new(),
496                    is_portable,
497                    is_shared,
498                }
499            }
500            _ => {
501                self.fail(format!(
502                    "`{gname}` is applied to type arguments but is not a generic record or enum"
503                ));
504                return None;
505            }
506        };
507        self.out_registry.register(name, def);
508        Some(name)
509    }
510
511    /// A declared field type at one application of its record or enum, `params` giving each of
512    /// the type's own parameters. A field naming no parameter and no applied generic is kept
513    /// exactly as written.
514    fn field_type(&mut self, ft: &FieldType, params: &HashMap<Symbol, InferType>) -> FieldType {
515        if !self.field_mentions(ft, params) {
516            return ft.clone();
517        }
518        // A tuple is opaque to inference: substitute inside it position by position.
519        match ft {
520            FieldType::Tuple(items) => {
521                return FieldType::Tuple(items.iter().map(|t| self.field_type(t, params)).collect())
522            }
523            FieldType::Record(fields) => {
524                return FieldType::Record(
525                    fields
526                        .iter()
527                        .map(|(n, t)| (*n, self.field_type(t, params)))
528                        .collect(),
529                )
530            }
531            _ => {}
532        }
533        let ty = InferType::from_field_type_in(
534            ft,
535            &TypeScope {
536                interner: self.interner,
537                registry: Some(self.registry),
538                params,
539                twins: Some(&self.twins),
540            },
541        );
542        match self.ground(&ty) {
543            Ok(g) => self.ground_field_type(&g),
544            Err(why) => {
545                self.fail(format!("cannot lay out a field: {why}"));
546                ft.clone()
547            }
548        }
549    }
550
551    fn field_mentions(&self, ft: &FieldType, params: &HashMap<Symbol, InferType>) -> bool {
552        match ft {
553            FieldType::TypeParam(p) | FieldType::Named(p) => params.contains_key(p),
554            FieldType::Primitive(_) => false,
555            FieldType::Generic { base, params: ps } => {
556                self.is_generic_type(*base) || ps.iter().any(|p| self.field_mentions(p, params))
557            }
558            FieldType::Tuple(items) => items.iter().any(|t| self.field_mentions(t, params)),
559            FieldType::Record(fields) => fields.iter().any(|(_, t)| self.field_mentions(t, params)),
560        }
561    }
562
563    /// A registered generic record or enum, or (lowered) the built-in `Option`.
564    fn is_generic_type(&self, base: Symbol) -> bool {
565        match self.registry.get(base) {
566            Some(TypeDef::Struct { generics, .. } | TypeDef::Enum { generics, .. }) => {
567                !generics.is_empty()
568            }
569            _ => false,
570        }
571    }
572
573    fn ground_field_type(&mut self, t: &InferType) -> FieldType {
574        if let Some(inst) = self.type_instance(t) {
575            return FieldType::Named(inst);
576        }
577        match t {
578            InferType::Seq(i) => FieldType::Generic {
579                base: self.sym("Seq"),
580                params: vec![self.ground_field_type(i)],
581            },
582            InferType::Set(i) => FieldType::Generic {
583                base: self.sym("Set"),
584                params: vec![self.ground_field_type(i)],
585            },
586            InferType::Option(i) => FieldType::Generic {
587                base: self.sym("Option"),
588                params: vec![self.ground_field_type(i)],
589            },
590            InferType::Map(k, v) => FieldType::Generic {
591                base: self.sym("Map"),
592                params: vec![self.ground_field_type(k), self.ground_field_type(v)],
593            },
594            InferType::UserDefined(s, _) => FieldType::Named(*s),
595            other => match other.primitive_name() {
596                Some(name) => FieldType::Primitive(self.sym(name)),
597                None => {
598                    let shown = other.to_logos_name();
599                    self.fail(format!("a record field cannot hold a {shown} on this tier"));
600                    FieldType::Primitive(self.sym("Int"))
601                }
602            },
603        }
604    }
605
606    /// A ground type written back as a type expression.
607    fn ground_type_expr(&mut self, t: &InferType) -> TypeExpr<'a> {
608        if let Some(inst) = self.type_instance(t) {
609            return TypeExpr::Named(inst);
610        }
611        let types = self.arenas.types;
612        match t {
613            InferType::Seq(i) => {
614                let p = self.ground_type_expr(i);
615                TypeExpr::Generic {
616                    base: self.sym("Seq"),
617                    params: types.alloc_slice([p]),
618                }
619            }
620            InferType::Set(i) => {
621                let p = self.ground_type_expr(i);
622                TypeExpr::Generic {
623                    base: self.sym("Set"),
624                    params: types.alloc_slice([p]),
625                }
626            }
627            InferType::Option(i) => {
628                let p = self.ground_type_expr(i);
629                TypeExpr::Generic {
630                    base: self.sym("Option"),
631                    params: types.alloc_slice([p]),
632                }
633            }
634            InferType::Map(k, v) => {
635                let (k, v) = (self.ground_type_expr(k), self.ground_type_expr(v));
636                TypeExpr::Generic {
637                    base: self.sym("Map"),
638                    params: types.alloc_slice([k, v]),
639                }
640            }
641            InferType::Function(ps, r) => {
642                let inputs: Vec<TypeExpr<'a>> =
643                    ps.iter().map(|p| self.ground_type_expr(p)).collect();
644                let output = self.ground_type_expr(r);
645                TypeExpr::Function {
646                    inputs: types.alloc_slice(inputs),
647                    output: types.alloc(output),
648                }
649            }
650            InferType::UserDefined(s, _) => TypeExpr::Named(*s),
651            other => match other.primitive_name() {
652                Some(name) => TypeExpr::Primitive(self.sym(name)),
653                None => {
654                    let shown = other.to_logos_name();
655                    self.fail(format!(
656                        "a {shown} cannot be written as a type on this tier"
657                    ));
658                    TypeExpr::Primitive(self.sym("Int"))
659                }
660            },
661        }
662    }
663
664    /// Whether a written type names this instance's type parameters or an applied generic.
665    fn type_mentions(&self, t: &TypeExpr) -> bool {
666        match t {
667            TypeExpr::Primitive(s) | TypeExpr::Named(s) => self.param_types.contains_key(s),
668            TypeExpr::Generic { base, params } => {
669                self.is_generic_type(*base)
670                    || (self.options.lower_option && self.is_option_name(*base))
671                    || params.iter().any(|p| self.type_mentions(p))
672            }
673            TypeExpr::Tuple(items) => items.iter().any(|p| self.type_mentions(p)),
674            TypeExpr::Record { field_types, .. } => {
675                field_types.iter().any(|p| self.type_mentions(p))
676            }
677            TypeExpr::Function { inputs, output } => {
678                inputs.iter().any(|p| self.type_mentions(p)) || self.type_mentions(output)
679            }
680            TypeExpr::Refinement { base, .. } => self.type_mentions(base),
681            TypeExpr::Persistent { inner } | TypeExpr::Mutable { inner } => {
682                self.type_mentions(inner)
683            }
684        }
685    }
686
687    fn is_option_name(&self, base: Symbol) -> bool {
688        let name = self.interner.resolve(base);
689        name == "Option"
690            || (name == "Maybe"
691                && !matches!(
692                    self.registry.get(base),
693                    Some(TypeDef::Struct { .. } | TypeDef::Enum { .. })
694                ))
695    }
696
697    /// The instance function for one `(generic function, ground type arguments)`.
698    fn instantiate_function(
699        &mut self,
700        generic: Symbol,
701        args: &[InferType],
702        name: Symbol,
703    ) -> Stmt<'a> {
704        let def = self.generic_fns[&generic];
705        let Stmt::FunctionDef {
706            params,
707            body,
708            return_type,
709            is_native,
710            native_path,
711            is_exported,
712            export_target,
713            opt_flags,
714            ..
715        } = def
716        else {
717            unreachable!("generic_fns holds function definitions only")
718        };
719        let declared = self
720            .inst
721            .type_params
722            .get(&generic)
723            .cloned()
724            .unwrap_or_default();
725        let saved_subst = std::mem::take(&mut self.subst);
726        let saved_params = std::mem::take(&mut self.param_types);
727        for ((param, resolved), arg) in declared.iter().zip(args) {
728            if let InferType::Var(tv) = resolved {
729                self.subst.insert(*tv, arg.clone());
730            }
731            self.param_types.insert(*param, arg.clone());
732        }
733        let params = params.iter().map(|(p, t)| (*p, self.map_type(t))).collect();
734        let return_type = return_type.map(|t| self.map_type(t));
735        let body = self.map_block(body);
736        self.subst = saved_subst;
737        self.param_types = saved_params;
738        Stmt::FunctionDef {
739            name,
740            generics: Vec::new(),
741            params,
742            body,
743            return_type,
744            is_native: *is_native,
745            native_path: *native_path,
746            is_exported: *is_exported,
747            export_target: *export_target,
748            opt_flags: *opt_flags,
749        }
750    }
751
752    /// An arm's bindings against the instance's own variant: a binding naming no field of the
753    /// variant is POSITIONAL (`When Some (v)` binds the first field, whatever it is called), which
754    /// the parser could only resolve for an enum it had registered — never the built-in `Option`.
755    fn fields_by_position(
756        &self,
757        inst: Symbol,
758        variant: Symbol,
759        bindings: &[(Symbol, Symbol)],
760    ) -> Vec<(Symbol, Symbol)> {
761        let fields: Vec<Symbol> = match self.out_registry.get(inst) {
762            Some(TypeDef::Enum { variants, .. }) => variants
763                .iter()
764                .find(|v| v.name == variant)
765                .map(|v| v.fields.iter().map(|f| f.name).collect())
766                .unwrap_or_default(),
767            _ => Vec::new(),
768        };
769        bindings
770            .iter()
771            .enumerate()
772            .map(|(i, (field, binding))| match fields.get(i) {
773                Some(declared) if !fields.contains(field) => (*declared, *binding),
774                _ => (*field, *binding),
775            })
776            .collect()
777    }
778
779    /// The instance type a site's recorded type becomes, if it is one.
780    fn site_instance(&mut self, recorded: Option<&InferType>, what: &str) -> Option<Symbol> {
781        let recorded = recorded?.clone();
782        match self.ground(&recorded) {
783            Ok(g) => self.type_instance(&g),
784            Err(why) => {
785                self.fail(format!("cannot instantiate {what}: {why}"));
786                None
787            }
788        }
789    }
790}
791
792impl<'a, 'r> AstMap<'a> for Mono<'a, 'r> {
793    fn arenas(&self) -> Arenas<'a> {
794        self.arenas
795    }
796
797    fn map_type(&mut self, t: &'a TypeExpr<'a>) -> &'a TypeExpr<'a> {
798        if !self.type_mentions(t) {
799            return t;
800        }
801        match t {
802            TypeExpr::Primitive(s) | TypeExpr::Named(s) if self.param_types.contains_key(s) => {
803                let g = self.param_types[s].clone();
804                let written = self.ground_type_expr(&g);
805                self.arenas.types.alloc(written)
806            }
807            TypeExpr::Generic { base, .. }
808                if self.is_generic_type(*base)
809                    || (self.options.lower_option && self.is_option_name(*base)) =>
810            {
811                let params = self.param_types.clone();
812                let ty = InferType::from_type_expr_in(
813                    t,
814                    &TypeScope {
815                        interner: self.interner,
816                        registry: Some(self.registry),
817                        params: &params,
818                        twins: Some(&self.twins),
819                    },
820                );
821                match self.ground(&ty) {
822                    Ok(g) => {
823                        let written = self.ground_type_expr(&g);
824                        self.arenas.types.alloc(written)
825                    }
826                    Err(why) => {
827                        self.fail(format!("cannot instantiate a written type: {why}"));
828                        t
829                    }
830                }
831            }
832            _ => ast_map::walk_type(self, t),
833        }
834    }
835
836    fn map_expr(&mut self, e: &'a Expr<'a>) -> &'a Expr<'a> {
837        let site = Site::of_expr(e);
838        let exprs = self.arenas.exprs;
839        let mapped = match e {
840            Expr::Call { function, args } if self.generic_fns.contains_key(function) => {
841                let function = self.call_instance(*function, site).unwrap_or(*function);
842                let args = args.iter().map(|a| self.map_expr(a)).collect();
843                exprs.alloc(Expr::Call { function, args })
844            }
845            Expr::New {
846                type_name,
847                init_fields,
848                ..
849            } if self.is_generic_type(*type_name) => {
850                let what = format!("a new {}", self.interner.resolve(*type_name));
851                let recorded = self.inst.constructed.get(&site).cloned();
852                let type_name = self
853                    .site_instance(recorded.as_ref(), &what)
854                    .unwrap_or(*type_name);
855                let init_fields = init_fields
856                    .iter()
857                    .map(|(f, v)| (*f, self.map_expr(v)))
858                    .collect();
859                exprs.alloc(Expr::New {
860                    type_name,
861                    type_args: Vec::new(),
862                    init_fields,
863                })
864            }
865            Expr::NewVariant {
866                enum_name,
867                variant,
868                fields,
869            } if self.is_generic_type(*enum_name) => {
870                let what = format!("a new {}", self.interner.resolve(*variant));
871                let recorded = self.inst.constructed.get(&site).cloned();
872                let enum_name = self
873                    .site_instance(recorded.as_ref(), &what)
874                    .unwrap_or(*enum_name);
875                let fields = fields.iter().map(|(f, v)| (*f, self.map_expr(v))).collect();
876                exprs.alloc(Expr::NewVariant {
877                    enum_name,
878                    variant: *variant,
879                    fields,
880                })
881            }
882            Expr::OptionSome { value } if self.options.lower_option => {
883                let recorded = self.inst.constructed.get(&site).cloned();
884                let value = self.map_expr(value);
885                match self.site_instance(recorded.as_ref(), "`some`") {
886                    Some(enum_name) => {
887                        let (variant, field) = (self.sym("Some"), self.sym("value"));
888                        exprs.alloc(Expr::NewVariant {
889                            enum_name,
890                            variant,
891                            fields: vec![(field, value)],
892                        })
893                    }
894                    None => exprs.alloc(Expr::OptionSome { value }),
895                }
896            }
897            Expr::OptionNone if self.options.lower_option => {
898                let recorded = self.inst.constructed.get(&site).cloned();
899                match self.site_instance(recorded.as_ref(), "`none`") {
900                    Some(enum_name) => {
901                        let variant = self.sym("None");
902                        exprs.alloc(Expr::NewVariant {
903                            enum_name,
904                            variant,
905                            fields: Vec::new(),
906                        })
907                    }
908                    None => e,
909                }
910            }
911            Expr::List(items) if items.is_empty() => {
912                let recorded = self.inst.empty_lists.get(&site).cloned();
913                let elem = match recorded.map(|t| self.ground(&t)) {
914                    Some(Ok(InferType::Seq(elem)))
915                        if is_retyped_empty_list(&InferType::Seq(elem.clone())) =>
916                    {
917                        *elem
918                    }
919                    _ => return preserve_expr_facts(e, e),
920                };
921                let written = self.ground_type_expr(&elem);
922                let seq = self.sym("Seq");
923                exprs.alloc(Expr::New {
924                    type_name: seq,
925                    type_args: vec![written],
926                    init_fields: Vec::new(),
927                })
928            }
929            _ => ast_map::walk_expr(self, e),
930        };
931        preserve_expr_facts(e, mapped)
932    }
933
934    fn map_stmt(&mut self, s: &Stmt<'a>) -> Stmt<'a> {
935        match s {
936            Stmt::Call { function, args } if self.generic_fns.contains_key(function) => {
937                let function = self
938                    .call_instance(*function, Site::of_stmt(s))
939                    .unwrap_or(*function);
940                Stmt::Call {
941                    function,
942                    args: args.iter().map(|a| self.map_expr(a)).collect(),
943                }
944            }
945            Stmt::LaunchTask { function, .. } | Stmt::LaunchTaskWithHandle { function, .. }
946                if self.generic_fns.contains_key(function) =>
947            {
948                let fname = self.interner.resolve(*function).to_string();
949                self.fail(format!(
950                    "the generic function `{fname}` cannot be launched as a task on this tier"
951                ));
952                ast_map::walk_stmt(self, s)
953            }
954            Stmt::Inspect {
955                target,
956                arms,
957                has_otherwise,
958            } => {
959                let recorded = self.inst.scrutinees.get(&Site::of_stmt(s)).cloned();
960                let instance = self.site_instance(recorded.as_ref(), "an inspected value");
961                let target = self.map_expr(target);
962                let arms = arms
963                    .iter()
964                    .map(|a| {
965                        let mapped = self.map_arm(a);
966                        match (instance, mapped.variant) {
967                            (Some(inst), Some(variant)) => {
968                                let bindings =
969                                    self.fields_by_position(inst, variant, &mapped.bindings);
970                                MatchArm {
971                                    enum_name: Some(inst),
972                                    bindings,
973                                    ..mapped
974                                }
975                            }
976                            _ => mapped,
977                        }
978                    })
979                    .collect();
980                Stmt::Inspect {
981                    target,
982                    arms,
983                    has_otherwise: *has_otherwise,
984                }
985            }
986            _ => ast_map::walk_stmt(self, s),
987        }
988    }
989}
990
991/// Monomorphization changes only representation and type names, never the value or control meaning
992/// of an expression. Preserve optimizer proofs on the equivalent arena node it creates so a
993/// backend without generics does not silently lose optimizations that generic-capable Rust keeps.
994fn preserve_expr_facts<'a>(from: &Expr<'a>, to: &'a Expr<'a>) -> &'a Expr<'a> {
995    use crate::optimize::facts::{self, Fact};
996
997    let had_tile_fact = facts::holds_expr(Fact::TileLegal, from);
998    facts::copy_expr_facts(from, to);
999    if had_tile_fact && std::env::var_os("LOGOS_DEBUG_C_TILE").is_some() {
1000        eprintln!("C TileLegal handoff: {:p} -> {:p}", from, to);
1001    }
1002    to
1003}
1004
1005#[cfg(test)]
1006#[path = "../../logicaffeine_tests/unit/logicaffeine_compile/monomorphize/tests.rs"]
1007mod tests;