Skip to main content

zelkova_compiler/ir/
specialise.rs

1//! Specialisation: which instance a use of a class member is, and which copy of a constrained
2//! function a use needs, worked out once for the whole build.
3//!
4//! Every phase before this one reads a module. This one reads all of them, because a
5//! constrained function is written in one module, used in another and answered by an
6//! instance in a third, and none of the three can see what the others hold.
7//! [`specialise`] is handed every checked module of a build and changes each [`Module`]
8//! in place; nothing else about the build moves. A backend then reads the result. One IR
9//! serves both targets ([`DEC-18` decision
10//! 2](../../../docs/decisions/dec-18.md#2--one-ir-serves-both-targets-and-javascript-is-written-first)),
11//! so the pass is here and not in `zelkova_js`.
12//!
13//! # What it makes
14//!
15//! No dictionary is built or passed at run time
16//! ([`DEC-2` decision 7](../../../docs/decisions/dec-2.md#7--dictionaries-are-erased-by-specialisation-not-passed)).
17//! A reference that carried obligations is rewritten to name the function that answers them:
18//!
19//! - **A class member** at a type whose instance has no context becomes
20//!   [`ReferenceKind::InstanceMember`], a direct reference to that instance's binding, an
21//!   ordinary declaration of the module that declares the instance.
22//! - **A constrained function**, or a class member at a type whose instance has a context,
23//!   becomes [`ReferenceKind::Specialised`]: a [`Specialisation`] of the module the reference
24//!   is in, which is a copy of the declaration with its constrained variables at the ground
25//!   types the reference gave them. Its body is read the same way, so the obligation on the
26//!   declaration's own variable that the type checker discharged as given is, in the copy,
27//!   one at a ground type, and its instance a lookup.
28//!
29//! Where an obligation's instance is found is [the lookup the type checker
30//! did](crate::typer): the class and the name at the front of the type, with at most one
31//! answer by [the head
32//! rule](../../../docs/spec/type-classes.md#what-an-instance-is-declared-for). A superclass
33//! needs nothing of its own. A use of `eq` inside a function constrained by `Comparable a`
34//! asks for `Eq a`, which at a ground type is an instance like any other, and
35//! `instance Comparable Colour` could not have been declared without it.
36//!
37//! # Where a copy goes, and why
38//!
39//! A specialisation is placed in **the module that uses it**. Its body calls the members of
40//! an instance, and the instance may be declared by a module that *imports* the declaring
41//! one: `Basics.min` at `App.Colour` calls a `compare` that `App` declares. Placed beside
42//! `min`, the copy would make `Basics` import `App`, and the build's modules could no
43//! longer be initialised in dependency order. The using module is downstream of everything
44//! the copy mentions.
45//!
46//! The cost is a copy in each module that uses a key. Nothing a program can observe: a copy
47//! of a function is code written twice, and for a binding with no parameters it is one
48//! evaluation for each using module where [the chapter
49//! says](../../../docs/spec/evaluation-semantics.md#a-binding-with-no-parameters-is-evaluated-once)
50//! "once", which changes work done and never an answer, a Zelkova value having no identity.
51//! A reading of that promise that covers it is a `SPEC-` ticket to file, and not a design to
52//! change here.
53//!
54//! A copy of a body written in another module names that module's values, so its
55//! references are carried across: a [`TopLevel`](ReferenceKind::TopLevel) name of the
56//! declaring module becomes a [`Foreign`](ReferenceKind::Foreign) one of the using module,
57//! with the arity its declaration was written with, and a `Foreign` one that names the using
58//! module itself becomes a `TopLevel`. A backend therefore needs the declaring module to make
59//! such a value reachable even where its `exposing` list does not, which is
60//! [`mentioned_by_copies`].
61//!
62//! # What a key is
63//!
64//! A specialisation is one declaration at one assignment of ground types to its **constrained**
65//! variables ([`Specialisation::key`]). A variable with no constraint needs no copy, since
66//! nothing a JavaScript module emits depends on it; two uses at one key in one module are one
67//! specialisation. The assignment is found by matching the types the declaration's
68//! [`context`](Declaration::context) is over against the ground ones the reference gave them.
69//!
70//! A member of an instance with a context is specialised at the ground types of the variables
71//! its own context constrains. They are found by reading the member's declared type against
72//! the type of the use, and not by reading the instance's head: the member's IR is over the
73//! variables its own inference gave it, which are the head's only when its patterns happen to
74//! pin them there (`same = sameWrap` does not).
75//!
76//! Only what the key is made of has to be a type. The instance a use asks for is found from
77//! the name at the front of its type, so a use at `Phantom b`, which no one can make ground,
78//! is the instance of `Phantom` all the same; and a variable with no constraint is not in the
79//! key. A constrained variable that is still a variable is [`Error::NotGround`].
80//!
81//! # The limit
82//!
83//! A constrained function that asks for itself at an ever larger type has no finite set of
84//! specialisations. `f x = f (Box x)` under `Eq a` needs `f` at `Colour`, at `Box Colour`, at
85//! `Box (Box Colour)`, without end
86//! ([`DEC-24` decision 9](../../../docs/decisions/dec-24.md#9--a-constrained-function-whose-specialisations-never-end-is-an-error)).
87//! The pass reads one chain of specialisations to its end before the next, and a chain
88//! that holds one declaration [`SPECIALISATION_LIMIT`] times is stopped and reported as
89//! [`Error::Unbounded`], naming the declaration and the type it had reached. The count is of
90//! one declaration within one chain: a chain through a hundred different functions is a finite
91//! set, and the same loop written through two functions is caught the same way.
92//!
93//! The first such chain stops the module's work: what was waiting to be read is dropped and
94//! nothing new is found, because a loop that grows at two types has a leaf for each way down,
95//! about 2^32 of them, and a build that has failed has no use for any. A declaration is
96//! reported once, however many modules reach its limit.
97//!
98//! # Order
99//!
100//! Specialisations are numbered in the order they were found, which is fixed by the order of
101//! the modules and of what each holds: every module's declarations in name order, then its
102//! instances in the order written. Nothing here iterates a hash table to produce an order,
103//! so two runs over one unchanged build produce the same text.
104//!
105//! [`initialisation_items`] is the order a module's parameterless items are initialised in
106//! once the new ones are among them. It reads what the items mention, through functions as
107//! well as directly, because an instance's bindings are not in the dependency graph
108//! canonicalization read: which of them a name reaches is a fact about types.
109
110use std::collections::{BTreeSet, HashMap, HashSet};
111
112use super::{
113    Body, Declaration, Field, InstanceMember, Module, Predicate, Reference, ReferenceKind,
114    Saturation, SubPattern, Subject, TermPattern, TermPatternKind, TypeBinder, TypedTerm,
115    TypedTermKind,
116};
117use crate::canonical::HeadName;
118use crate::name::{Name, QualName};
119use crate::typer::{head_of, Type, TypeVariable};
120use crate::{CheckedModule, ModuleName, PhaseError, SpanLabel};
121use zelkova_syntax::position::NodeSpan;
122use zelkova_syntax::tuple::Tuple;
123
124/// How many times one declaration may appear in one chain of specialisations before the chain
125/// is reported as having no end.
126///
127/// Generous on purpose: a type is nested this deep in no program anyone writes, and a legal
128/// chain holds a declaration once for each level of the type it walks, so `show` at
129/// `List (List (List Int))` holds it three times. The count is of one declaration, which is
130/// why a program with more than this many constrained functions is not affected.
131pub const SPECIALISATION_LIMIT: usize = 32;
132
133// ── Errors ────────────────────────────────────────────────────────────────────
134
135/// Why the specialisations of a build could not be found.
136///
137/// [`Unbounded`](Self::Unbounded) is a mistake in a program the type checker cannot see.
138/// [`NotGround`](Self::NotGround) is a program it accepted whose use asks for a constrained
139/// function at a type that is still a variable, one that has no copy to make. The other two
140/// are what is left if a module reaches this pass that the type checker did not accept, which
141/// nothing does today: a build with an error never gets here. They are errors and not panics
142/// so that a caller holding one is told which declaration it was reading.
143#[derive(Debug, Clone, PartialEq)]
144pub enum Error {
145    /// A constrained declaration whose specialisations never end: it needs itself, directly
146    /// or through other declarations, at a type larger each time.
147    Unbounded {
148        /// The declaration, as the source names it: a function, or the member an instance
149        /// binds.
150        declaration: Name,
151        /// The ground types it had been reached at when the limit was: its
152        /// [key](super::Specialisation::key).
153        types: Vec<Type>,
154        /// Where the declaration was written.
155        span: NodeSpan,
156        /// The module whose use began the chain.
157        used_in: Name,
158    },
159    /// A use that asks for an instance of `class` at `tpe` and no instance of it is part of
160    /// the build.
161    NoInstance {
162        class: Name,
163        tpe: Type,
164        /// The declaration the use was written in.
165        within: Name,
166        used_in: Name,
167        span: NodeSpan,
168    },
169    /// A use of a constrained name whose constrained variable was still a type variable once
170    /// the declaration it is in was specialised, so there is no key to copy at; or a use of a
171    /// class member at a bare variable, which has no name to look an instance up by. A use at
172    /// `Phantom b` is neither, whatever `b` is.
173    NotGround {
174        class: Name,
175        tpe: Type,
176        within: Name,
177        used_in: Name,
178        span: NodeSpan,
179    },
180    /// A use of a constrained name whose declaration, or whose instance's member, has no IR to
181    /// copy: the type checker could not check it.
182    NoDeclaration {
183        name: Name,
184        within: Name,
185        used_in: Name,
186        span: NodeSpan,
187    },
188}
189
190impl PhaseError for Error {
191    fn message(&self) -> String {
192        match self {
193            Error::Unbounded { declaration, .. } => format!(
194                "`{}` needs itself at ever larger types, so it has no finite set of specialisations to compile",
195                declaration.as_str()
196            ),
197            Error::NoInstance {
198                class,
199                tpe,
200                within,
201                ..
202            } => format!(
203                "no instance of `{}` at `{}` was found for the use in `{}`",
204                class.as_str(),
205                tpe.written_with_letters(),
206                within.as_str()
207            ),
208            Error::NotGround {
209                class,
210                tpe,
211                within,
212                ..
213            } => format!(
214                "the use of an instance of `{}` in `{}` is at `{}`, which is not a type yet",
215                class.as_str(),
216                within.as_str(),
217                tpe.written_with_letters()
218            ),
219            Error::NoDeclaration { name, within, .. } => format!(
220                "`{}` has nothing to specialise, but `{}` uses it as a name that asks for an instance",
221                name.as_str(),
222                within.as_str()
223            ),
224        }
225    }
226
227    fn notes(&self) -> Vec<String> {
228        match self {
229            Error::Unbounded {
230                declaration,
231                types,
232                used_in,
233                ..
234            } => vec![
235                format!(
236                    "{} nested specialisations of `{}`, the limit, were reached at `{}`, while compiling `{}`",
237                    SPECIALISATION_LIMIT,
238                    declaration.as_str(),
239                    join(types),
240                    used_in.as_str()
241                ),
242                "a constrained function is compiled once for each type it is used at, so the types it is used at have to be finite".to_string(),
243            ],
244            Error::NoInstance { tpe, used_in, .. } => {
245                let mut notes = vec![format!("while compiling `{}`", used_in.as_str())];
246                if matches!(tpe, Type::Record(_)) {
247                    notes.push(
248                        "a class at a record type is not compiled yet (`LANG-85`)".to_string(),
249                    );
250                }
251                notes
252            }
253            Error::NotGround { used_in, .. } | Error::NoDeclaration { used_in, .. } => {
254                vec![format!("while compiling `{}`", used_in.as_str())]
255            }
256        }
257    }
258
259    fn labels(&self) -> Vec<SpanLabel> {
260        let (span, message) = match self {
261            Error::Unbounded { span, .. } => (span, "this declaration"),
262            Error::NoInstance { span, .. }
263            | Error::NotGround { span, .. }
264            | Error::NoDeclaration { span, .. } => (span, "this use"),
265        };
266
267        match span.span() {
268            Some(span) => vec![SpanLabel {
269                span,
270                message: message.to_owned(),
271                primary: true,
272                file: None,
273            }],
274            None => Vec::new(),
275        }
276    }
277}
278
279/// Types as a message writes a list of them: `Box Colour, Int`.
280fn join(types: &[Type]) -> String {
281    types
282        .iter()
283        .map(|tpe| tpe.to_string())
284        .collect::<Vec<_>>()
285        .join(", ")
286}
287
288/// The errors one module of the build has, by the module the code that raised them was
289/// written in: the module whose file the labels point into.
290#[derive(Debug)]
291pub struct ModuleErrors {
292    pub module: ModuleName,
293    pub errors: Vec<Error>,
294}
295
296// ── The pass ──────────────────────────────────────────────────────────────────
297
298/// Find every specialisation `modules` need and resolve every reference that carried
299/// obligations, in place.
300///
301/// `modules` is the whole of a build, or at least of one tree of it: a module is read
302/// against the others by name, and what one of them refers to that is not here is
303/// [`Error::NoDeclaration`] or [`Error::NoInstance`]. A build that emits a second tree holding
304/// more modules passes all of them, once: what a module of the first tree holds does not
305/// depend on the others, since a copy is made for the module that uses it and for none
306/// other.
307///
308/// The roots are every declaration with no context and every member of an instance with no
309/// context, in every module. The body of each is read, and each reference in it that
310/// carries obligations is resolved at the types it is now at: to a member of an instance
311/// directly, or to a specialisation of the module the body is in, which is read in its turn
312/// if its key is new. See the module's documentation for what a key is and for the limit.
313///
314/// On `Err` nothing has been changed, and each error is in the bucket of the module its
315/// labels point into, in the order the modules were handed in.
316pub fn specialise(modules: &mut [&mut CheckedModule]) -> Result<(), Vec<ModuleErrors>> {
317    let outcome = {
318        let world = World::of(modules.iter().map(|module| &**module).collect());
319        world.read()
320    };
321
322    if outcome.errors.iter().any(|errors| !errors.is_empty()) {
323        return Err(outcome
324            .errors
325            .into_iter()
326            .enumerate()
327            .filter(|(_, errors)| !errors.is_empty())
328            .map(|(index, errors)| ModuleErrors {
329                module: modules[index].ir.name.clone(),
330                errors,
331            })
332            .collect());
333    }
334
335    for (module, found) in modules.iter_mut().zip(outcome.found) {
336        for (place, body) in found.roots {
337            let declaration = match place {
338                Place::Declaration(index) => module.ir.declarations.get_mut(index),
339                Place::Member { instance, member } => module
340                    .ir
341                    .instances
342                    .get_mut(instance)
343                    .and_then(|instance| instance.members.get_mut(member)),
344            };
345            if let Some(declaration) = declaration {
346                declaration.body = Some(body);
347            }
348        }
349        module.ir.specialisations = found.specialisations;
350    }
351
352    Ok(())
353}
354
355/// What the pass reads: every module, and the three indexes it looks things up by.
356struct World<'a> {
357    modules: Vec<&'a CheckedModule>,
358    /// A module's place in `modules`, by name.
359    index: HashMap<ModuleName, usize>,
360    /// Each module's declarations, by name, as a place in `ir.declarations`.
361    declarations: Vec<HashMap<&'a Name, usize>>,
362    /// The class each class member belongs to, by the member's qualified name. A member is a
363    /// value of the module that declares its class.
364    members: HashMap<QualName, QualName>,
365    /// Every instance of the build, by class and the name at the front of its head: the
366    /// module, and the place in that module's `ir.instances`.
367    instances: HashMap<(QualName, HeadName), (usize, usize)>,
368}
369
370/// What reading the build found: for each module, what to put back, and the errors.
371struct Outcome {
372    found: Vec<Found>,
373    errors: Vec<Vec<Error>>,
374}
375
376/// What one module is given back.
377#[derive(Default)]
378struct Found {
379    /// The body of each root, resolved.
380    roots: Vec<(Place, Body)>,
381    specialisations: Vec<super::Specialisation>,
382}
383
384/// Where a declaration is in a module.
385#[derive(Debug, Clone, Copy, PartialEq, Eq)]
386enum Place {
387    Declaration(usize),
388    Member { instance: usize, member: usize },
389}
390
391/// Where a declaration to be copied is: the module, and the place in it.
392#[derive(Debug, Clone, Copy)]
393struct Location {
394    module: usize,
395    place: Place,
396}
397
398/// A map from a type variable to the ground type it is at.
399type Assignment = HashMap<TypeVariable, Type>;
400
401impl<'a> World<'a> {
402    fn of(modules: Vec<&'a CheckedModule>) -> World<'a> {
403        let mut index = HashMap::new();
404        let mut declarations = Vec::new();
405        let mut members = HashMap::new();
406        let mut instances = HashMap::new();
407
408        for (position, module) in modules.iter().enumerate() {
409            index.insert(module.ir.name.clone(), position);
410            declarations.push(
411                module
412                    .ir
413                    .declarations
414                    .iter()
415                    .enumerate()
416                    .map(|(at, declaration)| (&declaration.name, at))
417                    .collect(),
418            );
419
420            let name = &module.canonical.name;
421            for (class_name, class) in &module.canonical.classes {
422                let class_qualified = name.qualify_name(class_name);
423                for member in &class.signature.members {
424                    members.insert(name.qualify_name(&member.name), class_qualified.clone());
425                }
426            }
427
428            for (at, instance) in module.ir.instances.iter().enumerate() {
429                instances.insert(
430                    (instance.class.clone(), instance.head_name.clone()),
431                    (position, at),
432                );
433            }
434        }
435
436        World {
437            modules,
438            index,
439            declarations,
440            members,
441            instances,
442        }
443    }
444
445    /// The module a name is declared in, as a place in `modules`.
446    fn module_of(&self, name: &QualName) -> Option<usize> {
447        self.index
448            .get(&ModuleName::new(name.package().clone(), name.module_name()))
449            .copied()
450    }
451
452    /// The declaration at `location`.
453    fn declaration(&self, location: Location) -> Option<&'a Declaration> {
454        let module = self.modules.get(location.module)?;
455        match location.place {
456            Place::Declaration(index) => module.ir.declarations.get(index),
457            Place::Member { instance, member } => {
458                module.ir.instances.get(instance)?.members.get(member)
459            }
460        }
461    }
462
463    fn read(&self) -> Outcome {
464        let mut found = Vec::new();
465        let mut errors: Vec<Vec<Error>> = self.modules.iter().map(|_| Vec::new()).collect();
466
467        for using in 0..self.modules.len() {
468            found.push(self.read_module(using, &mut errors));
469        }
470
471        Outcome { found, errors }
472    }
473
474    /// The roots of module `using`, and every specialisation they lead to.
475    fn read_module(&self, using: usize, errors: &mut [Vec<Error>]) -> Found {
476        let ir = &self.modules[using].ir;
477        let mut used = Used::default();
478        let mut found = Found::default();
479
480        for (index, declaration) in ir.declarations.iter().enumerate() {
481            if !declaration.context.is_empty() || declaration.body.is_none() {
482                continue;
483            }
484            let location = Location {
485                module: using,
486                place: Place::Declaration(index),
487            };
488            if let Some(body) =
489                self.read_body(using, location, declaration, None, &mut used, errors)
490            {
491                found.roots.push((location.place, body));
492            }
493        }
494
495        for (instance_index, instance) in ir.instances.iter().enumerate() {
496            if instance.rejected || !instance.context.is_empty() {
497                continue;
498            }
499            for (member_index, member) in instance.members.iter().enumerate() {
500                if !member.context.is_empty() || member.body.is_none() {
501                    continue;
502                }
503                let location = Location {
504                    module: using,
505                    place: Place::Member {
506                        instance: instance_index,
507                        member: member_index,
508                    },
509                };
510                if let Some(body) = self.read_body(using, location, member, None, &mut used, errors)
511                {
512                    found.roots.push((location.place, body));
513                }
514            }
515        }
516
517        // One chain at a time: the last found is read first, so a chain that never ends
518        // reaches the limit along its own length and not after every sibling of every step.
519        while let Some(index) = used.pending.pop() {
520            let (location, assignment) = {
521                let spec = &used.specs[index];
522                (spec.location, spec.assignment.clone())
523            };
524            let Some(source) = self.declaration(location) else {
525                continue;
526            };
527            let declaration = self.read_copy(
528                using,
529                location,
530                source,
531                &assignment,
532                Some(index),
533                &mut used,
534                errors,
535            );
536            used.specs[index].declaration = declaration;
537        }
538
539        found.specialisations = used
540            .specs
541            .into_iter()
542            .filter_map(|spec| {
543                Some(super::Specialisation {
544                    of: spec.subject,
545                    key: spec.key,
546                    declaration: spec.declaration?,
547                })
548            })
549            .collect();
550        found
551    }
552
553    /// The body of `declaration`, with every reference that carried obligations resolved,
554    /// for a root: nothing is assigned, and nothing is copied.
555    fn read_body(
556        &self,
557        using: usize,
558        location: Location,
559        declaration: &Declaration,
560        parent: Option<usize>,
561        used: &mut Used,
562        errors: &mut [Vec<Error>],
563    ) -> Option<Body> {
564        let body = declaration.body.as_ref()?;
565        let assignment = Assignment::new();
566        let mut reader = Reader {
567            world: self,
568            using,
569            source: location.module,
570            assignment: &assignment,
571            within: &declaration.name,
572            parent,
573            used,
574            errors,
575        };
576        Some(reader.body(body))
577    }
578
579    /// `source` copied for module `using` with `assignment` applied.
580    #[allow(clippy::too_many_arguments)]
581    fn read_copy(
582        &self,
583        using: usize,
584        location: Location,
585        source: &Declaration,
586        assignment: &Assignment,
587        parent: Option<usize>,
588        used: &mut Used,
589        errors: &mut [Vec<Error>],
590    ) -> Option<Declaration> {
591        let body = source.body.as_ref()?;
592        let mut reader = Reader {
593            world: self,
594            using,
595            source: location.module,
596            assignment,
597            within: &source.name,
598            parent,
599            used,
600            errors,
601        };
602        let body = reader.body(body);
603
604        Some(Declaration {
605            name: source.name.clone(),
606            arity: source.arity,
607            tpe: apply(&source.tpe, assignment),
608            context: Vec::new(),
609            body: Some(body),
610            span: source.span,
611        })
612    }
613}
614
615/// The specialisations of the module being read.
616#[derive(Default)]
617struct Used {
618    specs: Vec<Spec>,
619    /// The specialisation at a key, by what it is a copy of.
620    table: HashMap<(Subject, Vec<Type>), usize>,
621    /// The specialisations found and not yet read, the last found on top.
622    pending: Vec<usize>,
623    /// Whether a chain of this module has reached the limit. The build has failed by then, so
624    /// nothing more is found: see [`Reader::specialise`].
625    stopped: bool,
626}
627
628/// A specialisation, from the moment it is found until its body has been read.
629struct Spec {
630    subject: Subject,
631    /// Where the declaration it is a copy of is.
632    location: Location,
633    key: Vec<Type>,
634    assignment: Assignment,
635    /// The specialisation whose body mentioned this one first, which is how the limit
636    /// follows a chain back.
637    parent: Option<usize>,
638    /// How many arguments a direct call supplies, which a use that is a class member needs
639    /// before the copy has been read.
640    arity: usize,
641    declaration: Option<Declaration>,
642}
643
644// ── Reading a body ────────────────────────────────────────────────────────────
645
646/// One declaration being copied: its body is rebuilt node by node, each type with the
647/// assignment applied and each reference resolved.
648struct Reader<'r, 'a> {
649    world: &'r World<'a>,
650    /// The module the copy is for.
651    using: usize,
652    /// The module the declaration was written in.
653    source: usize,
654    assignment: &'r Assignment,
655    /// The declaration being read, which an error names.
656    within: &'r Name,
657    /// The specialisation being read, if it is one.
658    parent: Option<usize>,
659    used: &'r mut Used,
660    errors: &'r mut [Vec<Error>],
661}
662
663impl Reader<'_, '_> {
664    fn ty(&self, tpe: &Type) -> Type {
665        apply(tpe, self.assignment)
666    }
667
668    fn binder(&self, binder: &TypeBinder) -> TypeBinder {
669        TypeBinder {
670            name: binder.name.clone(),
671            tpe: self.ty(&binder.tpe),
672        }
673    }
674
675    fn body(&mut self, body: &Body) -> Body {
676        Body {
677            parameters: body
678                .parameters
679                .iter()
680                .map(|parameter| self.binder(parameter))
681                .collect(),
682            expression: self.term(&body.expression),
683        }
684    }
685
686    fn term(&mut self, term: &TypedTerm) -> TypedTerm {
687        let kind = match &term.kind {
688            TypedTermKind::Int(value) => TypedTermKind::Int(*value),
689            TypedTermKind::Char(value) => TypedTermKind::Char(*value),
690            TypedTermKind::String(value) => TypedTermKind::String(value.clone()),
691            TypedTermKind::Float(value) => TypedTermKind::Float(*value),
692            TypedTermKind::Unit => TypedTermKind::Unit,
693            TypedTermKind::Hole => TypedTermKind::Hole,
694            TypedTermKind::Identifier { reference, context } => {
695                return self.identifier(term, reference, context);
696            }
697            TypedTermKind::Apply { .. } => return self.application(term),
698            TypedTermKind::Fun { param, body } => TypedTermKind::Fun {
699                param: self.binder(param),
700                body: Box::new(self.term(body)),
701            },
702            TypedTermKind::If {
703                cond,
704                true_branch,
705                false_branch,
706            } => TypedTermKind::If {
707                cond: Box::new(self.term(cond)),
708                true_branch: Box::new(self.term(true_branch)),
709                false_branch: Box::new(self.term(false_branch)),
710            },
711            TypedTermKind::Let {
712                binding,
713                value,
714                body,
715            } => TypedTermKind::Let {
716                binding: self.binder(binding),
717                value: Box::new(self.term(value)),
718                body: Box::new(self.term(body)),
719            },
720            TypedTermKind::Tuple(tuple) => TypedTermKind::Tuple(match tuple {
721                Tuple::Two(a, b) => Tuple::two(self.term(a), self.term(b)),
722                Tuple::Three(a, b, c) => Tuple::three(self.term(a), self.term(b), self.term(c)),
723            }),
724            TypedTermKind::Case {
725                scrutinee,
726                branches,
727                form,
728            } => TypedTermKind::Case {
729                scrutinee: Box::new(self.term(scrutinee)),
730                branches: branches
731                    .iter()
732                    .map(|(pattern, body)| (self.pattern(pattern), Box::new(self.term(body))))
733                    .collect(),
734                form: *form,
735            },
736            TypedTermKind::Record(fields) => TypedTermKind::Record(self.fields(fields)),
737            TypedTermKind::Update { record, fields } => TypedTermKind::Update {
738                record: Box::new(self.term(record)),
739                fields: self.fields(fields),
740            },
741            TypedTermKind::Access {
742                record,
743                label,
744                label_span,
745            } => TypedTermKind::Access {
746                record: Box::new(self.term(record)),
747                label: label.clone(),
748                label_span: *label_span,
749            },
750            TypedTermKind::Accessor { label, label_span } => TypedTermKind::Accessor {
751                label: label.clone(),
752                label_span: *label_span,
753            },
754        };
755
756        TypedTerm {
757            span: term.span,
758            tpe: self.ty(&term.tpe),
759            kind,
760        }
761    }
762
763    fn fields(&mut self, fields: &[Field<TypedTerm>]) -> Vec<Field<TypedTerm>> {
764        fields
765            .iter()
766            .map(|field| Field {
767                label: field.label.clone(),
768                label_span: field.label_span,
769                value: self.term(&field.value),
770            })
771            .collect()
772    }
773
774    fn pattern(&self, pattern: &TermPattern) -> TermPattern {
775        let kind = match &pattern.kind {
776            TermPatternKind::Anything => TermPatternKind::Anything,
777            TermPatternKind::Bind(name) => TermPatternKind::Bind(name.clone()),
778            TermPatternKind::Unit => TermPatternKind::Unit,
779            TermPatternKind::Literal { tpe, value } => TermPatternKind::Literal {
780                tpe: self.ty(tpe),
781                value: value.clone(),
782            },
783            TermPatternKind::Constructor {
784                ctor,
785                adt_args,
786                args,
787            } => TermPatternKind::Constructor {
788                ctor: ctor.clone(),
789                adt_args: adt_args.iter().map(|tpe| self.ty(tpe)).collect(),
790                args: args.iter().map(|arg| self.sub_pattern(arg)).collect(),
791            },
792            TermPatternKind::Tuple { elements } => TermPatternKind::Tuple {
793                elements: elements.map(|element| self.sub_pattern(element)),
794            },
795            TermPatternKind::Hole { args } => TermPatternKind::Hole {
796                args: args.iter().map(|arg| self.sub_pattern(arg)).collect(),
797            },
798            TermPatternKind::Record { fields } => TermPatternKind::Record {
799                fields: fields
800                    .iter()
801                    .map(|field| Field {
802                        label: field.label.clone(),
803                        label_span: field.label_span,
804                        value: self.sub_pattern(&field.value),
805                    })
806                    .collect(),
807            },
808        };
809
810        TermPattern {
811            span: pattern.span,
812            kind,
813        }
814    }
815
816    fn sub_pattern(&self, sub: &SubPattern) -> SubPattern {
817        SubPattern {
818            tpe: self.ty(&sub.tpe),
819            pattern: self.pattern(&sub.pattern),
820        }
821    }
822
823    /// An application spine, rebuilt: the head, then each argument in the order written.
824    ///
825    /// A class member's reference was left unsaturated by the type checker, which knew no
826    /// arity for it — a member is not a declaration of any module — so a head that resolves to
827    /// one is where the spine's saturation is worked out: the node that supplies the member's
828    /// last parameter is the direct call, as for any other declaration. Every other spine
829    /// keeps the flags it was given.
830    fn application(&mut self, term: &TypedTerm) -> TypedTerm {
831        let mut spine = Vec::new();
832        let mut head = term;
833        while let TypedTermKind::Apply {
834            fun,
835            arg,
836            saturation,
837        } = &head.kind
838        {
839            spine.push((head, arg.as_ref(), *saturation));
840            head = fun;
841        }
842        spine.reverse();
843
844        let mut built = self.term(head);
845        let member_arity = self.member_arity(&built);
846
847        for (position, (node, argument, saturation)) in spine.into_iter().enumerate() {
848            let argument = self.term(argument);
849            let saturation = match member_arity {
850                Some(arity) if arity == position + 1 => Saturation::Saturated,
851                Some(_) => Saturation::Partial,
852                None => saturation,
853            };
854            built = TypedTerm {
855                span: node.span,
856                tpe: self.ty(&node.tpe),
857                kind: TypedTermKind::Apply {
858                    fun: Box::new(built),
859                    arg: Box::new(argument),
860                    saturation,
861                },
862            };
863        }
864
865        built
866    }
867
868    /// The arity of the function `head` is, when it is a class member resolved.
869    fn member_arity(&self, head: &TypedTerm) -> Option<usize> {
870        let TypedTermKind::Identifier { reference, .. } = &head.kind else {
871            return None;
872        };
873        match &reference.kind {
874            ReferenceKind::InstanceMember(member) => Some(member.arity),
875            ReferenceKind::Specialised(index) => {
876                let spec = self.used.specs.get(*index)?;
877                matches!(spec.subject, Subject::InstanceMember { .. }).then_some(spec.arity)
878            }
879            _ => None,
880        }
881    }
882
883    /// An error about a use, which is written in the module the code being read was written
884    /// in: that module's file is the one the label points into.
885    fn error(&mut self, error: Error) {
886        self.errors[self.source].push(error);
887    }
888
889    fn used_in(&self) -> Name {
890        self.world.modules[self.using].ir.name.name().clone()
891    }
892
893    /// A reference, and what it asks. One that asks nothing is carried across modules; one
894    /// that does is resolved at the types it is now at.
895    fn identifier(
896        &mut self,
897        term: &TypedTerm,
898        reference: &Reference,
899        context: &[Predicate],
900    ) -> TypedTerm {
901        let tpe = self.ty(&term.tpe);
902        let span = term.span;
903
904        if context.is_empty() {
905            return TypedTerm {
906                span,
907                tpe,
908                kind: TypedTermKind::Identifier {
909                    reference: self.rebase(reference),
910                    context: Vec::new(),
911                },
912            };
913        }
914
915        let ground: Vec<Predicate> = context
916            .iter()
917            .map(|predicate| Predicate {
918                class: predicate.class.clone(),
919                tpe: self.ty(&predicate.tpe),
920            })
921            .collect();
922
923        let resolved = self.resolve(reference, &ground, &tpe, span);
924
925        // A reference no obligation could be resolved for keeps its obligations, and an
926        // error stands behind it, so the build that holds it writes nothing.
927        let (reference, context) = match resolved {
928            Some(kind) => (
929                Reference {
930                    name: reference.name.clone(),
931                    kind,
932                },
933                Vec::new(),
934            ),
935            None => (self.rebase(reference), ground),
936        };
937
938        TypedTerm {
939            span,
940            tpe,
941            kind: TypedTermKind::Identifier { reference, context },
942        }
943    }
944
945    /// What a reference that asks for instances at `ground` is, once they are found.
946    fn resolve(
947        &mut self,
948        reference: &Reference,
949        ground: &[Predicate],
950        use_tpe: &Type,
951        span: NodeSpan,
952    ) -> Option<ReferenceKind> {
953        let name = match &reference.kind {
954            ReferenceKind::TopLevel(name) | ReferenceKind::Foreign(name, _, _) => name,
955            _ => {
956                self.no_declaration(Name::new(reference.name.clone()), span);
957                return None;
958            }
959        };
960
961        match self.world.members.get(name) {
962            Some(class) => self.resolve_member(name, class, ground, use_tpe, span),
963            None => self.resolve_declaration(reference, name, ground, span),
964        }
965    }
966
967    /// The types `assignment` gives the variables `context` is over, in the order they occur:
968    /// a declaration's key. Only these variables matter, so a type that holds others, or none
969    /// of them, is as good as any: what has to be a type is what the key is made of.
970    ///
971    /// A variable that is still a variable here, or still holds one, is [`Error::NotGround`]
972    /// and `None`. A variable `assignment` has nothing for is left out of the key.
973    fn bind(
974        &mut self,
975        context: &[Predicate],
976        assignment: &Assignment,
977        span: NodeSpan,
978    ) -> Option<Vec<(TypeVariable, Type)>> {
979        let bound: Vec<(TypeVariable, Type)> = constrained(context)
980            .into_iter()
981            .filter_map(|variable| {
982                let tpe = assignment.get(&variable)?.clone();
983                Some((variable, tpe))
984            })
985            .collect();
986
987        let Some((variable, _)) = bound.iter().find(|(_, tpe)| !is_ground(tpe)) else {
988            return Some(bound);
989        };
990        if let Some(predicate) = context
991            .iter()
992            .find(|predicate| constrained(std::slice::from_ref(predicate)).contains(variable))
993        {
994            let tpe = apply(&predicate.tpe, assignment);
995            self.not_ground(&predicate.class, &tpe, span);
996        }
997        None
998    }
999
1000    fn not_ground(&mut self, class: &QualName, tpe: &Type, span: NodeSpan) {
1001        let error = Error::NotGround {
1002            class: class.unqualified_name(),
1003            tpe: tpe.clone(),
1004            within: self.within.clone(),
1005            used_in: self.used_in(),
1006            span,
1007        };
1008        self.error(error);
1009    }
1010
1011    fn no_declaration(&mut self, name: Name, span: NodeSpan) {
1012        let error = Error::NoDeclaration {
1013            name,
1014            within: self.within.clone(),
1015            used_in: self.used_in(),
1016            span,
1017        };
1018        self.error(error);
1019    }
1020
1021    fn no_instance(&mut self, class: &QualName, tpe: &Type, span: NodeSpan) {
1022        let error = Error::NoInstance {
1023            class: class.unqualified_name(),
1024            tpe: tpe.clone(),
1025            within: self.within.clone(),
1026            used_in: self.used_in(),
1027            span,
1028        };
1029        self.error(error);
1030    }
1031
1032    /// A class member at a type: the binding of the instance for the type's head, or a
1033    /// specialisation of it when the instance has a context.
1034    fn resolve_member(
1035        &mut self,
1036        member: &QualName,
1037        class: &QualName,
1038        ground: &[Predicate],
1039        use_tpe: &Type,
1040        span: NodeSpan,
1041    ) -> Option<ReferenceKind> {
1042        let predicate = ground
1043            .iter()
1044            .find(|predicate| &predicate.class == class)
1045            .or_else(|| ground.first())?;
1046
1047        // An instance is found by the name at the front of the type and nothing else, so the
1048        // rest of the type may still hold variables. A bare variable has no name to look up.
1049        let Some((head, _)) = head_of(&predicate.tpe) else {
1050            if matches!(predicate.tpe, Type::Variable(_)) {
1051                self.not_ground(class, &predicate.tpe, span);
1052            } else {
1053                self.no_instance(class, &predicate.tpe, span);
1054            }
1055            return None;
1056        };
1057        let Some(&(module, instance_index)) =
1058            self.world.instances.get(&(class.clone(), head.clone()))
1059        else {
1060            self.no_instance(class, &predicate.tpe, span);
1061            return None;
1062        };
1063
1064        let ir = &self.world.modules[module].ir;
1065        let instance = &ir.instances[instance_index];
1066        let member_name = member.unqualified_name();
1067        let Some(member_index) = instance
1068            .members
1069            .iter()
1070            .position(|declaration| declaration.name == member_name)
1071        else {
1072            self.no_declaration(member_name, span);
1073            return None;
1074        };
1075        if instance.rejected {
1076            self.no_instance(class, &predicate.tpe, span);
1077            return None;
1078        }
1079        let declaration = &instance.members[member_index];
1080
1081        if declaration.context.is_empty() {
1082            return Some(ReferenceKind::InstanceMember(Box::new(InstanceMember {
1083                module: ir.name.clone(),
1084                class: class.clone(),
1085                head,
1086                member: member_name,
1087                arity: declaration.arity,
1088            })));
1089        }
1090
1091        // What each constrained variable of the member is at comes from the member's own
1092        // type read against the type of the use, and not from the instance's head: the
1093        // member's IR is over the variables its own inference gave it, which are the head's
1094        // only when the member's patterns pinned them to it (`same = sameWrap` does not).
1095        let mut assignment = Assignment::new();
1096        match_type(&declaration.tpe, use_tpe, &mut assignment);
1097        let bound = self.bind(&declaration.context, &assignment, span)?;
1098
1099        let subject = Subject::InstanceMember {
1100            class: class.clone(),
1101            head,
1102            member: member_name,
1103        };
1104        let location = Location {
1105            module,
1106            place: Place::Member {
1107                instance: instance_index,
1108                member: member_index,
1109            },
1110        };
1111        self.specialise(subject, location, declaration, bound)
1112            .map(ReferenceKind::Specialised)
1113    }
1114
1115    /// A constrained function at the types its context was given: a specialisation of it.
1116    fn resolve_declaration(
1117        &mut self,
1118        reference: &Reference,
1119        name: &QualName,
1120        ground: &[Predicate],
1121        span: NodeSpan,
1122    ) -> Option<ReferenceKind> {
1123        let found = self.world.module_of(name).and_then(|module| {
1124            let at = *self.world.declarations[module].get(&name.unqualified_name())?;
1125            Some((module, at, &self.world.modules[module].ir.declarations[at]))
1126        });
1127        let Some((module, at, declaration)) = found else {
1128            self.no_declaration(name.unqualified_name(), span);
1129            return None;
1130        };
1131
1132        // A name whose declaration asks nothing has nothing to copy, whatever its use carried.
1133        if declaration.context.is_empty() {
1134            return Some(self.rebase(reference).kind);
1135        }
1136
1137        let mut assignment = Assignment::new();
1138        for (pattern, predicate) in declaration.context.iter().zip(ground) {
1139            // What the pattern does not bind stays out of `assignment`, as `bind` reads it.
1140            match_type(&pattern.tpe, &predicate.tpe, &mut assignment);
1141        }
1142        let bound = self.bind(&declaration.context, &assignment, span)?;
1143
1144        let location = Location {
1145            module,
1146            place: Place::Declaration(at),
1147        };
1148        self.specialise(
1149            Subject::Declaration(name.clone()),
1150            location,
1151            declaration,
1152            bound,
1153        )
1154        .map(ReferenceKind::Specialised)
1155    }
1156
1157    /// The specialisation of `subject` at `bound`, found if it is new, or `None` when the
1158    /// chain it ends has reached the limit.
1159    fn specialise(
1160        &mut self,
1161        subject: Subject,
1162        location: Location,
1163        declaration: &Declaration,
1164        bound: Vec<(TypeVariable, Type)>,
1165    ) -> Option<usize> {
1166        let key: Vec<Type> = bound.iter().map(|(_, tpe)| tpe.clone()).collect();
1167
1168        if let Some(&index) = self.used.table.get(&(subject.clone(), key.clone())) {
1169            return Some(index);
1170        }
1171
1172        let mut occurrences = 0;
1173        let mut ancestor = self.parent;
1174        while let Some(index) = ancestor {
1175            let spec = &self.used.specs[index];
1176            if spec.subject == subject {
1177                occurrences += 1;
1178            }
1179            ancestor = spec.parent;
1180        }
1181        if occurrences >= SPECIALISATION_LIMIT {
1182            // The build has failed, and everything still waiting to be read could only add
1183            // more of the same: a loop that grows at two types is a tree of keys with a
1184            // leaf for each way down, 2^32 of them. So the module's work stops here.
1185            self.used.stopped = true;
1186            self.used.pending.clear();
1187
1188            // The declaration is in its own module's file, and its span is that file's. One
1189            // declaration is one error, however many modules use it.
1190            let reported = self.errors[location.module].iter().any(|error| {
1191                matches!(error, Error::Unbounded { declaration: reported, span, .. }
1192                    if reported == &declaration.name && span.to_range() == declaration.span.to_range())
1193            });
1194            if !reported {
1195                let used_in = self.used_in();
1196                self.errors[location.module].push(Error::Unbounded {
1197                    declaration: declaration.name.clone(),
1198                    types: key,
1199                    span: declaration.span,
1200                    used_in,
1201                });
1202            }
1203            return None;
1204        }
1205        if self.used.stopped {
1206            return None;
1207        }
1208
1209        let index = self.used.specs.len();
1210        self.used
1211            .table
1212            .insert((subject.clone(), key.clone()), index);
1213        self.used.specs.push(Spec {
1214            subject,
1215            location,
1216            key,
1217            assignment: bound.into_iter().collect(),
1218            parent: self.parent,
1219            arity: declaration.arity,
1220            declaration: None,
1221        });
1222        self.used.pending.push(index);
1223        Some(index)
1224    }
1225
1226    /// `reference` as it reads in the module the copy is for, when it was written in
1227    /// another.
1228    ///
1229    /// A name of the declaring module is the using module's import, with the arity its
1230    /// declaration was written with; a name of the using module that the declaring module
1231    /// imported is the using module's own.
1232    fn rebase(&self, reference: &Reference) -> Reference {
1233        let kind = match &reference.kind {
1234            ReferenceKind::TopLevel(name) if self.source != self.using => {
1235                let arity = self.world.declarations[self.source]
1236                    .get(&name.unqualified_name())
1237                    .map(|at| self.world.modules[self.source].ir.declarations[*at].arity)
1238                    .unwrap_or(0);
1239                ReferenceKind::Foreign(name.clone(), name.package().clone(), arity)
1240            }
1241            ReferenceKind::Foreign(name, _, _)
1242                if self.world.module_of(name) == Some(self.using) =>
1243            {
1244                ReferenceKind::TopLevel(name.clone())
1245            }
1246            other => other.clone(),
1247        };
1248
1249        Reference {
1250            name: reference.name.clone(),
1251            kind,
1252        }
1253    }
1254}
1255
1256// ── Types ─────────────────────────────────────────────────────────────────────
1257
1258/// `tpe` with each variable `assignment` has a type for replaced by it.
1259fn apply(tpe: &Type, assignment: &Assignment) -> Type {
1260    if assignment.is_empty() {
1261        return tpe.clone();
1262    }
1263
1264    match tpe {
1265        Type::Variable(variable) => assignment
1266            .get(variable)
1267            .cloned()
1268            .unwrap_or_else(|| tpe.clone()),
1269        Type::Literal(_) | Type::Unit => tpe.clone(),
1270        Type::Fun {
1271            param_tpe,
1272            return_tpe,
1273        } => Type::Fun {
1274            param_tpe: Box::new(apply(param_tpe, assignment)),
1275            return_tpe: Box::new(apply(return_tpe, assignment)),
1276        },
1277        Type::Tuple(tuple) => Type::Tuple(tuple.map(|element| apply(element, assignment))),
1278        Type::Adt(name, arguments) => Type::Adt(
1279            name.clone(),
1280            arguments
1281                .iter()
1282                .map(|argument| apply(argument, assignment))
1283                .collect(),
1284        ),
1285        Type::Record(fields) => Type::Record(
1286            fields
1287                .iter()
1288                .map(|(label, tpe)| (label.clone(), apply(tpe, assignment)))
1289                .collect(),
1290        ),
1291    }
1292}
1293
1294/// Whether `tpe` holds no variable.
1295fn is_ground(tpe: &Type) -> bool {
1296    match tpe {
1297        Type::Variable(_) => false,
1298        Type::Literal(_) | Type::Unit => true,
1299        Type::Fun {
1300            param_tpe,
1301            return_tpe,
1302        } => is_ground(param_tpe) && is_ground(return_tpe),
1303        Type::Tuple(tuple) => tuple.iter().all(is_ground),
1304        Type::Adt(_, arguments) => arguments.iter().all(is_ground),
1305        Type::Record(fields) => fields.values().all(is_ground),
1306    }
1307}
1308
1309/// Read `ground` against `pattern`, binding each variable of `pattern` to the type it meets
1310/// in `assignment`. Whether the two have the same shape.
1311///
1312/// A variable met twice must meet one type both times. What is bound before a mismatch stays
1313/// bound, which is why a caller that cares about the answer reads the whole of `pattern`.
1314fn match_type(pattern: &Type, ground: &Type, assignment: &mut Assignment) -> bool {
1315    match (pattern, ground) {
1316        (Type::Variable(variable), ground) => match assignment.get(variable) {
1317            Some(bound) => bound == ground,
1318            None => {
1319                assignment.insert(variable.clone(), ground.clone());
1320                true
1321            }
1322        },
1323        (Type::Literal(a), Type::Literal(b)) => a == b,
1324        (Type::Unit, Type::Unit) => true,
1325        (
1326            Type::Fun {
1327                param_tpe: a_param,
1328                return_tpe: a_return,
1329            },
1330            Type::Fun {
1331                param_tpe: b_param,
1332                return_tpe: b_return,
1333            },
1334        ) => {
1335            // Both halves are read even when the first mismatches, so the assignment holds
1336            // all that can be bound.
1337            let param = match_type(a_param, b_param, assignment);
1338            let result = match_type(a_return, b_return, assignment);
1339            param && result
1340        }
1341        (Type::Tuple(a), Type::Tuple(b)) => match (a, b) {
1342            (Tuple::Two(a1, a2), Tuple::Two(b1, b2)) => {
1343                let first = match_type(a1, b1, assignment);
1344                let second = match_type(a2, b2, assignment);
1345                first && second
1346            }
1347            (Tuple::Three(a1, a2, a3), Tuple::Three(b1, b2, b3)) => {
1348                let first = match_type(a1, b1, assignment);
1349                let second = match_type(a2, b2, assignment);
1350                let third = match_type(a3, b3, assignment);
1351                first && second && third
1352            }
1353            _ => false,
1354        },
1355        (Type::Adt(a_name, a_args), Type::Adt(b_name, b_args)) => {
1356            if a_name != b_name || a_args.len() != b_args.len() {
1357                return false;
1358            }
1359            let mut matched = true;
1360            for (a, b) in a_args.iter().zip(b_args) {
1361                matched &= match_type(a, b, assignment);
1362            }
1363            matched
1364        }
1365        (Type::Record(a), Type::Record(b)) => {
1366            if a.len() != b.len() || !a.keys().eq(b.keys()) {
1367                return false;
1368            }
1369            let mut matched = true;
1370            for (a, b) in a.values().zip(b.values()) {
1371                matched &= match_type(a, b, assignment);
1372            }
1373            matched
1374        }
1375        _ => false,
1376    }
1377}
1378
1379/// The variables a context is over, each once, in the order they first occur.
1380fn constrained(context: &[Predicate]) -> Vec<TypeVariable> {
1381    fn collect(tpe: &Type, into: &mut Vec<TypeVariable>) {
1382        match tpe {
1383            Type::Variable(variable) => {
1384                if !into.contains(variable) {
1385                    into.push(variable.clone());
1386                }
1387            }
1388            Type::Literal(_) | Type::Unit => {}
1389            Type::Fun {
1390                param_tpe,
1391                return_tpe,
1392            } => {
1393                collect(param_tpe, into);
1394                collect(return_tpe, into);
1395            }
1396            Type::Tuple(tuple) => tuple.iter().for_each(|element| collect(element, into)),
1397            Type::Adt(_, arguments) => arguments
1398                .iter()
1399                .for_each(|argument| collect(argument, into)),
1400            Type::Record(fields) => fields.values().for_each(|field| collect(field, into)),
1401        }
1402    }
1403
1404    let mut variables = Vec::new();
1405    for predicate in context {
1406        collect(&predicate.tpe, &mut variables);
1407    }
1408    variables
1409}
1410
1411// ── What a module mentions ────────────────────────────────────────────────────
1412
1413/// Every reference in `term`, in the order a reader meets them.
1414fn references<'a>(term: &'a TypedTerm, into: &mut Vec<&'a Reference>) {
1415    match &term.kind {
1416        TypedTermKind::Identifier { reference, .. } => into.push(reference),
1417        TypedTermKind::Apply { fun, arg, .. } => {
1418            references(fun, into);
1419            references(arg, into);
1420        }
1421        TypedTermKind::Fun { body, .. } => references(body, into),
1422        TypedTermKind::If {
1423            cond,
1424            true_branch,
1425            false_branch,
1426        } => {
1427            references(cond, into);
1428            references(true_branch, into);
1429            references(false_branch, into);
1430        }
1431        TypedTermKind::Let { value, body, .. } => {
1432            references(value, into);
1433            references(body, into);
1434        }
1435        TypedTermKind::Tuple(tuple) => tuple.iter().for_each(|element| references(element, into)),
1436        TypedTermKind::Case {
1437            scrutinee,
1438            branches,
1439            ..
1440        } => {
1441            references(scrutinee, into);
1442            for (_, body) in branches {
1443                references(body, into);
1444            }
1445        }
1446        TypedTermKind::Record(fields) => fields
1447            .iter()
1448            .for_each(|field| references(&field.value, into)),
1449        TypedTermKind::Update { record, fields } => {
1450            references(record, into);
1451            fields
1452                .iter()
1453                .for_each(|field| references(&field.value, into));
1454        }
1455        TypedTermKind::Access { record, .. } => references(record, into),
1456        TypedTermKind::Int(_)
1457        | TypedTermKind::Char(_)
1458        | TypedTermKind::String(_)
1459        | TypedTermKind::Float(_)
1460        | TypedTermKind::Unit
1461        | TypedTermKind::Hole
1462        | TypedTermKind::Accessor { .. } => {}
1463    }
1464}
1465
1466/// The values of `module` that a copy of its code, placed in another module, names: the
1467/// declarations its constrained declarations and the bindings of its instances mention.
1468///
1469/// A copy is made from what was written in `module`, and it can name a value `module` does
1470/// not expose — `exposing` is a rule about what another module's source may write, and
1471/// canonicalization enforces it whatever this returns. So a backend that makes each copy
1472/// reachable exports these as well as what the header lists. A constrained declaration
1473/// has no function under its own name, so it is never in the answer; the instance bindings
1474/// of a module are every one of its instances', whether or not the instance has a context,
1475/// since a binding that is not copied is not harmed by being named. A derivation's bindings
1476/// are placed in the instances that derive them, so they are among those.
1477///
1478/// Sorted by name.
1479pub fn mentioned_by_copies(module: &Module) -> Vec<Name> {
1480    let emitted: HashSet<&Name> = module
1481        .declarations
1482        .iter()
1483        .filter(|declaration| declaration.context.is_empty() && declaration.body.is_some())
1484        .map(|declaration| &declaration.name)
1485        .collect();
1486
1487    let constrained = module
1488        .declarations
1489        .iter()
1490        .filter(|declaration| !declaration.context.is_empty());
1491    let bindings = module
1492        .instances
1493        .iter()
1494        .flat_map(|instance| instance.members.iter());
1495
1496    let mut found = BTreeSet::new();
1497    for declaration in constrained.chain(bindings) {
1498        let Some(body) = &declaration.body else {
1499            continue;
1500        };
1501        let mut mentioned = Vec::new();
1502        references(&body.expression, &mut mentioned);
1503
1504        for reference in mentioned {
1505            if let ReferenceKind::TopLevel(name) = &reference.kind {
1506                let name = name.unqualified_name();
1507                if emitted.contains(&name) {
1508                    found.insert(name);
1509                }
1510            }
1511        }
1512    }
1513
1514    found.into_iter().collect()
1515}
1516
1517// ── Initialisation order ──────────────────────────────────────────────────────
1518
1519/// One thing a module emits under a name of its own: where it is, in the module.
1520#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
1521pub enum Item {
1522    /// A declaration: a place in [`Module::declarations`].
1523    Declaration(usize),
1524    /// A member of an instance that has no context.
1525    InstanceMember { instance: usize, member: usize },
1526    /// A specialisation: a place in [`Module::specialisations`].
1527    Specialisation(usize),
1528}
1529
1530/// The items of `module` that take no parameter, in the order they must be initialised: each
1531/// only after every parameterless item it depends on, directly or through a function it
1532/// mentions.
1533///
1534/// [`Module::initialisation_order`] is that order for the declarations alone, and is where
1535/// this starts: every declaration in it keeps its place, and the others follow in the order
1536/// they were found, each placed after what it depends on. An instance's bindings are not in
1537/// the graph that order was computed from, since which instance a name reaches is a fact
1538/// about types; and a specialisation was not there to be found. So this reads what each item
1539/// mentions in the IR, now that every mention names its target, and puts what a parameterless
1540/// item reaches ahead of it. An item in a cycle is placed once and the cycle is left as it
1541/// is, in name order: canonicalization rejects a cycle of declarations, and one through an
1542/// instance is a language question and not this function's.
1543///
1544/// A module that holds no instance member and no specialisation gets exactly
1545/// [`Module::initialisation_order`], as [`Item::Declaration`]s.
1546pub fn initialisation_items(module: &Module) -> Vec<Item> {
1547    let mut items: Vec<(Item, &Declaration)> = Vec::new();
1548    let mut declarations: HashMap<Name, Item> = HashMap::new();
1549
1550    for (index, declaration) in module.declarations.iter().enumerate() {
1551        if declaration.context.is_empty() && declaration.body.is_some() {
1552            let item = Item::Declaration(index);
1553            declarations.insert(declaration.name.clone(), item);
1554            items.push((item, declaration));
1555        }
1556    }
1557
1558    let mut members: HashMap<(QualName, HeadName, Name), Item> = HashMap::new();
1559    for (instance_index, instance) in module.instances.iter().enumerate() {
1560        if instance.rejected || !instance.context.is_empty() {
1561            continue;
1562        }
1563        let head = &instance.head_name;
1564        for (member_index, member) in instance.members.iter().enumerate() {
1565            if member.context.is_empty() && member.body.is_some() {
1566                let item = Item::InstanceMember {
1567                    instance: instance_index,
1568                    member: member_index,
1569                };
1570                members.insert(
1571                    (instance.class.clone(), head.clone(), member.name.clone()),
1572                    item,
1573                );
1574                items.push((item, member));
1575            }
1576        }
1577    }
1578
1579    for (index, specialisation) in module.specialisations.iter().enumerate() {
1580        items.push((Item::Specialisation(index), &specialisation.declaration));
1581    }
1582
1583    // What each item mentions that this module emits, in the order a reader meets it.
1584    let mut mentions: HashMap<Item, Vec<Item>> = HashMap::new();
1585    let mut constants: HashSet<Item> = HashSet::new();
1586    for (item, declaration) in &items {
1587        let Some(body) = &declaration.body else {
1588            continue;
1589        };
1590        if body.parameters.is_empty() {
1591            constants.insert(*item);
1592        }
1593
1594        let mut found = Vec::new();
1595        references(&body.expression, &mut found);
1596        let reached: Vec<Item> = found
1597            .into_iter()
1598            .filter_map(|reference| match &reference.kind {
1599                ReferenceKind::TopLevel(name) => {
1600                    declarations.get(&name.unqualified_name()).copied()
1601                }
1602                ReferenceKind::Specialised(index) => {
1603                    (*index < module.specialisations.len()).then_some(Item::Specialisation(*index))
1604                }
1605                ReferenceKind::InstanceMember(member) if member.module == module.name => members
1606                    .get(&(
1607                        member.class.clone(),
1608                        member.head.clone(),
1609                        member.member.clone(),
1610                    ))
1611                    .copied(),
1612                _ => None,
1613            })
1614            .collect();
1615        mentions.insert(*item, reached);
1616    }
1617
1618    // The parameterless items an item reaches, through functions and not through another
1619    // parameterless item, whose own dependencies are placed when it is.
1620    let dependencies = |item: Item| -> Vec<Item> {
1621        let mut seen = HashSet::from([item]);
1622        let mut reached = Vec::new();
1623        let mut pending: Vec<Item> = mentions
1624            .get(&item)
1625            .map(|mentioned| mentioned.iter().rev().copied().collect())
1626            .unwrap_or_default();
1627
1628        while let Some(next) = pending.pop() {
1629            if !seen.insert(next) {
1630                continue;
1631            }
1632            if constants.contains(&next) {
1633                reached.push(next);
1634            } else if let Some(mentioned) = mentions.get(&next) {
1635                pending.extend(mentioned.iter().rev().copied());
1636            }
1637        }
1638        reached
1639    };
1640
1641    let mut sequence: Vec<Item> = module
1642        .initialisation_order
1643        .iter()
1644        .filter_map(|name| declarations.get(name).copied())
1645        .filter(|item| constants.contains(item))
1646        .collect();
1647    let placed: HashSet<Item> = sequence.iter().copied().collect();
1648    sequence.extend(
1649        items
1650            .iter()
1651            .map(|(item, _)| *item)
1652            .filter(|item| constants.contains(item) && !placed.contains(item)),
1653    );
1654
1655    let mut order = Vec::new();
1656    let mut started: HashSet<Item> = HashSet::new();
1657    for root in sequence {
1658        if !started.insert(root) {
1659            continue;
1660        }
1661        let mut stack = vec![(root, dependencies(root).into_iter())];
1662
1663        while let Some((current, remaining)) = stack.last_mut() {
1664            let current = *current;
1665
1666            match remaining.next() {
1667                Some(dependency) => {
1668                    if started.insert(dependency) {
1669                        stack.push((dependency, dependencies(dependency).into_iter()));
1670                    }
1671                }
1672                None => {
1673                    order.push(current);
1674                    stack.pop();
1675                }
1676            }
1677        }
1678    }
1679
1680    order
1681}