Skip to main content

candela/compiler/
type_system.rs

1// This file is derived from keel (https://github.com/horacehoff/keel),
2// Copyright 2026 Horace Hoff, licensed under the Apache License, Version 2.0.
3// It has been modified by the candela authors. See the NOTICE file.
4use super::expr::Expr;
5use super::expr::METHOD_SEP;
6use super::expr::Span;
7use super::expr::UNARY_MINUS_METHOD;
8use super::expr::is_operator_method;
9use super::expr::is_unary_operator_method;
10use super::expr::mangle_method;
11use super::expr::operator_method;
12use super::expr::self_operator_method;
13use super::expr::symbol_of_expr;
14use crate::compiler::FileNamespaces;
15use crate::compiler::Namespace;
16use crate::compiler::SymbolKind;
17use crate::compiler::compiler_data::Ctx;
18use crate::compiler::compiler_data::EnumType;
19use crate::compiler::compiler_data::EnumVariant;
20use crate::compiler::compiler_data::FnGenerics;
21use crate::compiler::compiler_data::Function;
22use crate::compiler::compiler_data::Source;
23use crate::compiler::compiler_data::State;
24use crate::compiler::compiler_data::Struct;
25use crate::compiler::compiler_data::TypeNames;
26use crate::compiler::compiler_data::Variable;
27use crate::compiler::compiler_errors::error_instantiation_depth;
28use crate::compiler::compiler_errors::error_invalid_obj_type;
29use crate::compiler::compiler_errors::error_invalid_type;
30use crate::compiler::compiler_errors::error_missing_return;
31use crate::compiler::compiler_errors::error_op;
32use crate::compiler::compiler_errors::error_operator_method;
33use crate::compiler::compiler_errors::error_struct_default_signature;
34use crate::compiler::compiler_errors::error_struct_unknown_field;
35use crate::compiler::compiler_errors::error_type_arg_count;
36use crate::compiler::compiler_errors::error_type_args_on_plain_function;
37use crate::compiler::compiler_errors::error_type_args_on_plain_type;
38use crate::compiler::compiler_errors::error_type_not_indexable;
39use crate::compiler::compiler_errors::error_unknown_function;
40use crate::compiler::compiler_errors::error_unknown_function_in_namespace;
41use crate::compiler::compiler_errors::error_unknown_namespace;
42use crate::compiler::compiler_errors::error_unknown_struct;
43use crate::compiler::compiler_errors::error_unknown_type;
44use crate::compiler::compiler_errors::error_unknown_type_param;
45use crate::compiler::compiler_errors::error_unknown_type_with_namespace;
46use crate::compiler::compiler_errors::error_unknown_variable;
47use crate::compiler::expr::closure_free_names;
48use crate::compiler::functions::Callee;
49use crate::compiler::functions::reject_default_default;
50use crate::compiler::functions::resolve_callee;
51use crate::compiler::methods::check_receiver;
52use crate::compiler::methods::infer_operator_method;
53use crate::compiler::methods::reject_block_dot_call;
54use crate::compiler::resolve_enum_variant;
55use crate::rt::FnValue;
56use rustc_hash::FxHashMap;
57use rustc_hash::FxHashSet;
58use smol_strc::SmolStr;
59use smol_strc::ToSmolStr;
60use std::cell::RefCell;
61use std::hint::cold_path;
62use std::hint::unreachable_unchecked;
63use std::rc::Rc;
64
65pub use crate::rt::DataType;
66
67/// Name prefix for the synthetic top-level function an anonymous function is
68/// hoisted to. `<` is not a legal identifier character, so a hoisted name can
69/// never collide with a user-written function.
70///
71/// Public because a frontend reading the function table has to tell the
72/// entries a person wrote from the ones the compiler made: an outline lists
73/// the first and leaves out the second.
74pub const ANON_FN_PREFIX: &str = "<anon>";
75
76// Tracks which user-defined functions are currently being analysed for their
77// return type. Used to break mutual-recursion cycles in type inference
78thread_local! {
79    static RETURN_TYPE_INFERRING: RefCell<FxHashSet<usize>> =
80        RefCell::new(FxHashSet::default());
81}
82
83/// Clears inference bookkeeping left behind when a previous compilation on
84/// this thread was aborted by an error unwind (see `errors::collect_diagnostic`).
85pub fn reset_inference_state() {
86    RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().clear());
87}
88
89/// A declared `-> Type` return annotation with the span it was written at.
90///
91/// `None` leaves the return type inferred. Boxed because a declaration is
92/// carried inside [`Expr`], where the annotation is the rarest field.
93pub type ReturnAnnotation = Option<Box<(TypeExpr, Span)>>;
94
95/// The type parameters a declaration introduces (`struct Cell<T>`), in the
96/// order they were written. Empty for a declaration that takes none.
97pub type TypeParams = Box<[SmolStr]>;
98
99#[derive(Debug, PartialEq, Eq, Clone)]
100pub enum TypeExpr {
101    Identifier(SmolStr, Span),
102    NamespacedIdentifier(Box<[SmolStr]>, Span),
103    /// A generic type applied to its arguments, `Cell<int>`, with or without
104    /// a module path in front of the name (`g::Slot<int>`).
105    Generic(Box<GenericType>),
106    Array(Box<Self>),
107    Map(Box<Self>, Box<Self>),
108    Union(Box<[Self]>),
109    /// `fn(A, B) -> R`: a position that holds a function of that shape rather
110    /// than one particular function. The return type is `None` where the arrow
111    /// is left off, which is a function that hands nothing back.
112    Fn(Box<FnTypeExpr>),
113}
114
115/// The parameter types and return type a `fn(...)` annotation was written with.
116#[derive(Debug, PartialEq, Eq, Clone)]
117pub struct FnTypeExpr {
118    pub args: Box<[TypeExpr]>,
119    pub return_type: Option<TypeExpr>,
120    pub span: Span,
121}
122
123/// A generic type and the arguments it is applied to. Boxed inside
124/// [`TypeExpr`], which every declaration carries by value.
125#[derive(Debug, PartialEq, Eq, Clone)]
126pub struct GenericType {
127    /// The module path the name was written behind, empty for a name written
128    /// on its own. A module bound with `as` puts its alias here
129    /// (`g::Slot<int>`).
130    pub namespace: Box<[SmolStr]>,
131    pub name: SmolStr,
132    pub args: Box<[TypeExpr]>,
133    pub span: Span,
134}
135
136impl TypeExpr {
137    /// Whether this type mentions any of `params`.
138    ///
139    /// An annotation that does is left un-pinned when the call site supplies no
140    /// type arguments: candela infers such a parameter from the argument, the
141    /// same as an un-annotated one.
142    #[must_use]
143    pub fn mentions_any(&self, params: &[SmolStr]) -> bool {
144        match self {
145            Self::Identifier(name, _) => params.contains(name),
146            Self::NamespacedIdentifier(_, _) => false,
147            Self::Fn(sig) => {
148                sig.args.iter().any(|a| a.mentions_any(params))
149                    || sig
150                        .return_type
151                        .as_ref()
152                        .is_some_and(|r| r.mentions_any(params))
153            }
154            Self::Generic(generic) => {
155                // A name written behind a module path names that module's
156                // generic type, never a type parameter of the body being
157                // compiled.
158                (generic.namespace.is_empty() && params.contains(&generic.name))
159                    || generic.args.iter().any(|a| a.mentions_any(params))
160            }
161            Self::Array(inner) => inner.mentions_any(params),
162            Self::Map(k, val) => k.mentions_any(params) || val.mentions_any(params),
163            Self::Union(poly) => poly.iter().any(|t| t.mentions_any(params)),
164        }
165    }
166
167    #[must_use]
168    pub fn to_datatype(&self, ctx: &mut TypeCtx<'_>) -> DataType {
169        match self {
170            Self::Identifier(s, span) => match s.as_str() {
171                "int" => DataType::Int,
172                "float" => DataType::Float,
173                "bool" => DataType::Bool,
174                "string" => DataType::String,
175                "null" => DataType::Null,
176                // A dynamically-typed slot. Written `any`; modeled as `Unknown`,
177                // which the type checker already treats permissively. Used for
178                // enum payloads that hold a value of any type (option/result).
179                "any" => DataType::Unknown,
180                struct_name => {
181                    if let Some(bound) = ctx.generics.bound(struct_name) {
182                        bound
183                    } else if let Some(struct_id) =
184                        ctx.scope()
185                            .find_struct(&[], struct_name, *span, ctx.file_idx, ctx.sources)
186                    {
187                        DataType::Struct(struct_id as u16)
188                    } else if let Some(enum_id) = ctx.scope().find_enum(&[], struct_name) {
189                        DataType::Enum(enum_id as u16)
190                    } else if find_template(&[], struct_name, ctx.scope(), ctx.generics).is_some() {
191                        // A generic type named without its arguments is the
192                        // dynamic slot: candela never makes a missing type
193                        // argument an error.
194                        DataType::Unknown
195                    } else if ctx.generics.in_generic_body() {
196                        error_unknown_type_param(
197                            *span,
198                            ctx.file_idx,
199                            struct_name,
200                            &ctx.generics.bound_names(),
201                            ctx.sources,
202                        );
203                    } else {
204                        error_unknown_type(
205                            *span,
206                            ctx.file_idx,
207                            struct_name,
208                            ctx.sources,
209                            ctx.scope(),
210                        );
211                    }
212                }
213            },
214            Self::NamespacedIdentifier(s, span) => {
215                if let Some(struct_id) = ctx.scope().find_struct(
216                    &s[..s.len() - 1],
217                    unsafe { s.last().unwrap_unchecked() },
218                    *span,
219                    ctx.file_idx,
220                    ctx.sources,
221                ) {
222                    DataType::Struct(struct_id as u16)
223                } else if let Some(enum_id) = ctx
224                    .scope()
225                    .find_enum(&s[..s.len() - 1], unsafe { s.last().unwrap_unchecked() })
226                {
227                    DataType::Enum(enum_id as u16)
228                } else {
229                    cold_path();
230                    error_unknown_type_with_namespace(
231                        *span,
232                        ctx.file_idx,
233                        unsafe { s.last().unwrap_unchecked() },
234                        ctx.sources,
235                        ctx.scope(),
236                        &s[..s.len() - 1],
237                    )
238                }
239            }
240            Self::Generic(generic) => {
241                // The path in front of the name says which module the type
242                // comes from, so a path that names no module is reported here
243                // rather than resolving to whatever declared the name.
244                if !generic.namespace.is_empty()
245                    && ctx.scope().resolve(&generic.namespace).is_none()
246                {
247                    cold_path();
248                    error_unknown_namespace(
249                        &generic.namespace,
250                        generic.span,
251                        ctx.scope(),
252                        ctx.file_idx,
253                        ctx.sources,
254                    );
255                }
256                let args: Vec<DataType> = generic.args.iter().map(|a| a.to_datatype(ctx)).collect();
257                instantiate(&generic.namespace, &generic.name, &args, generic.span, ctx)
258            }
259            Self::Array(inner_t) => DataType::Array(Some(Box::new(inner_t.to_datatype(ctx)))),
260            Self::Map(k_t, v_t) => DataType::Map(Box::from((
261                Some(k_t.to_datatype(ctx)),
262                Some(v_t.to_datatype(ctx)),
263            ))),
264            Self::Union(poly) => {
265                DataType::Union(poly.iter().map(|t| t.to_datatype(ctx)).collect()).check_poly()
266            }
267            Self::Fn(sig) => DataType::FnValue(Box::new(FnValue {
268                sig: Some((
269                    sig.args.iter().map(|a| a.to_datatype(ctx)).collect(),
270                    sig.return_type
271                        .as_ref()
272                        .map_or(DataType::Null, |r| r.to_datatype(ctx)),
273                )),
274                candidates: Box::from([]),
275                set: None,
276            })),
277        }
278    }
279}
280
281/// How deep one generic type may be instantiated inside another before the
282/// compiler stops. A type whose own fields name a deeper instantiation of
283/// itself (`struct L<T> { next: L<L<T>> }`) has no finite set of
284/// instantiations, and this is where that is reported instead of hanging.
285const MAX_INSTANTIATION_DEPTH: u32 = 32;
286
287/// What a declaration of a generic type keeps: its parameters and the field or
288/// variant types they appear in, unresolved. Substituting the parameters and
289/// resolving the result is what [`instantiate`] does.
290#[derive(Debug)]
291struct TypeTemplate {
292    name: SmolStr,
293    params: TypeParams,
294    /// File the declaration was written in; its field types resolve against
295    /// that file's namespace whatever file the instantiation is written in.
296    file_idx: u16,
297    body: TemplateBody,
298    /// The `= value` each field of a struct template was declared with, empty
299    /// when none was; handed to every instantiation.
300    defaults: Box<[Option<(Expr, Span)>]>,
301}
302
303/// The `= value` a struct's fields were declared with, and the file the
304/// declaration was written in, which is the scope the values compile in.
305#[derive(Debug, Clone)]
306pub struct StructDefaults {
307    pub file_idx: u16,
308    /// One entry per field, `None` for a field declared without a value, with
309    /// the span the value was written at.
310    pub values: Box<[Option<(Expr, Span)>]>,
311}
312
313/// One type made from a generic declaration: which declaration, the name it is
314/// registered under, the type it became, and the arguments it was made with.
315/// The arguments are what lets an instantiation left open (`Option<any>`) be
316/// recognised as the same declaration as `Option<P>`.
317#[derive(Debug)]
318struct Instantiation {
319    template: usize,
320    name: SmolStr,
321    instantiated: DataType,
322    args: Box<[DataType]>,
323}
324
325#[derive(Debug, Clone)]
326enum TemplateBody {
327    Struct(Box<[(SmolStr, TypeExpr, Span)]>),
328    Enum(Box<[(SmolStr, Box<[TypeExpr]>, Span)]>),
329}
330
331/// An `impl` block written against a generic type, kept until the type is
332/// instantiated.
333///
334/// `args` is the header as written: `impl Cell<T>` applies to every
335/// instantiation and binds `T`, `impl Cell<int>` applies to that one.
336#[derive(Debug)]
337pub struct ImplTemplate {
338    pub type_name: SmolStr,
339    pub args: Box<[TypeExpr]>,
340    /// The methods, as [`Expr::FunctionDecl`] carrying the plain method name.
341    /// The name is mangled per instantiated type when the block is lowered.
342    pub methods: Box<[Expr]>,
343    pub file_idx: u16,
344    pub span: Span,
345}
346
347/// The type parameters in scope while one body is compiled.
348///
349/// `named` are the ones the call site's type arguments and the enclosing `impl`
350/// block fixed. `unnamed` are the parameters neither of them mentions: they
351/// stand for `any`, so a body that writes such a parameter in a type position
352/// compiles instead of reporting a type that has no value yet. The two are kept
353/// apart because an annotation mentioning an unnamed parameter stays un-pinned:
354/// what the body returns is inferred rather than checked against `any`.
355#[derive(Debug, Default)]
356pub struct BindingFrame {
357    named: Box<[(SmolStr, DataType)]>,
358    unnamed: Box<[SmolStr]>,
359}
360
361impl BindingFrame {
362    /// A frame in which every parameter is fixed to a type, which is what an
363    /// `impl` block and a generic instantiation produce.
364    #[must_use]
365    pub fn all_named(named: Box<[(SmolStr, DataType)]>) -> Self {
366        Self {
367            named,
368            unnamed: Box::from([]),
369        }
370    }
371
372    fn is_empty(&self) -> bool {
373        self.named.is_empty() && self.unnamed.is_empty()
374    }
375}
376
377/// The generic declarations of a program, the instantiations made from them,
378/// and the type parameters bound while a body is being compiled.
379#[derive(Debug, Default)]
380pub struct Generics {
381    templates: Vec<TypeTemplate>,
382    impls: Vec<ImplTemplate>,
383    /// Instantiations by the declaration they came from, their rendered name
384    /// and the arguments they were made with, so `Cell<int>` written twice is
385    /// one struct and two modules each declaring `Cell<T>` keep their own.
386    /// `<` and `>` cannot occur in an identifier, so a rendered name never
387    /// collides with a user-written one.
388    instantiations: Vec<Instantiation>,
389    /// Type parameters bound for the body being compiled. Only the top frame is
390    /// in scope: the parameters of a function never reach the body of a
391    /// function it calls.
392    bindings: Vec<BindingFrame>,
393    depth: u32,
394    /// The declared field values of every struct that has any, by struct id.
395    /// Kept here because this table travels with every compile against a
396    /// program, and an instantiation of a generic struct adds to it.
397    struct_defaults: FxHashMap<u16, StructDefaults>,
398    /// The templates the prelude registered. A program's own declaration of a
399    /// name the prelude also declares is the one a bare name reaches, wherever
400    /// the two were registered relative to each other.
401    prelude_templates: std::ops::Range<usize>,
402    /// The files that are prelude modules, whether the prelude loaded them or
403    /// a program imported one by name first. Their templates are bare names
404    /// everywhere.
405    prelude_files: Vec<u16>,
406}
407
408impl Generics {
409    /// How many generic declarations are registered.
410    #[must_use]
411    pub const fn template_count(&self) -> usize {
412        self.templates.len()
413    }
414
415    /// Records that file `file_idx` is a prelude module.
416    pub fn mark_prelude_file(&mut self, file_idx: u16) {
417        self.prelude_files.push(file_idx);
418    }
419
420    /// Records which templates the prelude registered.
421    pub const fn set_prelude_templates(&mut self, range: std::ops::Range<usize>) {
422        self.prelude_templates = range;
423    }
424
425    /// The last-registered template `matches` accepts, a program's own before
426    /// the prelude's.
427    fn last_template_where(&self, matches: impl Fn(&TypeTemplate) -> bool) -> Option<usize> {
428        let prelude = &self.prelude_templates;
429        self.templates
430            .iter()
431            .enumerate()
432            .rev()
433            .find(|(i, t)| !prelude.contains(i) && matches(t))
434            .or_else(|| {
435                self.templates
436                    .iter()
437                    .enumerate()
438                    .rev()
439                    .find(|(i, t)| prelude.contains(i) && matches(t))
440            })
441            .map(|(i, _)| i)
442    }
443
444    /// The type this name is currently bound to, if it names a type parameter
445    /// of the body being compiled. A parameter nothing named is `any`.
446    #[must_use]
447    pub fn bound(&self, name: &str) -> Option<DataType> {
448        let frame = self.bindings.last()?;
449        frame
450            .named
451            .iter()
452            .find(|(param, _)| param == name)
453            .map(|(_, t)| t.clone())
454            .or_else(|| {
455                frame
456                    .unnamed
457                    .iter()
458                    .any(|param| param == name)
459                    .then_some(DataType::Unknown)
460            })
461    }
462
463    /// Whether the call site or an enclosing `impl` block fixed this type
464    /// parameter to a type, as opposed to leaving it standing for `any`. An
465    /// annotation that mentions a parameter nothing named stays un-pinned.
466    #[must_use]
467    pub fn names(&self, name: &str) -> bool {
468        self.bindings
469            .last()
470            .is_some_and(|frame| frame.named.iter().any(|(param, _)| param == name))
471    }
472
473    /// Whether any type parameter is in scope, which is what makes an unknown
474    /// type name worth reporting as a type parameter rather than a type.
475    #[must_use]
476    fn in_generic_body(&self) -> bool {
477        self.bindings.last().is_some_and(|frame| !frame.is_empty())
478    }
479
480    fn bound_names(&self) -> Vec<SmolStr> {
481        self.bindings
482            .last()
483            .map(|frame| {
484                frame
485                    .named
486                    .iter()
487                    .map(|(p, _)| p.clone())
488                    .chain(frame.unnamed.iter().cloned())
489                    .collect()
490            })
491            .unwrap_or_default()
492    }
493
494    /// The parameters of the generic declaration `name` names, for a caller
495    /// with no scope to resolve it in: a mangled method name
496    /// (`Cell<int>#get`) carries the type name and no module path. Takes the
497    /// declaration registered last when two modules declare the name.
498    #[must_use]
499    pub fn params_of(&self, name: &str) -> Option<&[SmolStr]> {
500        self.last_template_where(|t| t.name == name)
501            .map(|i| &*self.templates[i].params)
502    }
503
504    /// Records the values the fields of struct `id` were declared with,
505    /// replacing whatever an earlier struct of that id left, so an id reused
506    /// after a rollback starts clean.
507    pub fn set_struct_defaults(
508        &mut self,
509        id: u16,
510        file_idx: u16,
511        values: Box<[Option<(Expr, Span)>]>,
512    ) {
513        if values.iter().any(Option::is_some) {
514            self.struct_defaults
515                .insert(id, StructDefaults { file_idx, values });
516        } else {
517            self.struct_defaults.remove(&id);
518        }
519    }
520
521    /// The value field `field` of struct `id` was declared with, and the file
522    /// it was written in.
523    #[must_use]
524    pub fn struct_default(&self, id: u16, field: usize) -> Option<(u16, &Expr, Span)> {
525        let defaults = self.struct_defaults.get(&id)?;
526        defaults
527            .values
528            .get(field)
529            .and_then(Option::as_ref)
530            .map(|(value, span)| (defaults.file_idx, value, *span))
531    }
532
533    /// For each type parameter of a struct template, the field declared with
534    /// that parameter as its type. A literal written without type arguments
535    /// takes each parameter from the value in that field.
536    #[must_use]
537    pub fn param_fields(&self, template_idx: usize) -> Vec<Option<SmolStr>> {
538        let Some(template) = self.templates.get(template_idx) else {
539            return Vec::new();
540        };
541        let TemplateBody::Struct(fields) = &template.body else {
542            return vec![None; template.params.len()];
543        };
544        template
545            .params
546            .iter()
547            .map(|param| {
548                fields
549                    .iter()
550                    .find(|(_, field_type, _)| {
551                        matches!(field_type, TypeExpr::Identifier(t, _) if t == param)
552                    })
553                    .map(|(field_name, _, _)| field_name.clone())
554            })
555            .collect()
556    }
557
558    /// The generic declaration the last-registered template under `name` is,
559    /// which is what an unqualified name falls back to when the scope it was
560    /// written in registers no template by that name.
561    ///
562    /// A template a program file declares is reached only through a scope,
563    /// so a module's `Slot<T>` is not a bare name in a file that bound the
564    /// module under a namespace. What is left is the prelude's, however its
565    /// module was loaded, and any registered after it, while a body was being
566    /// compiled.
567    fn last_template_named(&self, name: &str) -> Option<usize> {
568        let in_prelude = |i: usize| self.prelude_files.contains(&self.templates[i].file_idx);
569        let reachable = |i: usize| {
570            self.templates[i].name == name && (i >= self.prelude_templates.start || in_prelude(i))
571        };
572        (0..self.templates.len())
573            .rev()
574            .find(|&i| reachable(i) && !in_prelude(i))
575            .or_else(|| (0..self.templates.len()).rev().find(|&i| reachable(i)))
576    }
577
578    /// The declaration an instantiated type came from and the arguments it was
579    /// made with, for a type that came from one.
580    #[must_use]
581    pub fn instantiation_of(&self, t: &DataType) -> Option<(usize, &[DataType])> {
582        if !matches!(t, DataType::Struct(_) | DataType::Enum(_)) {
583            return None;
584        }
585        self.instantiations
586            .iter()
587            .find(|i| &i.instantiated == t)
588            .map(|i| (i.template, &*i.args))
589    }
590
591    /// The generic enum declaration that declares a variant of this name, and
592    /// the payload types the variant declares.
593    ///
594    /// A generic enum has no registered type until something names one, so a
595    /// bare `Some(x)` is looked up here rather than among the enums already
596    /// registered. The last declaration of the name wins, the same as
597    /// [`find_template`] does for a type name.
598    #[must_use]
599    pub fn enum_template_with_variant(&self, variant: &str) -> Option<usize> {
600        self.last_template_where(|t| match &t.body {
601            TemplateBody::Enum(variants) => variants.iter().any(|(name, _, _)| name == variant),
602            TemplateBody::Struct(_) => false,
603        })
604    }
605
606    /// Whether the only generic enums declaring a variant called `variant` are
607    /// the prelude's.
608    #[must_use]
609    pub fn only_the_prelude_declares(&self, variant: &str) -> bool {
610        self.enum_template_with_variant(variant)
611            .is_some_and(|template| self.prelude_templates.contains(&template))
612    }
613
614    /// The payload a variant of a generic enum declares, unresolved.
615    #[must_use]
616    fn variant_payload(&self, template: usize, variant: &str) -> Option<&[TypeExpr]> {
617        let TemplateBody::Enum(variants) = &self.templates[template].body else {
618            return None;
619        };
620        variants
621            .iter()
622            .find(|(name, _, _)| name == variant)
623            .map(|(_, payload, _)| &**payload)
624    }
625
626    /// The parameters a generic declaration takes.
627    #[must_use]
628    fn params(&self, template: usize) -> &[SmolStr] {
629        &self.templates[template].params
630    }
631
632    /// The name a generic declaration was written under.
633    #[must_use]
634    fn template_name(&self, template: usize) -> &SmolStr {
635        &self.templates[template].name
636    }
637
638    /// The file a generic declaration was written in.
639    #[must_use]
640    fn template_file(&self, template: usize) -> u16 {
641        self.templates[template].file_idx
642    }
643
644    /// Records a generic `struct` declaration and returns the index the
645    /// declaring scope registers it under, which is what a name written
646    /// behind a module path resolves to.
647    pub fn add_struct_template(
648        &mut self,
649        name: SmolStr,
650        params: TypeParams,
651        file_idx: u16,
652        fields: Box<[(SmolStr, TypeExpr, Span)]>,
653        defaults: Box<[Option<(Expr, Span)>]>,
654    ) -> u32 {
655        self.templates.push(TypeTemplate {
656            name,
657            params,
658            file_idx,
659            body: TemplateBody::Struct(fields),
660            defaults,
661        });
662        (self.templates.len() - 1) as u32
663    }
664
665    /// Records a generic `enum` declaration. Returns its index, as
666    /// [`Generics::add_struct_template`] does.
667    pub fn add_enum_template(
668        &mut self,
669        name: SmolStr,
670        params: TypeParams,
671        file_idx: u16,
672        variants: Box<[(SmolStr, Box<[TypeExpr]>, Span)]>,
673    ) -> u32 {
674        self.templates.push(TypeTemplate {
675            name,
676            params,
677            file_idx,
678            body: TemplateBody::Enum(variants),
679            defaults: Box::from([]),
680        });
681        (self.templates.len() - 1) as u32
682    }
683
684    /// Records the `impl` blocks a file declared against a generic type,
685    /// stamping each with the file it came from.
686    /// Whether any `impl` block the program has read defines an operator,
687    /// which makes an operator on that type a call to candela code.
688    #[must_use]
689    pub fn defines_operator_methods(&self) -> bool {
690        self.impls.iter().any(|block| {
691            block.methods.iter().any(|method| {
692                matches!(method, Expr::FunctionDecl(name, ..) if operator_method(name).is_some())
693            })
694        })
695    }
696
697    pub fn add_impls(&mut self, impls: Vec<ImplTemplate>, file_idx: u16) {
698        self.impls.extend(impls.into_iter().map(|mut block| {
699            block.file_idx = file_idx;
700            block
701        }));
702    }
703
704    /// The path a receiverless function `name` of generic declaration
705    /// `template` is called by, `Set<T>::new()`, when an `impl` block on it
706    /// declares one.
707    #[must_use]
708    pub fn path_fn_of_template(&self, template: usize, name: &str) -> Option<String> {
709        let decl = &self.templates[template];
710        self.impls
711            .iter()
712            .filter(|block| impl_base_name(&block.type_name) == decl.name.as_str())
713            .flat_map(|block| block.methods.iter())
714            .any(|method| {
715                matches!(method, Expr::FunctionDecl(fn_name, args, ..)
716                    if fn_name == name && args.is_empty())
717            })
718            .then(|| format!("{}<{}>::{name}()", decl.name, decl.params.join(", ")))
719    }
720
721    /// Binds `frame` for the body about to be compiled. Every body pushes a
722    /// frame, an empty one when it has no type parameters, so the caller's
723    /// parameters do not resolve inside it.
724    pub fn push_bindings(&mut self, frame: Box<[(SmolStr, DataType)]>) {
725        self.bindings.push(BindingFrame::all_named(frame));
726    }
727
728    /// Binds a frame that also carries the parameters nothing named, which a
729    /// function specialisation has and an `impl` block does not.
730    pub fn push_frame(&mut self, frame: BindingFrame) {
731        self.bindings.push(frame);
732    }
733
734    pub fn pop_bindings(&mut self) {
735        self.bindings.pop();
736    }
737
738    /// Snapshots the state a single generic instantiation (or a function
739    /// specialization's own type-parameter frame) can grow or unbalance, so an
740    /// aborted compile attempt can undo it with [`Generics::rollback_to`].
741    ///
742    /// `instantiations` and the structs/enums it names are a cache: an
743    /// `instantiate` call registers the pair before the instantiation's own
744    /// fields are resolved, so a type whose fields name itself resolves to the
745    /// type being built instead of recursing. A diagnostic raised while
746    /// resolving those fields (or while lowering an `impl` block against the
747    /// instantiation, which pushes its lowered methods the same way a closure
748    /// literal pushes an anonymous function) leaves the cache entry pointing at
749    /// a struct or enum whose fields were never filled in. `bindings` and
750    /// `depth` are pushed and incremented, respectively, before that same
751    /// resolution and are only popped or decremented after it returns; a
752    /// `push_bindings` without a matching `pop_bindings` (function
753    /// specialization has its own such pair too, see
754    /// `functions/user_functions.rs`) leaks a frame, and an unmatched `depth`
755    /// increment eventually trips the instantiation-depth cap for programs
756    /// nowhere near it.
757    #[must_use]
758    pub const fn checkpoint(&self) -> GenericsCheckpoint {
759        GenericsCheckpoint {
760            instantiations: self.instantiations.len(),
761            bindings: self.bindings.len(),
762            depth: self.depth,
763        }
764    }
765
766    /// Undoes everything a failed compile attempt did to the instantiation
767    /// cache and the binding/depth bookkeeping, back to `checkpoint`. The
768    /// structs and enums an aborted `instantiate` call registered are not
769    /// `Generics`' to remove; the caller truncates those (see
770    /// `Program::rollback_to`) using the same pre-attempt lengths.
771    pub fn rollback_to(&mut self, checkpoint: &GenericsCheckpoint) {
772        self.instantiations.truncate(checkpoint.instantiations);
773        self.bindings.truncate(checkpoint.bindings);
774        self.depth = checkpoint.depth;
775    }
776}
777
778/// A checkpoint of the [`Generics`] state taken by [`Generics::checkpoint`] and
779/// undone by [`Generics::rollback_to`].
780pub struct GenericsCheckpoint {
781    instantiations: usize,
782    bindings: usize,
783    depth: u32,
784}
785
786/// What resolving a [`TypeExpr`] needs: the scope the type is written in, and
787/// the registries an instantiation adds to.
788pub struct TypeCtx<'a> {
789    pub file_idx: u16,
790    pub namespaces: &'a FileNamespaces,
791    pub sources: &'a [Source],
792    pub structs: &'a mut Vec<Struct>,
793    pub enums: &'a mut Vec<EnumType>,
794    pub fns: &'a mut Vec<Function>,
795    pub generics: &'a mut Generics,
796}
797
798impl<'a> TypeCtx<'a> {
799    /// The scope the type being resolved is written in.
800    #[must_use]
801    pub fn scope(&self) -> &'a Namespace {
802        self.namespaces.get(self.file_idx)
803    }
804    /// The same registries, resolving names in another file's scope. A
805    /// declaration resolves its own types where it was written, whatever file
806    /// the use is written in.
807    pub const fn reborrow(&mut self, file_idx: u16) -> TypeCtx<'_> {
808        TypeCtx {
809            file_idx,
810            namespaces: self.namespaces,
811            sources: self.sources,
812            structs: self.structs,
813            enums: self.enums,
814            fns: self.fns,
815            generics: self.generics,
816        }
817    }
818}
819
820/// Renders `t` as the name an instantiation is registered under.
821///
822/// The name comes from the resolved type, never from the source text, so two
823/// spellings of one type give one instantiation and two types can never give
824/// the same name.
825#[must_use]
826fn render_type(t: &DataType, structs: &[Struct], enums: &[EnumType]) -> SmolStr {
827    match t {
828        DataType::Int => SmolStr::new_static("int"),
829        DataType::Float => SmolStr::new_static("float"),
830        DataType::Bool => SmolStr::new_static("bool"),
831        DataType::String => SmolStr::new_static("string"),
832        DataType::Null => SmolStr::new_static("null"),
833        DataType::Unknown => SmolStr::new_static("any"),
834        DataType::FnValue(sig) => sig.to_smolstr(),
835        DataType::Array(inner) => match inner {
836            Some(inner) => format_args!("{}[]", render_type(inner, structs, enums)).to_smolstr(),
837            None => SmolStr::new_static("any[]"),
838        },
839        DataType::Map(m) => format_args!(
840            "{{{}: {}}}",
841            m.0.as_ref().map_or_else(
842                || SmolStr::new_static("any"),
843                |k| render_type(k, structs, enums)
844            ),
845            m.1.as_ref().map_or_else(
846                || SmolStr::new_static("any"),
847                |val| render_type(val, structs, enums)
848            )
849        )
850        .to_smolstr(),
851        DataType::Union(poly) => poly
852            .iter()
853            .map(|t| render_type(t, structs, enums))
854            .collect::<Vec<SmolStr>>()
855            .join("|")
856            .into(),
857        DataType::Struct(id) => structs[*id as usize].name.clone(),
858        DataType::Enum(id) => enums[*id as usize].name.clone(),
859        DataType::Fn(id) => format_args!("fn:{id}").to_smolstr(),
860    }
861}
862
863/// The name a generic type is registered under once its arguments are known.
864///
865/// `qualifier` is the module the declaration was written in, present only when
866/// another module declares a generic type by the same name. Two such types are
867/// separate types, and the name is what a diagnostic prints and what a method
868/// on the type is mangled under, so both have to say which module they came
869/// from.
870#[must_use]
871fn render_instantiation(
872    qualifier: Option<&str>,
873    base: &str,
874    args: &[DataType],
875    structs: &[Struct],
876    enums: &[EnumType],
877) -> SmolStr {
878    let rendered = args
879        .iter()
880        .map(|a| render_type(a, structs, enums))
881        .collect::<Vec<SmolStr>>()
882        .join(", ");
883    match qualifier {
884        Some(module) => format_args!("{module}::{base}<{rendered}>").to_smolstr(),
885        None => format_args!("{base}<{rendered}>").to_smolstr(),
886    }
887}
888
889/// The path segments a file is known by: its path with the `.cdl` taken off,
890/// split on the directory separator, which is what an `import` writes.
891#[must_use]
892fn module_segments(file_idx: u16, sources: &[Source]) -> Vec<&str> {
893    let Some(source) = sources.get(file_idx as usize) else {
894        return Vec::new();
895    };
896    let path: &str = source
897        .filename
898        .strip_suffix(".cdl")
899        .unwrap_or(&source.filename);
900    path.split(['/', '\\']).filter(|s| !s.is_empty()).collect()
901}
902
903/// The module prefix a type declared in `file_idx` takes when the modules in
904/// `declarers` declare that name too: the fewest trailing path segments that
905/// tell this file apart from the others. One `plain.cdl` gives `plain`; two of
906/// them, one per package, give `strutil::plain` and `sqlite::plain`, so a
907/// qualified name is one type and no more.
908#[must_use]
909fn module_qualifier(file_idx: u16, declarers: &[u16], sources: &[Source]) -> SmolStr {
910    let mine = module_segments(file_idx, sources);
911    let others: Vec<Vec<&str>> = declarers
912        .iter()
913        .filter(|other| **other != file_idx)
914        .map(|other| module_segments(*other, sources))
915        .collect();
916    for take in 1..=mine.len() {
917        let tail = &mine[mine.len() - take..];
918        if others
919            .iter()
920            .all(|other| other.len() < take || &other[other.len() - take..] != tail)
921        {
922            return tail.join("::").into();
923        }
924    }
925    mine.join("::").into()
926}
927
928/// Puts the declaring module in front of every plain `struct` or `enum` name
929/// that more than one module declares, so a package's types never collide with
930/// a consumer's types of the same name.
931///
932/// Plain types share one program-wide table keyed by name, and a method lowers
933/// to a free function named after its type (`Plain#get`), so two modules each
934/// declaring `Plain` leave one `Plain#get` answering calls on both. The name a
935/// duplicate is registered under becomes `right::Plain`, which is what a
936/// diagnostic prints and what a method on it is mangled under; a generic type
937/// two modules declare is qualified the same way, see `render_instantiation`.
938/// A name only one module declares is left as it was written.
939///
940/// Every `impl` method is re-mangled against the name its receiver ended up
941/// with, resolved in the scope the `impl` block was written in, and so are the
942/// calls a method makes on its own receiver, which the recursion check reads.
943pub fn qualify_duplicate_type_names(
944    structs: &mut [Struct],
945    enums: &mut [EnumType],
946    fns: &mut [Function],
947    struct_files: &[(u16, u16)],
948    enum_files: &[(u16, u16)],
949    namespaces: &FileNamespaces,
950    sources: &[Source],
951) {
952    // The modules that declare each name. A struct and an enum of one name are
953    // as much two types as two structs are: both mangle their methods against
954    // that one name.
955    let mut declarers: FxHashMap<SmolStr, Vec<u16>> = FxHashMap::default();
956    for (name, file_idx) in struct_files
957        .iter()
958        .filter_map(|(id, file_idx)| Some((&structs.get(*id as usize)?.name, *file_idx)))
959        .chain(
960            enum_files
961                .iter()
962                .filter_map(|(id, file_idx)| Some((&enums.get(*id as usize)?.name, *file_idx))),
963        )
964    {
965        declarers.entry(name.clone()).or_default().push(file_idx);
966    }
967    if declarers.values().all(|files| files.len() <= 1) {
968        return;
969    }
970
971    for &(struct_id, file_idx) in struct_files {
972        let Some(declared) = structs.get_mut(struct_id as usize) else {
973            continue;
974        };
975        if let Some(files) = declarers.get(&declared.name)
976            && files.len() > 1
977        {
978            declared.name = qualified_type_name(file_idx, files, &declared.name, sources);
979        }
980    }
981    for &(enum_id, file_idx) in enum_files {
982        let Some(declared) = enums.get_mut(enum_id as usize) else {
983            continue;
984        };
985        if let Some(files) = declarers.get(&declared.name)
986            && files.len() > 1
987        {
988            declared.name = qualified_type_name(file_idx, files, &declared.name, sources);
989        }
990    }
991
992    for func in fns.iter_mut() {
993        let scope = namespaces.get(func.src_file);
994        if let Some(mangled) = requalify_method(&func.name, scope, structs, enums) {
995            func.name = mangled;
996        }
997        for callee in &mut func.direct_calls {
998            if let Some(mangled) = requalify_method(callee, scope, structs, enums) {
999                *callee = mangled;
1000            }
1001        }
1002    }
1003}
1004
1005/// The name a type declared in `file_idx` is registered under once the modules
1006/// in `declarers` declare that name too.
1007#[must_use]
1008fn qualified_type_name(
1009    file_idx: u16,
1010    declarers: &[u16],
1011    name: &str,
1012    sources: &[Source],
1013) -> SmolStr {
1014    format_args!("{}::{name}", module_qualifier(file_idx, declarers, sources)).to_smolstr()
1015}
1016
1017/// The mangled symbol a method ends up with, when the type its `impl` block
1018/// named was qualified. `None` when `name` is not a method, when the type it
1019/// names is not a plain type in `scope` (a builtin receiver, or a generic
1020/// instantiation, which carries its own qualifier already), or when that type
1021/// kept the name it was written with.
1022#[must_use]
1023fn requalify_method(
1024    name: &str,
1025    scope: &Namespace,
1026    structs: &[Struct],
1027    enums: &[EnumType],
1028) -> Option<SmolStr> {
1029    let (type_name, method) = name.split_once(METHOD_SEP)?;
1030    let declared = scope.symbols.iter().find_map(|(symbol, kind)| {
1031        if symbol.as_str() != type_name {
1032            return None;
1033        }
1034        match kind {
1035            SymbolKind::Struct(id) => structs.get(*id as usize).map(|s| &s.name),
1036            SymbolKind::Enum(id) => enums.get(*id as usize).map(|e| &e.name),
1037            SymbolKind::Fn(_) | SymbolKind::Template(_) => None,
1038        }
1039    })?;
1040    (declared != type_name).then(|| mangle_method(declared, method))
1041}
1042
1043/// The generic declaration `namespace::name` names, as an index into
1044/// `Generics::templates`.
1045///
1046/// A name written behind a module path resolves only to the declaration that
1047/// module makes, so two modules each declaring `Slot<T>` stay apart. A name
1048/// written on its own resolves in the scope it was written in, which holds the
1049/// file's own declarations and the ones its bare imports merged in; when that
1050/// scope has none it falls back to the last declaration of the name anywhere
1051/// in the program, which is where a name reaches a template registered while a
1052/// body was being compiled.
1053#[must_use]
1054pub fn find_template(
1055    namespace: &[SmolStr],
1056    name: &str,
1057    scope: &Namespace,
1058    generics: &Generics,
1059) -> Option<usize> {
1060    scope.find_template(namespace, name).or_else(|| {
1061        namespace
1062            .is_empty()
1063            .then(|| generics.last_template_named(name))
1064            .flatten()
1065    })
1066}
1067
1068/// Resolves `base<args>` to an ordinary struct or enum, registering it the
1069/// first time it is asked for.
1070///
1071/// Past this point nothing generic is left: the instantiation is a concrete
1072/// type with concrete field types, and every later stage (field access, method
1073/// dispatch, the artifact codec, the VM) treats it like any other.
1074pub fn instantiate(
1075    namespace: &[SmolStr],
1076    base: &str,
1077    args: &[DataType],
1078    span: Span,
1079    ctx: &mut TypeCtx<'_>,
1080) -> DataType {
1081    let Some(template_idx) = find_template(namespace, base, ctx.scope(), ctx.generics) else {
1082        if ctx
1083            .scope()
1084            .find_struct(namespace, base, span, ctx.file_idx, ctx.sources)
1085            .is_some()
1086            || ctx.scope().find_enum(namespace, base).is_some()
1087        {
1088            error_type_args_on_plain_type(span, ctx.file_idx, base, ctx.sources);
1089        }
1090        if !namespace.is_empty() {
1091            error_unknown_type_with_namespace(
1092                span,
1093                ctx.file_idx,
1094                base,
1095                ctx.sources,
1096                ctx.scope(),
1097                namespace,
1098            );
1099        }
1100        error_unknown_type(span, ctx.file_idx, base, ctx.sources, ctx.scope());
1101    };
1102    // Another module declaring the same name makes the two separate types, and
1103    // the name has to say so; see `render_instantiation`.
1104    let declarers: Vec<u16> = ctx
1105        .generics
1106        .templates
1107        .iter()
1108        .filter(|t| t.name == base)
1109        .map(|t| t.file_idx)
1110        .collect();
1111    let qualifier = (declarers.len() > 1).then(|| {
1112        module_qualifier(
1113            ctx.generics.templates[template_idx].file_idx,
1114            &declarers,
1115            ctx.sources,
1116        )
1117    });
1118    let name = render_instantiation(qualifier.as_deref(), base, args, ctx.structs, ctx.enums);
1119    if let Some(existing) = ctx
1120        .generics
1121        .instantiations
1122        .iter()
1123        .find(|i| i.template == template_idx && i.name == name)
1124    {
1125        return existing.instantiated.clone();
1126    }
1127    if ctx.generics.templates[template_idx].params.len() != args.len() {
1128        error_type_arg_count(
1129            span,
1130            ctx.file_idx,
1131            base,
1132            ctx.generics.templates[template_idx].params.len(),
1133            args.len(),
1134            ctx.sources,
1135        );
1136    }
1137    if ctx.generics.depth >= MAX_INSTANTIATION_DEPTH {
1138        error_instantiation_depth(span, ctx.file_idx, base, ctx.sources);
1139    }
1140
1141    let template_file = ctx.generics.templates[template_idx].file_idx;
1142    let frame: Box<[(SmolStr, DataType)]> = ctx.generics.templates[template_idx]
1143        .params
1144        .iter()
1145        .cloned()
1146        .zip(args.iter().cloned())
1147        .collect();
1148
1149    // The instantiation is registered and cached before its own field types are
1150    // resolved, so a type whose fields name it resolves to the type being built
1151    // instead of instantiating it again.
1152    let is_struct = matches!(
1153        ctx.generics.templates[template_idx].body,
1154        TemplateBody::Struct(_)
1155    );
1156    let instantiated = if is_struct {
1157        let id = ctx.structs.len() as u16;
1158        ctx.structs.push(Struct {
1159            name: name.clone(),
1160            fields: Box::from([]),
1161            id,
1162            name_span: span,
1163        });
1164        let defaults = ctx.generics.templates[template_idx].defaults.clone();
1165        ctx.generics
1166            .set_struct_defaults(id, template_file, defaults);
1167        DataType::Struct(id)
1168    } else {
1169        let id = ctx.enums.len() as u16;
1170        ctx.enums.push(EnumType {
1171            name: name.clone(),
1172            variants: Box::from([]),
1173            id,
1174            name_span: span,
1175        });
1176        DataType::Enum(id)
1177    };
1178    ctx.generics.instantiations.push(Instantiation {
1179        template: template_idx,
1180        name: name.clone(),
1181        instantiated: instantiated.clone(),
1182        args: args.into(),
1183    });
1184
1185    let body = ctx.generics.templates[template_idx].body.clone();
1186    ctx.generics.depth += 1;
1187    ctx.generics.push_bindings(frame.clone());
1188    {
1189        let mut inner = ctx.reborrow(template_file);
1190        match body {
1191            TemplateBody::Struct(fields) => {
1192                let resolved = fields
1193                    .iter()
1194                    .map(|(field_name, field_type, field_span)| {
1195                        (
1196                            field_name.clone(),
1197                            field_type.to_datatype(&mut inner),
1198                            *field_span,
1199                        )
1200                    })
1201                    .collect();
1202                if let DataType::Struct(id) = instantiated {
1203                    inner.structs[id as usize].fields = resolved;
1204                }
1205            }
1206            TemplateBody::Enum(variants) => {
1207                let resolved = variants
1208                    .iter()
1209                    .map(|(variant_name, payload, name_span)| EnumVariant {
1210                        name: variant_name.clone(),
1211                        payload: payload.iter().map(|t| t.to_datatype(&mut inner)).collect(),
1212                        name_span: *name_span,
1213                    })
1214                    .collect();
1215                if let DataType::Enum(id) = instantiated {
1216                    inner.enums[id as usize].variants = resolved;
1217                }
1218            }
1219        }
1220    }
1221    ctx.generics.pop_bindings();
1222
1223    lower_impls(template_idx, base, args, &name, &frame, ctx);
1224    ctx.generics.depth -= 1;
1225
1226    instantiated
1227}
1228
1229/// Lowers every `impl` block that applies to a freshly instantiated type.
1230///
1231/// A generic block (`impl Cell<T>`) binds its parameters from the
1232/// instantiation's arguments; a concrete one (`impl Cell<int>`) applies only
1233/// when the arguments match. Each method becomes an ordinary free function
1234/// named `Cell<int>#get`, exactly as a method on a plain type does.
1235fn lower_impls(
1236    template_idx: usize,
1237    base: &str,
1238    args: &[DataType],
1239    type_name: &SmolStr,
1240    type_frame: &[(SmolStr, DataType)],
1241    ctx: &mut TypeCtx<'_>,
1242) {
1243    let applicable: Vec<usize> = ctx
1244        .generics
1245        .impls
1246        .iter()
1247        .enumerate()
1248        .filter(|(_, block)| block.type_name == base && block.args.len() == args.len())
1249        .map(|(i, _)| i)
1250        .collect();
1251    for idx in applicable {
1252        let impl_file = ctx.generics.impls[idx].file_idx;
1253        // The header names a type in the scope of the file the block was
1254        // written in, so a block in one module never attaches to another
1255        // module's declaration of the same name.
1256        if find_template(&[], base, ctx.namespaces.get(impl_file), ctx.generics)
1257            != Some(template_idx)
1258        {
1259            continue;
1260        }
1261        let header = ctx.generics.impls[idx].args.clone();
1262        let mut frame: Vec<(SmolStr, DataType)> = Vec::with_capacity(header.len());
1263        let mut applies = true;
1264        for (header_arg, arg) in header.iter().zip(args) {
1265            match header_arg {
1266                // A bare name that is not a type of its own is a parameter the
1267                // header introduces, bound to whatever this instantiation
1268                // passes. Anything else is a concrete type the header pins, and
1269                // the block applies only when the argument is that type.
1270                TypeExpr::Identifier(pname, _) if is_type_parameter(pname, impl_file, ctx) => {
1271                    frame.push((pname.clone(), arg.clone()));
1272                }
1273                other => {
1274                    let mut inner = ctx.reborrow(impl_file);
1275                    inner.generics.push_bindings(Box::from(type_frame));
1276                    let pinned = other.to_datatype(&mut inner);
1277                    ctx.generics.pop_bindings();
1278                    if &pinned != arg {
1279                        applies = false;
1280                        break;
1281                    }
1282                }
1283            }
1284        }
1285        if !applies {
1286            continue;
1287        }
1288        let methods = ctx.generics.impls[idx].methods.clone();
1289        let bindings: Box<[(SmolStr, DataType)]> = Box::from(frame);
1290        for method in methods {
1291            lower_method(&method, type_name, &bindings, impl_file, ctx);
1292        }
1293    }
1294}
1295
1296/// Whether a name written as a type argument in an `impl` header introduces a
1297/// type parameter rather than naming a type.
1298fn is_type_parameter(name: &SmolStr, file_idx: u16, ctx: &TypeCtx<'_>) -> bool {
1299    if matches!(
1300        name.as_str(),
1301        "int" | "float" | "bool" | "string" | "null" | "any"
1302    ) {
1303        return false;
1304    }
1305    find_template(&[], name, ctx.namespaces.get(file_idx), ctx.generics).is_none()
1306        && !ctx
1307            .namespaces
1308            .get(file_idx)
1309            .symbols
1310            .iter()
1311            .any(|(symbol, kind)| {
1312                symbol == name && matches!(kind, SymbolKind::Struct(_) | SymbolKind::Enum(_))
1313            })
1314}
1315
1316/// The bare name of the type an `impl` block attaches to, with the module
1317/// qualifier and the type arguments taken off: `g::Cell<int>` reads `Cell`.
1318fn impl_base_name(type_name: &str) -> &str {
1319    let without_args = type_name.split('<').next().unwrap_or(type_name);
1320    without_args.rsplit("::").next().unwrap_or(without_args)
1321}
1322
1323/// The name an annotation is written with, for the comparison that keeps a
1324/// receiver's declared type the one its `impl` block names.
1325fn annotation_base_name(annotation: &TypeExpr) -> Option<&SmolStr> {
1326    match annotation {
1327        TypeExpr::Identifier(name, _) => Some(name),
1328        TypeExpr::NamespacedIdentifier(path, _) => path.last(),
1329        TypeExpr::Generic(generic) => Some(&generic.name),
1330        TypeExpr::Array(_) | TypeExpr::Map(_, _) | TypeExpr::Union(_) | TypeExpr::Fn(_) => None,
1331    }
1332}
1333
1334/// Checks a method named by an operator symbol where it is declared.
1335///
1336/// `mangled` carries both halves of the declaration, the type the `impl` block
1337/// names and the operator, so one call covers the whole rule: the built-in
1338/// types settle their own operators and take none, an operator takes exactly
1339/// the operands it has, and the first parameter is the receiver. A method
1340/// named with an identifier passes straight through.
1341pub fn check_operator_method(
1342    mangled: &str,
1343    args: &[(SmolStr, Option<TypeExpr>)],
1344    name_span: Span,
1345    file_idx: u16,
1346    sources: &[Source],
1347) {
1348    let Some((type_name, method)) = mangled.split_once(METHOD_SEP) else {
1349        return;
1350    };
1351    if !is_operator_method(method) {
1352        return;
1353    }
1354    let symbol = if method == UNARY_MINUS_METHOD {
1355        "-"
1356    } else {
1357        method
1358    };
1359    if matches!(
1360        type_name,
1361        "int" | "float" | "string" | "bool" | "list" | "map"
1362    ) {
1363        cold_path();
1364        error_operator_method(
1365            "Operator on a built-in type",
1366            &format!("{type_name} does not take a {symbol} method"),
1367            "What an operator means on a built-in type is part of the language. Put the value in a struct of your own and define the operator there.",
1368            "operator_method_on_builtin",
1369            name_span,
1370            file_idx,
1371            sources,
1372        );
1373    }
1374    let wanted = usize::from(!is_unary_operator_method(method)) + 1;
1375    if args.len() != wanted {
1376        cold_path();
1377        error_operator_method(
1378            "Operator method takes the wrong number of parameters",
1379            &format!(
1380                "{symbol} on {type_name} is declared with {} parameter{}",
1381                args.len(),
1382                if args.len() == 1 { "" } else { "s" }
1383            ),
1384            if symbol == "-" {
1385                "- takes the receiver and the value to subtract, or the receiver alone to negate it."
1386            } else if wanted == 1 {
1387                "A unary operator takes the receiver and nothing else."
1388            } else {
1389                "A binary operator takes the receiver and the other operand."
1390            },
1391            "operator_method_arity",
1392            name_span,
1393            file_idx,
1394            sources,
1395        );
1396    }
1397    if let Some((_, Some(annotation))) = args.first() {
1398        let base = impl_base_name(type_name);
1399        if annotation_base_name(annotation).is_none_or(|written| written != base) {
1400            cold_path();
1401            error_operator_method(
1402                "Operator method receives another type",
1403                &format!("The first parameter of {symbol} is not a {base}"),
1404                "The first parameter of a method is the receiver, and its type is the one the impl block names. Leave it un-annotated or annotate it with that type.",
1405                "operator_method_receiver",
1406                name_span,
1407                file_idx,
1408                sources,
1409            );
1410        }
1411    }
1412}
1413
1414/// The name a struct's own default is declared under in its `impl` block.
1415pub const STRUCT_DEFAULT_METHOD: &str = "default";
1416
1417/// The struct whose `impl` block declares the function named `fn_name` as its
1418/// `default`, when it names one.
1419#[must_use]
1420pub fn struct_of_default_fn(fn_name: &str, structs: &[Struct]) -> Option<u16> {
1421    let (type_name, method) = fn_name.split_once(METHOD_SEP)?;
1422    if method != STRUCT_DEFAULT_METHOD {
1423        return None;
1424    }
1425    structs.iter().rfind(|s| s.name == type_name).map(|s| s.id)
1426}
1427
1428/// Checks the `default` function an `impl` block on struct `struct_id`
1429/// declares.
1430///
1431/// Every path that builds the struct's default calls it with nothing and takes
1432/// the struct from what it hands back, so it declares no parameters and
1433/// returns the struct.
1434///
1435/// `returns` is the type it hands back and the span that says so, when that is
1436/// known: the `-> Type` annotation where the function is declared, or what its
1437/// body returns once a default is built from it.
1438pub fn check_struct_default_fn(
1439    func: &Function,
1440    struct_id: u16,
1441    returns: Option<(&DataType, Span)>,
1442    sources: &[Source],
1443    types: TypeNames<'_>,
1444) {
1445    let struct_type = DataType::Struct(struct_id);
1446    let struct_name = types.of(&struct_type).to_string();
1447    if !func.args.is_empty() {
1448        cold_path();
1449        error_struct_default_signature(
1450            "Default function takes parameters",
1451            &format!(
1452                "default in impl {struct_name} is declared with {} parameter{}",
1453                func.args.len(),
1454                if func.args.len() == 1 { "" } else { "s" }
1455            ),
1456            &format!(
1457                "{struct_name}::default() and {struct_name} {{ .. }} call it with nothing, so it takes no parameters. A method that takes the value needs another name."
1458            ),
1459            func.name_span,
1460            func.src_file,
1461            sources,
1462        );
1463    }
1464    if let Some((returned, span)) = returns
1465        && *returned != struct_type
1466    {
1467        cold_path();
1468        error_struct_default_signature(
1469            "Default function returns another type",
1470            &format!(
1471                "default in impl {struct_name} returns {}, not {struct_name}",
1472                types.of(returned)
1473            ),
1474            &format!(
1475                "It builds the default of {struct_name}, so its return type is {struct_name}."
1476            ),
1477            span,
1478            func.src_file,
1479            sources,
1480        );
1481    }
1482}
1483
1484/// Registers one method of an instantiated `impl` block as the mangled free
1485/// function its call sites resolve to.
1486fn lower_method(
1487    method: &Expr,
1488    type_name: &SmolStr,
1489    bindings: &[(SmolStr, DataType)],
1490    file_idx: u16,
1491    ctx: &mut TypeCtx<'_>,
1492) {
1493    let Expr::FunctionDecl(method_name, args, code, name_span, return_type, params) = method else {
1494        return;
1495    };
1496    let mangled = mangle_method(type_name, method_name);
1497    check_operator_method(&mangled, args, *name_span, file_idx, ctx.sources);
1498    if let Some(existing) = ctx.fns.iter().find(|f| f.name == mangled) {
1499        crate::compiler::compiler_errors::error_function_already_defined(
1500            existing,
1501            *name_span,
1502            file_idx,
1503            ctx.sources,
1504        );
1505    }
1506    let mut inner = ctx.reborrow(file_idx);
1507    inner.generics.push_bindings(Box::from(bindings));
1508    let resolved_args: Box<[(SmolStr, Option<DataType>)]> = args
1509        .iter()
1510        .map(|(arg_name, arg_type)| {
1511            (
1512                arg_name.clone(),
1513                arg_type
1514                    .as_ref()
1515                    .filter(|t| !t.mentions_any(params))
1516                    .map(|t| t.to_datatype(&mut inner)),
1517            )
1518        })
1519        .collect();
1520    let resolved_return = return_type
1521        .as_deref()
1522        .filter(|(t, _)| !t.mentions_any(params))
1523        .map(|(t, t_span)| (t.to_datatype(&mut inner), *t_span));
1524    ctx.generics.pop_bindings();
1525
1526    let mut callees = Vec::new();
1527    collect_direct_fn_calls(code, Some(type_name.as_str()), &mut callees);
1528    ctx.fns.push(Function {
1529        name: mangled,
1530        args: resolved_args,
1531        code: Rc::clone(code),
1532        impls: Vec::new(),
1533        is_recursive: None,
1534        returns_null: check_if_returns_void(code),
1535        src_file: file_idx,
1536        return_type_cache: Vec::new(),
1537        direct_calls: callees.into_boxed_slice(),
1538        name_span: *name_span,
1539        return_type: resolved_return,
1540        captures: Box::from([]),
1541        generics: Some(Box::new(FnGenerics {
1542            params: params.clone(),
1543            arg_types: args.iter().map(|(_, t)| t.clone()).collect(),
1544            return_type: return_type.clone(),
1545            bindings: Box::from(bindings),
1546            file_idx,
1547        })),
1548        entry_register: None,
1549    });
1550    let func = &ctx.fns[ctx.fns.len() - 1];
1551    if let Some(struct_id) = struct_of_default_fn(&func.name, ctx.structs) {
1552        check_struct_default_fn(
1553            func,
1554            struct_id,
1555            func.return_type.as_ref().map(|(t, span)| (t, *span)),
1556            ctx.sources,
1557            TypeNames {
1558                structs: ctx.structs,
1559                enums: ctx.enums,
1560            },
1561        );
1562    }
1563}
1564
1565/// Resolves the struct a literal names, instantiating the generic type when the
1566/// literal carries type arguments.
1567///
1568/// A literal of a generic type written without them takes each type parameter
1569/// from the value in the field declared with that parameter as its type, so
1570/// `Cell{ value: 3 }` is a `Cell<int>`. A parameter no field pins is `any`.
1571pub fn struct_literal_id(
1572    namespace: &[SmolStr],
1573    fields: &[(SmolStr, Expr, Span, Span)],
1574    type_args: &[TypeExpr],
1575    span: Span,
1576    v: &mut Vec<Variable>,
1577    ctx: Ctx,
1578    state: &mut State<'_>,
1579) -> u16 {
1580    let name = namespace[namespace.len() - 1].clone();
1581    let path = &namespace[..namespace.len() - 1];
1582    if !type_args.is_empty() {
1583        let args = resolve_type_args(type_args, ctx, state);
1584        return instantiated_struct_id(path, &name, &args, span, ctx, state);
1585    }
1586    if let Some(template_idx) =
1587        find_template(path, &name, state.scope(ctx.file_idx), state.generics)
1588    {
1589        let param_fields = state.generics.param_fields(template_idx);
1590        let mut args: Vec<DataType> = Vec::with_capacity(param_fields.len());
1591        for field_name in param_fields {
1592            args.push(
1593                field_name
1594                    .and_then(|f| fields.iter().find(|(n, _, _, _)| *n == f))
1595                    .map_or(DataType::Unknown, |(_, value, _, _)| {
1596                        value.infer_type(v, ctx, state)
1597                    }),
1598            );
1599        }
1600        return instantiated_struct_id(path, &name, &args, span, ctx, state);
1601    }
1602    state
1603        .scope(ctx.file_idx)
1604        .find_struct(path, &name, span, ctx.file_idx, state.sources)
1605        .unwrap_or_else(|| {
1606            error_unknown_struct(
1607                &name,
1608                span,
1609                state.scope(ctx.file_idx),
1610                state.sources,
1611                ctx.file_idx,
1612            );
1613        }) as u16
1614}
1615
1616/// Resolves the struct a literal names.
1617///
1618/// This is [`struct_literal_id`] with one more source for a generic type's
1619/// arguments: a literal that writes none and takes its other fields from a
1620/// `..base` of that type is the base's instantiation.
1621pub fn literal_struct_id(
1622    namespace: &[SmolStr],
1623    fields: &[(SmolStr, Expr, Span, Span)],
1624    type_args: &[TypeExpr],
1625    base: Option<&Expr>,
1626    span: Span,
1627    v: &mut Vec<Variable>,
1628    ctx: Ctx,
1629    state: &mut State<'_>,
1630) -> u16 {
1631    if type_args.is_empty()
1632        && let Some(base) = base
1633        && let Some((name, path)) = namespace.split_last()
1634        && let Some(template_idx) =
1635            find_template(path, name, state.scope(ctx.file_idx), state.generics)
1636        && let DataType::Struct(id) = base.infer_type(v, ctx, state)
1637        && state
1638            .generics
1639            .instantiation_of(&DataType::Struct(id))
1640            .is_some_and(|(template, _)| template == template_idx)
1641    {
1642        return id;
1643    }
1644    struct_literal_id(namespace, fields, type_args, span, v, ctx, state)
1645}
1646
1647/// The struct `S::default()` names.
1648///
1649/// `path` is a struct (or a generic struct, instantiated at `type_args`)
1650/// followed by `default`, and the call passes nothing. `None` leaves the path
1651/// to the function lookups.
1652pub fn struct_default_target(
1653    path: &[SmolStr],
1654    args: &[Expr],
1655    type_args: &[TypeExpr],
1656    span: Span,
1657    ctx: Ctx,
1658    state: &mut State<'_>,
1659) -> Option<u16> {
1660    let [module @ .., type_name, method] = path else {
1661        return None;
1662    };
1663    if method != "default" || !args.is_empty() {
1664        return None;
1665    }
1666    let scope = state.scope(ctx.file_idx);
1667    let is_struct = scope.resolve(module).is_some_and(|ns| {
1668        ns.symbols
1669            .iter()
1670            .any(|(name, kind)| name == type_name && matches!(kind, SymbolKind::Struct(_)))
1671    });
1672    let is_template = find_template(module, type_name, scope, state.generics)
1673        .is_some_and(|idx| matches!(state.generics.templates[idx].body, TemplateBody::Struct(_)));
1674    if !is_struct && !is_template {
1675        return None;
1676    }
1677    let mut type_path = module.to_vec();
1678    type_path.push(type_name.clone());
1679    Some(struct_literal_id(
1680        &type_path,
1681        &[],
1682        type_args,
1683        span,
1684        &mut Vec::new(),
1685        ctx,
1686        state,
1687    ))
1688}
1689
1690/// The type a path call names in front of its function: the second-to-last
1691/// segment of `Point::origin()` or `Set<int>::new()`, behind whatever module
1692/// path precedes it. A generic type is instantiated at `type_args`, or at
1693/// `any` for each parameter when the call writes none. `None` when the
1694/// segment names no struct or enum, or names a plain one while the call
1695/// carries type arguments, which then belong to a generic function.
1696fn path_call_type(
1697    module: &[SmolStr],
1698    type_name: &SmolStr,
1699    type_args: &[TypeExpr],
1700    span: Span,
1701    ctx: Ctx,
1702    state: &mut State<'_>,
1703) -> Option<DataType> {
1704    let scope = state.scope(ctx.file_idx);
1705    if let Some(template) = find_template(module, type_name, scope, state.generics) {
1706        let args = if type_args.is_empty() {
1707            vec![DataType::Unknown; state.generics.params(template).len()]
1708        } else {
1709            resolve_type_args(type_args, ctx, state)
1710        };
1711        return Some(instantiate(
1712            module,
1713            type_name,
1714            &args,
1715            span,
1716            &mut state.type_ctx(ctx.file_idx),
1717        ));
1718    }
1719    if !type_args.is_empty() {
1720        return None;
1721    }
1722    scope
1723        .resolve(module)?
1724        .symbols
1725        .iter()
1726        .rev()
1727        .find_map(|(name, kind)| match kind {
1728            SymbolKind::Struct(id) if name == type_name => Some(DataType::Struct(*id)),
1729            SymbolKind::Enum(id) if name == type_name => Some(DataType::Enum(*id)),
1730            _ => None,
1731        })
1732}
1733
1734/// The `impl` function a call written by its path names.
1735///
1736/// `Point::origin()`, `Set<int>::new()` and `shapes::Point::origin()` are such
1737/// calls: `path` is a struct or an enum followed by the name of a function its
1738/// `impl` block declares, and the answer is that function's id. `None` leaves
1739/// the path to the other lookups: a variant of the enum, a module function, a
1740/// generic function.
1741///
1742/// A function declared with no parameters is the only one a path reaches. One
1743/// that declares a receiver is a method, and a path call to it is reported
1744/// here with the dot call it needs.
1745pub fn path_call_target(
1746    path: &[SmolStr],
1747    type_args: &[TypeExpr],
1748    span: Span,
1749    ctx: Ctx,
1750    state: &mut State<'_>,
1751) -> Option<usize> {
1752    let [module @ .., type_name, method] = path else {
1753        return None;
1754    };
1755    let ty = path_call_type(module, type_name, type_args, span, ctx, state)?;
1756    let registered = match ty {
1757        DataType::Struct(id) => state.structs[id as usize].name.clone(),
1758        DataType::Enum(id) => {
1759            let e = &state.enums[id as usize];
1760            if e.variants.iter().any(|variant| variant.name == *method) {
1761                return None;
1762            }
1763            e.name.clone()
1764        }
1765        _ => return None,
1766    };
1767    let mangled = mangle_method(&registered, method);
1768    let fn_id = state.fns.iter().position(|f| f.name == mangled)?;
1769    if !state.fns[fn_id].args.is_empty() {
1770        cold_path();
1771        crate::compiler::compiler_errors::error_path_call_with_receiver(
1772            method,
1773            &registered,
1774            span,
1775            (state.fns[fn_id].name_span, state.fns[fn_id].src_file),
1776            ctx.file_idx,
1777            state.sources,
1778        );
1779    }
1780    Some(fn_id)
1781}
1782
1783fn instantiated_struct_id(
1784    namespace: &[SmolStr],
1785    name: &SmolStr,
1786    args: &[DataType],
1787    span: Span,
1788    ctx: Ctx,
1789    state: &mut State<'_>,
1790) -> u16 {
1791    match instantiate(
1792        namespace,
1793        name,
1794        args,
1795        span,
1796        &mut state.type_ctx(ctx.file_idx),
1797    ) {
1798        DataType::Struct(id) => id,
1799        _ => error_unknown_struct(
1800            name,
1801            span,
1802            state.scope(ctx.file_idx),
1803            state.sources,
1804            ctx.file_idx,
1805        ),
1806    }
1807}
1808
1809/// Resolves each type argument of a call, struct literal or variant path in the
1810/// scope it was written in.
1811#[must_use]
1812pub fn resolve_type_args(type_args: &[TypeExpr], ctx: Ctx, state: &mut State<'_>) -> Vec<DataType> {
1813    type_args
1814        .iter()
1815        .map(|t| t.to_datatype(&mut state.type_ctx(ctx.file_idx)))
1816        .collect()
1817}
1818
1819/// Whether a call path written with type arguments names an enum variant
1820/// rather than a generic function.
1821///
1822/// The list is written on the segment before the variant
1823/// (`Slot<int>::Filled`, `g::Slot<int>::Filled`) and on the last segment for a
1824/// function (`first<int>`, `m::first<int>`), so whether that earlier segment
1825/// names a type is what tells the two apart. A non-generic enum counts too, so
1826/// `Color::Red<int>(1)` still reports type arguments on a plain type instead of
1827/// looking for a function in a namespace called `Color`.
1828#[must_use]
1829pub fn type_args_name_a_variant(path: &[SmolStr], ctx: Ctx, state: &State<'_>) -> bool {
1830    let Some(base_idx) = path.len().checked_sub(2) else {
1831        return false;
1832    };
1833    let base = &path[base_idx];
1834    find_template(
1835        &path[..base_idx],
1836        base,
1837        state.scope(ctx.file_idx),
1838        state.generics,
1839    )
1840    .is_some()
1841        || state
1842            .scope(ctx.file_idx)
1843            .find_enum(&path[..base_idx], base)
1844            .is_some()
1845}
1846
1847/// Resolves a variant constructor to the enum it names and the index of the
1848/// variant, instantiating a generic enum at the types its payload names.
1849///
1850/// A plain enum resolves by name, the way it always has. A generic enum has no
1851/// registered type until something names one, so the constructor makes it: the
1852/// arguments bind the parameters the variant declares, and a parameter the
1853/// payload does not mention stands for `any`. `Ok(2)` is therefore a
1854/// `Result<int, any>` and `None` on its own an `Option<any>`, and
1855/// [`param_type_matches`] is what lets those go where a fully named
1856/// instantiation is expected.
1857///
1858/// Returns `None` when no generic enum declares a variant of that name, which
1859/// is what leaves plain enums and ordinary calls to the paths that follow.
1860/// The enum and variant a constructor names, at the types its payload is
1861/// given: a generic enum instantiated at what the payload binds, or a plain
1862/// enum resolved by name.
1863pub fn variant_constructor_at(
1864    path: &[SmolStr],
1865    arg_types: &[DataType],
1866    span: Span,
1867    ctx: Ctx,
1868    state: &mut State<'_>,
1869) -> Option<(u16, u16)> {
1870    // A program's own enum declaring a bare variant the prelude also declares
1871    // (`Some`) is the one the name reaches.
1872    if let [variant] = path
1873        && state.generics.only_the_prelude_declares(variant)
1874        && let Some(own) = state.enums.iter().find_map(|e| {
1875            let idx = e.variants.iter().position(|vt| vt.name == *variant)?;
1876            state
1877                .generics
1878                .instantiation_of(&DataType::Enum(e.id))
1879                .is_none()
1880                .then_some((e.id, idx as u16))
1881        })
1882    {
1883        return Some(own);
1884    }
1885    resolve_variant_constructor(path, arg_types, span, ctx, state)
1886        .or_else(|| resolve_enum_variant(path, ctx.file_idx, state))
1887}
1888
1889pub fn resolve_variant_constructor(
1890    path: &[SmolStr],
1891    arg_types: &[DataType],
1892    span: Span,
1893    ctx: Ctx,
1894    state: &mut State<'_>,
1895) -> Option<(u16, u16)> {
1896    let variant = path.last()?.clone();
1897    let (namespace, template) = if path.len() >= 2 {
1898        let namespace = &path[..path.len() - 2];
1899        let base = &path[path.len() - 2];
1900        let template = find_template(namespace, base, state.scope(ctx.file_idx), state.generics)?;
1901        (namespace, template)
1902    } else {
1903        (
1904            &path[..0],
1905            state.generics.enum_template_with_variant(&variant)?,
1906        )
1907    };
1908    let params: Vec<SmolStr> = state.generics.params(template).to_vec();
1909    let payload: Vec<TypeExpr> = state.generics.variant_payload(template, &variant)?.to_vec();
1910    let mut bound: Vec<Option<DataType>> = vec![None; params.len()];
1911    for (declared, found) in payload.iter().zip(arg_types) {
1912        bind_params_from_payload(declared, found, &params, &mut bound);
1913    }
1914    let args: Vec<DataType> = bound
1915        .into_iter()
1916        .map(|b| b.unwrap_or(DataType::Unknown))
1917        .collect();
1918    let base = state.generics.template_name(template).clone();
1919    let namespace: Box<[SmolStr]> = namespace.into();
1920    let DataType::Enum(enum_id) = instantiate(
1921        &namespace,
1922        &base,
1923        &args,
1924        span,
1925        &mut state.type_ctx(ctx.file_idx),
1926    ) else {
1927        return None;
1928    };
1929    let variant_idx = state.enums[enum_id as usize]
1930        .variants
1931        .iter()
1932        .position(|vt| vt.name == variant)? as u16;
1933    Some((enum_id, variant_idx))
1934}
1935
1936/// Binds the type parameters a variant's declared payload mentions to the types
1937/// the constructor was handed. A parameter the payload does not mention, and one
1938/// whose argument carries no type of its own, is left for the caller to fill
1939/// with `any`.
1940fn bind_params_from_payload(
1941    declared: &TypeExpr,
1942    found: &DataType,
1943    params: &[SmolStr],
1944    bound: &mut [Option<DataType>],
1945) {
1946    match declared {
1947        TypeExpr::Identifier(name, _) => {
1948            if *found != DataType::Unknown
1949                && let Some(i) = params.iter().position(|p| p == name)
1950                && bound[i].is_none()
1951            {
1952                bound[i] = Some(found.clone());
1953            }
1954        }
1955        TypeExpr::Array(inner) => {
1956            if let DataType::Array(Some(element)) = found {
1957                bind_params_from_payload(inner, element, params, bound);
1958            }
1959        }
1960        TypeExpr::Map(key, value) => {
1961            if let DataType::Map(entry) = found {
1962                if let Some(t) = &entry.0 {
1963                    bind_params_from_payload(key, t, params, bound);
1964                }
1965                if let Some(t) = &entry.1 {
1966                    bind_params_from_payload(value, t, params, bound);
1967                }
1968            }
1969        }
1970        _ => {}
1971    }
1972}
1973
1974/// Resolves a variant of a generic enum named with its arguments
1975/// (`Slot<int>::Empty`) to the instantiated enum and the variant's index.
1976pub fn resolve_generic_variant(
1977    path: &[SmolStr],
1978    type_args: &[TypeExpr],
1979    span: Span,
1980    ctx: Ctx,
1981    state: &mut State<'_>,
1982) -> (u16, u16) {
1983    let variant = path[path.len() - 1].clone();
1984    let base = path[path.len() - 2].clone();
1985    let namespace = &path[..path.len() - 2];
1986    let args = resolve_type_args(type_args, ctx, state);
1987    let DataType::Enum(enum_id) = instantiate(
1988        namespace,
1989        &base,
1990        &args,
1991        span,
1992        &mut state.type_ctx(ctx.file_idx),
1993    ) else {
1994        crate::compiler::compiler_errors::error_enum(
1995            "Unknown enum",
1996            &format!("{base} does not name an enum"),
1997            span,
1998            ctx.file_idx,
1999            state.sources,
2000        );
2001    };
2002    let Some(variant_idx) = state.enums[enum_id as usize]
2003        .variants
2004        .iter()
2005        .position(|vt| vt.name == variant)
2006    else {
2007        crate::compiler::compiler_errors::error_enum(
2008            "Unknown enum variant",
2009            &format!("{} does not name an enum variant", path.join("::")),
2010            span,
2011            ctx.file_idx,
2012            state.sources,
2013        );
2014    };
2015    (enum_id, variant_idx as u16)
2016}
2017
2018/// Resolves a call written with type arguments to the function it names and
2019/// the arguments bound to its type parameters.
2020///
2021/// `namespace` is the path in front of the name, empty for a call the file
2022/// writes unqualified (`first<int>(nums)`) and the module alias for one it
2023/// reaches through an import (`m::first<int>(nums)`).
2024pub fn resolve_generic_call(
2025    namespace: &[SmolStr],
2026    fn_name: &SmolStr,
2027    type_args: &[TypeExpr],
2028    span: Span,
2029    ctx: Ctx,
2030    state: &mut State<'_>,
2031) -> (usize, Vec<DataType>) {
2032    let Some(fn_id) = state.scope(ctx.file_idx).find_function(namespace, fn_name) else {
2033        if !namespace.is_empty() {
2034            error_unknown_function_in_namespace(fn_name, namespace, span, ctx.file_idx, state);
2035        }
2036        error_unknown_function(
2037            fn_name,
2038            span,
2039            state.scope(ctx.file_idx),
2040            ctx.file_idx,
2041            state.sources,
2042        );
2043    };
2044    let args = resolve_call_type_args(fn_id, fn_name, type_args, span, ctx, state);
2045    (fn_id, args)
2046}
2047
2048/// Checks the type arguments a call is written with against the parameters the
2049/// function it resolves to declares, and resolves them to types.
2050///
2051/// `name` is the spelling to report against, which for a method is the method
2052/// name rather than the mangled symbol the call reaches.
2053pub fn resolve_call_type_args(
2054    fn_id: usize,
2055    name: &str,
2056    type_args: &[TypeExpr],
2057    span: Span,
2058    ctx: Ctx,
2059    state: &mut State<'_>,
2060) -> Vec<DataType> {
2061    let params_len = state.fns[fn_id]
2062        .generics
2063        .as_ref()
2064        .map_or(0, |g| g.params.len());
2065    if params_len == 0 {
2066        error_type_args_on_plain_function(span, ctx.file_idx, name, state.sources);
2067    }
2068    if params_len != type_args.len() {
2069        error_type_arg_count(
2070            span,
2071            ctx.file_idx,
2072            name,
2073            params_len,
2074            type_args.len(),
2075            state.sources,
2076        );
2077    }
2078    resolve_type_args(type_args, ctx, state)
2079}
2080
2081/// The return type a `host` or `dylib` block declares for a namespaced call,
2082/// or `None` when the path names no declared function.
2083///
2084/// The path is resolved whole, the way the call is compiled: the leading
2085/// element selects the block and the last element the function in it. A `host`
2086/// declaration wins over a `dylib` one of the same name, matching the order the
2087/// two are bound in.
2088fn declared_return_type(namespace: &[SmolStr], state: &State<'_>) -> Option<DataType> {
2089    let fn_name = namespace.last()?;
2090    let block = &namespace[0];
2091    let declared = |is_host: bool| {
2092        state
2093            .dyn_libs
2094            .iter()
2095            .find(|lib| lib.is_host == is_host && lib.name == *block)
2096            .and_then(|lib| lib.fns.iter().find(|f| f.name == *fn_name))
2097            .map(|f| f.return_type.clone())
2098    };
2099    declared(true).or_else(|| declared(false))
2100}
2101
2102/// The type an unqualified built-in call yields, or `None` when no built-in
2103/// takes that name.
2104///
2105/// Keep in step with the match in `builtin_functions`, which lowers these
2106/// calls: a name that lowers there and is missing here is reported as an
2107/// unknown function, and a name here that does not lower there types a call
2108/// that never reaches a built-in. `in_std` says the call is written in a
2109/// standard library module, the only place the [`std_primitive_return_type`]
2110/// names resolve.
2111fn builtin_fn_return_type(name: &str, in_std: bool) -> Option<DataType> {
2112    if in_std && let Some(t) = std_primitive_return_type(name) {
2113        return Some(t);
2114    }
2115    Some(match name {
2116        "print" | "exit" | "throw" => DataType::Null,
2117        "type" | "string" | "input" => DataType::String,
2118        "float" => DataType::Float,
2119        "int" | "the_answer" => DataType::Int,
2120        "bool" | "[int text]" | "[float text]" => DataType::Bool,
2121        "range" => DataType::Array(Some(Box::from(DataType::Int))),
2122        "argv" => DataType::Array(Some(Box::from(DataType::String))),
2123        _ => return None,
2124    })
2125}
2126
2127/// The type a native primitive of the standard library yields, or `None` when
2128/// none takes that name.
2129///
2130/// These are what `std/json` and `std/fs` are written on; only a standard
2131/// library module reaches them, so a program has one spelling of each, the
2132/// module's. Keep in step with `builtin_functions`.
2133#[must_use]
2134pub fn std_primitive_return_type(name: &str) -> Option<DataType> {
2135    Some(match name {
2136        "json_stringify" | "fs_read" => DataType::String,
2137        // json::parse yields a fully dynamic value.
2138        "json_parse" => DataType::Unknown,
2139        "fs_exists" => DataType::Bool,
2140        "fs_write" | "fs_append" | "fs_delete" | "fs_delete_dir" => DataType::Null,
2141        _ => return None,
2142    })
2143}
2144
2145/// Renders a [`DataType`] the way a program spells it.
2146///
2147/// This is what the `type` builtin hands back, so its output is a string the
2148/// program can read, and every part of it is written the way the same type
2149/// would be written in source: `any` for the dynamic slot, a struct or an enum
2150/// by the name it was declared under, and a function as `fn(int) -> int`.
2151///
2152/// Names are resolved against the compiler `State` by `Struct`/`Fn` id. The
2153/// plain `Display` impl (in `candela-vm`) has no `State`, so it renders those
2154/// variants opaquely; a diagnostic names them through [`TypeNames`] instead.
2155#[must_use]
2156pub fn format_detailed(t: &DataType, state: &State<'_>) -> SmolStr {
2157    match t {
2158        DataType::Float => SmolStr::new_static("float"),
2159        DataType::Int => SmolStr::new_static("int"),
2160        DataType::Bool => SmolStr::new_static("bool"),
2161        DataType::String => SmolStr::new_static("string"),
2162        DataType::Array(array_type) => match array_type {
2163            Some(array_type) => {
2164                format_args!("{}[]", format_detailed(array_type, state)).to_smolstr()
2165            }
2166            None => SmolStr::new_static("any[]"),
2167        },
2168        DataType::Null => SmolStr::new_static("null"),
2169        DataType::Unknown => SmolStr::new_static("any"),
2170        // A position that says what it holds is written the way it was
2171        // declared. One whose functions the compiler collected names no
2172        // signature, since the functions in it need not agree on one.
2173        DataType::FnValue(fn_type) => match &fn_type.sig {
2174            Some((params, returned)) => format_signature(params, returned, state),
2175            None => SmolStr::new_static("function"),
2176        },
2177        DataType::Union(types) => format_args!(
2178            "{}",
2179            types
2180                .into_iter()
2181                .map(|x| format_detailed(x, state))
2182                .collect::<Vec<SmolStr>>()
2183                .join("|")
2184        )
2185        .to_smolstr(),
2186        DataType::Struct(s) => state.structs[*s as usize].name.clone(),
2187        DataType::Enum(e) => state.enums[*e as usize].name.clone(),
2188        // Both halves are rendered through this same function, so a map of a
2189        // user type names that type the way a list of it does. Reaching for
2190        // `Display` here is what made `type({"a": Value::Num(1)})` answer
2191        // `{string: enum}`.
2192        DataType::Map(m) => format_args!(
2193            "{{{}: {}}}",
2194            m.0.as_ref()
2195                .map_or_else(|| SmolStr::new_static("any"), |k| format_detailed(k, state)),
2196            m.1.as_ref().map_or_else(
2197                || SmolStr::new_static("any"),
2198                |val| format_detailed(val, state)
2199            )
2200        )
2201        .to_smolstr(),
2202        // A declaration is what a function's type says: a parameter with no
2203        // annotation takes `any`, and so does a return the declaration left to
2204        // the body. A function that hands nothing back is written without the
2205        // arrow, the way `fn()` is written in source.
2206        DataType::Fn(id) => {
2207            let f = &state.fns[*id as usize];
2208            let params: Box<[DataType]> = f
2209                .args
2210                .iter()
2211                .map(|(_, declared)| declared.clone().unwrap_or(DataType::Unknown))
2212                .collect();
2213            let returned = match &f.return_type {
2214                Some((declared, _)) => declared.clone(),
2215                None if f.returns_null => DataType::Null,
2216                None => DataType::Unknown,
2217            };
2218            format_signature(&params, &returned, state)
2219        }
2220    }
2221}
2222
2223/// A function type written the way a declaration writes it: `fn(int) -> int`,
2224/// and `fn()` where it hands nothing back.
2225fn format_signature(params: &[DataType], returned: &DataType, state: &State<'_>) -> SmolStr {
2226    let params = params
2227        .iter()
2228        .map(|param| format_detailed(param, state))
2229        .collect::<Vec<SmolStr>>()
2230        .join(", ");
2231    if matches!(returned, DataType::Null) {
2232        format_args!("fn({params})").to_smolstr()
2233    } else {
2234        format_args!("fn({params}) -> {}", format_detailed(returned, state)).to_smolstr()
2235    }
2236}
2237
2238/// Whether a value of type `received` fits a field declared `expected`.
2239///
2240/// `null` fits every field, because it is what an absent value carries.
2241/// Everything else is [`param_type_matches`], the rule a parameter uses: a
2242/// field declared `any` is a dynamic slot and holds a value of any type, and
2243/// two instantiations of one generic declaration line up when their arguments
2244/// do.
2245///
2246/// The one place a field is stricter than a parameter is a dynamic value put
2247/// into a typed field. A field is read back at the type it declares and used
2248/// without a run-time test, so a `string` stored in an `int` field would be
2249/// reported from inside the arithmetic that later read it, or not at all. It
2250/// is reported at the line that wrote it instead; name the type with `as int`
2251/// or another downcast to store one.
2252#[inline(always)]
2253#[must_use]
2254pub fn struct_field_type_matches(
2255    expected: &DataType,
2256    received: &DataType,
2257    generics: &Generics,
2258) -> bool {
2259    if *received == DataType::Unknown {
2260        return *expected == DataType::Unknown;
2261    }
2262    received == &DataType::Null || param_type_matches(expected, received, generics)
2263}
2264
2265/// Whether an argument of type `received` satisfies a parameter declared as
2266/// `expected`.
2267///
2268/// `Unknown` is the `any` slot and the type of a value the checker cannot pin
2269/// down (a `json::parse` result, for instance). It stands in for every type on
2270/// either side, so annotating a parameter `any` keeps the parameter dynamic and
2271/// passing a dynamic value to a typed parameter is still allowed. Every other
2272/// pair uses the ordinary type equality.
2273///
2274/// The same rule reaches inside an instantiation: a constructor names only the
2275/// parameters its payload mentions, so `Ok(2)` is a `Result<int, any>` and
2276/// `None` is an `Option<any>`. Two instantiations of one declaration line up
2277/// when every pair of arguments does, which is what lets those values be
2278/// passed and returned where a fully named instantiation is expected.
2279#[inline(always)]
2280#[must_use]
2281pub fn param_type_matches(expected: &DataType, received: &DataType, generics: &Generics) -> bool {
2282    *expected == DataType::Unknown
2283        || *received == DataType::Unknown
2284        || expected == received
2285        || instantiations_line_up(expected, received, generics)
2286}
2287
2288/// Whether a body returning `body` satisfies a function declared to return
2289/// `declared`.
2290///
2291/// Every pair [`param_type_matches`] accepts fits. A return also fits where the
2292/// body hands back something narrower than a declaration that names `any`
2293/// inside it: an `int[]` fits `any[]` and a `{string: string}` fits
2294/// `{any: any}`, because the call site reads the declared type and every value
2295/// is one an `any` slot holds. A union fits when every member does, and a
2296/// member fits a declared union when it fits one of its members. Parameters
2297/// keep the stricter rule: an `int[]` a callee may push a string into is not
2298/// an `any[]`.
2299#[must_use]
2300pub fn return_type_fits(declared: &DataType, body: &DataType, generics: &Generics) -> bool {
2301    if param_type_matches(declared, body, generics) {
2302        return true;
2303    }
2304    match (declared, body) {
2305        (_, DataType::Union(members)) => members
2306            .iter()
2307            .all(|member| return_type_fits(declared, member, generics)),
2308        (DataType::Union(members), _) => members
2309            .iter()
2310            .any(|member| return_type_fits(member, body, generics)),
2311        (DataType::Array(Some(declared)), DataType::Array(Some(body))) => {
2312            return_type_fits(declared, body, generics)
2313        }
2314        (DataType::Map(declared), DataType::Map(body)) => {
2315            slot_fits(declared.0.as_ref(), body.0.as_ref(), generics)
2316                && slot_fits(declared.1.as_ref(), body.1.as_ref(), generics)
2317        }
2318        _ => false,
2319    }
2320}
2321
2322/// Whether a value of type `value` may be written into a variable whose `let`
2323/// declares `declared`.
2324///
2325/// A declared variable is read at its declared type without a run-time test,
2326/// so a dynamic value goes in only through a downcast (`as int`), the rule a
2327/// struct field follows, and a union goes in only when every member fits.
2328/// `fresh` marks a list or map literal, which nothing else holds yet: it may
2329/// be widened into a declaration that names `any` inside it, the way a return
2330/// may, since no other holder sees what is put into it afterwards.
2331#[must_use]
2332pub fn let_type_fits(
2333    declared: &DataType,
2334    value: &DataType,
2335    fresh: bool,
2336    generics: &Generics,
2337) -> bool {
2338    match value {
2339        DataType::Unknown => matches!(declared, DataType::Unknown),
2340        DataType::Union(members) => members
2341            .iter()
2342            .all(|member| let_type_fits(declared, member, fresh, generics)),
2343        _ if fresh => return_type_fits(declared, value, generics),
2344        _ => param_type_matches(declared, value, generics),
2345    }
2346}
2347
2348/// Whether one half of a returned map's type fits the declared half. A half
2349/// either side leaves open fits, the way map equality treats it.
2350fn slot_fits(declared: Option<&DataType>, body: Option<&DataType>, generics: &Generics) -> bool {
2351    match (declared, body) {
2352        (Some(declared), Some(body)) => return_type_fits(declared, body, generics),
2353        _ => true,
2354    }
2355}
2356
2357/// Whether two instantiations come from one declaration and every pair of their
2358/// type arguments lines up.
2359#[must_use]
2360pub(crate) fn instantiations_line_up(a: &DataType, b: &DataType, generics: &Generics) -> bool {
2361    let (Some((ta, args_a)), Some((tb, args_b))) =
2362        (generics.instantiation_of(a), generics.instantiation_of(b))
2363    else {
2364        return false;
2365    };
2366    ta == tb
2367        && args_a.len() == args_b.len()
2368        && args_a
2369            .iter()
2370            .zip(args_b)
2371            .all(|(x, y)| param_type_matches(x, y, generics))
2372}
2373
2374/// Fills in element types a value left open, taking them from the type that was
2375/// declared for it.
2376///
2377/// An empty array literal has no element type: it is `Array(None)`, so indexing
2378/// it yields `null` and a body specialised on it cannot match on its elements.
2379/// An empty map literal is `Map(None, None)`, so reading a key out of it yields
2380/// nothing the body can match on either. Where the declaration says what the
2381/// collection holds, the declaration wins and the specialisation compiles at the
2382/// declared types. Only an open position is filled, so a collection that does
2383/// name what it holds still has to match what was declared. The walk descends
2384/// through arrays and through both halves of a map, so an empty literal nested
2385/// inside one is pinned too.
2386fn pin_open_element_types(inferred: &mut DataType, declared: &DataType) {
2387    match (inferred, declared) {
2388        (DataType::Array(element), DataType::Array(Some(declared_element))) => match element {
2389            None => *element = Some(declared_element.clone()),
2390            Some(element) => pin_open_element_types(element, declared_element),
2391        },
2392        (DataType::Map(entry), DataType::Map(declared_entry)) => {
2393            pin_open_slot(&mut entry.0, declared_entry.0.as_ref());
2394            pin_open_slot(&mut entry.1, declared_entry.1.as_ref());
2395        }
2396        _ => {}
2397    }
2398}
2399
2400/// Pins a caller's binding that still holds an empty literal to the type the
2401/// parameter it is passed to declares.
2402///
2403/// `let` takes no annotation, so a binding that starts out as `[]` or `{}`
2404/// holds nothing until something says what it holds. The first `push` or
2405/// `insert` on it is one such statement; handing it to a parameter that
2406/// declares a collection type is another, and it is often the first one the
2407/// caller writes, because the callee is what fills the collection. Pinning it
2408/// here gives the caller's later reads the element or value type the callee
2409/// put in.
2410///
2411/// Only a binding that is still the empty-literal placeholder is pinned. One
2412/// that already names what it holds keeps its type, so a parameter declaring
2413/// something else stays the argument mismatch the call site reports.
2414pub(crate) fn pin_empty_literal_bindings(
2415    args: &[Expr],
2416    declared_arg_types: &[Option<DataType>],
2417    v: &mut [Variable],
2418) {
2419    for (arg, declared) in args.iter().zip(declared_arg_types) {
2420        let (Expr::Var(name, _), Some(declared)) = (arg, declared) else {
2421            continue;
2422        };
2423        let Some(var) = v.iter_mut().rfind(|var| &var.name == name) else {
2424            continue;
2425        };
2426        if is_empty_literal_type(&var.var_type) {
2427            pin_open_element_types(&mut var.var_type, declared);
2428        }
2429    }
2430}
2431
2432/// Pins a binding that still holds an empty array literal to what the first
2433/// `push` puts in it.
2434///
2435/// Only an array with no element type at all upgrades: an array of `any`
2436/// compares equal to `Array(None)` and keeps its dynamic element type.
2437pub(crate) fn pin_pushed_element(obj: &Expr, element: &DataType, v: &mut [Variable]) {
2438    let Expr::Var(var_name, _) = obj else {
2439        return;
2440    };
2441    if let Some(var) = v.iter_mut().rfind(|var| &var.name == var_name)
2442        && matches!(var.var_type, DataType::Array(None))
2443    {
2444        var.var_type = DataType::Array(Some(Box::new(element.clone())));
2445    }
2446}
2447
2448/// Pins a binding that still holds an empty map literal to what the first
2449/// `m[k] = v` puts in it, so later reads and iteration see concrete types.
2450///
2451/// The test is on missing key and value types, not on `== Map((None, None))`:
2452/// a map of `any` compares equal to it and keeps taking entries of any type,
2453/// which is what a downcast (`as {any: any}`) hands back.
2454pub(crate) fn pin_inserted_entry(obj: &Expr, key: &DataType, value: &DataType, v: &mut [Variable]) {
2455    let Expr::Var(var_name, _) = obj else {
2456        return;
2457    };
2458    if let Some(var) = v.iter_mut().rfind(|var| &var.name == var_name)
2459        && matches!(&var.var_type, DataType::Map(m) if m.0.is_none() && m.1.is_none())
2460    {
2461        var.var_type = DataType::Map(Box::from((Some(key.clone()), Some(value.clone()))));
2462    }
2463}
2464
2465/// Whether a type is what an empty literal leaves behind: an array with no
2466/// element type, or a map with neither a key nor a value type. A downcast
2467/// (`as {any: any}`) hands back entries of `any`, which names a type and is left
2468/// alone.
2469#[must_use]
2470fn is_empty_literal_type(ty: &DataType) -> bool {
2471    match ty {
2472        DataType::Array(element) => element.is_none(),
2473        DataType::Map(entry) => entry.0.is_none() && entry.1.is_none(),
2474        _ => false,
2475    }
2476}
2477
2478/// One half of a map's type: its keys or its values. An open slot takes the
2479/// declared type, a slot that names a type is descended into so a nested empty
2480/// literal is pinned as well, and a declaration that is itself open leaves the
2481/// slot alone.
2482fn pin_open_slot(inferred: &mut Option<DataType>, declared: Option<&DataType>) {
2483    let Some(declared) = declared else {
2484        return;
2485    };
2486    match inferred {
2487        None => *inferred = Some(declared.clone()),
2488        Some(inferred) => pin_open_element_types(inferred, declared),
2489    }
2490}
2491
2492/// Equality for monomorphization and return-type cache keys.
2493///
2494/// Identical to the loose type `==` except that function-typed arguments compare
2495/// by exact `Fn` id, so each distinct function passed to a higher-order function
2496/// keys its own specialization. Function references are always top-level
2497/// arguments (a function is passed directly, never nested inside an array or
2498/// map), so only the top-level `Fn` case needs the stricter rule.
2499#[must_use]
2500pub fn arg_types_specialize_equal(a: &[DataType], b: &[DataType]) -> bool {
2501    a.len() == b.len()
2502        && a.iter().zip(b).all(|(x, y)| match (x, y) {
2503            (DataType::Fn(i), DataType::Fn(j)) => i == j,
2504            (DataType::Fn(_), _) | (_, DataType::Fn(_)) => false,
2505            _ => x == y,
2506        })
2507}
2508
2509/// Collects the functions the given code calls by name.
2510///
2511/// `self_type` is the type a method's body is compiled against, so a call the
2512/// body makes on its own receiver (`self.down(n - 1)`) is recorded under the
2513/// mangled name that method resolves to (`Box#down`). It is `None` for an
2514/// ordinary function, whose `self` names no receiver. A call on any other
2515/// receiver is left out: which function it reaches depends on the receiver's
2516/// type, which only the call site knows.
2517///
2518/// What this list is for is recursion: a function that can reach itself
2519/// through it is compiled as a call rather than inlined, so a method that
2520/// calls itself is compiled the way a recursive function is.
2521///
2522/// # Panics
2523///
2524/// Panics when a `FunctionCall` node carries an empty namespace path, which
2525/// the parser never produces.
2526pub fn collect_direct_fn_calls(
2527    content: &[Expr],
2528    self_type: Option<&str>,
2529    calls: &mut Vec<SmolStr>,
2530) {
2531    let mut expr_stack: Vec<&Expr> = content.iter().collect();
2532    while let Some(expression) = expr_stack.pop() {
2533        // An operator on `self` is a call of the method the receiver's type
2534        // defines for it, so it counts the same as `self.method(...)` does.
2535        if let Some(type_name) = self_type
2536            && let Some(method) = self_operator_method(expression)
2537        {
2538            calls.push(mangle_method(type_name, method));
2539        }
2540        match expression {
2541            Expr::FunctionCall(args, namespace, _, _, _) => {
2542                let (name, path) = namespace.split_last().unwrap();
2543                // `Type::f()` reaches the function `Type`'s `impl` block
2544                // declares, which inside that block is the type the body is
2545                // compiled for.
2546                if let Some(type_name) = path.last() {
2547                    match self_type {
2548                        Some(self_type) if impl_base_name(self_type) == type_name.as_str() => {
2549                            calls.push(mangle_method(self_type, name));
2550                        }
2551                        _ => calls.push(mangle_method(type_name, name)),
2552                    }
2553                }
2554                calls.push(name.clone());
2555                expr_stack.extend(args.iter());
2556            }
2557            Expr::Condition(x, y, _, _)
2558            | Expr::InlineCondition(x, y, _, _)
2559            | Expr::ElseIfBlock(x, y, _)
2560            | Expr::WhileBlock(x, y, _) => {
2561                expr_stack.push(x);
2562                expr_stack.extend(y.iter());
2563            }
2564            Expr::ObjFunctionCall(obj, args, namespace, _, _, _, _) => {
2565                if let Some(type_name) = self_type
2566                    && matches!(&**obj, Expr::Var(name, _) if name == "self")
2567                    && let Some(method) = namespace.last()
2568                {
2569                    calls.push(mangle_method(type_name, method));
2570                }
2571                expr_stack.push(obj);
2572                expr_stack.extend(args.iter());
2573            }
2574            Expr::CallValue(callee, args, _, _) => {
2575                expr_stack.push(callee);
2576                expr_stack.extend(args.iter());
2577            }
2578            Expr::ElseBlock(x) | Expr::EvalBlock(x) | Expr::LoopBlock(x) => {
2579                expr_stack.extend(x.iter());
2580            }
2581            Expr::ReturnVal(code) => {
2582                if let Some(code) = code.as_ref() {
2583                    expr_stack.push(code);
2584                }
2585            }
2586            Expr::FunctionDecl(_, _, x, _, _, _) => expr_stack.extend(x.iter()),
2587            Expr::ArrayGetSlice(x, y, z, _) => {
2588                expr_stack.push(x);
2589                expr_stack.push(y);
2590                if let Some(z) = z {
2591                    expr_stack.push(z);
2592                }
2593            }
2594            Expr::VarDeclare(_, x, _)
2595            | Expr::VarAssign(_, x, _, _)
2596            | Expr::Propagate(x, _)
2597            | Expr::Is(x, _, _, _)
2598            | Expr::Cast(x, _, _, _)
2599            | Expr::Neg(x, _, _)
2600            | Expr::BitNot(x, _, _)
2601            | Expr::BoolNeg(x, _, _) => expr_stack.push(x),
2602            Expr::ForLoop(_, _, code, _) => expr_stack.extend(code.iter()),
2603            Expr::IntForLoop(_, start, end, code, _, _) => {
2604                expr_stack.push(start);
2605                expr_stack.push(end);
2606                expr_stack.extend(code.iter());
2607            }
2608            Expr::ArrayModify(array, index, value, _, _) => {
2609                expr_stack.push(array);
2610                expr_stack.push(index);
2611                expr_stack.push(value);
2612            }
2613            Expr::Array(elems, _) => expr_stack.extend(elems.iter()),
2614            Expr::Struct(_, fields, _, _, base) => {
2615                expr_stack.extend(fields.iter().map(|(_, expr, _, _)| expr));
2616                if let Some(base) = base.as_ref().and_then(|b| b.0.base()) {
2617                    expr_stack.push(base);
2618                }
2619            }
2620            Expr::GetStructField(expr, _, _, _) => expr_stack.push(expr),
2621            Expr::SetStructField(expr, _, value, _, _, _) => {
2622                expr_stack.push(expr);
2623                expr_stack.push(value);
2624            }
2625            Expr::TryCatchBlock(try_code, _, catch_code) => {
2626                expr_stack.extend(try_code.iter());
2627                expr_stack.extend(catch_code.iter());
2628            }
2629            Expr::Match(scrutinee, arms, wildcard, _, _) => {
2630                expr_stack.push(scrutinee);
2631                for (patterns, body) in arms {
2632                    expr_stack.extend(patterns.iter());
2633                    expr_stack.extend(body.iter());
2634                }
2635                if let Some(w) = wildcard {
2636                    expr_stack.extend(w.iter());
2637                }
2638            }
2639            Expr::ArrayGetIndex(x, y, _)
2640            | Expr::Mul(x, y, _, _)
2641            | Expr::Div(x, y, _, _)
2642            | Expr::Add(x, y, _, _)
2643            | Expr::Sub(x, y, _, _)
2644            | Expr::Mod(x, y, _, _)
2645            | Expr::Pow(x, y, _, _)
2646            | Expr::BitAnd(x, y, _, _)
2647            | Expr::BitOr(x, y, _, _)
2648            | Expr::BitXor(x, y, _, _)
2649            | Expr::Shl(x, y, _, _)
2650            | Expr::Shr(x, y, _, _)
2651            | Expr::Eq(x, y, _, _)
2652            | Expr::NotEq(x, y, _, _)
2653            | Expr::Sup(x, y, _, _)
2654            | Expr::SupEq(x, y, _, _)
2655            | Expr::Inf(x, y, _, _)
2656            | Expr::InfEq(x, y, _, _)
2657            | Expr::BoolAnd(x, y, _, _)
2658            | Expr::BoolOr(x, y, _, _) => {
2659                expr_stack.push(x);
2660                expr_stack.push(y);
2661            }
2662            _ => {}
2663        }
2664    }
2665}
2666
2667/// Check if the function src_fn can call target_fn
2668pub fn can_reach<S: std::hash::BuildHasher>(
2669    src_fn: &str,
2670    target_fn: &str,
2671    fns: &[Function],
2672    visited: &mut std::collections::HashSet<SmolStr, S>,
2673) -> bool {
2674    if let Some(from_fn) = fns.iter().find(|f| f.name.as_str() == src_fn) {
2675        for callee in &from_fn.direct_calls {
2676            if callee == target_fn {
2677                return true;
2678            }
2679            if visited.insert(callee.clone()) && can_reach(callee, target_fn, fns, visited) {
2680                return true;
2681            }
2682        }
2683    }
2684    false
2685}
2686
2687/// Which kinds of `return` a body writes, closures left out.
2688#[derive(Default)]
2689struct ReturnShapes {
2690    /// A `return expr;` somewhere in the body.
2691    value: bool,
2692    /// A bare `return;` somewhere in the body.
2693    bare: bool,
2694}
2695
2696fn collect_return_shapes(content: &[Expr], shapes: &mut ReturnShapes) {
2697    for content in content {
2698        match content {
2699            Expr::ElseIfBlock(_, code, _)
2700            | Expr::ElseBlock(code)
2701            | Expr::Condition(_, code, _, _)
2702            | Expr::InlineCondition(_, code, _, _)
2703            | Expr::WhileBlock(_, code, _)
2704            | Expr::ForLoop(_, _, code, _)
2705            | Expr::EvalBlock(code)
2706            | Expr::LoopBlock(code)
2707            | Expr::IntForLoop(_, _, _, code, _, _) => collect_return_shapes(code, shapes),
2708            Expr::TryCatchBlock(try_code, _, catch_code) => {
2709                collect_return_shapes(try_code, shapes);
2710                collect_return_shapes(catch_code, shapes);
2711            }
2712            Expr::Match(_, arms, wildcard, _, _) => {
2713                for (_, body) in arms {
2714                    collect_return_shapes(body, shapes);
2715                }
2716                if let Some(w) = wildcard {
2717                    collect_return_shapes(w, shapes);
2718                }
2719            }
2720            Expr::ReturnVal(value) => {
2721                if value.is_some() {
2722                    shapes.value = true;
2723                } else {
2724                    shapes.bare = true;
2725                }
2726            }
2727            _ => {}
2728        }
2729    }
2730}
2731
2732#[must_use]
2733pub fn check_if_returns_void(content: &[Expr]) -> bool {
2734    let mut shapes = ReturnShapes::default();
2735    collect_return_shapes(content, &mut shapes);
2736    !shapes.value
2737}
2738
2739macro_rules! extend_return_types {
2740    ($return_types: expr, $new_types: expr, $ctx: expr, $state: expr) => {
2741        for return_type in $new_types {
2742            add_return_type($return_types, return_type, $ctx, $state);
2743        }
2744    };
2745}
2746
2747/// Adds one of a body's return types to the set the function produces.
2748///
2749/// `any` says nothing about what comes back and is dropped. Two instantiations
2750/// of one generic declaration merge instead of making a union: a constructor
2751/// names only the parameters its payload mentions, so a body that returns
2752/// `Ok(2)` on one path and `Err("no")` on another produces a `Result<int, any>`
2753/// and a `Result<any, string>`, and those are the one type `Result<int,
2754/// string>`.
2755fn add_return_type(
2756    return_types: &mut Vec<DataType>,
2757    return_type: DataType,
2758    ctx: Ctx,
2759    state: &mut State<'_>,
2760) {
2761    if return_type == DataType::Unknown {
2762        return;
2763    }
2764    // Two functions handed back by one body make one value the caller calls
2765    // through, so the two types join: both bodies are compiled and the call
2766    // dispatches on the one that came back. Keeping only the first would leave
2767    // the second with no body to jump to.
2768    if matches!(return_type, DataType::Fn(_) | DataType::FnValue(_))
2769        && let Some(i) = return_types
2770            .iter()
2771            .position(|held| matches!(held, DataType::Fn(_) | DataType::FnValue(_)))
2772    {
2773        if let Some(merged) = merge_fn_types(&[return_types[i].clone(), return_type]) {
2774            return_types[i] = merged;
2775        }
2776        return;
2777    }
2778    if return_types.contains(&return_type) {
2779        return;
2780    }
2781    let mut replacement = None;
2782    for (i, existing) in return_types.iter().enumerate() {
2783        if let Some(merged) = merge_instantiations(existing, &return_type, ctx, state) {
2784            replacement = Some((i, merged));
2785            break;
2786        }
2787    }
2788    if let Some((i, merged)) = replacement {
2789        return_types[i] = merged;
2790        return;
2791    }
2792    return_types.push(return_type);
2793}
2794
2795/// What a `?` reads out of an enum shaped like `Option` or `Result`.
2796///
2797/// `Option` is `Some(T)` and `None`, `Result` is `Ok(T)` and `Err(E)`. Answers
2798/// the type `?` reads out of the success variant and the index of the failure
2799/// variant, which is the one it hands back to the caller; `None` for any other
2800/// type.
2801#[must_use]
2802pub fn propagation_sides(t: &DataType, state: &State<'_>) -> Option<(DataType, u16)> {
2803    let DataType::Enum(enum_id) = t else {
2804        return None;
2805    };
2806    let variants = &state.enums[*enum_id as usize].variants;
2807    let [first, second] = &**variants else {
2808        return None;
2809    };
2810    let (success, failure, failure_idx) = match (first.name.as_str(), second.name.as_str()) {
2811        ("Some", "None") | ("Ok", "Err") => (first, second, 1),
2812        ("None", "Some") | ("Err", "Ok") => (second, first, 0),
2813        _ => return None,
2814    };
2815    let failure_arity = usize::from(failure.name == "Err");
2816    if success.payload.len() != 1 || failure.payload.len() != failure_arity {
2817        return None;
2818    }
2819    Some((success.payload[0].clone(), failure_idx))
2820}
2821
2822/// The type a `?` on a value of type `operand` hands back to the caller: the
2823/// same declaration with the success side left open, `Option<any>` for an
2824/// `Option` and `Result<any, E>` for a `Result<T, E>`. The value it returns is
2825/// the operand's `None` or `Err`, which holds no `T`.
2826fn propagated_failure_type(operand: &DataType, state: &mut State<'_>) -> Option<DataType> {
2827    let (template, args) = state.generics.instantiation_of(operand)?;
2828    let mut args: Vec<DataType> = args.to_vec();
2829    // `Option<T>` and `Result<T, E>` both declare the success side's parameter
2830    // first.
2831    *args.first_mut()? = DataType::Unknown;
2832    let base = state.generics.template_name(template).clone();
2833    let file_idx = state.generics.template_file(template);
2834    Some(instantiate(
2835        &[],
2836        &base,
2837        &args,
2838        (0u32, 0u32).into(),
2839        &mut state.type_ctx(file_idx),
2840    ))
2841}
2842
2843/// The one type two instantiations of a declaration make, when every pair of
2844/// their arguments lines up. An argument left at `any` takes the other side's
2845/// type. Answers `None` for anything else, which keeps two unrelated types the
2846/// union they are.
2847fn merge_instantiations(
2848    a: &DataType,
2849    b: &DataType,
2850    ctx: Ctx,
2851    state: &mut State<'_>,
2852) -> Option<DataType> {
2853    let (template, args_a) = state.generics.instantiation_of(a)?;
2854    let args_a: Vec<DataType> = args_a.to_vec();
2855    let (template_b, args_b) = state.generics.instantiation_of(b)?;
2856    if template != template_b || args_a.len() != args_b.len() {
2857        return None;
2858    }
2859    let mut merged = Vec::with_capacity(args_a.len());
2860    for (x, y) in args_a.iter().zip(args_b) {
2861        merged.push(match (x, y) {
2862            (DataType::Unknown, other) | (other, DataType::Unknown) => other.clone(),
2863            (x, y) if x == y => x.clone(),
2864            _ => return None,
2865        });
2866    }
2867    let base = state.generics.template_name(template).clone();
2868    Some(instantiate(
2869        &[],
2870        &base,
2871        &merged,
2872        (0u32, 0u32).into(),
2873        &mut state.type_ctx(ctx.file_idx),
2874    ))
2875}
2876
2877/// The types a function body hands back.
2878///
2879/// A body that returns a value on one path has to return one on every path: a
2880/// call that reaches the end of the body, or leaves through a bare `return;`,
2881/// has nothing to hand back, and the value the caller would read is whatever
2882/// the last call left behind. That is reported at the function rather than
2883/// folded in as a `null` the caller cannot tell from one the body wrote.
2884pub fn track_returns(
2885    content: &[Expr],
2886    v: &mut Vec<Variable>,
2887    ctx: Ctx,
2888    state: &mut State<'_>,
2889    fn_name: &str,
2890    fn_id: usize,
2891) -> Vec<DataType> {
2892    // A `?` the walk types is a return of the `None` or the `Err` its operand
2893    // can hold; see `Expr::Propagate`.
2894    state.propagations.push(Vec::new());
2895    let mut flow = track_return_flow(content, v, ctx, state, fn_name);
2896    let propagated = state.propagations.pop().unwrap_or_default();
2897    // A declared return type is what the caller reads, and each `?` is checked
2898    // against it where it is compiled, which names the `?` in the report.
2899    let declared = state.fns[fn_id].return_type.is_some()
2900        || state.fns[fn_id]
2901            .generics
2902            .as_ref()
2903            .is_some_and(|g| g.return_type.is_some());
2904    for operand in propagated.into_iter().filter(|_| !declared) {
2905        if let Some(failure) = propagated_failure_type(&operand, state) {
2906            add_return_type(&mut flow.types, failure, ctx, state);
2907        }
2908    }
2909    let mut shapes = ReturnShapes::default();
2910    collect_return_shapes(content, &mut shapes);
2911    if shapes.value && (shapes.bare || !flow.always_returns) {
2912        // The report names the function as it was declared: a closure has no
2913        // name of its own, whatever the call site bound it to.
2914        let func = &state.fns[fn_id];
2915        let declared = (!func.name.starts_with(ANON_FN_PREFIX)).then_some(func.name.as_str());
2916        error_missing_return(declared, func.name_span, ctx.file_idx, state.sources);
2917    }
2918    flow.types
2919}
2920
2921struct FnReturnFlow {
2922    types: Vec<DataType>,
2923    always_returns: bool,
2924}
2925
2926fn track_scoped_returns(
2927    code: &[Expr],
2928    v: &mut Vec<Variable>,
2929    ctx: Ctx,
2930    state: &mut State<'_>,
2931    fn_name: &str,
2932) -> FnReturnFlow {
2933    let v_len = v.len();
2934    let flow = track_return_flow(code, v, ctx, state, fn_name);
2935    v.truncate(v_len);
2936    flow
2937}
2938
2939fn track_condition_returns(
2940    condition: &Expr,
2941    code: &[Expr],
2942    v: &mut Vec<Variable>,
2943    ctx: Ctx,
2944    state: &mut State<'_>,
2945    fn_name: &str,
2946) -> FnReturnFlow {
2947    let mut return_types = Vec::new();
2948    let first_branch_end = code
2949        .iter()
2950        .position(|expr| matches!(expr, Expr::ElseIfBlock(_, _, _) | Expr::ElseBlock(_)))
2951        .unwrap_or(code.len());
2952
2953    // Each branch is walked with what its condition proved in scope.
2954    let v_len = v.len();
2955    crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
2956    let first_flow = track_scoped_returns(&code[..first_branch_end], v, ctx, state, fn_name);
2957    v.truncate(v_len);
2958    let mut all_branches_return = first_flow.always_returns;
2959    let mut has_else = false;
2960    extend_return_types!(&mut return_types, first_flow.types, ctx, state);
2961
2962    for expr in &code[first_branch_end..] {
2963        match expr {
2964            Expr::ElseIfBlock(condition, branch_code, _) => {
2965                crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
2966                let flow = track_scoped_returns(branch_code, v, ctx, state, fn_name);
2967                v.truncate(v_len);
2968                all_branches_return &= flow.always_returns;
2969                extend_return_types!(&mut return_types, flow.types, ctx, state);
2970            }
2971            Expr::ElseBlock(branch_code) => {
2972                has_else = true;
2973                let flow = track_scoped_returns(branch_code, v, ctx, state, fn_name);
2974                all_branches_return &= flow.always_returns;
2975                extend_return_types!(&mut return_types, flow.types, ctx, state);
2976            }
2977            _ => {}
2978        }
2979    }
2980
2981    FnReturnFlow {
2982        types: return_types,
2983        always_returns: has_else && all_branches_return,
2984    }
2985}
2986
2987fn track_return_flow(
2988    content: &[Expr],
2989    v: &mut Vec<Variable>,
2990    ctx: Ctx,
2991    state: &mut State<'_>,
2992    fn_name: &str,
2993) -> FnReturnFlow {
2994    let mut return_types: Vec<DataType> = Vec::new();
2995    let mut threw = false;
2996    for expr in content {
2997        match expr {
2998            Expr::Condition(condition, code, _, _)
2999            | Expr::InlineCondition(condition, code, _, _) => {
3000                let flow = track_condition_returns(condition, code, v, ctx, state, fn_name);
3001                extend_return_types!(&mut return_types, flow.types, ctx, state);
3002                if flow.always_returns {
3003                    return FnReturnFlow {
3004                        types: return_types,
3005                        always_returns: true,
3006                    };
3007                }
3008            }
3009            Expr::ElseIfBlock(_, code, _) | Expr::ElseBlock(code) | Expr::EvalBlock(code) => {
3010                let flow = track_scoped_returns(code, v, ctx, state, fn_name);
3011                extend_return_types!(&mut return_types, flow.types, ctx, state);
3012                if flow.always_returns {
3013                    return FnReturnFlow {
3014                        types: return_types,
3015                        always_returns: true,
3016                    };
3017                }
3018            }
3019            // A `loop` is left through a `break` or a `return`, so one with no
3020            // break of its own never falls through to what follows it. A body
3021            // that returns at its end still leaves through a break written
3022            // before that return, so the break alone decides.
3023            Expr::LoopBlock(code) => {
3024                let flow = track_scoped_returns(code, v, ctx, state, fn_name);
3025                extend_return_types!(&mut return_types, flow.types, ctx, state);
3026                if !block_breaks(code) {
3027                    return FnReturnFlow {
3028                        types: return_types,
3029                        always_returns: true,
3030                    };
3031                }
3032            }
3033            Expr::VarDeclare(name, expr, annotation) => {
3034                let declared = annotation
3035                    .as_ref()
3036                    .map(|a| a.ty.to_datatype(&mut state.type_ctx(ctx.file_idx)));
3037                let var_type = match &declared {
3038                    Some(declared) => declared.clone(),
3039                    None => expr.infer_type(v, ctx, state),
3040                };
3041                v.push(Variable {
3042                    declared,
3043                    name: name.clone(),
3044                    register_id: 0,
3045                    cell: false,
3046                    var_type,
3047                });
3048            }
3049            Expr::VarAssign(name, expr, _, _) => {
3050                if v.iter()
3051                    .rfind(|var| &var.name == name)
3052                    .is_some_and(|var| var.declared.is_none())
3053                {
3054                    let var_type = expr.infer_type(v, ctx, state);
3055                    if let Some(var) = v.iter_mut().rfind(|var| &var.name == name) {
3056                        var.var_type = var_type;
3057                    }
3058                }
3059            }
3060            // A `while true` is a `loop` under another spelling and is left
3061            // the same way.
3062            Expr::WhileBlock(condition, code, _) => {
3063                let v_len = v.len();
3064                crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
3065                let flow = track_scoped_returns(code, v, ctx, state, fn_name);
3066                v.truncate(v_len);
3067                extend_return_types!(&mut return_types, flow.types, ctx, state);
3068                if matches!(**condition, Expr::Bool(true)) && !block_breaks(code) {
3069                    return FnReturnFlow {
3070                        types: return_types,
3071                        always_returns: true,
3072                    };
3073                }
3074            }
3075            Expr::IntForLoop(var_name, _, _, code, _, _) => {
3076                let v_len = v.len();
3077                v.push(Variable {
3078                    declared: None,
3079                    name: var_name.clone(),
3080                    register_id: 0,
3081                    cell: false,
3082                    var_type: DataType::Int,
3083                });
3084                let flow = track_return_flow(code, v, ctx, state, fn_name);
3085                extend_return_types!(&mut return_types, flow.types, ctx, state);
3086                v.truncate(v_len);
3087            }
3088            Expr::ForLoop(var_name, array_expr, array_code, span) => {
3089                let inferred_collection_type = array_expr.infer_type(v, ctx, state);
3090                let elem_type = match inferred_collection_type {
3091                    DataType::Array(inner) => inner.map_or(DataType::Unknown, |t| *t),
3092                    DataType::String => DataType::String,
3093                    DataType::Unknown => DataType::Unknown,
3094                    // A map iterates its keys.
3095                    DataType::Map(m) => m.0.unwrap_or(DataType::Unknown),
3096                    // A function whose return type is inferred has its body
3097                    // walked before the loop is compiled, so a loop over a
3098                    // value nothing can iterate arrives here first and reports
3099                    // what the compile stage would have.
3100                    t => error_type_not_indexable(
3101                        &t,
3102                        *span,
3103                        true,
3104                        ctx.file_idx,
3105                        state.sources,
3106                        state.type_names(),
3107                    ),
3108                };
3109                let v_len = v.len();
3110                if var_name.as_str() != "_" {
3111                    v.push(Variable {
3112                        declared: None,
3113                        name: var_name.clone(),
3114                        register_id: 0,
3115                        cell: false,
3116                        var_type: elem_type,
3117                    });
3118                }
3119                let flow = track_return_flow(array_code, v, ctx, state, fn_name);
3120                extend_return_types!(&mut return_types, flow.types, ctx, state);
3121                v.truncate(v_len);
3122            }
3123            // The statements that say what a collection a `let` left empty
3124            // holds. This walk runs over the body before the compile walk
3125            // lowers it, so it applies the same pins; without them a read
3126            // written in a `return` sees the empty-literal placeholder while
3127            // the same read written anywhere else sees the pinned type.
3128            Expr::ObjFunctionCall(obj, args, namespace, _, _, _, _)
3129                if namespace.last().unwrap().as_str() == "push" && args.len() == 1 =>
3130            {
3131                let element = args[0].infer_type(v, ctx, state);
3132                pin_pushed_element(obj, &element, v);
3133            }
3134            Expr::ArrayModify(obj, key, value, _, _)
3135                if matches!(obj.infer_type(v, ctx, state), DataType::Map(_)) =>
3136            {
3137                let key = key.infer_type(v, ctx, state);
3138                let value = value.infer_type(v, ctx, state);
3139                pin_inserted_entry(obj, &key, &value, v);
3140            }
3141            // A `throw` or an `exit` never comes back, so the path it ends is
3142            // one the function returns on: a match arm or a catch that only
3143            // raises leaves the other arms to answer. The walk goes on past
3144            // it, since a return written after the throw still says what the
3145            // function hands back. This comes before the arm that pins a
3146            // call's empty-literal arguments, which matches every call.
3147            Expr::FunctionCall(_, namespace, _, _, _)
3148                if namespace.len() == 1 && matches!(namespace[0].as_str(), "throw" | "exit") =>
3149            {
3150                threw = true;
3151            }
3152            Expr::FunctionCall(args, namespace, _, _, type_args) if type_args.is_empty() => {
3153                let (fn_name, path) = namespace.split_last().unwrap();
3154                if let Some(fn_id) = state.scope(ctx.file_idx).find_function(path, fn_name) {
3155                    let declared = specialized_arg_types(fn_id, &[], ctx, state);
3156                    pin_empty_literal_bindings(args, &declared, v);
3157                }
3158            }
3159            Expr::Match(scrutinee, arms, wildcard, span, _) => {
3160                let scrut_type = scrutinee.infer_type(v, ctx, state);
3161                let is_enum = matches!(scrut_type, DataType::Enum(_));
3162                if !is_enum {
3163                    crate::compiler::check_match_scrutinee_is_enum(
3164                        &scrut_type,
3165                        arms,
3166                        *span,
3167                        v,
3168                        ctx,
3169                        state,
3170                    );
3171                }
3172                let mut all_return = true;
3173                for (patterns, body) in arms {
3174                    let v_len = v.len();
3175                    if let DataType::Enum(enum_id) = scrut_type {
3176                        crate::compiler::declare_arm_bindings(
3177                            enum_id, patterns, *span, v, ctx, state,
3178                        );
3179                    }
3180                    let flow = track_return_flow(body, v, ctx, state, fn_name);
3181                    v.truncate(v_len);
3182                    all_return &= flow.always_returns;
3183                    extend_return_types!(&mut return_types, flow.types, ctx, state);
3184                }
3185                let exhaustive = if wildcard.is_some() {
3186                    if let Some(w) = wildcard {
3187                        let flow = track_scoped_returns(w, v, ctx, state, fn_name);
3188                        all_return &= flow.always_returns;
3189                        extend_return_types!(&mut return_types, flow.types, ctx, state);
3190                    }
3191                    true
3192                } else {
3193                    // An enum match with no wildcard is compile-time exhaustive.
3194                    is_enum
3195                };
3196                if exhaustive && all_return {
3197                    return FnReturnFlow {
3198                        types: return_types,
3199                        always_returns: true,
3200                    };
3201                }
3202            }
3203            // A try block and its catch are two paths out of the statement,
3204            // and the function returns on every path when both do. The catch
3205            // sees the error kind under the name the block binds.
3206            Expr::TryCatchBlock(try_code, err_var, catch_code) => {
3207                let try_flow = track_scoped_returns(try_code, v, ctx, state, fn_name);
3208                extend_return_types!(&mut return_types, try_flow.types, ctx, state);
3209                let v_len = v.len();
3210                v.push(Variable {
3211                    declared: None,
3212                    name: err_var.clone(),
3213                    register_id: 0,
3214                    cell: false,
3215                    var_type: DataType::String,
3216                });
3217                let catch_flow = track_return_flow(catch_code, v, ctx, state, fn_name);
3218                v.truncate(v_len);
3219                extend_return_types!(&mut return_types, catch_flow.types, ctx, state);
3220                if try_flow.always_returns && catch_flow.always_returns {
3221                    return FnReturnFlow {
3222                        types: return_types,
3223                        always_returns: true,
3224                    };
3225                }
3226            }
3227            Expr::ReturnVal(return_val) => {
3228                if let Some(val) = return_val.as_ref() {
3229                    let infered = val.infer_type(v, ctx, state);
3230                    // A returned name hands the function on as a value, and the
3231                    // caller has no declaration to read it against, so the type
3232                    // carries the signature the function was declared with.
3233                    let infered = if matches!(infered, DataType::Fn(_)) {
3234                        bare_fn_value_type(val, v, ctx, state).unwrap_or(infered)
3235                    } else {
3236                        infered
3237                    };
3238                    add_return_type(&mut return_types, infered, ctx, state);
3239                } else {
3240                    add_return_type(&mut return_types, DataType::Null, ctx, state);
3241                }
3242                return FnReturnFlow {
3243                    types: return_types,
3244                    always_returns: true,
3245                };
3246            }
3247            _ => {}
3248        }
3249    }
3250    FnReturnFlow {
3251        types: return_types,
3252        always_returns: threw,
3253    }
3254}
3255
3256/// Whether a `break` written in `code` leaves the loop it belongs to. A break
3257/// inside a nested loop leaves that loop only, so nested loops are not
3258/// searched.
3259fn block_breaks(code: &[Expr]) -> bool {
3260    code.iter().any(|expr| match expr {
3261        Expr::Break => true,
3262        Expr::Condition(_, body, _, _)
3263        | Expr::InlineCondition(_, body, _, _)
3264        | Expr::ElseIfBlock(_, body, _)
3265        | Expr::ElseBlock(body)
3266        | Expr::EvalBlock(body) => block_breaks(body),
3267        Expr::TryCatchBlock(try_code, _, catch_code) => {
3268            block_breaks(try_code) || block_breaks(catch_code)
3269        }
3270        Expr::Match(_, arms, wildcard, _, _) => {
3271            arms.iter().any(|(_, body)| block_breaks(body))
3272                || wildcard.as_ref().is_some_and(|w| block_breaks(w))
3273        }
3274        _ => false,
3275    })
3276}
3277
3278/// Infers the return type of a user function specialised for
3279/// `infered_arg_types`, caching the result on the function.
3280///
3281/// Shared by direct `FunctionCall`s and by `impl` method calls (which resolve
3282/// to a mangled free function with the receiver as argument 0).
3283/// `function_name` is only used for diagnostics inside `track_returns`.
3284///
3285/// `type_args` are the arguments a generic call named. They are part of the
3286/// specialisation key because a type parameter no argument mentions still
3287/// changes what the body builds.
3288/// Declares a closure's captures in `v`, ahead of its parameters, which shadow
3289/// a capture of the same name. A closure body reads what the closure captured,
3290/// so those names are in scope both while its return type is worked out and
3291/// while its body compiles.
3292pub fn push_capture_scope(
3293    v: &mut Vec<Variable>,
3294    captures: &[(SmolStr, DataType, Option<DataType>)],
3295) {
3296    for (name, capture_type, declared) in captures {
3297        v.push(Variable {
3298            declared: declared.clone(),
3299            name: name.clone(),
3300            register_id: 0,
3301            cell: true,
3302            var_type: capture_type.clone(),
3303        });
3304    }
3305}
3306
3307pub fn infer_user_fn_return_type(
3308    fn_id: usize,
3309    infered_arg_types: &[DataType],
3310    type_args: &[DataType],
3311    function_name: &str,
3312    v: &mut Vec<Variable>,
3313    ctx: Ctx,
3314    state: &mut State<'_>,
3315) -> DataType {
3316    // The body is compiled at the types `handle_user_function` specialises on,
3317    // which pin an argument's open element type to what the parameter declares.
3318    // Infer against the same types, or the caller reads a return type from a
3319    // body that was never compiled that way. Reading the declarations costs a
3320    // clone, so the arguments are asked first whether any left one open.
3321    let pinned = if infered_arg_types.iter().any(has_open_element_type) {
3322        let declared_arg_types = specialized_arg_types(fn_id, type_args, ctx, state);
3323        pinned_arg_types(infered_arg_types, &declared_arg_types)
3324    } else {
3325        None
3326    };
3327    let infered_arg_types = pinned.as_deref().unwrap_or(infered_arg_types);
3328
3329    let key = specialization_key(type_args, infered_arg_types);
3330    // Check the return type cache
3331    if let Some((_, ret)) = state.fns[fn_id]
3332        .return_type_cache
3333        .iter()
3334        .find(|(args, _)| arg_types_specialize_equal(args, &key))
3335    {
3336        return ret.clone();
3337    }
3338
3339    let fn_ctx = Ctx {
3340        file_idx: state.fns[fn_id].src_file,
3341        ..ctx
3342    };
3343    // A declared return type is what the call hands back, read with this call's
3344    // type arguments bound so a generic `-> T[]` resolves to what it names. An
3345    // annotation naming a type parameter the call left unbound stays unread,
3346    // and the body says what comes back.
3347    state
3348        .generics
3349        .push_frame(fn_bindings(fn_id, type_args, state));
3350    let declared_return = specialized_return_type(fn_id, fn_ctx, state).map(|(t, _)| t);
3351    state.generics.pop_bindings();
3352
3353    // Mutual-recursion cycle guard: a call reached while this function's return
3354    // type is still being worked out gets the declaration, or `Unknown` when
3355    // there is none, which breaks the cycle.
3356    let already_inferring = RETURN_TYPE_INFERRING.with(|s| s.borrow().contains(&fn_id));
3357    if already_inferring {
3358        return declared_return.unwrap_or(DataType::Unknown);
3359    }
3360    // A call can reach inference before anything checks how many arguments it
3361    // passes. The body cannot be walked with a parameter left unbound or an
3362    // argument bound to no parameter, so the call takes the declared type and
3363    // compiling it reports the count.
3364    if infered_arg_types.len() != state.fns[fn_id].args.len() {
3365        return declared_return.unwrap_or(DataType::Unknown);
3366    }
3367
3368    let func = &state.fns[fn_id];
3369    let fn_args = func.args.clone();
3370    let fn_code = func.code.clone();
3371    let fn_captures = func.captures.clone();
3372    let v_len_before_args = v.len();
3373    push_capture_scope(v, &fn_captures);
3374    for (i, infered_type) in infered_arg_types.iter().cloned().enumerate() {
3375        // 0 => placeholder id, it's never used
3376        v.push(Variable {
3377            declared: None,
3378            name: fn_args[i].0.clone(),
3379            register_id: 0,
3380            cell: false,
3381            var_type: infered_type,
3382        });
3383    }
3384
3385    RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().insert(fn_id));
3386
3387    // The body is walked whether or not a type is declared: the errors it holds
3388    // are reported here, in the same order either way.
3389    state
3390        .generics
3391        .push_frame(fn_bindings(fn_id, type_args, state));
3392    let fn_type = track_returns(&fn_code, v, fn_ctx, state, function_name, fn_id);
3393    state.generics.pop_bindings();
3394
3395    RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().remove(&fn_id));
3396
3397    v.truncate(v_len_before_args);
3398
3399    let body_type = if fn_type.is_empty() {
3400        // No tracked type means either no value is returned at all, or every
3401        // returned value was itself dynamic (return-type tracking records no
3402        // type for `Unknown`). A function handing back an `any` payload is
3403        // dynamic, not null.
3404        if check_if_returns_void(&fn_code) {
3405            DataType::Null
3406        } else {
3407            DataType::Unknown
3408        }
3409    } else {
3410        // If function returns anything, check if it returns the same thing each time
3411        DataType::Union(Box::from(fn_type)).check_poly()
3412    };
3413    let to_return = call_return_type(declared_return, body_type);
3414
3415    // Cache the result
3416    state.fns[fn_id]
3417        .return_type_cache
3418        .push((key, to_return.clone()));
3419
3420    to_return
3421}
3422
3423/// The type a call to a function hands back, from what the function declares
3424/// and what its body returns.
3425///
3426/// A declared type wins: the call has the type the signature names, even where
3427/// the body returns something narrower. Only an element type the declaration
3428/// leaves open is taken from the body. With nothing declared, the body's type
3429/// is the call's.
3430#[must_use]
3431pub(crate) fn call_return_type(declared: Option<DataType>, body_type: DataType) -> DataType {
3432    match declared {
3433        Some(mut declared) => {
3434            pin_open_element_types(&mut declared, &body_type);
3435            declared
3436        }
3437        None => body_type,
3438    }
3439}
3440
3441/// The `-> Type` annotation as it reads for the specialisation being compiled,
3442/// with the type parameters currently bound.
3443///
3444/// An annotation naming a parameter the call left unbound stays un-pinned, so
3445/// what the body returns is inferred rather than checked against a type that
3446/// has no value yet.
3447pub(crate) fn specialized_return_type(
3448    fn_id: usize,
3449    ctx: Ctx,
3450    state: &mut State<'_>,
3451) -> Option<(DataType, Span)> {
3452    let Some(generics) = state.fns[fn_id].generics.as_ref() else {
3453        return state.fns[fn_id].return_type.clone();
3454    };
3455    let unbound: Vec<SmolStr> = generics
3456        .params
3457        .iter()
3458        .filter(|param| !state.generics.names(param))
3459        .cloned()
3460        .collect();
3461    let generics = state.fns[fn_id].generics.as_ref()?;
3462    let annotation = generics.return_type.as_deref()?;
3463    if annotation.0.mentions_any(&unbound) {
3464        return state.fns[fn_id].return_type.clone();
3465    }
3466    let (return_type, return_span) = annotation.clone();
3467    let file_idx = generics.file_idx;
3468    let mut base = state.type_ctx(ctx.file_idx);
3469    let mut type_ctx = base.reborrow(file_idx);
3470    Some((return_type.to_datatype(&mut type_ctx), return_span))
3471}
3472
3473/// The parameter types this call specialises on.
3474///
3475/// Without type arguments these are the function's own declared types, where an
3476/// annotation naming a type parameter was left un-pinned. A call that names its
3477/// type arguments resolves the annotations again with them bound, which is what
3478/// makes `first<int>(xs)` reject a `float[]`.
3479pub(crate) fn specialized_arg_types(
3480    fn_id: usize,
3481    type_args: &[DataType],
3482    ctx: Ctx,
3483    state: &mut State<'_>,
3484) -> Vec<Option<DataType>> {
3485    let declared = state.fns[fn_id]
3486        .args
3487        .iter()
3488        .map(|(_, t)| t.clone())
3489        .collect::<Vec<Option<DataType>>>();
3490    if type_args.is_empty() {
3491        return declared;
3492    }
3493    let Some(generics) = state.fns[fn_id].generics.as_ref() else {
3494        return declared;
3495    };
3496    let arg_types = generics.arg_types.clone();
3497    let file_idx = generics.file_idx;
3498    let frame = fn_bindings(fn_id, type_args, state);
3499    let mut base = state.type_ctx(ctx.file_idx);
3500    let mut type_ctx = base.reborrow(file_idx);
3501    type_ctx.generics.push_frame(frame);
3502    let resolved = arg_types
3503        .iter()
3504        .map(|t| t.as_ref().map(|t| t.to_datatype(&mut type_ctx)))
3505        .collect();
3506    type_ctx.generics.pop_bindings();
3507    resolved
3508}
3509
3510/// The argument types a call specialises on: what its arguments infer to, with
3511/// any element type they left open filled in from `declared_arg_types`, the
3512/// parameter declarations as [`specialized_arg_types`] reads them.
3513///
3514/// Answers `None` when no argument left an element type open, which is every
3515/// call that passes no empty collection literal.
3516pub(crate) fn pinned_arg_types(
3517    infered_arg_types: &[DataType],
3518    declared_arg_types: &[Option<DataType>],
3519) -> Option<Vec<DataType>> {
3520    if !infered_arg_types.iter().any(has_open_element_type) {
3521        return None;
3522    }
3523    let mut pinned = infered_arg_types.to_vec();
3524    for (inferred, declared) in pinned.iter_mut().zip(declared_arg_types) {
3525        if let Some(declared) = declared {
3526            pin_open_element_types(inferred, declared);
3527        }
3528    }
3529    Some(pinned)
3530}
3531
3532/// Whether this type leaves an element type open, which is what an empty array
3533/// or map literal produces.
3534#[must_use]
3535fn has_open_element_type(ty: &DataType) -> bool {
3536    match ty {
3537        DataType::Array(None) => true,
3538        DataType::Array(Some(element)) => has_open_element_type(element),
3539        DataType::Map(entry) => has_open_slot(entry.0.as_ref()) || has_open_slot(entry.1.as_ref()),
3540        _ => false,
3541    }
3542}
3543
3544/// Whether one half of a map's type is open: either the map names no type there
3545/// at all, or what it names holds an open element type itself.
3546#[must_use]
3547fn has_open_slot(slot: Option<&DataType>) -> bool {
3548    slot.is_none_or(has_open_element_type)
3549}
3550
3551/// The key one specialisation of a function is found by: the type arguments the
3552/// call named, then the argument types it passed.
3553#[must_use]
3554pub fn specialization_key(type_args: &[DataType], arg_types: &[DataType]) -> Box<[DataType]> {
3555    let mut key: Vec<DataType> = Vec::with_capacity(type_args.len() + arg_types.len());
3556    key.extend(type_args.iter().cloned());
3557    key.extend(arg_types.iter().cloned());
3558    key.into_boxed_slice()
3559}
3560
3561/// The type parameters bound while a function's body is compiled: what its
3562/// enclosing `impl` block fixed, plus what the call site named.
3563///
3564/// A parameter neither of them mentions is recorded as unnamed, which stands
3565/// for `any`. A call never has to name its type arguments, so `signal("x")` and
3566/// `signal<any>("x")` compile the same body; without this the body could not
3567/// write `T` in a type position at all.
3568#[must_use]
3569pub fn fn_bindings(fn_id: usize, type_args: &[DataType], state: &State<'_>) -> BindingFrame {
3570    let Some(generics) = state.fns[fn_id].generics.as_ref() else {
3571        return BindingFrame::default();
3572    };
3573    let mut named: Vec<(SmolStr, DataType)> = generics.bindings.to_vec();
3574    for (param, arg) in generics.params.iter().zip(type_args) {
3575        named.push((param.clone(), arg.clone()));
3576    }
3577    let unnamed: Box<[SmolStr]> = generics
3578        .params
3579        .iter()
3580        .filter(|param| !named.iter().any(|(bound, _)| bound == *param))
3581        .cloned()
3582        .collect();
3583    BindingFrame {
3584        named: named.into_boxed_slice(),
3585        unnamed,
3586    }
3587}
3588
3589/// The type a builtin method returns for a receiver, applied across a union
3590/// the way the compile-time receiver check does: a union is accepted only when
3591/// every member is, so the answer is the union of the per-member answers.
3592///
3593/// `rule` gives the return type for one receiver type and `None` for a receiver
3594/// the method does not take, which is the set `builtin_methods` rejects.
3595fn builtin_method_return(
3596    obj_type: &DataType,
3597    rule: fn(&DataType) -> Option<DataType>,
3598) -> Option<DataType> {
3599    let DataType::Union(members) = obj_type else {
3600        return rule(obj_type);
3601    };
3602    let mut types: Vec<DataType> = Vec::with_capacity(members.len());
3603    for member in members {
3604        let member_type = rule(member)?;
3605        if !types.contains(&member_type) {
3606            types.push(member_type);
3607        }
3608    }
3609    Some(DataType::Union(types.into_boxed_slice()).check_poly())
3610}
3611
3612/// Whether a struct field holds a function.
3613///
3614/// A field whose type names one function lets `obj.field(x)` lower to the same
3615/// direct call `fs[0](x)` does. A field declared `fn(...)` holds a function
3616/// value instead, and the call through it dispatches on what the value carries.
3617#[must_use]
3618pub(crate) fn struct_field_holds_fn(struct_id: u16, field: &str, state: &State<'_>) -> bool {
3619    state.structs[struct_id as usize]
3620        .fields
3621        .iter()
3622        .find(|(name, _, _)| name == field)
3623        .is_some_and(|(_, field_type, _)| {
3624            matches!(field_type, DataType::Fn(_) | DataType::FnValue(_))
3625        })
3626}
3627
3628/// The type an operator produces on operands the built-in rules do not accept.
3629///
3630/// A struct or an enum reaches the method its type defines for that operator;
3631/// anything else is the operator error it has always been. A unary operator is
3632/// reported against its one operand, which is the shape [`error_op`] reads from
3633/// a `null` left type.
3634#[allow(clippy::too_many_arguments)]
3635fn operator_result_type(
3636    symbol: &str,
3637    l: &Expr,
3638    r: Option<&Expr>,
3639    t_l: &DataType,
3640    t_r: &DataType,
3641    span_l: Span,
3642    span_r: Span,
3643    v: &mut Vec<Variable>,
3644    ctx: Ctx,
3645    state: &mut State<'_>,
3646) -> DataType {
3647    if let Some(result) =
3648        infer_operator_method(symbol, l, r, t_l, t_r, span_l, span_r, v, ctx, state)
3649    {
3650        return result;
3651    }
3652    let reported = if symbol == UNARY_MINUS_METHOD {
3653        "-"
3654    } else {
3655        symbol
3656    };
3657    let (report_l, report_r) = if r.is_none() {
3658        (&DataType::Null, t_l)
3659    } else {
3660        (t_l, t_r)
3661    };
3662    error_op(
3663        report_l,
3664        report_r,
3665        reported,
3666        span_l,
3667        span_r,
3668        ctx.file_idx,
3669        state.sources,
3670        state.type_names(),
3671    );
3672}
3673
3674impl Expr {
3675    /// Infers this expression's static [`DataType`] without emitting code.
3676    ///
3677    /// # Panics
3678    ///
3679    /// Panics when a call node carries an empty namespace path, which the
3680    /// parser never produces.
3681    pub fn infer_type(&self, v: &mut Vec<Variable>, ctx: Ctx, state: &mut State<'_>) -> DataType {
3682        match self {
3683            Self::Var(name, span) => {
3684                if let Some(var) = v.iter().rfind(|x| &x.name == name) {
3685                    var.var_type.clone()
3686                } else if let Some(fn_id) = state.scope(ctx.file_idx).find_function(&[], name) {
3687                    // A bare identifier that names a function is a function
3688                    // reference (a compile-time value passed to a higher-order
3689                    // function). Its static type is the callee's Fn id.
3690                    DataType::Fn(fn_id as u16)
3691                } else if let Some((enum_id, _)) =
3692                    variant_constructor_at(std::slice::from_ref(name), &[], *span, ctx, state)
3693                {
3694                    DataType::Enum(enum_id)
3695                } else {
3696                    error_unknown_variable(name, *span, v, ctx.file_idx, state.sources);
3697                }
3698            }
3699            Self::Float(_) => DataType::Float,
3700            Self::Int(_) => DataType::Int,
3701            Self::String(_) => DataType::String,
3702            Self::Bool(_) | Self::Eq(..) | Self::NotEq(..) => DataType::Bool,
3703            // A statement match has no value. One used as a value has the
3704            // type its arms give, each read with the names its pattern binds.
3705            Self::Null | Self::Match(_, _, _, _, false) => DataType::Null,
3706            Self::Array(x, _) => DataType::Array(if x.is_empty() {
3707                None
3708            } else {
3709                let elem_types = x
3710                    .iter()
3711                    .map(|elem| elem.infer_type(v, ctx, state))
3712                    .collect::<Vec<DataType>>();
3713                let elem_type = merge_fn_types(&elem_types).unwrap_or_else(|| {
3714                    elem_types
3715                        .into_iter()
3716                        .find(|elem_type| *elem_type != DataType::Unknown)
3717                        .unwrap_or(DataType::Unknown)
3718                });
3719                Some(Box::from(elem_type))
3720            }),
3721            Self::Map(kv_pairs, _) => {
3722                if kv_pairs.is_empty() {
3723                    // An empty map literal has no key/value types yet, like an
3724                    // empty array (`Array(None)`); `insert` fills them in.
3725                    DataType::Map(Box::from((None, None)))
3726                } else {
3727                    let entry_types = kv_pairs
3728                        .iter()
3729                        .map(|(key, _, value, _)| {
3730                            (
3731                                key.infer_type(v, ctx, state),
3732                                value.infer_type(v, ctx, state),
3733                            )
3734                        })
3735                        .collect::<Vec<(DataType, DataType)>>();
3736                    let value_types = entry_types
3737                        .iter()
3738                        .map(|(_, val_t)| val_t.clone())
3739                        .collect::<Vec<DataType>>();
3740                    let kv_type = entry_types
3741                        .into_iter()
3742                        .find(|(key_t, val_t)| {
3743                            key_t != &DataType::Unknown || val_t != &DataType::Unknown
3744                        })
3745                        .map_or(
3746                            (Some(DataType::Unknown), Some(DataType::Unknown)),
3747                            |(key_t, val_t)| (Some(key_t), Some(val_t)),
3748                        );
3749                    // A map whose values are two different functions holds a
3750                    // function value, the same as a list does.
3751                    let kv_type = match merge_fn_types(&value_types) {
3752                        Some(merged) => (kv_type.0, Some(merged)),
3753                        None => kv_type,
3754                    };
3755                    DataType::Map(Box::from(kv_type))
3756                }
3757            }
3758            Self::Add(x, y, span_l, span_r) => {
3759                match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3760                    (DataType::Unknown, t) | (t, DataType::Unknown) => t,
3761                    (DataType::Float, DataType::Float) => DataType::Float,
3762                    (DataType::Int, DataType::Int) => DataType::Int,
3763                    (DataType::String, DataType::String) => DataType::String,
3764                    (DataType::Array(t1), DataType::Array(t2)) => DataType::Array(t1.or(t2)),
3765                    (l, r) => operator_result_type(
3766                        "+",
3767                        x,
3768                        Some(&**y),
3769                        &l,
3770                        &r,
3771                        *span_l,
3772                        *span_r,
3773                        v,
3774                        ctx,
3775                        state,
3776                    ),
3777                }
3778            }
3779            Self::Mul(x, y, span_l, span_r)
3780            | Self::Div(x, y, span_l, span_r)
3781            | Self::Sub(x, y, span_l, span_r)
3782            | Self::Mod(x, y, span_l, span_r)
3783            | Self::Pow(x, y, span_l, span_r) => {
3784                match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3785                    (DataType::Unknown, t) | (t, DataType::Unknown)
3786                        if matches!(t, DataType::Float | DataType::Int | DataType::Unknown) =>
3787                    {
3788                        t
3789                    }
3790                    (DataType::Float, DataType::Float) => DataType::Float,
3791                    (DataType::Int, DataType::Int) => DataType::Int,
3792                    (l, r) => operator_result_type(
3793                        symbol_of_expr(self),
3794                        x,
3795                        Some(&**y),
3796                        &l,
3797                        &r,
3798                        *span_l,
3799                        *span_r,
3800                        v,
3801                        ctx,
3802                        state,
3803                    ),
3804                }
3805            }
3806            Self::BitAnd(x, y, span_l, span_r)
3807            | Self::BitOr(x, y, span_l, span_r)
3808            | Self::BitXor(x, y, span_l, span_r)
3809            | Self::Shl(x, y, span_l, span_r)
3810            | Self::Shr(x, y, span_l, span_r) => {
3811                match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3812                    (DataType::Unknown, t) | (t, DataType::Unknown)
3813                        if matches!(t, DataType::Int | DataType::Unknown) =>
3814                    {
3815                        t
3816                    }
3817                    (DataType::Int, DataType::Int) => DataType::Int,
3818                    (l, r) => operator_result_type(
3819                        symbol_of_expr(self),
3820                        x,
3821                        Some(&**y),
3822                        &l,
3823                        &r,
3824                        *span_l,
3825                        *span_r,
3826                        v,
3827                        ctx,
3828                        state,
3829                    ),
3830                }
3831            }
3832            Self::Sup(x, y, span_l, span_r)
3833            | Self::SupEq(x, y, span_l, span_r)
3834            | Self::Inf(x, y, span_l, span_r)
3835            | Self::InfEq(x, y, span_l, span_r) => {
3836                match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3837                    (DataType::Unknown, DataType::Float | DataType::Int)
3838                    | (DataType::Float | DataType::Int, DataType::Unknown)
3839                    | (DataType::Float, DataType::Float)
3840                    | (DataType::Int, DataType::Int)
3841                    | (DataType::String, DataType::String) => DataType::Bool,
3842                    (l, r) => operator_result_type(
3843                        symbol_of_expr(self),
3844                        x,
3845                        Some(&**y),
3846                        &l,
3847                        &r,
3848                        *span_l,
3849                        *span_r,
3850                        v,
3851                        ctx,
3852                        state,
3853                    ),
3854                }
3855            }
3856            // `is` answers a bool; resolving its right side reports a test the
3857            // operand's type rules out, or a name that is neither a type nor
3858            // a variant.
3859            Self::Is(operand, target, operand_span, target_span) => {
3860                let have = operand.infer_type(v, ctx, state);
3861                crate::compiler::type_test::resolve_test(
3862                    &have,
3863                    target,
3864                    *operand_span,
3865                    *target_span,
3866                    ctx,
3867                    state,
3868                );
3869                DataType::Bool
3870            }
3871            Self::Cast(_, target, _, target_span) => {
3872                crate::compiler::type_test::resolve_type(target, *target_span, ctx, state)
3873            }
3874            Self::BoolAnd(x, y, span_l, span_r) | Self::BoolOr(x, y, span_l, span_r) => {
3875                // The right of an `&&` runs only where the left held, so it
3876                // sees what an `is` on the left proved.
3877                let x_type = x.infer_type(v, ctx, state);
3878                let v_len = v.len();
3879                if matches!(self, Self::BoolAnd(..)) {
3880                    crate::compiler::type_test::declare_condition_facts(x, v, ctx, state);
3881                }
3882                let y_type = y.infer_type(v, ctx, state);
3883                v.truncate(v_len);
3884                match (x_type, y_type) {
3885                    (DataType::Unknown | DataType::Bool, DataType::Bool)
3886                    | (DataType::Bool, DataType::Unknown) => DataType::Bool,
3887                    (l, r) => {
3888                        error_op(
3889                            &l,
3890                            &r,
3891                            "&&",
3892                            *span_l,
3893                            *span_r,
3894                            ctx.file_idx,
3895                            state.sources,
3896                            state.type_names(),
3897                        );
3898                    }
3899                }
3900            }
3901            Self::Neg(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
3902                DataType::Float => DataType::Float,
3903                DataType::Int => DataType::Int,
3904                DataType::Unknown => DataType::Unknown,
3905                operand_type => operator_result_type(
3906                    UNARY_MINUS_METHOD,
3907                    e,
3908                    None,
3909                    &operand_type,
3910                    &operand_type,
3911                    *span_l,
3912                    *span_r,
3913                    v,
3914                    ctx,
3915                    state,
3916                ),
3917            },
3918            Self::BitNot(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
3919                DataType::Int => DataType::Int,
3920                DataType::Unknown => DataType::Unknown,
3921                operand_type => operator_result_type(
3922                    "~",
3923                    e,
3924                    None,
3925                    &operand_type,
3926                    &operand_type,
3927                    *span_l,
3928                    *span_r,
3929                    v,
3930                    ctx,
3931                    state,
3932                ),
3933            },
3934            Self::BoolNeg(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
3935                DataType::Bool => DataType::Bool,
3936                operand_type => error_op(
3937                    &DataType::Null,
3938                    &operand_type,
3939                    "!",
3940                    *span_l,
3941                    *span_r,
3942                    ctx.file_idx,
3943                    state.sources,
3944                    state.type_names(),
3945                ),
3946            },
3947            Self::Propagate(operand, span) => {
3948                let operand_type = operand.infer_type(v, ctx, state);
3949                let Some((success, _)) = propagation_sides(&operand_type, state) else {
3950                    crate::compiler::compiler_errors::error_propagate_operand(
3951                        &operand_type,
3952                        *span,
3953                        ctx.file_idx,
3954                        state.sources,
3955                        state.type_names(),
3956                    );
3957                };
3958                if let Some(frame) = state.propagations.last_mut()
3959                    && !frame.contains(&operand_type)
3960                {
3961                    frame.push(operand_type);
3962                }
3963                success
3964            }
3965            Self::ArrayGetIndex(array, _, span) => match array.infer_type(v, ctx, state) {
3966                DataType::Array(array_type) => array_type.map_or(DataType::Null, |t| *t),
3967                // `m[k]` reads the value stored under `k`.
3968                DataType::Map(m) => m.1.unwrap_or(DataType::Unknown),
3969                DataType::String => DataType::String,
3970                DataType::Unknown => DataType::Unknown,
3971                t => error_type_not_indexable(
3972                    &t,
3973                    *span,
3974                    false,
3975                    ctx.file_idx,
3976                    state.sources,
3977                    state.type_names(),
3978                ),
3979            },
3980            Self::GetStructField(s, field, struct_span, field_span) => {
3981                let s = s.infer_type(v, ctx, state);
3982                if let DataType::Struct(s_id) = s {
3983                    state.structs[s_id as usize]
3984                        .fields
3985                        .iter()
3986                        .find(|x| &x.0 == field)
3987                        .unwrap_or_else(|| {
3988                            let s = &state.structs[s_id as usize];
3989                            error_struct_unknown_field(
3990                                ctx.file_idx,
3991                                *field_span,
3992                                field,
3993                                &s.name,
3994                                &s.fields,
3995                                state.sources,
3996                            )
3997                        })
3998                        .1
3999                        .clone()
4000                } else {
4001                    error_invalid_type(
4002                        &DataType::Struct(0),
4003                        &s,
4004                        *struct_span,
4005                        None,
4006                        None,
4007                        ctx.file_idx,
4008                        state.sources,
4009                        TypeNames {
4010                            structs: state.structs,
4011                            enums: state.enums,
4012                        },
4013                    );
4014                }
4015            }
4016            Self::ArrayGetSlice(array, _, _, span) => match array.infer_type(v, ctx, state) {
4017                DataType::Array(array_type) => DataType::Array(array_type),
4018                DataType::String => DataType::String,
4019                DataType::Unknown => DataType::Unknown,
4020                t => error_type_not_indexable(
4021                    &t,
4022                    *span,
4023                    false,
4024                    ctx.file_idx,
4025                    state.sources,
4026                    state.type_names(),
4027                ),
4028            },
4029            // The return type of an indirect call is the return type of the
4030            // function the callee's type names, at the argument types this
4031            // call site passes.
4032            Self::CallValue(callee, args, span, _) => {
4033                match resolve_callee(callee, *span, v, ctx, state) {
4034                    Callee::Direct(fn_id) => {
4035                        let infered_arg_types = args
4036                            .iter()
4037                            .map(|x| x.infer_type(v, ctx, state))
4038                            .collect::<Vec<DataType>>();
4039                        let fn_name = state.fns[fn_id].name.clone();
4040                        infer_user_fn_return_type(
4041                            fn_id,
4042                            &infered_arg_types,
4043                            &[],
4044                            &fn_name,
4045                            v,
4046                            ctx,
4047                            state,
4048                        )
4049                    }
4050                    Callee::Indirect(fn_type) => {
4051                        indirect_return_type(&fn_type, args, v, ctx, state)
4052                    }
4053                }
4054            }
4055            Self::FunctionCall(args, namespace, span, _, type_args) => {
4056                // `S::default()` is the struct's default; see
4057                // `handle_functions`, which lowers it in the same order.
4058                if let Some(struct_id) =
4059                    struct_default_target(namespace, args, type_args, *span, ctx, state)
4060                {
4061                    return DataType::Struct(struct_id);
4062                }
4063                reject_default_default(namespace, *span, ctx, state);
4064                if let Some(fn_id) = path_call_target(namespace, type_args, *span, ctx, state) {
4065                    let arg_types: Vec<DataType> =
4066                        args.iter().map(|a| a.infer_type(v, ctx, state)).collect();
4067                    let fn_name = state.fns[fn_id].name.clone();
4068                    return infer_user_fn_return_type(
4069                        fn_id,
4070                        &arg_types,
4071                        &[],
4072                        &fn_name,
4073                        v,
4074                        ctx,
4075                        state,
4076                    );
4077                }
4078                // A call written with type arguments names either a variant of a
4079                // generic enum (`Slot<int>::Filled(x)`) or a generic function,
4080                // which may itself sit behind a module alias
4081                // (`m::first<int>(xs)`).
4082                if !type_args.is_empty() {
4083                    if type_args_name_a_variant(namespace, ctx, state) {
4084                        let (enum_id, _) =
4085                            resolve_generic_variant(namespace, type_args, *span, ctx, state);
4086                        return DataType::Enum(enum_id);
4087                    }
4088                    let len = namespace.len() - 1;
4089                    let fn_name = namespace[len].clone();
4090                    let (fn_id, call_type_args) = resolve_generic_call(
4091                        &namespace[..len],
4092                        &fn_name,
4093                        type_args,
4094                        *span,
4095                        ctx,
4096                        state,
4097                    );
4098                    let infered_arg_types = args
4099                        .iter()
4100                        .map(|x| x.infer_type(v, ctx, state))
4101                        .collect::<Vec<DataType>>();
4102                    return infer_user_fn_return_type(
4103                        fn_id,
4104                        &infered_arg_types,
4105                        &call_type_args,
4106                        &fn_name,
4107                        v,
4108                        ctx,
4109                        state,
4110                    );
4111                }
4112                // A qualified enum-variant construction (`Color::Red(x)`) has an
4113                // enum type; intercept before the function paths, which is where
4114                // `handle_functions` intercepts it too.
4115                if namespace.len() >= 2 {
4116                    let arg_types = args
4117                        .iter()
4118                        .map(|x| x.infer_type(v, ctx, state))
4119                        .collect::<Vec<DataType>>();
4120                    if let Some((enum_id, _)) =
4121                        variant_constructor_at(namespace, &arg_types, *span, ctx, state)
4122                    {
4123                        return DataType::Enum(enum_id);
4124                    }
4125                }
4126                // What follows resolves the name in the order `handle_functions`
4127                // lowers it: the path picks the family, and inside a family a
4128                // function in scope wins over a built-in of the same name. One
4129                // flat table of built-in names, read before the scope, is what
4130                // typed a program's own `read` as the string `fs::read` returns.
4131                let (fn_name, path) = namespace.split_last().unwrap();
4132                let infered_args = |v: &mut Vec<Variable>, state: &mut State<'_>| {
4133                    args.iter()
4134                        .map(|x| x.infer_type(v, ctx, state))
4135                        .collect::<Vec<DataType>>()
4136                };
4137                if !path.is_empty() {
4138                    // A call into a `host` or `dylib` block takes its type from
4139                    // the declaration: `gpio::read` is whatever its block says it
4140                    // is, not the `read` that returns a string.
4141                    if let Some(declared) = declared_return_type(namespace, state) {
4142                        return declared;
4143                    }
4144                    let Some(fn_id) = state.scope(ctx.file_idx).find_function(path, fn_name) else {
4145                        error_unknown_function_in_namespace(
4146                            fn_name,
4147                            path,
4148                            *span,
4149                            ctx.file_idx,
4150                            state,
4151                        );
4152                    };
4153                    let infered_arg_types = infered_args(v, state);
4154                    return infer_user_fn_return_type(
4155                        fn_id,
4156                        &infered_arg_types,
4157                        &[],
4158                        fn_name,
4159                        v,
4160                        ctx,
4161                        state,
4162                    );
4163                }
4164                // A call to a function-typed parameter (a higher-order function
4165                // calling the function it was handed): the callee comes from the
4166                // parameter's static Fn type. Lowering reads the same function
4167                // off the scope symbol `handle_user_function` declares for that
4168                // parameter, which inference has not run yet.
4169                // A name that holds a function value: what it hands back is
4170                // what the type says, since no one function is what it names.
4171                if let Some(DataType::FnValue(fn_type)) = v
4172                    .iter()
4173                    .rfind(|var| var.name.as_str() == fn_name.as_str())
4174                    .map(|var| var.var_type.clone())
4175                {
4176                    return indirect_return_type(&fn_type, args, v, ctx, state);
4177                }
4178                if let Some(DataType::Fn(fn_id)) = v
4179                    .iter()
4180                    .rfind(|var| var.name.as_str() == fn_name.as_str())
4181                    .map(|var| var.var_type.clone())
4182                {
4183                    let infered_arg_types = infered_args(v, state);
4184                    return infer_user_fn_return_type(
4185                        fn_id as usize,
4186                        &infered_arg_types,
4187                        &[],
4188                        fn_name,
4189                        v,
4190                        ctx,
4191                        state,
4192                    );
4193                }
4194                if let Some(fn_id) = state.scope(ctx.file_idx).find_function(&[], fn_name) {
4195                    let infered_arg_types = infered_args(v, state);
4196                    return infer_user_fn_return_type(
4197                        fn_id,
4198                        &infered_arg_types,
4199                        &[],
4200                        fn_name,
4201                        v,
4202                        ctx,
4203                        state,
4204                    );
4205                }
4206                if let Some(return_type) =
4207                    builtin_fn_return_type(fn_name, state.namespaces.is_std(ctx.file_idx))
4208                {
4209                    return return_type;
4210                }
4211                // An unqualified call whose name is an enum variant (`Some(x)`)
4212                // constructs that variant. Functions above keep priority.
4213                let arg_types = infered_args(v, state);
4214                if let Some((enum_id, _)) =
4215                    variant_constructor_at(namespace, &arg_types, *span, ctx, state)
4216                {
4217                    return DataType::Enum(enum_id);
4218                }
4219                error_unknown_function(
4220                    fn_name,
4221                    *span,
4222                    state.scope(ctx.file_idx),
4223                    ctx.file_idx,
4224                    state.sources,
4225                )
4226            }
4227            Self::ObjFunctionCall(
4228                obj,
4229                args,
4230                namespace,
4231                obj_span,
4232                fn_span,
4233                args_indexes,
4234                type_args,
4235            ) => {
4236                let method = namespace.last().unwrap().as_str();
4237                // A block's name is a namespace, not a value, so a dot call on
4238                // one is refused before the receiver is typed, which would
4239                // report the name as an unknown variable.
4240                if namespace.len() == 1 {
4241                    reject_block_dot_call(obj, method, v, ctx, state);
4242                }
4243                let obj_type = obj.infer_type(v, ctx, state);
4244                // A user-defined impl method resolves by the receiver's static
4245                // struct type to the mangled free function `Type#method`; its
4246                // return type is inferred exactly like any free function's. This
4247                // is checked before the builtin-method table so a struct method
4248                // that happens to share a name with a builtin (e.g. `len`) uses
4249                // its own return type rather than the builtin's.
4250                if let DataType::Struct(struct_id) = obj_type {
4251                    let struct_name = state.structs[struct_id as usize].name.clone();
4252                    let mangled = mangle_method(&struct_name, method);
4253                    if let Some(fn_id) = state.fns.iter().position(|f| f.name == mangled) {
4254                        check_receiver(fn_id, method, *fn_span, ctx, state);
4255                        let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
4256                        arg_types.push(DataType::Struct(struct_id));
4257                        for a in args {
4258                            arg_types.push(a.infer_type(v, ctx, state));
4259                        }
4260                        let call_type_args = if type_args.is_empty() {
4261                            Vec::new()
4262                        } else {
4263                            resolve_call_type_args(fn_id, method, type_args, *fn_span, ctx, state)
4264                        };
4265                        return infer_user_fn_return_type(
4266                            fn_id,
4267                            &arg_types,
4268                            &call_type_args,
4269                            &mangled,
4270                            v,
4271                            ctx,
4272                            state,
4273                        );
4274                    }
4275                    // No method of that name: a field holding a function is
4276                    // called through the same dot, so `obj.field(x)` calls what
4277                    // the field holds. A method wins, which is why this comes
4278                    // second.
4279                    if struct_field_holds_fn(struct_id, method, state) {
4280                        let callee = Self::GetStructField(
4281                            Box::new(obj.as_ref().clone()),
4282                            SmolStr::new(method),
4283                            *obj_span,
4284                            *fn_span,
4285                        );
4286                        return Self::CallValue(
4287                            Box::new(callee),
4288                            Box::from(args.to_vec()),
4289                            *fn_span,
4290                            Box::from(args_indexes.to_vec()),
4291                        )
4292                        .infer_type(v, ctx, state);
4293                    }
4294                    // Neither: mirror the compile-time error path so inference
4295                    // does not hit the builtin arms with a struct type.
4296                    crate::compiler::compiler_errors::error_no_such_method(
4297                        method,
4298                        &struct_name,
4299                        *fn_span,
4300                        ctx.file_idx,
4301                        state.sources,
4302                    );
4303                }
4304                if let DataType::Enum(enum_id) = obj_type {
4305                    let enum_name = state.enums[enum_id as usize].name.clone();
4306                    let mangled = mangle_method(&enum_name, method);
4307                    if let Some(fn_id) = state.fns.iter().position(|f| f.name == mangled) {
4308                        check_receiver(fn_id, method, *fn_span, ctx, state);
4309                        let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
4310                        arg_types.push(DataType::Enum(enum_id));
4311                        for a in args {
4312                            arg_types.push(a.infer_type(v, ctx, state));
4313                        }
4314                        let call_type_args = if type_args.is_empty() {
4315                            Vec::new()
4316                        } else {
4317                            resolve_call_type_args(fn_id, method, type_args, *fn_span, ctx, state)
4318                        };
4319                        return infer_user_fn_return_type(
4320                            fn_id,
4321                            &arg_types,
4322                            &call_type_args,
4323                            &mangled,
4324                            v,
4325                            ctx,
4326                            state,
4327                        );
4328                    }
4329                    crate::compiler::compiler_errors::error_no_such_method(
4330                        method,
4331                        &enum_name,
4332                        *fn_span,
4333                        ctx.file_idx,
4334                        state.sources,
4335                    );
4336                }
4337                if method == "parse" && obj_type == DataType::String {
4338                    let parsed =
4339                        crate::compiler::methods::parse_call(args, type_args, *fn_span, ctx, state);
4340                    let v_len = v.len();
4341                    crate::compiler::methods::declare_parse_text(v, 0);
4342                    let parsed_type = parsed.infer_type(v, ctx, state);
4343                    v.truncate(v_len);
4344                    return parsed_type;
4345                }
4346                // A builtin-typed receiver resolving to an `impl` method
4347                // (`impl list { fn sum(self) ... }` -> `list#sum`) infers its
4348                // return type from that method, specialized for the receiver
4349                // and argument types.
4350                if let Some(fn_id) = crate::compiler::methods::impl_method_on_builtin(
4351                    method, &obj_type, args, *fn_span, v, ctx, state,
4352                ) {
4353                    check_receiver(fn_id, method, *fn_span, ctx, state);
4354                    let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
4355                    arg_types.push(obj_type.clone());
4356                    for a in args {
4357                        arg_types.push(a.infer_type(v, ctx, state));
4358                    }
4359                    let call_type_args = if type_args.is_empty() {
4360                        Vec::new()
4361                    } else {
4362                        resolve_call_type_args(fn_id, method, type_args, *fn_span, ctx, state)
4363                    };
4364                    return infer_user_fn_return_type(
4365                        fn_id,
4366                        &arg_types,
4367                        &call_type_args,
4368                        method,
4369                        v,
4370                        ctx,
4371                        state,
4372                    );
4373                }
4374                // Each arm below answers for a receiver the compile stage
4375                // accepts. A call whose value is used reaches inference before
4376                // anything compiles it, so a receiver or a name the compile
4377                // stage would reject has to be rejected here, with the same
4378                // diagnostic it would have raised.
4379                macro_rules! receiver_type {
4380                    ($rule:expr, $expected:expr) => {
4381                        builtin_method_return(&obj_type, $rule).unwrap_or_else(|| {
4382                            error_invalid_obj_type(
4383                                $expected,
4384                                &obj_type,
4385                                method,
4386                                *obj_span,
4387                                state.sources,
4388                                ctx.file_idx,
4389                                state.type_names(),
4390                            )
4391                        })
4392                    };
4393                }
4394                match method {
4395                    "uppercase" | "lowercase" | "replace" | "trim" | "trim_start" | "trim_end"
4396                    | "trim_chars" | "trim_start_chars" | "trim_end_chars" | "join" => {
4397                        DataType::String
4398                    }
4399                    "starts_with" | "ends_with" | "contains" => DataType::Bool,
4400                    "len" => DataType::Int,
4401                    "index_of" => {
4402                        receiver_type!(
4403                            |t| matches!(t, DataType::String | DataType::Array(_))
4404                                .then_some(DataType::Null),
4405                            &[DataType::String, DataType::Array(None)]
4406                        );
4407                        let v_len = v.len();
4408                        crate::compiler::methods::declare_index_found(v, 0);
4409                        let found = crate::compiler::methods::index_of_value(*fn_span)
4410                            .infer_type(v, ctx, state);
4411                        v.truncate(v_len);
4412                        found
4413                    }
4414                    "repeat" => receiver_type!(
4415                        |t| match t {
4416                            DataType::String => Some(DataType::String),
4417                            DataType::Array(element) => Some(DataType::Array(element.clone())),
4418                            _ => None,
4419                        },
4420                        &[DataType::String, DataType::Array(None)]
4421                    ),
4422                    // A string's reverse is a new string; a list's reverses
4423                    // the list in place and, like every method that changes
4424                    // its receiver, returns nothing.
4425                    "reverse" => receiver_type!(
4426                        |t| match t {
4427                            DataType::String => Some(DataType::String),
4428                            DataType::Array(_) => Some(DataType::Null),
4429                            _ => None,
4430                        },
4431                        &[DataType::String, DataType::Array(None)]
4432                    ),
4433                    "push" | "sort" | "remove" => DataType::Null,
4434                    "sqrt" | "round" | "floor" => DataType::Float,
4435                    "abs" => receiver_type!(
4436                        |t| match t {
4437                            DataType::Float => Some(DataType::Float),
4438                            DataType::Int => Some(DataType::Int),
4439                            _ => None,
4440                        },
4441                        &[DataType::Int, DataType::Float]
4442                    ),
4443                    "split" => receiver_type!(
4444                        |t| match t {
4445                            DataType::String =>
4446                                Some(DataType::Array(Some(Box::from(DataType::String)))),
4447                            DataType::Array(element) => Some(DataType::Array(Some(Box::from(
4448                                DataType::Array(element.clone())
4449                            )))),
4450                            _ => None,
4451                        },
4452                        &[DataType::String, DataType::Array(None)]
4453                    ),
4454                    "keys" => receiver_type!(
4455                        |t| match t {
4456                            DataType::Map(m) => Some(DataType::Array(m.0.clone().map(Box::new))),
4457                            _ => None,
4458                        },
4459                        &[DataType::Map(Box::from((None, None)))]
4460                    ),
4461                    "values" => receiver_type!(
4462                        |t| match t {
4463                            DataType::Map(m) => Some(DataType::Array(m.1.clone().map(Box::new))),
4464                            _ => None,
4465                        },
4466                        &[DataType::Map(Box::from((None, None)))]
4467                    ),
4468                    // No builtin takes this name, and the impl-method and
4469                    // struct/enum lookups above already missed, so the call
4470                    // names nothing. The report names the module that
4471                    // declares the method, or the spelling that replaced it.
4472                    _ => crate::compiler::compiler_errors::error_unknown_builtin_method(
4473                        method,
4474                        crate::compiler::methods::builtin_receiver_name(&obj_type),
4475                        *fn_span,
4476                        ctx.file_idx,
4477                        state.sources,
4478                    ),
4479                }
4480            }
4481            Self::Match(scrutinee, arms, wildcard, span, true) => {
4482                let scrut_type = scrutinee.infer_type(v, ctx, state);
4483                let mut types: Vec<DataType> = Vec::with_capacity(arms.len() + 1);
4484                for (patterns, body) in arms {
4485                    let v_len = v.len();
4486                    if let DataType::Enum(enum_id) = scrut_type {
4487                        crate::compiler::declare_arm_bindings(
4488                            enum_id, patterns, *span, v, ctx, state,
4489                        );
4490                    }
4491                    types.push(body[body.len() - 1].infer_type(v, ctx, state));
4492                    v.truncate(v_len);
4493                }
4494                if let Some(w) = wildcard {
4495                    types.push(w[w.len() - 1].infer_type(v, ctx, state));
4496                }
4497                branch_value_type(types, ctx, state)
4498            }
4499            Self::InlineCondition(condition, code, _, _) => {
4500                // Each branch is typed with what its condition proved.
4501                let mut types: Vec<DataType> = Vec::with_capacity(code.len());
4502                let v_len = v.len();
4503                crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
4504                types.push(code[0].infer_type(v, ctx, state));
4505                v.truncate(v_len);
4506                for t in &code[0..] {
4507                    if let Self::ElseIfBlock(condition, code, _) = t {
4508                        crate::compiler::type_test::declare_condition_facts(
4509                            condition, v, ctx, state,
4510                        );
4511                        types.push(code[0].infer_type(v, ctx, state));
4512                        v.truncate(v_len);
4513                    } else if let Self::ElseBlock(code) = t {
4514                        types.push(code[0].infer_type(v, ctx, state));
4515                    }
4516                }
4517                branch_value_type(types, ctx, state)
4518            }
4519            Self::NamespacedRef(path, span, type_args) => {
4520                if !type_args.is_empty() {
4521                    let (enum_id, _) = resolve_generic_variant(path, type_args, *span, ctx, state);
4522                    return DataType::Enum(enum_id);
4523                }
4524                if let Some((enum_id, _)) = variant_constructor_at(path, &[], *span, ctx, state) {
4525                    DataType::Enum(enum_id)
4526                } else {
4527                    crate::compiler::compiler_errors::error_enum(
4528                        "Unknown enum variant",
4529                        &format!("{} does not name an enum variant", path.join("::")),
4530                        *span,
4531                        ctx.file_idx,
4532                        state.sources,
4533                    );
4534                }
4535            }
4536            Self::Struct(namespace, fields, span, type_args, base) => {
4537                DataType::Struct(literal_struct_id(
4538                    namespace,
4539                    fields,
4540                    type_args,
4541                    base.as_ref().and_then(|b| b.0.base()),
4542                    *span,
4543                    v,
4544                    ctx,
4545                    state,
4546                ))
4547            }
4548            Self::StructDefault(struct_id, _) => DataType::Struct(*struct_id),
4549            Self::AnonymousFunction(args, code, span) => {
4550                // An anonymous function is hoisted to a synthetic non-capturing
4551                // top-level function and referred to by its Fn id, exactly like a
4552                // named function reference. Inference runs many times, so the
4553                // hoist is keyed by the file and span the literal was written at
4554                // and reused: the first encounter registers the function, later
4555                // ones resolve to the same id, and two files whose closures sit
4556                // at the same offset stay apart.
4557                let fn_name = format_args!(
4558                    "{ANON_FN_PREFIX}{}:{}:{}",
4559                    ctx.file_idx, span.start, span.end
4560                )
4561                .to_smolstr();
4562                if let Some(id) = state.fns.iter().rposition(|f| f.name == fn_name) {
4563                    return DataType::Fn(id as u16);
4564                }
4565                let returns_null = check_if_returns_void(code);
4566                let mut callees = Vec::new();
4567                collect_direct_fn_calls(code, None, &mut callees);
4568                // The scope the literal is written in is the one its body
4569                // reads, and this is where that scope is in hand: the body
4570                // itself compiles later, at the first call, which can sit in
4571                // another function entirely. A free name that resolves to no
4572                // variable here names a declared function, which the body
4573                // reaches the same way any other code does.
4574                let captures: Box<[(SmolStr, DataType, Option<DataType>)]> =
4575                    closure_free_names(args, code)
4576                        .into_iter()
4577                        .filter_map(|name| {
4578                            v.iter()
4579                                .rfind(|var| var.name == name)
4580                                .map(|var| (name, var.var_type.clone(), var.declared.clone()))
4581                        })
4582                        .collect();
4583                let id = state.fns.len() as u16;
4584                state.fns.push(Function {
4585                    name: fn_name,
4586                    args: args.iter().map(|a| (a.clone(), None)).collect(),
4587                    code: Rc::from(code.clone()),
4588                    impls: Vec::new(),
4589                    is_recursive: None,
4590                    returns_null,
4591                    src_file: ctx.file_idx,
4592                    return_type_cache: Vec::new(),
4593                    direct_calls: callees.into_boxed_slice(),
4594                    name_span: *span,
4595                    // An anonymous function takes no return annotation.
4596                    return_type: None,
4597                    generics: None,
4598                    captures,
4599                    entry_register: None,
4600                });
4601                DataType::Fn(id)
4602            }
4603            _ => unsafe { unreachable_unchecked() },
4604        }
4605    }
4606}
4607
4608/// The type of a construct used as a value, an `if` or a `match`, from the
4609/// types its branches give, in order.
4610///
4611/// Branches that give different functions give a function value, which a call
4612/// dispatches on, so every branch's type is kept for that test: `Fn` types
4613/// compare equal whichever function they name. Otherwise the branches give a
4614/// union of their distinct types.
4615///
4616/// Two instantiations of one generic declaration merge the way two returns of
4617/// a body do (see [`add_return_type`]): `if c { Some(x) } else { None }` is an
4618/// `Option<int>`, not a union of it with the `Option<any>` the bare `None`
4619/// names.
4620fn branch_value_type(types: Vec<DataType>, ctx: Ctx, state: &mut State<'_>) -> DataType {
4621    if let Some(fn_value) = merge_fn_types(&types) {
4622        return fn_value;
4623    }
4624    let mut distinct: Vec<DataType> = Vec::with_capacity(types.len());
4625    for t in types {
4626        if distinct.contains(&t) {
4627            continue;
4628        }
4629        if let Some((i, merged)) = distinct
4630            .iter()
4631            .enumerate()
4632            .find_map(|(i, held)| merge_instantiations(held, &t, ctx, state).map(|m| (i, m)))
4633        {
4634            distinct[i] = merged;
4635            continue;
4636        }
4637        distinct.push(t);
4638    }
4639    DataType::Union(Box::from(distinct)).check_poly()
4640}
4641
4642/// The type a declared function has where a value holds it.
4643///
4644/// A function whose parameters and return are annotated says its own signature,
4645/// so a call through the value is checked against what the declaration names.
4646/// One the compiler infers says only which function it holds, and the first
4647/// call through the value settles the types its body is compiled at. The
4648/// function is a candidate of the type either way, which is what compiles the
4649/// body a call through the value jumps to.
4650#[must_use]
4651pub fn declared_fn_value_type(fn_id: u16, state: &State<'_>) -> DataType {
4652    let function = &state.fns[fn_id as usize];
4653    let params: Option<Vec<DataType>> = function
4654        .generics
4655        .is_none()
4656        .then(|| function.args.iter().map(|(_, arg)| arg.clone()).collect())
4657        .flatten();
4658    let return_type = function
4659        .return_type
4660        .as_ref()
4661        .map(|(declared, _)| declared.clone())
4662        .or_else(|| function.returns_null.then_some(DataType::Null));
4663    let sig = match (params, return_type) {
4664        (Some(params), Some(return_type)) => Some((params.into_boxed_slice(), return_type)),
4665        _ => None,
4666    };
4667    DataType::FnValue(Box::new(FnValue {
4668        sig,
4669        candidates: Box::from([fn_id]),
4670        set: None,
4671    }))
4672}
4673
4674/// The type of `expr` where it is a bare name that means a declared function
4675/// and the position holds the function rather than calls it.
4676///
4677/// `None` for anything else, which leaves a closure bound to a name and a call
4678/// through a name the compiler can settle lowering to the jump they were.
4679#[must_use]
4680pub fn bare_fn_value_type(
4681    expr: &Expr,
4682    v: &[Variable],
4683    ctx: Ctx,
4684    state: &State<'_>,
4685) -> Option<DataType> {
4686    let Expr::Var(name, _) = expr else {
4687        return None;
4688    };
4689    if v.iter().any(|var| var.name == *name) {
4690        return None;
4691    }
4692    let fn_id = state.scope(ctx.file_idx).find_function(&[], name)?;
4693    Some(declared_fn_value_type(fn_id as u16, state))
4694}
4695
4696/// The one function type that holds every type in `types`, where more than one
4697/// function can land in the same position.
4698///
4699/// A position every function in it agrees on stays pinned to that function, so
4700/// a list of one closure and a call through it resolve at compile time exactly
4701/// as they did. Two different functions make the position a function value: no
4702/// function is the one it holds, so the call dispatches on what the value
4703/// carries. `None` where the types name no function, which leaves the position
4704/// to the ordinary rules.
4705#[must_use]
4706pub fn merge_fn_types(types: &[DataType]) -> Option<DataType> {
4707    let mut candidates: Vec<u16> = Vec::new();
4708    let mut sig = None;
4709    let mut saw_fn = false;
4710    for t in types {
4711        match t {
4712            DataType::Fn(id) => {
4713                saw_fn = true;
4714                if !candidates.contains(id) {
4715                    candidates.push(*id);
4716                }
4717            }
4718            DataType::FnValue(fn_type) => {
4719                saw_fn = true;
4720                if sig.is_none() {
4721                    sig.clone_from(&fn_type.sig);
4722                }
4723                for id in &fn_type.candidates {
4724                    if !candidates.contains(id) {
4725                        candidates.push(*id);
4726                    }
4727                }
4728            }
4729            _ => {}
4730        }
4731    }
4732    if !saw_fn || (sig.is_none() && candidates.len() < 2) {
4733        return None;
4734    }
4735    Some(DataType::FnValue(Box::new(FnValue {
4736        sig,
4737        candidates: candidates.into_boxed_slice(),
4738        set: None,
4739    })))
4740}
4741
4742/// What a call through a function value hands back.
4743///
4744/// A declared `fn(...) -> R` says it. A type inferred from the functions
4745/// written into the position asks each of them, at the argument types this call
4746/// passes, and they have to agree.
4747pub fn indirect_return_type(
4748    fn_type: &FnValue,
4749    args: &[Expr],
4750    v: &mut Vec<Variable>,
4751    ctx: Ctx,
4752    state: &mut State<'_>,
4753) -> DataType {
4754    if let Some((_, return_type)) = &fn_type.sig {
4755        return return_type.clone();
4756    }
4757    let infered_arg_types = args
4758        .iter()
4759        .map(|arg| arg.infer_type(v, ctx, state))
4760        .collect::<Vec<DataType>>();
4761    let return_types = state
4762        .fn_value_candidates(fn_type)
4763        .into_iter()
4764        .map(|fn_id| {
4765            let fn_id = fn_id as usize;
4766            let fn_name = state.fns[fn_id].name.clone();
4767            infer_user_fn_return_type(fn_id, &infered_arg_types, &[], &fn_name, v, ctx, state)
4768        })
4769        .collect::<Vec<DataType>>();
4770    let mut return_types = return_types.into_iter();
4771    match return_types.next() {
4772        None => DataType::Unknown,
4773        Some(first) if return_types.len() == 0 => first,
4774        Some(first) => {
4775            let all = std::iter::once(first).chain(return_types).collect();
4776            DataType::Union(all).check_poly()
4777        }
4778    }
4779}