Skip to main content

cove_sema/
typeck.rs

1//! Static type checking, between resolution and execution.
2//!
3//! ADR 0004 decides what this checks and how: annotations are mandatory at
4//! boundaries and inferred inside, types are nominal with no subtyping, and
5//! checking is per-module. A module sees its own declarations, whatever it
6//! imports with `use`, and the builtins. ADR 0006 replaces that ADR's
7//! "parametric and unbounded" with "parametric with bounds", which is the
8//! change it anticipated.
9//!
10//! # The import environment
11//!
12//! ADR 0005 makes a module able to name another module's exported
13//! declarations, and ADR 0004 anticipated exactly one change for it: the
14//! checker gains an import environment. That is `Checker::import`, and
15//! nothing else about the pass is different.
16//!
17//! One rule holds it together. A declaration is known by the module that
18//! declares it: its table key is its bare name inside that module, and
19//! `module.Name` everywhere else. So two modules may each declare a
20//! `Config` without the checker confusing them, and a type keeps one
21//! identity however many imports it is reached through. Traits and
22//! conformances travel with it, so an imported trait can be named in a bound
23//! and a conformance declared anywhere in the package is found wherever the
24//! trait and the type are both in scope. Modules are checked in dependency
25//! order, which exists because ADR 0005 forbids import cycles.
26//!
27//! # Traits and the two dispatch forms
28//!
29//! A bound (`fn render<T: Display>(value: T)`) is checked at the call site
30//! that instantiates `T`, because that is the only place a type parameter is
31//! given a type. Inside the body the parameter is rigid and its bound is a
32//! fact: a method call on a value of type `T` resolves through `T`'s bounds,
33//! and a parameter with no bound has no methods at all.
34//!
35//! `dyn Display` is a type of its own, not a type parameter. Only the
36//! trait's plain `self`-taking methods can be called on it: an associated
37//! function has no receiver to dispatch on, and a `var self` method needs the
38//! caller's own place, which a converted value is not. It never satisfies a
39//! bound either — not even its own trait's — because it is not a type
40//! parameter.
41//!
42//! # The one implicit conversion
43//!
44//! A concrete value is accepted where a `dyn Trait` is expected, exactly when
45//! it conforms to that trait. That is the language's only implicit
46//! conversion, and it is deliberately narrow:
47//!
48//! - it runs one way only: a `dyn Trait` value is never a concrete type, and
49//!   never converts to another `dyn Trait`;
50//! - it never reaches inside a generic argument. `Array<Booking>` is not an
51//!   `Array<dyn Display>`, because generic arguments are invariant here like
52//!   everywhere else. `[booking, receipt]` *is* an `Array<dyn Display>`,
53//!   because each element is checked against `dyn Display` on its own;
54//! - it satisfies no bound. `render(someDyn)` is an error even when
55//!   `render<T: Display>` and the value is a `dyn Display`.
56//!
57//! It is spelled out here, in `coerces`, and nowhere else: every place that
58//! compares a found type against an expected one goes through
59//! `Checker::expect` or `unify`, and both consult it.
60//!
61//! # The type representation
62//!
63//! [`Ty`] is a closed enum of the builtin types, the structs and enums the
64//! module declares, function types, rigid type parameters, `dyn Trait`, and
65//! the `Any` a Host API schema declares. Two types are equal when they name
66//! the same declaration and their arguments are equal: there is no subtyping
67//! and no variance, so `Array<Int>` is not an `Array<Any>`.
68//!
69//! Three variants are not types a program can write:
70//!
71//! - [`Ty::Unknown`] is *the checker does not know*, and carries an
72//!   [`Unknown`] saying why. It compares equal to every type whatever the
73//!   reason, and every operation on it produces an unknown again, so one
74//!   unknown never becomes a cascade of wrong errors.
75//! - [`Ty::Never`] is the type of an expression that does not produce a
76//!   value, such as `return`. It also compares equal to every type, because
77//!   an arm that never produces a value never disagrees with one that does.
78//! - [`Ty::Any`] is what a Host API schema declares where nothing it does
79//!   depends on a type. It compares equal to every type and every operation
80//!   on it abstains, which is what the schema promised; what it is *not* is
81//!   a `Ty::Unknown`, because a promise and an absence are different facts
82//!   and a reader of [`Facts`] has to be able to tell them apart. The two
83//!   share one erased representation in the backends, which is
84//!   `cove_ir`'s `Shapes` to decide and not this pass's.
85//!
86//! # The four kinds of unknown
87//!
88//! `Unknown` is one variant doing four jobs, and telling them apart is what
89//! makes a successful `cove check` worth reading. The kind is *carried by the
90//! type*, not implied by which constructor built it, so a form can ask what
91//! the silence around it is made of — and so one kind can be asserted never
92//! to escape:
93//!
94//! | kind | constructor | `cove check` |
95//! |------|-------------|--------------|
96//! | [`Unknown::Recovery`] | `Ty::recovery` | silent |
97//! | [`Unknown::DynamicBoundary`] | `Ty::dynamic_boundary` | silent here; see below |
98//! | [`Unknown::Unconstrained`] | `Ty::unconstrained` | error |
99//! | [`Unknown::Placeholder`] | `Ty::placeholder` | must not escape |
100//! | language gap | *none* | warning or error |
101//!
102//! **Recovery** is an unknown the checker owes no further word about,
103//! because everything there was to say was said — here, a few lines above
104//! the constructor, or upstream where the unknown being propagated came
105//! from. Every "the receiver is already unknown, so abstain" branch is one
106//! of these, and none of them adds a diagnostic. This is the job that keeps
107//! one mistake from printing as ten. Its reach goes one step further than
108//! the branch that builds it: the arguments of a rejected call are walked
109//! against a recovery expectation, so an empty array or an unannotated
110//! lambda parameter written inside one is not reported as a second mistake.
111//!
112//! **A dynamic boundary** is a host no Host API schema describes. ADR 0001's
113//! Host API schema is [`cove_schema`], which this crate reads:
114//! `console.println`, `http.Request`, and every other operation and type of
115//! a shipped host module is checked against the same description the
116//! boundary dispatches it through — and so is every operation and type of a
117//! module an *embedder* describes, because ADR 0017 lets an embedding hand
118//! its own [`cove_schema::ModuleSchema`] to `Compiler::with_host_schema` and
119//! this pass reads the two the same way. What stays unknown is a module
120//! neither table names: a host may register whatever it likes, and one it
121//! never described is one no compiler could read.
122//!
123//! Nothing is reported per call into one. The fact is about the `use` that
124//! named the module and about the compilation that was not shown it: no edit
125//! to `sensors.read` can fix it, the remedy is one thing to say however many
126//! calls a program makes, and it is the same remedy for a call, a member
127//! read, and a value passed in. `cove::resolve::unchecked_host` puts that
128//! warning at the `use`, where it belongs. What this pass owes such a call
129//! is the abstention itself, handed to the arguments as their expected type,
130//! so that a callback registered with an unschema'd host — the shape an
131//! embedding is written in — is not asked to state a type nothing on this
132//! side could have stated. A *type* named through such a module still warns
133//! ([`HOST_TYPE`]), as it did before this classification existed.
134//!
135//! `Checker::host_schema` is the one place an embedder-supplied schema has
136//! to reach, and reaching it is all it takes to turn any of that back into
137//! ordinary checking.
138//!
139//! **An unconstrained** unknown is a type nothing that has been read
140//! states: a type parameter no argument, annotation, expected type or later
141//! use settles. It is [`UNCONSTRAINED`], and it is an *error* — an empty
142//! array literal, a bare `None`, a struct's parameter no field mentions, an
143//! unannotated lambda parameter nothing expects a type of, a binding whose
144//! uses say nothing, and `Ok(1)` in a place expecting no `Result` are all
145//! the same fact and are all refused. `crates/cove-sema/tests/settled.rs` is
146//! the invariant that says why: a type nothing settles has no layout, so a
147//! program holding one is not a program a backend can run, and a `cove
148//! check` that reported no error about it would be reporting that the
149//! program is ready.
150//!
151//! A schema's `Any` is *not* one of these. It used to be — the same value,
152//! from a source that had said something exact — and it is [`Ty::Any`] now.
153//! What the schema said still costs the rest of the program wherever it is a
154//! result or a field, and those are noted ([`UNCONSTRAINED_RESULT`],
155//! [`UNCONSTRAINED_FIELD`]). A note rather than a warning, because the
156//! schema chose this and no strictness setting can make the checker prove
157//! what nobody stated.
158//!
159//! One shape of unconstrained type gets a diagnostic of its own. A use that
160//! describes a binding in terms of itself — `v.push(v)` — asks for
161//! `μX. Vector<X>`: regular, finitely representable, and with no surface
162//! syntax, because recursion here is nominal and this inference is
163//! structural. That is [`RECURSIVE_TYPE`], and it points at the use and
164//! names the declaration that would write the type instead.
165//!
166//! **A placeholder** is not a fourth kind of not-knowing; it is the marker
167//! for a position no reachable program observes. Some are internal
168//! positions the surrounding form settles before reading them, and some are
169//! branches no reachable program takes at all. `Checker::expr` and
170//! `Checker::declare` assert in debug builds that one never reaches a type
171//! a program can observe, so the claim each site makes about itself is one
172//! the test suite holds it to rather than a comment. Two sites used to break
173//! it — a struct's type parameter that no field mentions, and
174//! `Result.mapError`'s expected callback result — and each let a program
175//! check clean and then be wrong at run time.
176//!
177//! **A language gap** is information the checker should have been given and
178//! was not. These are the ones that used to pass silently, and none of them
179//! does now:
180//!
181//! - a name nothing in scope explains, capitalized or not, is an error
182//!   ([`UNRESOLVED_NAME`], [`UNKNOWN_NAME`], [`UNKNOWN_TYPE`]). A
183//!   capitalized one used to be assumed to come from a host and warn; a host
184//!   reaches a module through `use` like everything else, so the assumption
185//!   named no real way for the name to arrive and only let an unknown
186//!   through to validate whatever was done with it;
187//! - a type or a module written where a value belongs is an error
188//!   ([`NOT_A_VALUE`]). `Vector` in `Vector.of(1, 2)` is understood as part
189//!   of the call; a bare `Vector`, `console`, or `Counter` is not a form
190//!   with a type in this system, and never was. A host *operation* is not
191//!   one of these: it is a value, and reading the schema gives it the
192//!   function type it declares, so `let log = console.println` keeps working
193//!   and a call through the value is checked. The one exception is a
194//!   variadic operation, which no `fn` type in this language can describe —
195//!   the language's own gap, said out loud as a note
196//!   ([`VARIADIC_AS_VALUE`]) rather than hidden or refused;
197//! - an early `return` in a function value nothing expects is an error
198//!   ([`LAMBDA_RETURN`]). Such a lambda takes its result from its body's
199//!   value, so a `return` produces one where the body's value is not, and
200//!   nothing written anywhere says what the two have to agree on. "Nothing
201//!   expects it" is asked of the expected *result* type: an expectation this
202//!   pass abstained about answers for it, and one whose own result is a
203//!   placeholder does not;
204//! - an unannotated lambda parameter, an empty array literal, a bare `None`,
205//!   and a struct's type parameter no field mentions, each in a place that
206//!   expects nothing in particular, are refused ([`UNCONSTRAINED`]). Writing
207//!   the type is always available, which is what each `help` says. "Expects
208//!   nothing in particular" excludes a place this pass already abstained
209//!   about — a schema's `Any` answers for what is given to it — and a
210//!   sibling or a branch that settles the type counts as saying it:
211//!   `[[], [1]]` and `if c { None } else { Some(1) }` are proved, and are
212//!   silent.
213//!
214//! One thing is deliberately *not* an unknown: the value a `scope` binds is
215//! [`Ty::Scope`], a type the language gives no name to but this pass knows
216//! exactly.
217//!
218//! # What a `scope` asks of the function it is written in
219//!
220//! Leaving a `scope` waits for every task nothing awaited, and a task whose
221//! value is `Err(error)` returns that error from the enclosing function,
222//! exactly as `?` would — that is `cove_runtime::task::wait_for_children`,
223//! and it is the whole reason this pass has anything to say about a scope.
224//!
225//! So a `scope` constrains its function only where one of its children can
226//! produce a Cove `Err`. A scope of `Unit`-answering children asks nothing,
227//! and stays at home in a function that answers nothing. `Checker::spawned`,
228//! `Checker::handle_awaited` and `Checker::leaving_scope` are the three
229//! points of that: what was spawned, what the program settled itself, and
230//! what is left for the scope to return. A child that *raises* — fuel, an
231//! invariant, a Host-boundary failure — is not part of it: that travels as a
232//! runtime fault rather than as the function's value, so it depends on no
233//! Cove return type.
234//!
235//! # Inference variables
236//!
237//! One of those unknowns carries a number. [`Unknown::Var`] is an
238//! unconstrained unknown with an identity, and the identity is what lets the
239//! *uses* of a local binding settle a type its initializer left open:
240//!
241//! ```text
242//! var log = Vector.of()      // Vector<a>
243//! log.push(text)             // a = String
244//! ```
245//!
246//! `Checker::open_result` mints one wherever a call's result mentions a type
247//! parameter that neither its arguments nor its call site settled. A `let`
248//! or a `var` with no written type gives every variable in the type it takes
249//! to that binding (`Checker::attach`). Every comparison of a found type
250//! with an expected one is read for what it says about them
251//! (`Checker::constrain`, reached from `Checker::expect` and
252//! `Checker::check_argument`), so a method call, an argument position, an
253//! assignment and a declared return type are one rule and not four. And the
254//! end of the body writes the answers back (`Checker::finish_inference`).
255//!
256//! Issue #240 decided this, and drew the boundaries around it:
257//!
258//! - only a *local binding* holds one. A parameter, a return type, and
259//!   everything else a declaration publishes state their types where they
260//!   are written, and none of them reaches this;
261//! - two uses that disagree are an error ([`INFERENCE_CONFLICT`]) naming
262//!   both, rather than the first one quietly winning;
263//! - a variable nothing settled is asked for the annotation
264//!   ([`UNCONSTRAINED`]), in the same shape the empty array literal is: at
265//!   the binding when one took it, and at the call that produced the value
266//!   when none did;
267//! - the scope ends with the body. A variable never outlives the
268//!   declaration that minted it, so no use in one declaration settles a type
269//!   in another, and nothing downstream of the checker sees one: what
270//!   reaches [`Facts`] is the settled type, or the plain unconstrained
271//!   unknown that a variable nothing settled was all along.
272//!
273//! It is one mechanism and not a rule per collection: `Vector.of()`,
274//! `Set.of()`, `Map.of()`, a generic declaration of the package's own, a
275//! generic enum case, and every builtin method whose result mentions an
276//! unsettled parameter all reach `open_result`. Two nearby gaps are
277//! deliberately *not* on it, because both report where they are written
278//! rather than carrying a type forward: an empty array literal and an
279//! unannotated lambda parameter. Moving them onto this would move their
280//! diagnostics as well, which is a decision about where those warnings
281//! belong rather than one about inference.
282//!
283//! What a constraint cannot say, it does not say. A use whose own type still
284//! holds a variable settles nothing — `v.push(v)` asks for a `Vector` of
285//! itself, and no annotation writes that either. `TyVar::spoken_for` is that
286//! case, and it is [`RECURSIVE_TYPE`]: the type exists, it cannot be
287//! written, and a declared type is what writes it instead. It used to be
288//! carried silently, which made it the one way a check that reported nothing
289//! could hand a backend a `Vector<_>`.
290//!
291//! A variable given to a place this pass *abstained* about is settled by the
292//! abstention rather than reported. A schema declaring `Any` said there is
293//! nothing here that depends on a type, so `Ok(())` written in such a
294//! callback takes `Any` as its failure type; asking the program to state one
295//! would be asking it to state what the place declared it need not.
296//! `TyVar::abstained` is that.
297//!
298//! # What a clean check guarantees
299//!
300//! `cove check` reporting nothing at all means every type the package wrote
301//! down was checked: every struct field, declared parameter, call to a
302//! declared or imported function, and call into a Host API module some
303//! schema describes — shipped or embedder-supplied — was checked against a
304//! written or schema-declared type.
305//!
306//! One silence is not covered by that, and it is named here rather than left
307//! to be discovered: a host module no schema describes. Nothing about a call
308//! into one is proved, and nothing is said about it here either, because the
309//! fact belongs to the `use` that names the module, where
310//! `cove::resolve::unchecked_host` warns about it once. So a package
311//! reaching such a host does not have a clean check: it has one warning per
312//! `use`, naming the module whose schema was never handed over. It is the
313//! one exclusion `crates/cove-sema/tests/settled.rs` makes, for the same
314//! reason: what is missing is a description this *build* was never given, no
315//! edit to the call fixes it, and a program that reaches one cannot be
316//! lowered.
317//!
318//! There used to be a second: a type parameter of a builtin constructor that
319//! nothing settles. `Ok(1)` in a place expecting no `Result` was a
320//! `Result<Int, _>` with the `_` carried rather than reported. What `Ok(1)`
321//! alone means is settled now, and the answer is that it means nothing until
322//! something says what the failure type is — `Result` is generic in both,
323//! and a package writing `Result<Int, ParseError>` is why guessing `Error`
324//! would be a guess. The constructor opens an inference variable like any
325//! other call, a later use may settle it, and [`UNCONSTRAINED`] asks for the
326//! annotation when none does.
327//!
328//! A check whose only output is *notes* means the same, except at the places
329//! the notes name: a shipped schema declared `Any` there, or a variadic host
330//! operation was used as a value, and what the program does with the value
331//! from that point on is the boundary's to check.
332//!
333//! A check with *warnings* means the package left the checker something to
334//! infer that nothing written settles. `cove check --deny-warnings` is
335//! exactly the request that it did not.
336//!
337//! What none of these guarantee is anything the runtime keeps for itself:
338//! task safety of a host resource, and every rule listed under *What the
339//! runtime keeps* below.
340//!
341//! Two things about a shipped host module are read here and *not* enforced by
342//! the boundary, which is worth stating in one place. A host type's fields
343//! are typed from the schema — `request.path` is a `String` because the
344//! schema says a `Request` has one — while the boundary checks a declared
345//! type by name only, so what this checks is that the *program* built the
346//! value the schema describes. And a host resource's declared task-safety is
347//! still the runtime's alone: `Ty::Host` says nothing about crossing a task
348//! boundary, so a resource declaring `task_safe: false` is refused where it
349//! crosses and not before.
350//!
351//! # Places, and what kind of analysis this pass is
352//!
353//! This pass is not only a type checker. ADR 0021 settles what else it is:
354//! it may decide any fact the source settles through the binding structure
355//! it already walks, and mutability is one. `let` creates a read-only place
356//! and `var` a mutable one, so which places a program may write is read off
357//! the scope stack — `Checker::place_mutability` is the definition, and
358//! the interpreter and `cove_ir::lower` had a reading of it each until it
359//! moved here.
360//!
361//! Four constructs are refused by it, in the words the interpreter refused
362//! them in: an assignment to a read-only place, a `var` argument that is a
363//! read-only place or is no place at all, and a mutating receiver that is
364//! either. A fifth is the same kind of fact about a call's shape rather than
365//! about a place: labeled arguments appear in declaration order, and
366//! [`LABEL_ORDER`] is what says so.
367//!
368//! Two more are facts about a *declaration* rather than about a call, and
369//! ADR 0021's rule reaches them by the same test — the parameter list is
370//! structure this pass already walks to build a signature. A variadic
371//! parameter is the last one its declaration writes ([`VARIADIC_POSITION`])
372//! and is not written with a default ([`VARIADIC_DEFAULT`]).
373//! `Checker::check_variadic_shape` is where both are decided. Unlike the
374//! five above, these two are wording of this pass's own, because there was
375//! no behaviour to keep: `Interpreter::assign_labels` and `bind_params`
376//! disagreed about what a non-last variadic parameter binds, and nothing in
377//! either backend could ever reach a variadic parameter's default.
378//!
379//! A third is about where a variadic parameter may be written at all: on a
380//! declaration, and not on a function value ([`VARIADIC_LAMBDA`],
381//! `Checker::lambda`). This one does not come from ADR 0021 but from
382//! ADR 0016 — a function type names a fixed list of parameters, and a
383//! function value has exactly the parameters its type names. It was the VM's
384//! lowering that refused it first, and the two backends disagreed underneath
385//! that refusal: this pass typed such a parameter as its element type and
386//! dropped the `...`, while `Interpreter::bind_params` wrapped the argument
387//! in an `Array` as it does for any variadic slot, so `fn(items: Int...)`
388//! called with `1` bound `1` on one backend and `[1]` on the other. Deciding
389//! it here makes it one diagnostic on both rather than one backend's
390//! silence; issue #168 is where the question it does *not* settle — what
391//! such a parameter would mean — is written down.
392//!
393//! Two things bound it, and both are abstentions rather than gaps in the
394//! rule. A name this pass did not bind is not a place and is not reported as
395//! one — see `Checker::not_a_place`. And a receiver whose type is an
396//! unknown or a host type is left alone, because the interpreter reaches a
397//! host resource's own operations before it reaches any of this.
398//!
399//! # What the runtime keeps
400//!
401//! The interpreter's own checks stay, as ADR 0004 says. One rule about a
402//! call is left to it entirely, and it is worth naming because it is
403//! decidable here and is not decided here: whether a `var` marking written
404//! at a call site agrees with the one written at the declaration. A function
405//! *type* carries no marking, so a call through a value has nothing to check
406//! against, and the parameters this pass builds for a builtin, a host
407//! operation and a struct's initializer are not written with a marking at
408//! all. ADR 0021 records it as unfinished rather than as decided.
409//!
410//! # Where a form's value comes from
411//!
412//! `docs/LANGUAGE_REFERENCE.md` states one rule per expression form, and the
413//! two that this pass and the interpreter used to answer differently are
414//! stated there because they had to be decided rather than discovered:
415//!
416//! - An `if` with no `else` produces `()`, and its branch's value is
417//!   discarded. There is no second branch to give the missing case a value,
418//!   so the branch that runs does not supply one either.
419//! - Every loop produces `()`. A `for` runs out of items and a `while` runs
420//!   out of condition, so a loop can reach its end without breaking and
421//!   there is nothing at that end to produce but `()`; a `break` operand is
422//!   checked on its own and its value discarded, exactly as an `if`'s
423//!   branch value is. That a loop never carries a value is decided rather
424//!   than pending: issue #87 settled it, and the Language Reference gives
425//!   the reason.
426//!
427//! The interpreter obeys both, so a checked program's static and dynamic
428//! answers are the same one.
429
430use std::collections::{BTreeMap, BTreeSet};
431use std::fmt;
432use std::sync::Arc;
433
434use cove_diag::{Diagnostic, FileId, Severity, Span};
435use cove_schema::builtins::{
436    BuiltinSchema, BuiltinType, FreeBuiltinKind, FreeBuiltinSchema, MethodSchema, ParamSchema,
437    MAP_ENTRY, NONE_CASE, SCOPE,
438};
439use cove_schema::{
440    HostSchemas, HostType, ModuleSchema, OperationSchema, ResourceSchema, TypeSchema,
441};
442use cove_syntax::ast::{
443    Arg, BinaryOp, Block, EnumDecl, Expr, ExprId, ExprKind, FnDecl, GenericParam, Ident, ItemKind,
444    MatchArm, Param, Pattern, PatternKind, Stmt, StmtKind, StrPart, StructDecl, TraitMethod, Type,
445    TypeKind, UnaryOp,
446};
447
448use crate::facts::{Facts, MethodTarget, Signature};
449use crate::package::Package;
450use crate::resolve::{Conformance, Program, ResolvedModule, TraitEntry};
451
452/// An argument's type does not match the parameter, field, or payload it is
453/// given to.
454pub const MISMATCH: &str = "cove::type::mismatch";
455/// A call passes more arguments than the callee declares parameters.
456pub const ARITY: &str = "cove::type::arity";
457/// A call omits a parameter that has no default.
458pub const MISSING_ARGUMENT: &str = "cove::type::missing_argument";
459/// An argument label names no parameter of the callee.
460pub const UNKNOWN_LABEL: &str = "cove::type::unknown_label";
461/// A lowercase name is not in scope.
462pub const UNKNOWN_NAME: &str = "cove::type::unknown_name";
463/// A capitalized name no module declares and no `use` reaches.
464pub const UNRESOLVED_NAME: &str = "cove::type::unresolved_name";
465/// A type name no module declares.
466pub const UNKNOWN_TYPE: &str = "cove::type::unknown_type";
467/// A type reached through a host module the schema does not describe
468/// (warning).
469pub const HOST_TYPE: &str = "cove::type::host_type";
470/// A host module's schema declares no type of that name.
471pub const UNKNOWN_HOST_TYPE: &str = "cove::type::unknown_host_type";
472/// A host module's schema declares no operation of that name, on the module
473/// or on one of its resources.
474pub const UNKNOWN_HOST_OPERATION: &str = "cove::type::unknown_host_operation";
475/// A generic type is given the wrong number of type arguments.
476pub const TYPE_ARGUMENTS: &str = "cove::type::type_arguments";
477/// A type alias expands to itself.
478pub const ALIAS_CYCLE: &str = "cove::type::alias_cycle";
479/// A `struct` or an `enum` whose value layout would contain itself.
480pub const LAYOUT_CYCLE: &str = "cove::type::layout_cycle";
481/// A field access names no field of the receiver's type.
482pub const UNKNOWN_FIELD: &str = "cove::type::unknown_field";
483/// A field of an `export opaque struct` is named outside the module that
484/// declares it.
485pub const OPAQUE_FIELD: &str = "cove::type::opaque_field";
486/// The synthesized labeled constructor of an `export opaque struct` is
487/// called outside the module that declares it.
488pub const OPAQUE_CONSTRUCTION: &str = "cove::type::opaque_construction";
489/// A method call names no method of the receiver's type.
490pub const UNKNOWN_METHOD: &str = "cove::type::unknown_method";
491/// An associated call names no associated function of the type.
492pub const UNKNOWN_ASSOCIATED: &str = "cove::type::unknown_associated_function";
493/// A qualified case names no case of the enum.
494pub const UNKNOWN_CASE: &str = "cove::type::unknown_case";
495/// An enum case is constructed with the wrong number of payload values.
496pub const PAYLOAD_ARITY: &str = "cove::type::payload_arity";
497/// An operator is not defined for these operand types.
498pub const OPERATOR: &str = "cove::type::operator";
499/// A condition is not a `Bool`.
500pub const CONDITION: &str = "cove::type::condition";
501/// The branches of an `if` or the arms of a `match` produce different types.
502pub const BRANCHES: &str = "cove::type::branches";
503/// `?` was applied to something that is not a `Result` or an `Option`.
504pub const TRY_OPERAND: &str = "cove::type::try_operand";
505/// `?` propagates a failure the enclosing function cannot return.
506pub const TRY_RETURN: &str = "cove::type::try_return";
507/// `await` was applied to something that is not a `Task`.
508pub const AWAIT_OPERAND: &str = "cove::type::await_operand";
509/// A task nothing awaits can leave a `scope` as `Err`, and the function the
510/// scope was written in does not answer a `Result` that can carry it.
511pub const SCOPE_CHILD_FAILURE: &str = "cove::type::scope_child_failure";
512/// `for` was given something it cannot iterate.
513pub const ITERABLE: &str = "cove::type::iterable";
514/// A call was made to something that is not a function.
515pub const NOT_CALLABLE: &str = "cove::type::not_callable";
516/// A pattern matches a different type than the scrutinee.
517pub const PATTERN: &str = "cove::type::pattern";
518/// A method was called without a receiver, or an associated function with one.
519pub const RECEIVER: &str = "cove::type::receiver";
520/// An expression written where a place is required is not one: an
521/// assignment's target, a `var` argument, or a `var self` receiver.
522pub const NOT_A_PLACE: &str = "cove::type::not_a_place";
523/// A place `let` made read-only is written, passed as `var`, or given to a
524/// `var self` receiver.
525///
526/// One code for the one rule — `let` creates a read-only place; `var`
527/// creates a mutable place — however it is broken. The three messages differ
528/// because what the program was doing differs; the fact reported is the
529/// same, and a reader who wants to suppress or search for it wants all three.
530pub const READ_ONLY_PLACE: &str = "cove::type::read_only_place";
531/// A labeled argument fills a parameter that stands before one an earlier
532/// argument already filled.
533pub const LABEL_ORDER: &str = "cove::type::label_order";
534/// An entry function's shape does not fit the host boundary.
535pub const ENTRY: &str = "cove::type::entry";
536/// A `dyn` or a bound names something that is not a trait this module can see.
537pub const UNKNOWN_TRAIT: &str = "cove::type::unknown_trait";
538/// A type argument does not conform to the bound its type parameter declares.
539pub const UNSATISFIED_BOUND: &str = "cove::type::unsatisfied_bound";
540/// A method was called on a type parameter that declares no bound.
541pub const UNBOUNDED_PARAMETER: &str = "cove::type::unbounded_parameter";
542/// A conformance's method does not have the signature its trait declares.
543pub const CONFORMANCE_SIGNATURE: &str = "cove::type::conformance_signature";
544/// A trait method with no `self` was called through `dyn Trait`.
545pub const DYN_ASSOCIATED: &str = "cove::type::dyn_associated_function";
546/// A `var self` trait method was called through `dyn Trait`.
547pub const DYN_MUTATING: &str = "cove::type::dyn_mutating_method";
548/// A bound was written where the MVP does not check one.
549pub const UNSUPPORTED_BOUND: &str = "cove::type::unsupported_bound";
550/// A qualified name reaches nothing an imported module exports.
551pub const UNKNOWN_MEMBER: &str = "cove::type::unknown_member";
552/// A `test fn` does not have the shape the test runner calls.
553pub const TEST: &str = "cove::type::test";
554/// A type that may not cross a task boundary was written where one must.
555pub const TASK_SAFETY: &str = "cove::type::task_safety";
556/// A declaration's parameter has no written type. Unlike a lambda's, it has
557/// no expected type at a call site to infer from.
558pub const MISSING_PARAMETER_TYPE: &str = "cove::type::missing_parameter_type";
559/// A variadic parameter stands somewhere other than last in its
560/// declaration's parameter list.
561pub const VARIADIC_POSITION: &str = "cove::type::variadic_position";
562/// A variadic parameter is written with a default.
563pub const VARIADIC_DEFAULT: &str = "cove::type::variadic_default";
564/// A variadic parameter is written on a function value, whose parameters are
565/// its function type's and so are a fixed list.
566pub const VARIADIC_LAMBDA: &str = "cove::type::variadic_lambda";
567/// A host operation whose schema declares its result `Any`, so the checker
568/// can prove nothing about the value it produced (note).
569pub const UNCONSTRAINED_RESULT: &str = "cove::type::unconstrained_result";
570/// A host type's field whose schema declares it `Any`, so the checker can
571/// prove nothing about the value read from it (note).
572pub const UNCONSTRAINED_FIELD: &str = "cove::type::unconstrained_field";
573/// A variadic host operation used as a value, which no function type in this
574/// language can describe (note).
575pub const VARIADIC_AS_VALUE: &str = "cove::type::variadic_as_value";
576/// A type or a module is written where a value belongs.
577pub const NOT_A_VALUE: &str = "cove::type::not_a_value";
578/// A function value uses `return`, with nothing saying what it produces.
579pub const LAMBDA_RETURN: &str = "cove::type::lambda_return";
580/// Nothing written anywhere says what a type is: an unannotated lambda
581/// parameter, an empty array literal, a bare `None`, a struct's type
582/// parameter no field mentions, or a binding whose uses settle nothing, in a
583/// place that expects nothing in particular.
584pub const UNCONSTRAINED: &str = "cove::type::unconstrained";
585/// A use asks a binding to hold a type that contains itself, which this
586/// language writes by declaring a type rather than by inferring one.
587pub const RECURSIVE_TYPE: &str = "cove::type::recursive_type";
588/// Two uses of a local binding ask for different types where its initializer
589/// left one open.
590pub const INFERENCE_CONFLICT: &str = "cove::type::inference_conflict";
591
592/// The Language Card sentence a task-safety diagnostic quotes.
593///
594/// `cove_runtime::task` states the same rule for values; the compiler does
595/// not depend on the runtime, so the sentence appears in both places, and it
596/// is the card's own words in both.
597const TASK_SAFETY_RULE: &str = "Immutable task-safe values such as arrays may cross task boundaries. A vector cannot cross, even through `let`; finish it as an array or wrap mutable state in `Shared` or another synchronized type. Closures are task-safe only when every capture is.";
598
599/// What `cove_runtime::task::wait_for_children` does, said the way a reader
600/// has to act on it: the failure of a task nothing awaited is not lost at
601/// scope exit, it is returned, and that is why a scope constrains what its
602/// function answers.
603const SCOPE_CHILD_RULE: &str = "Leaving a `scope` waits for every task nothing awaited, and a task whose value is `Err` returns that failure from the function the scope was written in, exactly as `?` would.";
604
605/// The half of `?`'s rule only a function value makes a reader think about:
606/// `?` returns from the function it stands in, a lambda is one, and a lambda
607/// nobody typed is the one function in the language whose result the program
608/// never writes down.
609const TRY_LAMBDA_RULE: &str = "`expr?` returns the error from the function it is written in, and a function value is one. A function value no place declares a result type for produces what its body's value proves, so that value is what has to carry the failure.";
610
611/// The one sentence ADR 0035 decides, said the way a reader has to act on
612/// it: the rejection is what makes every finite value copy by word range,
613/// and the list is the whole set of escapes the language has today.
614const LAYOUT_CYCLE_RULE: &str = "A value type may not contain itself. A recursive cycle must pass through a type whose value is a reference: `String`, `Array`, `Map`, `Set`, `Vector`, `Shared`, a closure, or a `dyn` trait object.";
615
616/// Type-checks a resolved program.
617///
618/// Every module is checked against its own declarations, the declarations it
619/// imported, and the builtins, and every `[run.<name>]` entry against the
620/// shape the host boundary calls. The result holds both errors and warnings;
621/// an empty result means the program checks.
622///
623/// Modules are checked in dependency order, so a module's imports are
624/// already resolved signatures by the time its own declarations are. ADR
625/// 0005 forbids import cycles, which is what makes such an order exist.
626pub fn check(package: &Package, program: &Program) -> Vec<Diagnostic> {
627    check_with(package, program, &HostSchemas::new())
628}
629
630/// Type-checks a resolved program against `schemas`, the host modules this
631/// compilation may name.
632///
633/// This is [`check`] with the one thing an embedder can change. A module in
634/// `schemas` is checked exactly as a shipped one is: its operations' arity,
635/// argument types, and results; the fields of the types it declares; the
636/// cases of its enums; and the operations its resources answer.
637pub fn check_with(package: &Package, program: &Program, schemas: &HostSchemas) -> Vec<Diagnostic> {
638    check_facts(package, program, schemas).0
639}
640
641/// Type-checks a resolved program against `schemas`, keeping what the check
642/// worked out about each expression.
643///
644/// This is [`check_with`] with its second answer. The check is the same one
645/// — the facts are written as the walk settles them and read by nothing
646/// during it — so a caller that wants only the diagnostics loses nothing by
647/// taking this instead, and one that wants the types does not have to derive
648/// them a second time. [`Facts`] says why deriving them a second time is the
649/// thing worth avoiding.
650pub fn check_facts(
651    package: &Package,
652    program: &Program,
653    schemas: &HostSchemas,
654) -> (Vec<Diagnostic>, Facts) {
655    let mut diagnostics = Vec::new();
656    let mut envs: BTreeMap<&str, ImportEnv> = BTreeMap::new();
657    let mut checked: BTreeMap<&str, Checker> = BTreeMap::new();
658    for name in import_order(program) {
659        let module = &program.modules[name];
660        let mut checker = Checker::new(module, program, schemas);
661        checker.import(&envs);
662        checker.prepare();
663        envs.insert(name, checker.export_env());
664        checker.check_bodies();
665        diagnostics.append(&mut checker.diagnostics);
666        checked.insert(name, checker);
667    }
668    check_entries(package, &checked, &mut diagnostics);
669    check_tests(program, &checked, &mut diagnostics);
670    // Each module is checked by a checker of its own, so the facts arrive in
671    // as many tables as there are modules. A file belongs to one module, so
672    // gathering them into one table keyed by file loses nothing.
673    let mut facts = Facts::default();
674    for (_, checker) in checked {
675        facts.merge(checker.facts);
676    }
677    // The uniqueness proof `freeze()` needs runs last and only over a program
678    // that type-checked. It reads the types this walk settled, so a body the
679    // checker gave up on would give it a `Vector` it is not sure about; and a
680    // reader holding a type error has a first thing to fix that is not this.
681    if !diagnostics
682        .iter()
683        .any(|diagnostic| diagnostic.severity == Severity::Error)
684    {
685        diagnostics.extend(crate::unique::check(program, &facts));
686    }
687    (diagnostics, facts)
688}
689
690/// Checks every `test fn` against the one shape the test runner calls.
691///
692/// The runner passes nothing and reports the test's failure through its
693/// `Err`, so a test takes no parameters and returns `Result<Unit, Error>`.
694/// Anything else is rejected here rather than at run time, naming the shape
695/// that is required.
696fn check_tests(
697    program: &Program,
698    checked: &BTreeMap<&str, Checker<'_>>,
699    diagnostics: &mut Vec<Diagnostic>,
700) {
701    let required = Ty::Result(Box::new(Ty::Unit), Box::new(Ty::Error));
702    for test in program.tests() {
703        let Some(checker) = checked.get(test.module) else {
704            continue;
705        };
706        let Some(sig) = checker.functions.get(test.name) else {
707            continue;
708        };
709        let shape = format!("write `test fn {}() -> Result<Unit, Error>`", test.name);
710
711        if let Some(param) = sig.params.first() {
712            diagnostics.push(
713                Diagnostic::error(
714                    TEST,
715                    format!(
716                        "test `{}` declares {} parameter(s)",
717                        test.qualified_name(),
718                        sig.params.len()
719                    ),
720                )
721                .at(param.span)
722                .rule("A `test fn` takes no parameters: the test runner is its only caller, and it passes nothing.")
723                .help(shape.clone()),
724            );
725        }
726
727        if sig.is_async {
728            diagnostics.push(
729                Diagnostic::error(
730                    TEST,
731                    format!("test `{}` is `async`", test.qualified_name()),
732                )
733                .at(test.entry.decl.name.span)
734                .rule("A `test fn` is an ordinary function the test runner calls and awaits nothing of.")
735                .help(shape.clone()),
736            );
737        }
738
739        if !sig.ret.matches(&required) {
740            diagnostics.push(
741                Diagnostic::error(
742                    TEST,
743                    format!(
744                        "test `{}` returns `{}`, but a test returns `Result<Unit, Error>`",
745                        test.qualified_name(),
746                        sig.ret
747                    ),
748                )
749                .at(sig.ret_span)
750                .rule("A test reports failure the way every other Cove function reports expected failure, so it returns `Result<Unit, Error>` and `?` works inside it.")
751                .help(shape),
752            );
753        }
754    }
755}
756
757/// Every module of `program`, each after the modules it imports from.
758///
759/// A package whose modules form a cycle never reaches this pass, since
760/// resolution rejects one; if one somehow does, the modules left over are
761/// checked in name order rather than dropped.
762fn import_order(program: &Program) -> Vec<&str> {
763    let mut order: Vec<&str> = Vec::new();
764    let mut placed: BTreeSet<&str> = BTreeSet::new();
765    loop {
766        let mut progressed = false;
767        for (name, module) in &program.modules {
768            if placed.contains(name.as_str()) {
769                continue;
770            }
771            let ready = module
772                .dependencies()
773                .iter()
774                .all(|dep| placed.contains(dep) || !program.modules.contains_key(*dep));
775            if ready {
776                order.push(name.as_str());
777                placed.insert(name.as_str());
778                progressed = true;
779            }
780        }
781        if !progressed {
782            break;
783        }
784    }
785    order.extend(
786        program
787            .modules
788            .keys()
789            .map(String::as_str)
790            .filter(|name| !placed.contains(name)),
791    );
792    order
793}
794
795/// The canonical `(trait key, type key)` a recorded conformance names, as
796/// the module that declared it sees them: bare for a party this module
797/// declares, `module.Name` for an imported one.
798fn conformance_key(module: &ResolvedModule, conformance: &Conformance) -> (String, String) {
799    let key = |owner: &str, name: &str| {
800        if owner == module.name {
801            name.to_string()
802        } else {
803            format!("{owner}.{name}")
804        }
805    };
806    (
807        key(&conformance.trait_module, &conformance.trait_name),
808        key(&conformance.type_module, &conformance.type_name),
809    )
810}
811
812/// The canonical key of a declaration `module` makes, leaving a name that
813/// already carries a module alone.
814fn qualified_name(name: &Arc<str>, module: &str) -> Arc<str> {
815    if name.contains('.') {
816        name.clone()
817    } else {
818        format!("{module}.{name}").into()
819    }
820}
821
822/// Splits a table key into the module that declares the type and the type's
823/// own name, when the key names a type this module did not declare.
824///
825/// A checker keys its own module's declarations by their bare name and every
826/// imported one by `module.Name`, so a key that carries a module in front is
827/// exactly a declaration written somewhere else. That is the whole test an
828/// opaque type's boundary needs: inside the declaring module the key is
829/// bare, and the representation is in reach.
830fn foreign_type(key: &str) -> Option<(&str, &str)> {
831    key.rsplit_once('.')
832}
833
834/// What a field expression is doing with the field it names: taking the
835/// value out, or being the place a value goes.
836///
837/// Both reach a field through the same check, so refusing one across an
838/// opaque boundary refuses the other — but the two need different words,
839/// since telling someone to "read the value through an exported method" is
840/// no answer to an assignment.
841#[derive(Clone, Copy, PartialEq, Eq, Debug)]
842enum FieldUse {
843    Read,
844    Write,
845}
846
847impl FieldUse {
848    /// What this use cannot do, for the message.
849    fn refused(self) -> &'static str {
850        match self {
851            FieldUse::Read => "read",
852            FieldUse::Write => "assigned",
853        }
854    }
855
856    /// How to do it through the interface instead, for the help.
857    fn correction(self) -> &'static str {
858        match self {
859            FieldUse::Read => "read the value through an exported method, such as",
860            FieldUse::Write => "change the value through an exported method, such as",
861        }
862    }
863}
864
865/// Everything one module offers the modules that import it: the signatures
866/// of its own declarations, keyed by the canonical `module.Name` a foreign
867/// declaration is known by, plus every foreign signature it imported in
868/// turn, so a type reached through two imports keeps one identity.
869#[derive(Clone, Debug, Default)]
870struct ImportEnv {
871    structs: BTreeMap<String, StructSig>,
872    enums: BTreeMap<String, EnumSig>,
873    aliases: BTreeMap<String, (Vec<Arc<str>>, Ty)>,
874    functions: BTreeMap<String, FnSig>,
875    methods: BTreeMap<(String, String), FnSig>,
876    traits: BTreeMap<String, BTreeMap<String, FnSig>>,
877    /// Every conformance the module declares or can see, as canonical
878    /// `(trait key, type key)` pairs.
879    ///
880    /// Conformance travels with the declarations it joins because it is a
881    /// fact about them, not about the module that wrote it down: a bound is
882    /// satisfied wherever both parties are in scope, and the orphan rule is
883    /// what guarantees the conformance is somewhere on the import path that
884    /// brought them here.
885    conformances: BTreeSet<(String, String)>,
886}
887
888/// The first part of `ty` that may not cross a task boundary, if there is
889/// one.
890///
891/// A `Vector` may not cross even through `let`, and neither may a task or a
892/// task scope, which belong to the task that holds them. Everything else is
893/// task-safe exactly when what it contains is — except a `Shared`, which
894/// crosses by sharing rather than by copying and so answers for itself.
895fn not_task_safe(ty: &Ty) -> Option<&Ty> {
896    match ty {
897        Ty::Vector(_) | Ty::Task(_) | Ty::Scope => Some(ty),
898        Ty::Shared(_) => None,
899        Ty::Array(inner) | Ty::Set(inner) | Ty::Option(inner) => not_task_safe(inner),
900        Ty::Map(key, value) | Ty::MapEntry(key, value) | Ty::Result(key, value) => {
901            not_task_safe(key).or_else(|| not_task_safe(value))
902        }
903        Ty::Struct(_, args) | Ty::Enum(_, args) => args.iter().find_map(not_task_safe),
904        // A closure is task-safe when every capture is, which is a fact about
905        // the values it closed over rather than about its type.
906        _ => None,
907    }
908}
909
910/// Rewrites the nominal names `module` declares into the canonical
911/// `module.Name` form.
912///
913/// A name that already carries a module is left alone: it is already
914/// absolute, so a type reached through two imports keeps one identity. A
915/// name a module writes for its own declaration is bare, which is what makes
916/// the two cases distinguishable.
917fn qualify(ty: &Ty, module: &str) -> Ty {
918    let qualified = |name: &Arc<str>| qualified_name(name, module);
919    match ty {
920        Ty::Array(inner) => Ty::Array(Box::new(qualify(inner, module))),
921        Ty::Vector(inner) => Ty::Vector(Box::new(qualify(inner, module))),
922        Ty::Set(inner) => Ty::Set(Box::new(qualify(inner, module))),
923        Ty::Option(inner) => Ty::Option(Box::new(qualify(inner, module))),
924        Ty::Task(inner) => Ty::Task(Box::new(qualify(inner, module))),
925        Ty::Shared(inner) => Ty::Shared(Box::new(qualify(inner, module))),
926        Ty::Map(k, v) => Ty::Map(Box::new(qualify(k, module)), Box::new(qualify(v, module))),
927        Ty::MapEntry(k, v) => {
928            Ty::MapEntry(Box::new(qualify(k, module)), Box::new(qualify(v, module)))
929        }
930        Ty::Result(t, e) => Ty::Result(Box::new(qualify(t, module)), Box::new(qualify(e, module))),
931        Ty::Struct(name, args) => Ty::Struct(
932            qualified(name),
933            args.iter().map(|arg| qualify(arg, module)).collect(),
934        ),
935        Ty::Enum(name, args) => Ty::Enum(
936            qualified(name),
937            args.iter().map(|arg| qualify(arg, module)).collect(),
938        ),
939        // A `dyn Trait` names a trait, which belongs to a module exactly as
940        // a struct or an enum does.
941        Ty::Dyn(name) => Ty::Dyn(qualified(name)),
942        Ty::Fn(f) => Ty::func(
943            f.is_async,
944            f.params.iter().map(|p| qualify(p, module)).collect(),
945            qualify(&f.ret, module),
946        ),
947        other => other.clone(),
948    }
949}
950
951// ------------------------------------------------------------------- types
952
953/// Why the checker does not know a type.
954///
955/// This is the classification the module documentation describes, carried by
956/// the type rather than implied by which constructor built it. Every kind
957/// compares equal to every type — telling them apart decides what a reader is
958/// told, never what type-checks — so the only thing this changes about the
959/// checking rules is that a form can ask whether the unknown standing in for
960/// its context has already been accounted for.
961#[derive(Clone, Copy, Debug, PartialEq, Eq)]
962pub enum Unknown {
963    /// An error was already reported about this place, or about the value
964    /// this one was derived from. Silent.
965    Recovery,
966    /// A host module no schema describes — neither a shipped one nor one an
967    /// embedder handed over. The remedy is at the `use` that names the
968    /// module, not here.
969    DynamicBoundary,
970    /// Nothing that has been read states this type: a shipped schema's
971    /// `HostType::Any`, or a type parameter no argument, annotation, or
972    /// expected type settles.
973    Unconstrained,
974    /// An unconstrained unknown carrying an identity, so that a later use
975    /// can say what it is.
976    ///
977    /// This is not a fifth kind of not-knowing. It is the *same* fact as
978    /// [`Unknown::Unconstrained`] — a type parameter nothing read so far
979    /// settles — with a number attached, and the number is what lets the
980    /// uses of a local binding after its initializer settle the type its
981    /// initializer left open. See the module documentation under
982    /// "Inference variables": one never leaves the body that minted it, and
983    /// what is left in [`Facts`] is either the type its uses settled or a
984    /// plain unconstrained unknown.
985    Var(u32),
986    /// A position no reachable program observes.
987    ///
988    /// This is not a classification of a program's type. It marks the
989    /// internal positions the surrounding form settles before anything reads
990    /// them and the ones no reachable program produces at all, and
991    /// `Checker::expr` and `Checker::declare` assert in debug builds that
992    /// one never reaches a type a program can observe. If one ever does, the
993    /// assertion names the site rather than leaving the unknown to validate
994    /// whatever came after it.
995    Placeholder,
996}
997
998impl Unknown {
999    /// Whether the checker has already said whatever it has to say about the
1000    /// place this unknown stands for.
1001    ///
1002    /// Every kind but [`Unknown::Placeholder`] has: a recovery unknown has a
1003    /// diagnostic above it, a dynamic boundary belongs to a `use` naming a
1004    /// module this build cannot see, and an unconstrained one is either a
1005    /// schema's own `Any` or a parameter reported where it was left open. So
1006    /// a form given to a place typed by one of those adds nothing by
1007    /// complaining that the place said nothing — that is the whole content of
1008    /// the diagnostic already given. A placeholder has said nothing anywhere,
1009    /// which is why it must never reach a place a form can be given to.
1010    fn is_accounted_for(self) -> bool {
1011        !matches!(self, Unknown::Placeholder)
1012    }
1013}
1014
1015/// A Cove type.
1016///
1017/// A name inside one is shared by [`Arc`] rather than [`std::rc::Rc`]
1018/// because a type outlives the check that settled it: it is recorded in
1019/// [`Facts`] and published on [`Program`], which the runtime holds behind an
1020/// `Arc` and moves onto the stack it runs a program on. Sharing atomically
1021/// is what lets a type be a fact about a checked package rather than a value
1022/// that dies with the checker.
1023#[derive(Clone, Debug, PartialEq)]
1024pub enum Ty {
1025    /// The checker could not determine this type; see the module docs.
1026    Unknown(Unknown),
1027    /// The type of an expression that never produces a value, such as
1028    /// `return`.
1029    Never,
1030    /// `Any`: a value of some type, which a Host API schema declares where
1031    /// nothing it does depends on which type that is.
1032    ///
1033    /// This is a *promise* and not an absence, which is why it is a type of
1034    /// its own rather than a [`Ty::Unknown`]. A schema writing
1035    /// [`cove_schema::HostType::Any`] has said something exact — every value
1036    /// is accepted here, and what comes back is checked at the boundary and
1037    /// by nothing before it — where an unknown says only that the checker
1038    /// did not find out. Spelling them the same made a call's result and a
1039    /// type parameter nobody settled indistinguishable, and left the
1040    /// lowering asking the schema again at every position a value is
1041    /// produced because the type it was handed could not tell it which of
1042    /// the two it had.
1043    ///
1044    /// It carries no information, so it compares equal to every type and
1045    /// every operation on it abstains — exactly what the unconstrained
1046    /// unknown standing here used to do, and the reason this change moves
1047    /// no diagnostic. What it is *not* is a `dyn Trait`: the two share one
1048    /// erased representation (`docs/LINEAR_VM.md`), and sharing a
1049    /// representation is what `cove_ir`'s `Shapes` is for. As types they
1050    /// are opposites — a `dyn Display` accepts only a conforming value and
1051    /// answers only the trait's methods, an `Any` accepts every value and
1052    /// answers everything at run time — so writing one as the other would
1053    /// put an exception on every `Ty::Dyn` in this pass and a reserved
1054    /// trait name in the language.
1055    Any,
1056    Unit,
1057    Bool,
1058    Int,
1059    Float,
1060    Str,
1061    Duration,
1062    Error,
1063    Range,
1064    Array(Box<Ty>),
1065    Vector(Box<Ty>),
1066    Set(Box<Ty>),
1067    Map(Box<Ty>, Box<Ty>),
1068    /// One `key`/`value` pair: what `Map.of` collects and what `for` binds
1069    /// over a `Map`.
1070    MapEntry(Box<Ty>, Box<Ty>),
1071    Option(Box<Ty>),
1072    Result(Box<Ty>, Box<Ty>),
1073    Task(Box<Ty>),
1074    /// `Shared<T>`: mutable state more than one task may reach.
1075    ///
1076    /// The Language Card names it in the sentence that keeps a vector out of
1077    /// a task, and ADR 0008 makes it the one value that crosses a task
1078    /// boundary by sharing rather than by copying. Its argument must
1079    /// therefore be task-safe itself: a `Shared<Vector<T>>` would let a
1080    /// vector be reached from two tasks, which is what that sentence forbids.
1081    Shared(Box<Ty>),
1082    /// The value `scope name { ... }` binds.
1083    Scope,
1084    /// A struct this module declares, with its type arguments.
1085    Struct(Arc<str>, Vec<Ty>),
1086    /// An enum this module declares, with its type arguments.
1087    Enum(Arc<str>, Vec<Ty>),
1088    Fn(Arc<FnTy>),
1089    /// A type parameter, rigid inside the body that declares it.
1090    Param(Arc<str>),
1091    /// `dyn Display`: a value of some type that conforms to the named trait,
1092    /// carrying its implementation with it.
1093    ///
1094    /// This is a type of its own, not a type parameter: it cannot be written
1095    /// where a bounded type parameter is expected, and only the trait's
1096    /// `self`-taking methods can be called on it.
1097    Dyn(Arc<str>),
1098    /// A type a host module declares, named the way Cove source writes it:
1099    /// `http.Request`, `database.Connection`.
1100    ///
1101    /// It is nominal like every other type here and carries no arguments,
1102    /// because [`cove_schema::HostType`] has none to carry. Whether the host
1103    /// hands the value over or keeps it — a `TypeSchema` or a
1104    /// `ResourceSchema` — does not change how it is written or compared, so
1105    /// it does not change this either; what the schema says about it decides
1106    /// what may be read from it and what may be called on it.
1107    Host(Arc<str>),
1108}
1109
1110/// A function type: `fn(Int) -> Int`, `async fn() -> Result<Unit, Error>`.
1111#[derive(Clone, Debug, PartialEq)]
1112pub struct FnTy {
1113    pub is_async: bool,
1114    pub params: Vec<Ty>,
1115    pub ret: Ty,
1116}
1117
1118impl Ty {
1119    fn func(is_async: bool, params: Vec<Ty>, ret: Ty) -> Ty {
1120        Ty::Fn(Arc::new(FnTy {
1121            is_async,
1122            params,
1123            ret,
1124        }))
1125    }
1126
1127    /// An unknown the checker owes no further word about.
1128    ///
1129    /// Everything there was to say about this place has been said, either
1130    /// here — the diagnostic sits a few lines above every one of these — or
1131    /// upstream, where the unknown being propagated was first produced. A
1132    /// recovery unknown therefore never carries a diagnostic of its own,
1133    /// which is what keeps one mistake from becoming a page of them.
1134    fn recovery() -> Ty {
1135        Ty::Unknown(Unknown::Recovery)
1136    }
1137
1138    /// This type read as a place's abstention, when it is one.
1139    ///
1140    /// `Any` and the two unknowns that carry their own explanation — a
1141    /// mistake already reported, a host no schema describes — are answers a
1142    /// place gives about itself. `Never` is not: an arm that produces no
1143    /// value says nothing about what a value would have been. A placeholder
1144    /// is not either, because it reaches no place a form is given to.
1145    fn abstention(&self) -> Option<Ty> {
1146        match self {
1147            Ty::Any => Some(Ty::Any),
1148            Ty::Unknown(kind @ (Unknown::Recovery | Unknown::DynamicBoundary)) => {
1149                Some(Ty::Unknown(*kind))
1150            }
1151            _ => None,
1152        }
1153    }
1154
1155    /// The unknown a form produces when what it was given is already one.
1156    ///
1157    /// The kind travels. A recovery unknown stands for a mistake already
1158    /// reported, so everything derived from it is that same mistake and
1159    /// says nothing more. A dynamic boundary stands for a host module this
1160    /// build was shown no schema for, and a field read off such a value, a
1161    /// `?` applied to one, or a call made through one is the *same*
1162    /// unproved boundary rather than a second thing to say — which is what
1163    /// lets [ADR 0016](../../../docs/adr/0016-four-kinds-of-unknown.md) put
1164    /// the one diagnostic at the `use` and nowhere else. Turning it into a
1165    /// recovery unknown one step later loses the name of the silence, and a
1166    /// reader downstream is left with "an error was reported about this"
1167    /// when none was.
1168    ///
1169    /// `Never` produces a recovery unknown, as it always did: a value that
1170    /// never arrives has no boundary behind it to name.
1171    fn abstain(&self) -> Ty {
1172        match self {
1173            Ty::Unknown(Unknown::DynamicBoundary) => Ty::dynamic_boundary(),
1174            _ => Ty::recovery(),
1175        }
1176    }
1177
1178    /// An unknown that belongs to a host no schema describes.
1179    ///
1180    /// A host may register any module it likes, and one whose schema no
1181    /// compilation was shown is named in no table this pass could read, so a
1182    /// call into it, or a value of a type from it, is checked at the boundary
1183    /// rather than here. Nothing is reported where one of these is produced:
1184    /// the silence is a fact about this *compilation*, the remedy is to hand
1185    /// the module's schema to the compiler with
1186    /// `cove_sema::Compiler::with_host_schema`, and the place to say so is
1187    /// the `use` that named the module, where
1188    /// `cove::resolve::unchecked_host` says it once. `Checker::host_schema`
1189    /// is where an embedder-supplied schema arrives and turns all of it back
1190    /// into ordinary checking.
1191    fn dynamic_boundary() -> Ty {
1192        Ty::Unknown(Unknown::DynamicBoundary)
1193    }
1194
1195    /// An unknown nothing that has been read states.
1196    ///
1197    /// It has two sources. One is a shipped schema's `HostType::Any`, which
1198    /// is not a missing type but a statement that there is nothing here that
1199    /// depends on one: nothing is lost where it is a *parameter*, because the
1200    /// operation accepts every value, and a *result* or a *field* declared
1201    /// `Any` is noted where it is read, because from there on the program is
1202    /// working with a value whose type nothing stated.
1203    ///
1204    /// The other is a type parameter no argument, annotation, or expected
1205    /// type settles. Where the program could have said and did not — an empty
1206    /// array, a bare `None`, a struct parameter no field mentions — that
1207    /// warns where it is written; where nothing was asked of it at all, it is
1208    /// carried, which the module documentation names as one of the two things
1209    /// a clean check does not cover.
1210    fn unconstrained() -> Ty {
1211        Ty::Unknown(Unknown::Unconstrained)
1212    }
1213
1214    /// A fresh inference variable, which
1215    /// [`Checker::open_result`] mints and [`Checker::finish_inference`]
1216    /// settles.
1217    fn var(id: u32) -> Ty {
1218        Ty::Unknown(Unknown::Var(id))
1219    }
1220
1221    /// An unknown no program type is read from.
1222    ///
1223    /// This is not a fourth kind of not-knowing. It marks the few positions
1224    /// the surrounding form settles before anything looks at them — a return
1225    /// type a body is about to supply, a receiver only asked whether it is
1226    /// there — and the few no reachable program produces at all. Each site
1227    /// says which of the two it is, and `Checker::expr` and
1228    /// `Checker::declare` hold it to that claim in debug builds: a
1229    /// placeholder in the type of an expression or of a binding is a bug in
1230    /// this pass, not a fact about the program.
1231    fn placeholder() -> Ty {
1232        Ty::Unknown(Unknown::Placeholder)
1233    }
1234
1235    /// Whether this type carries no information, so a diagnostic about it
1236    /// would be a guess.
1237    fn is_wild(&self) -> bool {
1238        matches!(self, Ty::Unknown(_) | Ty::Never | Ty::Any)
1239    }
1240
1241    /// Whether a value given to a place of this type needs no diagnostic of
1242    /// its own about the place saying nothing.
1243    ///
1244    /// See `Unknown::is_accounted_for`. `Never` is here for the same
1245    /// reason: a place that never receives a value is one no diagnostic
1246    /// describes.
1247    fn is_accounted_for(&self) -> bool {
1248        match self {
1249            Ty::Unknown(kind) => kind.is_accounted_for(),
1250            Ty::Never => true,
1251            // A schema declaring `Any` is a design decision the schema made
1252            // and `Checker::host_result` already noted. A form given to such
1253            // a place adds nothing by observing that the place said nothing
1254            // about its type: saying nothing is what the place says.
1255            Ty::Any => true,
1256            _ => false,
1257        }
1258    }
1259
1260    /// Whether an [`Unknown::Placeholder`] is anywhere inside this type.
1261    ///
1262    /// This is what turns the classification from a convention into
1263    /// something the test suite holds: a placeholder stands for a position
1264    /// nothing reads, so finding one in a type a program can observe means
1265    /// the site that built it was wrong about itself.
1266    fn holds_placeholder(&self) -> bool {
1267        match self {
1268            Ty::Unknown(kind) => matches!(kind, Unknown::Placeholder),
1269            Ty::Array(inner)
1270            | Ty::Vector(inner)
1271            | Ty::Set(inner)
1272            | Ty::Option(inner)
1273            | Ty::Task(inner)
1274            | Ty::Shared(inner) => inner.holds_placeholder(),
1275            Ty::Map(k, v) | Ty::MapEntry(k, v) | Ty::Result(k, v) => {
1276                k.holds_placeholder() || v.holds_placeholder()
1277            }
1278            Ty::Struct(_, args) | Ty::Enum(_, args) => {
1279                args.iter().any(|arg| arg.holds_placeholder())
1280            }
1281            Ty::Fn(f) => f.params.iter().any(Ty::holds_placeholder) || f.ret.holds_placeholder(),
1282            _ => false,
1283        }
1284    }
1285
1286    /// Calls `f` with the identity of every inference variable inside this
1287    /// type.
1288    ///
1289    /// One walk answers all three questions asked of a variable: whether a
1290    /// type still holds one, which binding a type's variables belong to, and
1291    /// which facts have to be rewritten once they are settled.
1292    fn each_var<F: FnMut(u32)>(&self, f: &mut F) {
1293        match self {
1294            Ty::Unknown(Unknown::Var(id)) => f(*id),
1295            Ty::Array(inner)
1296            | Ty::Vector(inner)
1297            | Ty::Set(inner)
1298            | Ty::Option(inner)
1299            | Ty::Task(inner)
1300            | Ty::Shared(inner) => inner.each_var(f),
1301            Ty::Map(k, v) | Ty::MapEntry(k, v) | Ty::Result(k, v) => {
1302                k.each_var(f);
1303                v.each_var(f);
1304            }
1305            Ty::Struct(_, args) | Ty::Enum(_, args) => {
1306                for arg in args {
1307                    arg.each_var(f);
1308                }
1309            }
1310            Ty::Fn(func) => {
1311                for param in &func.params {
1312                    param.each_var(f);
1313                }
1314                func.ret.each_var(f);
1315            }
1316            _ => {}
1317        }
1318    }
1319
1320    /// Whether an inference variable is anywhere inside this type.
1321    ///
1322    /// This is what marks a type as not final yet: a fact recorded while a
1323    /// variable was still open is rewritten at the end of the body, and a
1324    /// binding holding one is a binding its uses may still settle.
1325    fn holds_var(&self) -> bool {
1326        let mut found = false;
1327        self.each_var(&mut |_| found = true);
1328        found
1329    }
1330
1331    /// The identities of the inference variables inside this type.
1332    fn vars(&self) -> Vec<u32> {
1333        let mut found = Vec::new();
1334        self.each_var(&mut |id| found.push(id));
1335        found
1336    }
1337
1338    /// This type with every inference variable a use has already settled
1339    /// replaced by what settled it, and every other one left open.
1340    ///
1341    /// [`Ty::settled`] is the end of the body, where an open variable has
1342    /// run out of uses and becomes an unconstrained unknown. This is the
1343    /// *middle* of it, where one has not: what the checker already knows is
1344    /// substituted in and what it does not yet know stays a variable, so a
1345    /// later use can still say.
1346    ///
1347    /// It is applied where every expression's type leaves
1348    /// [`Checker::expr`], which is what makes an earlier use's answer
1349    /// available to a later form rather than only to [`Facts`] at the end.
1350    /// Without it a variable is opaque for the whole body: `found.freeze()`
1351    /// after `found.push(item)` hands `sorted(by:)` a callback parameter
1352    /// whose type is a hole, the lambda's body reads a field off a hole,
1353    /// and the program checks clean holding a type nothing settled — even
1354    /// though the push two lines above said exactly what it was.
1355    fn resolved(&self, vars: &[TyVar]) -> Ty {
1356        match self {
1357            Ty::Unknown(Unknown::Var(id)) => vars
1358                .get(*id as usize)
1359                .and_then(|var| var.solved.as_ref())
1360                .map(|(ty, _)| ty.resolved(vars))
1361                .unwrap_or_else(|| self.clone()),
1362            Ty::Array(inner) => Ty::Array(Box::new(inner.resolved(vars))),
1363            Ty::Vector(inner) => Ty::Vector(Box::new(inner.resolved(vars))),
1364            Ty::Set(inner) => Ty::Set(Box::new(inner.resolved(vars))),
1365            Ty::Option(inner) => Ty::Option(Box::new(inner.resolved(vars))),
1366            Ty::Task(inner) => Ty::Task(Box::new(inner.resolved(vars))),
1367            Ty::Shared(inner) => Ty::Shared(Box::new(inner.resolved(vars))),
1368            Ty::Map(k, v) => Ty::Map(Box::new(k.resolved(vars)), Box::new(v.resolved(vars))),
1369            Ty::MapEntry(k, v) => {
1370                Ty::MapEntry(Box::new(k.resolved(vars)), Box::new(v.resolved(vars)))
1371            }
1372            Ty::Result(k, v) => Ty::Result(Box::new(k.resolved(vars)), Box::new(v.resolved(vars))),
1373            Ty::Struct(name, args) => Ty::Struct(
1374                name.clone(),
1375                args.iter().map(|a| a.resolved(vars)).collect(),
1376            ),
1377            Ty::Enum(name, args) => Ty::Enum(
1378                name.clone(),
1379                args.iter().map(|a| a.resolved(vars)).collect(),
1380            ),
1381            Ty::Fn(func) => Ty::func(
1382                func.is_async,
1383                func.params.iter().map(|p| p.resolved(vars)).collect(),
1384                func.ret.resolved(vars),
1385            ),
1386            other => other.clone(),
1387        }
1388    }
1389
1390    /// This type with every inference variable replaced by what settled it.
1391    ///
1392    /// A variable nothing settled becomes [`Ty::unconstrained`], which is
1393    /// what it would have been had this pass never opened it — so a type
1394    /// that leaves the checker is a type a reader of [`Facts`] can already
1395    /// read, and the inference is invisible to everything downstream except
1396    /// where it succeeded.
1397    fn settled(&self, vars: &[TyVar]) -> Ty {
1398        match self {
1399            Ty::Unknown(Unknown::Var(id)) => vars
1400                .get(*id as usize)
1401                .and_then(|var| var.solved.as_ref())
1402                .map(|(ty, _)| ty.clone())
1403                .unwrap_or_else(Ty::unconstrained),
1404            Ty::Array(inner) => Ty::Array(Box::new(inner.settled(vars))),
1405            Ty::Vector(inner) => Ty::Vector(Box::new(inner.settled(vars))),
1406            Ty::Set(inner) => Ty::Set(Box::new(inner.settled(vars))),
1407            Ty::Option(inner) => Ty::Option(Box::new(inner.settled(vars))),
1408            Ty::Task(inner) => Ty::Task(Box::new(inner.settled(vars))),
1409            Ty::Shared(inner) => Ty::Shared(Box::new(inner.settled(vars))),
1410            Ty::Map(k, v) => Ty::Map(Box::new(k.settled(vars)), Box::new(v.settled(vars))),
1411            Ty::MapEntry(k, v) => {
1412                Ty::MapEntry(Box::new(k.settled(vars)), Box::new(v.settled(vars)))
1413            }
1414            Ty::Result(k, v) => Ty::Result(Box::new(k.settled(vars)), Box::new(v.settled(vars))),
1415            Ty::Struct(name, args) => {
1416                Ty::Struct(name.clone(), args.iter().map(|a| a.settled(vars)).collect())
1417            }
1418            Ty::Enum(name, args) => {
1419                Ty::Enum(name.clone(), args.iter().map(|a| a.settled(vars)).collect())
1420            }
1421            Ty::Fn(func) => Ty::func(
1422                func.is_async,
1423                func.params.iter().map(|p| p.settled(vars)).collect(),
1424                func.ret.settled(vars),
1425            ),
1426            other => other.clone(),
1427        }
1428    }
1429
1430    /// Nominal equality, with `Unknown` and `Never` equal to everything.
1431    ///
1432    /// Generic arguments are invariant: `Array<Int>` and `Array<Float>` are
1433    /// unrelated types, in either direction.
1434    fn matches(&self, other: &Ty) -> bool {
1435        if self.is_wild() || other.is_wild() {
1436            return true;
1437        }
1438        match (self, other) {
1439            (Ty::Array(a), Ty::Array(b))
1440            | (Ty::Vector(a), Ty::Vector(b))
1441            | (Ty::Set(a), Ty::Set(b))
1442            | (Ty::Option(a), Ty::Option(b))
1443            | (Ty::Task(a), Ty::Task(b))
1444            | (Ty::Shared(a), Ty::Shared(b)) => a.matches(b),
1445            (Ty::Map(ak, av), Ty::Map(bk, bv))
1446            | (Ty::MapEntry(ak, av), Ty::MapEntry(bk, bv))
1447            | (Ty::Result(ak, av), Ty::Result(bk, bv)) => ak.matches(bk) && av.matches(bv),
1448            (Ty::Struct(a, aargs), Ty::Struct(b, bargs))
1449            | (Ty::Enum(a, aargs), Ty::Enum(b, bargs)) => {
1450                a == b
1451                    && aargs.len() == bargs.len()
1452                    && aargs.iter().zip(bargs).all(|(a, b)| a.matches(b))
1453            }
1454            (Ty::Fn(a), Ty::Fn(b)) => {
1455                a.is_async == b.is_async
1456                    && a.params.len() == b.params.len()
1457                    && a.params.iter().zip(&b.params).all(|(a, b)| a.matches(b))
1458                    && a.ret.matches(&b.ret)
1459            }
1460            (Ty::Param(a), Ty::Param(b))
1461            | (Ty::Dyn(a), Ty::Dyn(b))
1462            | (Ty::Host(a), Ty::Host(b)) => a == b,
1463            (a, b) => std::mem::discriminant(a) == std::mem::discriminant(b),
1464        }
1465    }
1466
1467    /// The more informative of two types that already [`Ty::matches`], used
1468    /// where two branches must agree: a known type wins over `Unknown`, and
1469    /// any type wins over `Never`.
1470    ///
1471    /// It reaches inside a shared shape as well, because that is where the
1472    /// information usually is: `[[], [1]]` joins `Array<_>` with
1473    /// `Array<Int>`, and answering `Array<_>` would leave the array's
1474    /// elements unchecked for the rest of the program even though one of
1475    /// them said exactly what they are.
1476    fn join(&self, other: &Ty) -> Ty {
1477        match (self, other) {
1478            (Ty::Never, other) | (other, Ty::Never) => other.clone(),
1479            (Ty::Unknown(_) | Ty::Any, other) | (other, Ty::Unknown(_) | Ty::Any) => other.clone(),
1480            (Ty::Array(a), Ty::Array(b)) => Ty::Array(Box::new(a.join(b))),
1481            (Ty::Vector(a), Ty::Vector(b)) => Ty::Vector(Box::new(a.join(b))),
1482            (Ty::Set(a), Ty::Set(b)) => Ty::Set(Box::new(a.join(b))),
1483            (Ty::Option(a), Ty::Option(b)) => Ty::Option(Box::new(a.join(b))),
1484            (Ty::Task(a), Ty::Task(b)) => Ty::Task(Box::new(a.join(b))),
1485            (Ty::Shared(a), Ty::Shared(b)) => Ty::Shared(Box::new(a.join(b))),
1486            (Ty::Map(ak, av), Ty::Map(bk, bv)) => {
1487                Ty::Map(Box::new(ak.join(bk)), Box::new(av.join(bv)))
1488            }
1489            (Ty::MapEntry(ak, av), Ty::MapEntry(bk, bv)) => {
1490                Ty::MapEntry(Box::new(ak.join(bk)), Box::new(av.join(bv)))
1491            }
1492            (Ty::Result(ak, av), Ty::Result(bk, bv)) => {
1493                Ty::Result(Box::new(ak.join(bk)), Box::new(av.join(bv)))
1494            }
1495            (Ty::Struct(a, aargs), Ty::Struct(b, bargs))
1496                if a == b && aargs.len() == bargs.len() =>
1497            {
1498                Ty::Struct(
1499                    a.clone(),
1500                    aargs.iter().zip(bargs).map(|(a, b)| a.join(b)).collect(),
1501                )
1502            }
1503            (Ty::Enum(a, aargs), Ty::Enum(b, bargs)) if a == b && aargs.len() == bargs.len() => {
1504                Ty::Enum(
1505                    a.clone(),
1506                    aargs.iter().zip(bargs).map(|(a, b)| a.join(b)).collect(),
1507                )
1508            }
1509            (Ty::Fn(a), Ty::Fn(b))
1510                if a.is_async == b.is_async && a.params.len() == b.params.len() =>
1511            {
1512                Ty::func(
1513                    a.is_async,
1514                    a.params
1515                        .iter()
1516                        .zip(&b.params)
1517                        .map(|(a, b)| a.join(b))
1518                        .collect(),
1519                    a.ret.join(&b.ret),
1520                )
1521            }
1522            _ => self.clone(),
1523        }
1524    }
1525
1526    /// This type as it stands when `generics` are the arguments `args`.
1527    ///
1528    /// A declared type's fields and an enum case's payload are recorded once,
1529    /// in terms of the type parameters the declaration binds:
1530    /// `Box<T>`'s field is a `T` however many `Box<Int>`s a program holds. A
1531    /// consumer holding a *use* — a `Ty::Struct(name, args)` — completes them
1532    /// with this. `args` shorter than `generics` leaves the rest unknown,
1533    /// which is what an unsettled type argument already means.
1534    pub fn instantiate(&self, generics: &[Arc<str>], args: &[Ty]) -> Ty {
1535        self.substitute(&substitution(generics, args))
1536    }
1537
1538    /// Replaces every type parameter bound in `subst`, leaving the rest.
1539    fn substitute(&self, subst: &BTreeMap<Arc<str>, Ty>) -> Ty {
1540        if subst.is_empty() {
1541            return self.clone();
1542        }
1543        match self {
1544            Ty::Param(name) => subst.get(name).cloned().unwrap_or_else(|| self.clone()),
1545            Ty::Array(inner) => Ty::Array(Box::new(inner.substitute(subst))),
1546            Ty::Vector(inner) => Ty::Vector(Box::new(inner.substitute(subst))),
1547            Ty::Set(inner) => Ty::Set(Box::new(inner.substitute(subst))),
1548            Ty::Option(inner) => Ty::Option(Box::new(inner.substitute(subst))),
1549            Ty::Task(inner) => Ty::Task(Box::new(inner.substitute(subst))),
1550            Ty::Shared(inner) => Ty::Shared(Box::new(inner.substitute(subst))),
1551            Ty::Map(k, v) => Ty::Map(Box::new(k.substitute(subst)), Box::new(v.substitute(subst))),
1552            Ty::MapEntry(k, v) => {
1553                Ty::MapEntry(Box::new(k.substitute(subst)), Box::new(v.substitute(subst)))
1554            }
1555            Ty::Result(t, e) => {
1556                Ty::Result(Box::new(t.substitute(subst)), Box::new(e.substitute(subst)))
1557            }
1558            Ty::Struct(name, args) => Ty::Struct(
1559                name.clone(),
1560                args.iter().map(|a| a.substitute(subst)).collect(),
1561            ),
1562            Ty::Enum(name, args) => Ty::Enum(
1563                name.clone(),
1564                args.iter().map(|a| a.substitute(subst)).collect(),
1565            ),
1566            Ty::Fn(f) => Ty::func(
1567                f.is_async,
1568                f.params.iter().map(|p| p.substitute(subst)).collect(),
1569                f.ret.substitute(subst),
1570            ),
1571            other => other.clone(),
1572        }
1573    }
1574}
1575
1576/// Renders a type in the source form it would be written in, so a diagnostic
1577/// shows the type the reader wrote.
1578impl fmt::Display for Ty {
1579    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1580        match self {
1581            // An unknown type reads as `_` because that is how an
1582            // unconstrained position is written in Cove source.
1583            Ty::Unknown(_) => f.write_str("_"),
1584            // The word the schema wrote. `_` is what the checker says when
1585            // it does not know; `Any` is what a schema says when there is
1586            // nothing to know.
1587            Ty::Any => f.write_str("Any"),
1588            Ty::Never => f.write_str("!"),
1589            Ty::Unit => f.write_str("()"),
1590            Ty::Bool => f.write_str("Bool"),
1591            Ty::Int => f.write_str("Int"),
1592            Ty::Float => f.write_str("Float"),
1593            Ty::Str => f.write_str("String"),
1594            Ty::Duration => f.write_str("Duration"),
1595            Ty::Error => f.write_str("Error"),
1596            Ty::Range => f.write_str("Range"),
1597            Ty::Scope => f.write_str("Scope"),
1598            Ty::Array(inner) => write!(f, "Array<{inner}>"),
1599            Ty::Vector(inner) => write!(f, "Vector<{inner}>"),
1600            Ty::Set(inner) => write!(f, "Set<{inner}>"),
1601            Ty::Option(inner) => write!(f, "Option<{inner}>"),
1602            Ty::Task(inner) => write!(f, "Task<{inner}>"),
1603            Ty::Shared(inner) => write!(f, "Shared<{inner}>"),
1604            Ty::Map(k, v) => write!(f, "Map<{k}, {v}>"),
1605            Ty::MapEntry(k, v) => write!(f, "MapEntry<{k}, {v}>"),
1606            Ty::Result(t, e) => write!(f, "Result<{t}, {e}>"),
1607            Ty::Param(name) => f.write_str(name),
1608            Ty::Host(name) => f.write_str(name),
1609            Ty::Dyn(name) => write!(f, "dyn {name}"),
1610            Ty::Struct(name, args) | Ty::Enum(name, args) => {
1611                f.write_str(name)?;
1612                if !args.is_empty() {
1613                    let args: Vec<String> = args.iter().map(Ty::to_string).collect();
1614                    write!(f, "<{}>", args.join(", "))?;
1615                }
1616                Ok(())
1617            }
1618            Ty::Fn(func) => {
1619                if func.is_async {
1620                    f.write_str("async ")?;
1621                }
1622                let params: Vec<String> = func.params.iter().map(Ty::to_string).collect();
1623                write!(f, "fn({})", params.join(", "))?;
1624                if func.ret != Ty::Unit {
1625                    write!(f, " -> {}", func.ret)?;
1626                }
1627                Ok(())
1628            }
1629        }
1630    }
1631}
1632
1633// -------------------------------------------------------------- signatures
1634
1635/// One parameter of a declared function, method, or synthesized struct
1636/// initializer.
1637#[derive(Clone, Debug)]
1638struct ParamSig {
1639    name: String,
1640    ty: Ty,
1641    variadic: bool,
1642    has_default: bool,
1643    /// Whether the declaration wrote `var` before this parameter's name, so
1644    /// that a body binds it as the mutable place it is.
1645    ///
1646    /// Only a `fn` declaration, a method and a lambda can write one; a
1647    /// struct's field, a builtin's parameter, a host operation's and the
1648    /// parameters read off a function *type* are all `false`, because none
1649    /// of those is written with a marking at all.
1650    is_var: bool,
1651    span: Span,
1652}
1653
1654/// One trait a type parameter is bounded by, and where the bound was
1655/// written, so an unsatisfied bound can point at it.
1656#[derive(Clone, Debug)]
1657struct TraitBound {
1658    name: Arc<str>,
1659    span: Span,
1660}
1661
1662/// A declared function's or method's type, as written at its boundary.
1663#[derive(Clone, Debug)]
1664struct FnSig {
1665    /// Type parameters this signature binds, rigid inside its own body.
1666    generics: Vec<Arc<str>>,
1667    /// The traits each type parameter is bounded by. A parameter with no
1668    /// bound is absent, which is also what makes a method call on it an
1669    /// error: it has no operations.
1670    bounds: BTreeMap<Arc<str>, Vec<TraitBound>>,
1671    params: Vec<ParamSig>,
1672    ret: Ty,
1673    ret_span: Span,
1674    is_async: bool,
1675    /// The type of `self`, for a method.
1676    receiver: Option<Ty>,
1677    /// Whether that receiver is written `var self`, which is what makes a
1678    /// call through it a write to the caller's place.
1679    receiver_is_var: bool,
1680}
1681
1682impl FnSig {
1683    /// This signature as a module importing it sees it: every nominal name
1684    /// `module` declares rewritten into its canonical `module.Name` form.
1685    fn qualified(&self, module: &str) -> FnSig {
1686        FnSig {
1687            generics: self.generics.clone(),
1688            bounds: self
1689                .bounds
1690                .iter()
1691                .map(|(param, bounds)| {
1692                    let bounds = bounds
1693                        .iter()
1694                        .map(|bound| TraitBound {
1695                            name: qualified_name(&bound.name, module),
1696                            span: bound.span,
1697                        })
1698                        .collect();
1699                    (param.clone(), bounds)
1700                })
1701                .collect(),
1702            params: self
1703                .params
1704                .iter()
1705                .map(|param| ParamSig {
1706                    ty: qualify(&param.ty, module),
1707                    ..param.clone()
1708                })
1709                .collect(),
1710            ret: qualify(&self.ret, module),
1711            ret_span: self.ret_span,
1712            is_async: self.is_async,
1713            receiver: self.receiver.as_ref().map(|ty| qualify(ty, module)),
1714            receiver_is_var: self.receiver_is_var,
1715        }
1716    }
1717
1718    /// The type of this function used as a value, which is what a bare
1719    /// reference to it evaluates to.
1720    fn as_value(&self) -> Ty {
1721        Ty::func(
1722            self.is_async,
1723            self.params.iter().map(|p| p.ty.clone()).collect(),
1724            self.ret.clone(),
1725        )
1726    }
1727}
1728
1729/// A struct's fields, in declaration order.
1730#[derive(Clone, Debug)]
1731struct StructSig {
1732    generics: Vec<Arc<str>>,
1733    fields: Vec<ParamSig>,
1734    /// `export opaque struct`: the fields below belong to the declaring
1735    /// module alone.
1736    ///
1737    /// They are still recorded, because the declaring module's own bodies
1738    /// are checked against them and a field's type still has to resolve.
1739    /// What `opaque` changes is who may name one: see [`foreign_type`].
1740    opaque: bool,
1741}
1742
1743/// An enum's cases, in declaration order.
1744#[derive(Clone, Debug)]
1745struct EnumSig {
1746    generics: Vec<Arc<str>>,
1747    cases: Vec<CaseSig>,
1748}
1749
1750#[derive(Clone, Debug)]
1751struct CaseSig {
1752    name: String,
1753    payload: Vec<Ty>,
1754    span: Span,
1755}
1756
1757/// One field, or one payload of one enum case: the type it holds, how a
1758/// diagnostic names it, and where that type is written.
1759///
1760/// A declaration is a list of these, and the layout-cycle analysis reads
1761/// nothing else about it. Struct and enum are the same shape to it because
1762/// the rule is the same for both: a case's payload sits in the value the way
1763/// a field does.
1764#[derive(Clone, Debug)]
1765struct LayoutMember {
1766    /// The member's type as the declaration writes it, so a type parameter
1767    /// is still a [`Ty::Param`] here.
1768    ty: Ty,
1769    /// `` field `next` `` or `` case `Cons` ``.
1770    label: String,
1771    /// The written type, which is the thing a correction changes.
1772    span: Span,
1773}
1774
1775/// One edge of a layout cycle: the member that carries a declaration's layout
1776/// into another declaration.
1777#[derive(Clone, Debug)]
1778struct LayoutStep {
1779    /// The declaration this step leaves.
1780    owner: String,
1781    /// [`LayoutMember::label`] of the member it leaves through.
1782    member: String,
1783    /// The declaration it reaches.
1784    reaches: String,
1785    span: Span,
1786}
1787
1788/// Which of a declaration's type parameters its own layout holds by value,
1789/// by position, keyed the way [`Checker::structs`] keys a declaration.
1790///
1791/// `Cell<T> { it: T }` holds its parameter; `Holder<T> { it: Vector<T> }`
1792/// does not, because a vector is one reference word whatever it holds. The
1793/// distinction is what lets `Cell<Node>` count as containing a `Node` while
1794/// `Vector<Node>` does not, without the analysis having to instantiate
1795/// anything.
1796type LayoutParams = BTreeMap<String, BTreeSet<usize>>;
1797
1798/// What a type holds *in* the value, rather than behind a reference.
1799#[derive(Debug, Default)]
1800struct InlineReach {
1801    /// Every declaration whose own layout is part of this type, in the order
1802    /// the type mentions them.
1803    declarations: Vec<String>,
1804    /// Every type parameter that is part of this type.
1805    params: BTreeSet<Arc<str>>,
1806}
1807
1808/// Collects what `ty` holds inline, given what each declaration holds inline.
1809///
1810/// This is the whole of ADR 0035's model of the layout. A value is a run of
1811/// consecutive words laid out where the value is, so a struct, an enum, and
1812/// the enum-shaped builtins — `Option`, `Result`, and the `MapEntry` a `for`
1813/// over a `Map` binds — put what they hold *inside* the value and are walked
1814/// through. Everything else stops the walk, because everything else is one
1815/// word: `String`, `Array`, `Map`, `Set`, `Vector`, `Shared`, a closure, a
1816/// `dyn` trait object and a host value are each a single address, and a
1817/// primitive holds nothing. ADR 0035 names every one of those but the host
1818/// value and the `Task`, which are added here: a host value is the host's,
1819/// and a task handle names a computation running elsewhere and holds no more
1820/// of its result than a `Vector` holds of its elements.
1821///
1822/// A generic type's arguments are followed only into the positions that
1823/// declaration holds inline, which is what `params` records. That is why
1824/// `Vector<Node>` reaches nothing — a vector holds its element behind an
1825/// address — while `Cell<Node>` reaches `Node`.
1826fn inline_reach(ty: &Ty, params: &LayoutParams, out: &mut InlineReach) {
1827    match ty {
1828        Ty::Param(name) => {
1829            out.params.insert(name.clone());
1830        }
1831        Ty::Struct(name, args) | Ty::Enum(name, args) => {
1832            out.declarations.push(name.to_string());
1833            let Some(inline) = params.get(&**name) else {
1834                return;
1835            };
1836            for (position, arg) in args.iter().enumerate() {
1837                if inline.contains(&position) {
1838                    inline_reach(arg, params, out);
1839                }
1840            }
1841        }
1842        Ty::Option(inner) => inline_reach(inner, params, out),
1843        Ty::Result(ok, err) => {
1844            inline_reach(ok, params, out);
1845            inline_reach(err, params, out);
1846        }
1847        Ty::MapEntry(key, value) => {
1848            inline_reach(key, params, out);
1849            inline_reach(value, params, out);
1850        }
1851        _ => {}
1852    }
1853}
1854
1855/// What a binding in a body means.
1856#[derive(Clone, Debug)]
1857struct Binding {
1858    ty: Ty,
1859    /// Whether source may write the place this name binds.
1860    ///
1861    /// `var` and a `var` parameter make one; `let`, an ordinary parameter, a
1862    /// variadic parameter, a pattern's binding, a `for` header's binding, a
1863    /// `scope`'s name and a local `fn` do not. It is `is_var` where a
1864    /// declaration writes one and `false` everywhere else, which is the same
1865    /// answer `Place::binding` gives each of them in
1866    /// `crates/cove-runtime/src/interp.rs`.
1867    mutable: bool,
1868}
1869
1870/// One inference variable: a type a call's result left open, which the uses
1871/// of the binding holding it may settle.
1872///
1873/// A variable is minted where a call's result mentions a type parameter
1874/// nothing settled ([`Checker::open_result`]), given to a binding where a
1875/// `let` or a `var` with no written type holds it ([`Checker::attach`]),
1876/// settled where a use of that binding meets a type ([`Checker::constrain`]),
1877/// and read back into [`Facts`] when the body ends
1878/// ([`Checker::finish_inference`]). Nothing outside that span of a single
1879/// body ever sees one.
1880#[derive(Debug)]
1881struct TyVar {
1882    /// The binding that holds this variable: its name, where that name was
1883    /// written, and the type it was given — which still holds this variable,
1884    /// so a diagnostic can show the whole type with the hole in it rather
1885    /// than the hole alone.
1886    ///
1887    /// `None` is a variable no binding took — the result of a call written
1888    /// in the middle of an expression — and one of those is settled where it
1889    /// can be and carried silently where it cannot, exactly as an
1890    /// unconstrained unknown was before any of this existed. The boundary
1891    /// the language draws is around a *local binding*, so it is the presence
1892    /// of an owner that decides whether the checker has anything to say.
1893    owner: Option<Owned>,
1894    /// The type a use settled this variable to, and the use that did it.
1895    solved: Option<(Ty, Span)>,
1896    /// Whether two uses have already been reported as disagreeing, so a
1897    /// third one does not report the same disagreement again.
1898    conflicted: bool,
1899    /// A use that said what this variable is in terms this pass cannot keep,
1900    /// and where it said it.
1901    ///
1902    /// A constraint whose own type still holds a variable settles nothing:
1903    /// `var v = Vector.of()` followed by `v.push(v)` asks for a `Vector` of
1904    /// itself. That type is regular and finitely representable — `μX.
1905    /// Vector<X>` — and Cove has no syntax for it, because recursion here is
1906    /// nominal and this inference is structural. So the constraint is read
1907    /// exactly and then cannot be kept, and what is left is a type no
1908    /// annotation could fill in either.
1909    ///
1910    /// It used to be carried silently, which made it the one way a clean
1911    /// `cove check` could hand a backend a type nothing settles. It is
1912    /// [`RECURSIVE_TYPE`] now, and the use that asked for it is what the
1913    /// diagnostic points at.
1914    spoken_for: Option<(Ty, Span)>,
1915    /// Where this variable was minted, for the diagnostic about a variable
1916    /// no binding took: a call in the middle of an expression has no name to
1917    /// name, so the call itself is what is pointed at.
1918    at: Span,
1919    /// The whole type the call that minted this variable produced, so a
1920    /// diagnostic can show `Result<Int, _>` rather than the hole alone.
1921    /// [`Owned::ty`] is the same thing once a binding has taken it.
1922    produced: Ty,
1923    /// A place the checker abstained about that this variable was given to.
1924    ///
1925    /// A schema declaring `Any` has said there is nothing here that depends
1926    /// on a type; a host module no schema describes says the same by
1927    /// silence; a recovery unknown says the mistake above already accounted
1928    /// for it. [`Checker::accounted_for`] is the same rule applied to a form
1929    /// rather than to a variable: asking the program for an annotation under
1930    /// one of these would be asking it to state what the *place* declared it
1931    /// need not state. So a variable nothing else settled takes the
1932    /// abstention as its answer, silently.
1933    ///
1934    /// It is read at the end of the body rather than where it is set, so
1935    /// that a use which says something real still wins wherever it is
1936    /// written.
1937    abstained: Option<Ty>,
1938    /// Whether a [`Checker::probe`] minted this one.
1939    ///
1940    /// A probe walks a tree to find one type out and throws away what it
1941    /// reported; the real walk of the same tree follows and mints its own.
1942    /// Reporting a probe's variable would report a hole in a tree that was
1943    /// walked twice, once.
1944    probed: bool,
1945}
1946
1947/// The binding an inference variable belongs to.
1948#[derive(Clone, Debug)]
1949struct Owned {
1950    name: String,
1951    /// Where the name was written, which is where a diagnostic about the
1952    /// type nothing settled belongs: the correction is an annotation there.
1953    span: Span,
1954    /// The binding's type as the initializer left it, variables and all.
1955    ty: Ty,
1956}
1957
1958/// Where an expectation came from, so a mismatch can point at the
1959/// declaration that imposed it as well as the expression that broke it.
1960#[derive(Clone, Debug)]
1961struct Origin {
1962    span: Span,
1963    label: String,
1964}
1965
1966/// A type an expression is checked against, and the declaration that asks
1967/// for it.
1968#[derive(Clone, Debug)]
1969struct Expected {
1970    ty: Ty,
1971    origin: Option<Origin>,
1972}
1973
1974impl Expected {
1975    fn new(ty: Ty, span: Span, label: impl Into<String>) -> Expected {
1976        Expected {
1977            ty,
1978            origin: Some(Origin {
1979                span,
1980                label: label.into(),
1981            }),
1982        }
1983    }
1984
1985    /// An expectation with nothing to point at, made of an unknown the
1986    /// checker has already accounted for.
1987    ///
1988    /// It never disagrees with anything, so it has no mismatch to label. What
1989    /// it does carry is the answer to *why* the place says nothing, which is
1990    /// what `Checker::accounted_for` reads: the diagnostic explaining that
1991    /// silence has already been given, or belongs somewhere else entirely.
1992    fn abstained(ty: Ty) -> Expected {
1993        Expected { ty, origin: None }
1994    }
1995}
1996
1997// ---------------------------------------------------------------- checking
1998
1999/// Checks one module against its own declarations, its imports, and the
2000/// builtins.
2001///
2002/// # How a declaration is named
2003///
2004/// Every table below is keyed by a declaration's *canonical name*: the bare
2005/// name for a declaration this module makes, and `module.Name` for one that
2006/// belongs to another module — whether this module imported it or only ever
2007/// meets it as the type of an imported function's result. One declaration
2008/// therefore has exactly one key here, so `Ty::Struct` and `Ty::Enum` can
2009/// compare two types by name without confusing two modules' `Config`.
2010/// [`Checker::key`] turns a name as written into that key.
2011struct Checker<'a> {
2012    module: &'a ResolvedModule,
2013    /// The whole program, for the declarations of the modules this one
2014    /// imports from.
2015    program: &'a Program,
2016    /// The host modules this compilation can see: the shipped ones, and any
2017    /// an embedder handed to the compiler. A call into a module that is not
2018    /// here is the one call this checker leaves to the boundary.
2019    schemas: &'a HostSchemas,
2020    diagnostics: Vec<Diagnostic>,
2021    functions: BTreeMap<String, FnSig>,
2022    methods: BTreeMap<(String, String), FnSig>,
2023    structs: BTreeMap<String, StructSig>,
2024    enums: BTreeMap<String, EnumSig>,
2025    /// Expanded type aliases, resolved once so the names inside an alias are
2026    /// reported once however many times it is used.
2027    aliases: BTreeMap<String, (Vec<Arc<str>>, Ty)>,
2028    /// Aliases currently being expanded, to catch `type A = A`.
2029    expanding: Vec<String>,
2030    /// Every trait the module declares, with the signature of each of its
2031    /// methods.
2032    traits: BTreeMap<String, BTreeMap<String, FnSig>>,
2033    /// Every declared conformance, as `(trait, type)`. Conformance is
2034    /// explicit, so this set is complete.
2035    conformances: BTreeSet<(String, String)>,
2036    /// Type parameters in scope, innermost last.
2037    type_params: Vec<Arc<str>>,
2038    /// The bounds of the type parameters currently in scope.
2039    bounds: BTreeMap<Arc<str>, Vec<TraitBound>>,
2040    scopes: Vec<BTreeMap<String, Binding>>,
2041    /// The lowest scope that belongs to the function value currently being
2042    /// checked.
2043    ///
2044    /// A lambda and a local `fn` are checked with the scopes around them
2045    /// still standing, because a body reads the names it closes over. What
2046    /// it closes over it holds a *copy* of: `Env::declare_capture` builds a
2047    /// `Place::binding(value, false)`, so a captured `var` is read-only
2048    /// inside the closure however it was declared outside. A name found
2049    /// below this index is therefore a capture, and no capture is writable.
2050    capture_floor: usize,
2051    /// The declared return type of the function whose body is being checked,
2052    /// and where it was written.
2053    ret: Ty,
2054    ret_span: Span,
2055    /// The field expression currently being checked as the target of an
2056    /// assignment, if any.
2057    ///
2058    /// A place is checked by the same walk as a value, so nothing about
2059    /// `x.field` says whether it is being read or written — the assignment
2060    /// above it is the only thing that knows. Recording its span is enough
2061    /// to tell the two apart, because the reads on the way to a place carry
2062    /// their own: in `a.b.c = v` the target is `a.b.c` and `a.b` is a read
2063    /// like any other.
2064    assigned_place: Option<Span>,
2065    /// Whether anything written says what the function being checked
2066    /// produces.
2067    ///
2068    /// It is true for every declaration, which writes its return type or
2069    /// returns `Unit`, and for a function value the place holding it typed.
2070    /// It is false only for a lambda nothing expects, whose result is
2071    /// whatever its body's value turns out to be — and which therefore has
2072    /// nothing for an early `return` to agree with.
2073    ret_stated: bool,
2074    /// Whether the walk currently running is a `Checker::probe`, whose
2075    /// diagnostics are discarded.
2076    probing: bool,
2077    /// How many diagnostics had been reported when the body being checked
2078    /// began.
2079    ///
2080    /// [`Checker::finish_inference`] reads it. Everything it reports is
2081    /// "the program did not say what this is", and a body that already has
2082    /// an error in it is a body the checker stopped being able to read: the
2083    /// type nothing settled is downstream of the mistake, and ADR 0016's
2084    /// rule is one mistake, one diagnostic, however far its unknown
2085    /// travels.
2086    body_mark: usize,
2087    /// What this checker settled about each expression it walked.
2088    ///
2089    /// It is written to and never read by the walk, which is what makes it
2090    /// unable to change a diagnostic. [`Facts`] says who reads it and why.
2091    facts: Facts,
2092    /// The inference variables minted while checking the body in hand.
2093    ///
2094    /// Indexed by the identity [`Unknown::Var`] carries. It is emptied at
2095    /// the end of every body, which is what makes the inference *local*: a
2096    /// use in one declaration can never settle a variable another
2097    /// declaration's binding holds, because the two are never in this table
2098    /// at the same time.
2099    vars: Vec<TyVar>,
2100    /// Every expression whose recorded type still held a variable when it
2101    /// was recorded.
2102    ///
2103    /// A fact is written as the walk settles it, and a variable is settled
2104    /// after that, so these are the facts that have to be written a second
2105    /// time. Keeping the list is what keeps the rewrite proportional to the
2106    /// expressions that actually held one rather than to the file.
2107    open_facts: Vec<(cove_diag::FileId, ExprId)>,
2108    /// One frame per `scope` being checked, innermost last, holding the
2109    /// tasks spawned into it whose value is a `Result`.
2110    ///
2111    /// A frame is emptied at the `scope` that opened it, which is where the
2112    /// question is decided: the waiting happens there, so that is where a
2113    /// child nothing awaited is measured against what the function answers.
2114    open_scopes: Vec<OpenScope>,
2115    /// One frame per function value being checked, innermost last, holding
2116    /// the `?`s written directly in its body that nothing outside it said
2117    /// where to put.
2118    ///
2119    /// A frame is emptied where the function value's own result type is
2120    /// settled, which is the only place the question can be decided: a
2121    /// lambda no place declared a result for produces what its body's value
2122    /// turns out to be, and that is not known until the body has been
2123    /// walked to the end.
2124    open_lambdas: Vec<Vec<PendingTry>>,
2125}
2126
2127/// A `scope` being checked, and the children of it that could fail.
2128struct OpenScope {
2129    /// The name the program gave the scope, for a spawn whose receiver is
2130    /// not a bare name to be described by.
2131    name: String,
2132    children: Vec<SpawnedChild>,
2133}
2134
2135/// A task spawned into a `scope`, whose value is a `Result`.
2136///
2137/// Only these are recorded, because only these carry a Cove `Err` for scope
2138/// exit to propagate. A child answering `Unit`, an `Int`, or anything else
2139/// that is not a `Result` leaves a scope with nothing to return, so a `scope`
2140/// full of them is at home in a function that answers `Unit` — which is what
2141/// `examples/covecheck/runner_test.cove`'s `counting` relies on. A child that
2142/// *raises* is a runtime error and does not travel as the function's value at
2143/// all, so it is not this pass's to decide either.
2144struct SpawnedChild {
2145    /// Where the `spawn` was written.
2146    span: Span,
2147    /// The scope the task was spawned into, as the program named it.
2148    scope: String,
2149    /// The name a `let` or `var` gave the handle, when one did. It is what
2150    /// the diagnostic calls the child.
2151    binding: Option<String>,
2152    /// What scope exit would return from the enclosing function.
2153    error: Ty,
2154    /// Whether the checker saw an `await` applied to the handle.
2155    ///
2156    /// This is a syntactic reading and it is deliberately the permissive
2157    /// one: an `await` reached on only some paths still counts, because the
2158    /// alternative is to reject `if stop { t.cancel() } else { t.await() }`,
2159    /// which runs. What a miss costs is a lowering that refuses the scope,
2160    /// which is where such a program stands today; what a false positive
2161    /// would cost is a working program the compiler stops accepting.
2162    awaited: bool,
2163}
2164
2165/// A `?` written in a function value's body, held until the value has a type.
2166///
2167/// `?` returns from the function it is *written in*, and a function value is
2168/// one: `Interpreter::eval` raises a `Control::Return` that the closure's own
2169/// call is what catches, so the failure lands in the lambda's result and not
2170/// in the declaration's. When a place declares the lambda's result type, the
2171/// check `Checker::try_expr` already makes against `Checker::ret` is that
2172/// check. When nothing does — a bare lambda, or a body a Host API schema
2173/// declared `Any` — the result is whatever the body proves, so there is
2174/// nothing to compare against until the body has been walked. These are the
2175/// `?`s that wait for it.
2176struct PendingTry {
2177    /// Where the `?` was written.
2178    span: Span,
2179    /// What it propagates: the `Err` type of a `Result`, or `None` for the
2180    /// `None` of an `Option`, which carries nothing.
2181    error: Option<Ty>,
2182}
2183
2184impl<'a> Checker<'a> {
2185    fn new(
2186        module: &'a ResolvedModule,
2187        program: &'a Program,
2188        schemas: &'a HostSchemas,
2189    ) -> Checker<'a> {
2190        Checker {
2191            module,
2192            program,
2193            schemas,
2194            diagnostics: Vec::new(),
2195            functions: BTreeMap::new(),
2196            methods: BTreeMap::new(),
2197            structs: BTreeMap::new(),
2198            enums: BTreeMap::new(),
2199            aliases: BTreeMap::new(),
2200            expanding: Vec::new(),
2201            traits: BTreeMap::new(),
2202            conformances: module
2203                .conformances
2204                .values()
2205                .map(|conformance| conformance_key(module, conformance))
2206                .collect(),
2207            type_params: Vec::new(),
2208            bounds: BTreeMap::new(),
2209            scopes: Vec::new(),
2210            capture_floor: 0,
2211            // No body is being checked yet, and every one of them sets all
2212            // three of these before it can reach a `return`.
2213            ret: Ty::placeholder(),
2214            ret_span: Span::new(cove_diag::FileId(0), 0, 0),
2215            assigned_place: None,
2216            ret_stated: false,
2217            probing: false,
2218            facts: Facts::default(),
2219            vars: Vec::new(),
2220            body_mark: 0,
2221            open_facts: Vec::new(),
2222            open_scopes: Vec::new(),
2223            open_lambdas: Vec::new(),
2224        }
2225    }
2226
2227    /// The Host API schema of the module named `module`, or `None` when this
2228    /// compilation was shown none for it.
2229    ///
2230    /// Every abstention this pass makes about a host goes through here, so
2231    /// this is the one seam an embedder-supplied schema has to reach. It
2232    /// answers from the [`HostSchemas`] the compilation was given: the
2233    /// modules an embedder handed over first, then — unless the set was
2234    /// built with `HostSchemas::only` — the ones the toolchain ships. That
2235    /// is what turns each of those abstentions into an ordinary check
2236    /// without any other part of this pass changing, and what a name no
2237    /// table answers for still gets is a [`Ty::dynamic_boundary`].
2238    ///
2239    /// It is a method taking `&self` and answering with an *owned*
2240    /// [`ModuleSchema`] rather than a free function answering with a
2241    /// `&'static` one, and both halves of that are the seam. A table an
2242    /// embedder registers is owned by the compilation, not by the binary, so
2243    /// it has no `'static` borrow to hand back; and a set of them is
2244    /// something the checker is given rather than something it looks up in a
2245    /// global. `ModuleSchema` is [`Copy`] and everything inside it is
2246    /// `'static`, so answering by value costs nothing and the schemas
2247    /// reached *through* the answer — operations, types, resources — are
2248    /// still `&'static`.
2249    fn host_schema(&self, module: &str) -> Option<ModuleSchema> {
2250        self.schemas.module(module)
2251    }
2252
2253    /// The schema of the host type `qualified` names, when it is one a host
2254    /// hands over rather than one it keeps.
2255    fn host_declared_type(&self, qualified: &str) -> Option<&'static TypeSchema> {
2256        let (module, name) = qualified.split_once('.')?;
2257        self.host_schema(module)?.declared_type(name)
2258    }
2259
2260    /// The schema of the host resource `qualified` names.
2261    fn host_resource(&self, qualified: &str) -> Option<&'static ResourceSchema> {
2262        let (module, name) = qualified.split_once('.')?;
2263        self.host_schema(module)?.resource(name)
2264    }
2265
2266    /// Walks something to find out its type, reporting nothing.
2267    ///
2268    /// A form whose type a sibling settles has to be walked once to learn
2269    /// that and once to be checked against it, and only the second walk
2270    /// describes the program. Nothing else about a walk is observable —
2271    /// diagnostics are appended to one vector that nothing reads until the
2272    /// pass ends, and every scope a walk pushes it pops — so truncating that
2273    /// vector is all undoing one takes.
2274    ///
2275    /// A probe never probes again. One level of it finds the same type a
2276    /// nested one would, and disabling the nested ones is what keeps a walk
2277    /// of nested literals from doubling per level.
2278    fn probe<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
2279        let mark = self.diagnostics.len();
2280        let outer = std::mem::replace(&mut self.probing, true);
2281        let found = f(self);
2282        self.probing = outer;
2283        self.diagnostics.truncate(mark);
2284        found
2285    }
2286
2287    // ------------------------------------------------------------ imports
2288
2289    /// The table key a name written in this module refers to: the name
2290    /// itself when this module declares it, and `module.Name` when a `use`
2291    /// imported it from `module`.
2292    ///
2293    /// Resolution refuses a `use` that binds a name the importing module
2294    /// also declares, so at most one of the two answers ever applies.
2295    fn key(&self, name: &str) -> String {
2296        match self.module.imports.get(name) {
2297            Some(owner) => format!("{owner}.{name}"),
2298            None => name.to_string(),
2299        }
2300    }
2301
2302    /// Whether `name` as written names a declaration of another module,
2303    /// which is what makes [`Checker::key`] answer something other than
2304    /// `name`.
2305    fn is_imported(&self, name: &str) -> bool {
2306        self.module.imports.contains_key(name)
2307    }
2308
2309    /// The key `head.name` refers to when `head` is a module imported whole
2310    /// and that module exports `name`.
2311    ///
2312    /// A module-private declaration is reported rather than resolved: a
2313    /// qualified name reaches exactly what a `use` of it would.
2314    fn qualified_key(&mut self, head: &str, name: &str, span: Span) -> Option<String> {
2315        let owner_name = self.module.module_imports.get(head)?;
2316        let owner = self.program.modules.get(owner_name)?;
2317        let exported = match owner.exported(name) {
2318            Some(exported) => exported,
2319            None => {
2320                self.diagnostics.push(
2321                    Diagnostic::error(
2322                        UNKNOWN_MEMBER,
2323                        format!("module `{owner_name}` declares no `{name}`"),
2324                    )
2325                    .at(span)
2326                    .rule(
2327                        "A qualified name reaches an exported declaration of the module it names.",
2328                    )
2329                    .help(format!(
2330                        "module `{owner_name}` exports {}",
2331                        list(&owner.exports())
2332                    )),
2333                );
2334                return None;
2335            }
2336        };
2337        if !exported {
2338            self.diagnostics.push(
2339                Diagnostic::error(
2340                    UNKNOWN_MEMBER,
2341                    format!("`{name}` is declared by module `{owner_name}`, but is not exported"),
2342                )
2343                .at(span)
2344                .rule("An `export` declaration is public; other declarations are module-private.")
2345                .help(format!(
2346                    "write `export` on `{name}` in module `{owner_name}`, or name something else"
2347                )),
2348            );
2349            return None;
2350        }
2351        Some(format!("{owner_name}.{name}"))
2352    }
2353
2354    // ------------------------------------------------------- opaque types
2355
2356    /// The exported operations of the type `module.type_name` that a caller
2357    /// outside `module` may use, written as it would call them.
2358    ///
2359    /// `with_receiver` picks between the two halves of the interface an
2360    /// opaque type has: its associated functions, which are how a caller
2361    /// builds one, and its methods, which are how a caller reads one.
2362    ///
2363    /// Only what `module` itself declares counts. `methods_of` also answers
2364    /// with the methods other modules attach to the type by conforming it to
2365    /// a trait of their own, and one of those may be the very method being
2366    /// written — a help that says "call `show()`" inside the body of `show`
2367    /// is no help at all. What a caller needs is what the declaring module
2368    /// published.
2369    fn exported_operations(
2370        &self,
2371        module: &str,
2372        type_name: &str,
2373        with_receiver: bool,
2374    ) -> Vec<String> {
2375        self.program
2376            .methods_of(module, type_name)
2377            .into_iter()
2378            .filter(|declared| {
2379                declared.module == module
2380                    && declared.entry.exported
2381                    && declared.entry.decl.receiver.is_some() == with_receiver
2382            })
2383            .map(|declared| {
2384                if with_receiver {
2385                    format!("{}()", declared.name)
2386                } else {
2387                    format!("{type_name}.{}()", declared.name)
2388                }
2389            })
2390            .collect()
2391    }
2392
2393    /// The `help` line that points a caller at what an opaque type does
2394    /// export, or at the fact that it exports nothing of that kind.
2395    fn opaque_help(
2396        &self,
2397        module: &str,
2398        type_name: &str,
2399        with_receiver: bool,
2400        instead: &str,
2401        nothing: &str,
2402    ) -> String {
2403        let operations = self.exported_operations(module, type_name, with_receiver);
2404        if operations.is_empty() {
2405            format!(
2406                "module `{module}` exports no {nothing} for `{type_name}`, so ask it to export one"
2407            )
2408        } else {
2409            format!("{instead} {}", list(&operations))
2410        }
2411    }
2412
2413    /// Reports a use of an opaque type's representation from outside the
2414    /// module that declares it, and answers whether it did.
2415    ///
2416    /// `export opaque struct` publishes a name and the methods declared for
2417    /// it, so a caller reaching for a field or for the synthesized labeled
2418    /// constructor is reaching for something that was deliberately not
2419    /// exported. The declaring module is unaffected: its own key for the
2420    /// type is bare, which is what [`foreign_type`] tests.
2421    fn reject_opaque_field(
2422        &mut self,
2423        key: &str,
2424        sig: &StructSig,
2425        field: &str,
2426        usage: FieldUse,
2427        span: Span,
2428    ) -> bool {
2429        if !sig.opaque {
2430            return false;
2431        }
2432        let Some((module, type_name)) = foreign_type(key) else {
2433            return false;
2434        };
2435        let help = self.opaque_help(module, type_name, true, usage.correction(), "method");
2436        self.diagnostics.push(
2437            Diagnostic::error(
2438                OPAQUE_FIELD,
2439                format!(
2440                    "`{type_name}` is opaque here, so its field `{field}` cannot be {}",
2441                    usage.refused()
2442                ),
2443            )
2444            .at(span)
2445            .rule(
2446                "An `export opaque struct` exports its name and its exported methods; its fields belong to the module that declares it.",
2447            )
2448            .help(help),
2449        );
2450        true
2451    }
2452
2453    /// Reports a call to the synthesized labeled constructor of an opaque
2454    /// type from outside the module that declares it, and answers whether it
2455    /// did. See [`Checker::reject_opaque_field`].
2456    fn reject_opaque_construction(&mut self, key: &str, sig: &StructSig, span: Span) -> bool {
2457        if !sig.opaque {
2458            return false;
2459        }
2460        let Some((module, type_name)) = foreign_type(key) else {
2461            return false;
2462        };
2463        let help = self.opaque_help(
2464            module,
2465            type_name,
2466            false,
2467            "build the value through an exported associated function, such as",
2468            "constructor",
2469        );
2470        self.diagnostics.push(
2471            Diagnostic::error(
2472                OPAQUE_CONSTRUCTION,
2473                format!("`{type_name}` is opaque here, so it cannot be built field by field"),
2474            )
2475            .at(span)
2476            .rule(
2477                "An `export opaque struct` does not export the labeled constructor its fields synthesize; only the module that declares it may write one.",
2478            )
2479            .help(help),
2480        );
2481        true
2482    }
2483
2484    /// Brings every declaration of every module this one imports from into
2485    /// its tables, under the canonical `module.Name` keys.
2486    ///
2487    /// A module's whole environment is brought in, not only the declarations
2488    /// a `use` named: a type reached as the result of an imported function
2489    /// must still have fields and methods, even when this module never
2490    /// names it. What a `use` decides is which of them this module can
2491    /// *write*, which is [`Checker::key`]'s business, not this one's.
2492    fn import(&mut self, envs: &BTreeMap<&str, ImportEnv>) {
2493        for dependency in self.module.dependencies() {
2494            let Some(env) = envs.get(dependency) else {
2495                continue;
2496            };
2497            self.structs
2498                .extend(env.structs.iter().map(|(k, v)| (k.clone(), v.clone())));
2499            self.enums
2500                .extend(env.enums.iter().map(|(k, v)| (k.clone(), v.clone())));
2501            self.aliases
2502                .extend(env.aliases.iter().map(|(k, v)| (k.clone(), v.clone())));
2503            self.functions
2504                .extend(env.functions.iter().map(|(k, v)| (k.clone(), v.clone())));
2505            self.methods
2506                .extend(env.methods.iter().map(|(k, v)| (k.clone(), v.clone())));
2507            self.traits
2508                .extend(env.traits.iter().map(|(k, v)| (k.clone(), v.clone())));
2509            self.conformances.extend(env.conformances.iter().cloned());
2510        }
2511    }
2512
2513    /// What this module offers the modules that import it, once its own
2514    /// declarations are resolved.
2515    fn export_env(&self) -> ImportEnv {
2516        let module = self.module.name.as_str();
2517        let key = |name: &String| {
2518            if name.contains('.') {
2519                name.clone()
2520            } else {
2521                format!("{module}.{name}")
2522            }
2523        };
2524        ImportEnv {
2525            structs: self
2526                .structs
2527                .iter()
2528                .map(|(name, sig)| {
2529                    (
2530                        key(name),
2531                        StructSig {
2532                            generics: sig.generics.clone(),
2533                            fields: sig
2534                                .fields
2535                                .iter()
2536                                .map(|field| ParamSig {
2537                                    ty: qualify(&field.ty, module),
2538                                    ..field.clone()
2539                                })
2540                                .collect(),
2541                            opaque: sig.opaque,
2542                        },
2543                    )
2544                })
2545                .collect(),
2546            enums: self
2547                .enums
2548                .iter()
2549                .map(|(name, sig)| {
2550                    (
2551                        key(name),
2552                        EnumSig {
2553                            generics: sig.generics.clone(),
2554                            cases: sig
2555                                .cases
2556                                .iter()
2557                                .map(|case| CaseSig {
2558                                    payload: case
2559                                        .payload
2560                                        .iter()
2561                                        .map(|ty| qualify(ty, module))
2562                                        .collect(),
2563                                    ..case.clone()
2564                                })
2565                                .collect(),
2566                        },
2567                    )
2568                })
2569                .collect(),
2570            aliases: self
2571                .aliases
2572                .iter()
2573                .map(|(name, (generics, ty))| (key(name), (generics.clone(), qualify(ty, module))))
2574                .collect(),
2575            functions: self
2576                .functions
2577                .iter()
2578                .map(|(name, sig)| (key(name), sig.qualified(module)))
2579                .collect(),
2580            methods: self
2581                .methods
2582                .iter()
2583                .map(|((type_name, name), sig)| {
2584                    ((key(type_name), name.clone()), sig.qualified(module))
2585                })
2586                .collect(),
2587            traits: self
2588                .traits
2589                .iter()
2590                .map(|(name, methods)| {
2591                    let methods = methods
2592                        .iter()
2593                        .map(|(name, sig)| (name.clone(), sig.qualified(module)))
2594                        .collect();
2595                    (key(name), methods)
2596                })
2597                .collect(),
2598            conformances: self
2599                .conformances
2600                .iter()
2601                .map(|(trait_name, type_name)| (key(trait_name), key(type_name)))
2602                .collect(),
2603        }
2604    }
2605
2606    /// Checks every body of this module, once every signature it can see is
2607    /// resolved.
2608    fn check_bodies(&mut self) {
2609        let fn_names: Vec<String> = self.module.functions.keys().cloned().collect();
2610        for name in fn_names {
2611            let decl = self.module.functions[&name].decl.clone();
2612            let sig = self.functions[&name].clone();
2613            self.check_body(&decl, &sig);
2614        }
2615        let method_keys: Vec<(String, String)> = self.module.methods.keys().cloned().collect();
2616        for key in method_keys {
2617            // A trait's default body is checked once against `Self`, below,
2618            // not once per conformance.
2619            if self.module.methods[&key].from_trait_default.is_some() {
2620                continue;
2621            }
2622            let decl = self.module.methods[&key].decl.clone();
2623            // The signature is filed under the type's canonical key, which
2624            // differs from the name written here when the conformance is for
2625            // an imported type.
2626            let sig = self.methods[&(self.key(&key.0), key.1.clone())].clone();
2627            self.check_body(&decl, &sig);
2628        }
2629        self.check_trait_defaults();
2630        // Every body settles its own variables above; this is the promise
2631        // that nothing at all leaves this checker holding one, whatever is
2632        // walked here later.
2633        self.body_mark = self.diagnostics.len();
2634        self.finish_inference();
2635    }
2636
2637    /// Checks every trait's default method bodies, once each, with `self`
2638    /// typed as a rigid `Self` bounded by that trait.
2639    ///
2640    /// A default body is written against its trait's own interface and
2641    /// nothing else. Checking it once against `Self: Trait` is what makes
2642    /// that true: checked once per conformance instead, it could reach a
2643    /// conforming type's fields, and conformance would be structural after
2644    /// all.
2645    fn check_trait_defaults(&mut self) {
2646        let trait_names: Vec<String> = self.module.traits.keys().cloned().collect();
2647        for trait_name in trait_names {
2648            let decl = self.module.traits[&trait_name].decl.clone();
2649            let self_param: Arc<str> = "Self".into();
2650            for method in &decl.methods {
2651                let sig = self.traits[&trait_name][&method.name.node].clone();
2652                self.type_params = vec![self_param.clone()];
2653                self.bounds = BTreeMap::from([(
2654                    self_param.clone(),
2655                    vec![TraitBound {
2656                        name: trait_name.as_str().into(),
2657                        span: decl.name.span,
2658                    }],
2659                )]);
2660                self.ret = sig.ret.clone();
2661                self.ret_span = sig.ret_span;
2662                self.ret_stated = true;
2663                self.scopes.push(BTreeMap::new());
2664                if let Some(receiver) = method.receiver {
2665                    self.declare("self", Ty::Param(self_param.clone()), receiver.is_var);
2666                }
2667                for param in &sig.params {
2668                    let ty = if param.variadic {
2669                        Ty::Array(Box::new(param.ty.clone()))
2670                    } else {
2671                        param.ty.clone()
2672                    };
2673                    self.declare(&param.name, ty, param.is_var);
2674                }
2675                for (param, declared) in method.params.iter().zip(&sig.params) {
2676                    if let Some(default) = &param.default {
2677                        let expected = Expected::new(
2678                            declared.ty.clone(),
2679                            param.name.span,
2680                            format!("this parameter is `{}`", declared.ty),
2681                        );
2682                        self.expr(default, Some(&expected));
2683                    }
2684                }
2685                self.body_mark = self.diagnostics.len();
2686                if let Some(body) = &method.default {
2687                    // A default body is a declaration like any other, and a
2688                    // consumer holding one needs to know its boundary: what
2689                    // its parameters are and what it answers. `check_body`
2690                    // records that for every *other* declaration and skips
2691                    // these, because a defaulted method is checked here
2692                    // instead of once per conforming type — so without this
2693                    // line the one kind of body that is shared by several
2694                    // types is the one kind whose signature nothing can read.
2695                    //
2696                    // The receiver and any `Self` in the boundary stay
2697                    // `Ty::Param("Self")`, which is what the declaration
2698                    // says. Completing it is the reader's job, exactly as for
2699                    // a generic declaration's `Ty::Param`.
2700                    //
2701                    // `resolve::conform` synthesises each conforming type's
2702                    // `FnDecl` with `span: method.span`, so a lookup keyed by
2703                    // that entry's span finds this.
2704                    self.facts.record_signature(
2705                        method.span.file,
2706                        method.span,
2707                        Signature {
2708                            receiver: method.receiver.map(|_| Ty::Param(self_param.clone())),
2709                            params: sig.params.iter().map(|param| param.ty.clone()).collect(),
2710                            ret: sig.ret.clone(),
2711                        },
2712                    );
2713                    let expected = Expected::new(
2714                        sig.ret.clone(),
2715                        sig.ret_span,
2716                        if method.return_type.is_some() {
2717                            format!("the declared return type is `{}`", sig.ret)
2718                        } else {
2719                            "this method declares no return type, so it returns `()`".to_string()
2720                        },
2721                    );
2722                    self.block(body, Some(&expected));
2723                }
2724                self.finish_inference();
2725                self.scopes.pop();
2726                self.type_params.clear();
2727                self.bounds.clear();
2728            }
2729        }
2730    }
2731
2732    /// Resolves every written type of every declaration, once.
2733    ///
2734    /// A type written once is reported once, however many bodies mention it,
2735    /// because a body reads the resolved signature rather than the syntax.
2736    fn prepare(&mut self) {
2737        let alias_names: Vec<String> = self.module.aliases.keys().cloned().collect();
2738        for name in alias_names {
2739            self.alias(&name);
2740        }
2741
2742        // Trait signatures come before everything else: a bound, a `dyn`, and
2743        // a conformance check all read them.
2744        let trait_names: Vec<String> = self.module.traits.keys().cloned().collect();
2745        for name in trait_names {
2746            let decl = self.module.traits[&name].decl.clone();
2747            let methods = decl
2748                .methods
2749                .iter()
2750                .map(|method| (method.name.node.clone(), self.trait_method_sig(method)))
2751                .collect();
2752            self.traits.insert(name, methods);
2753        }
2754
2755        let struct_names: Vec<String> = self.module.structs.keys().cloned().collect();
2756        for name in struct_names {
2757            let entry = &self.module.structs[&name];
2758            let (decl, opaque) = (entry.decl.clone(), entry.opaque);
2759            let sig = self.struct_sig(&decl, opaque);
2760            self.record_struct_signature(&decl, &sig);
2761            self.structs.insert(name, sig);
2762        }
2763
2764        let enum_names: Vec<String> = self.module.enums.keys().cloned().collect();
2765        for name in enum_names {
2766            let decl = self.module.enums[&name].decl.clone();
2767            let sig = self.enum_sig(&decl);
2768            self.record_case_signatures(&decl, &sig);
2769            self.enums.insert(name, sig);
2770        }
2771
2772        // Every declaration's members are resolved by here, which is all the
2773        // layout-cycle analysis reads. ADR 0035.
2774        self.check_layout_cycles();
2775
2776        let fn_names: Vec<String> = self.module.functions.keys().cloned().collect();
2777        for name in fn_names {
2778            let decl = self.module.functions[&name].decl.clone();
2779            let sig = self.fn_sig(&decl, None);
2780            self.functions.insert(name, sig);
2781        }
2782
2783        // A method's table key names the type's own module: a conformance
2784        // this module declares for an imported type extends *that* type, so
2785        // its methods have to be found under the same key everyone else
2786        // reaches it by.
2787        let method_keys: Vec<(String, String)> = self.module.methods.keys().cloned().collect();
2788        for key in method_keys {
2789            let decl = self.module.methods[&key].decl.clone();
2790            let sig = self.fn_sig(&decl, Some(&key.0));
2791            self.methods.insert((self.key(&key.0), key.1), sig);
2792        }
2793
2794        self.check_conformance_signatures();
2795    }
2796
2797    /// The signature of one trait method.
2798    ///
2799    /// A trait binds no type parameters of its own in the MVP, so its methods
2800    /// are checked in an empty generic scope. The receiver type is left
2801    /// `Unknown` because it is decided by the call site: `T` through a bound,
2802    /// `dyn Trait` through a trait object, and the concrete type through a
2803    /// conformance.
2804    fn trait_method_sig(&mut self, method: &TraitMethod) -> FnSig {
2805        let outer = std::mem::take(&mut self.type_params);
2806        self.check_variadic_shape(&method.params);
2807        let params = method
2808            .params
2809            .iter()
2810            .map(|param| self.param_sig(param))
2811            .collect::<Vec<_>>();
2812        let ret = match &method.return_type {
2813            Some(ty) => self.resolve(ty),
2814            None => Ty::Unit,
2815        };
2816        let ret_span = match &method.return_type {
2817            Some(ty) => ty.span,
2818            None => method.name.span,
2819        };
2820        self.type_params = outer;
2821        FnSig {
2822            generics: Vec::new(),
2823            bounds: BTreeMap::new(),
2824            params,
2825            ret,
2826            ret_span,
2827            is_async: method.is_async,
2828            receiver: method.receiver.map(|_| Ty::placeholder()),
2829            receiver_is_var: method.receiver.is_some_and(|receiver| receiver.is_var),
2830        }
2831    }
2832
2833    /// Checks that every method a conformance supplies has the signature its
2834    /// trait declares.
2835    ///
2836    /// Resolution already rejected a method the trait does not declare and a
2837    /// declared method the conformance does not supply; what is left is
2838    /// whether the two agree on parameters, result, and receiver. They must,
2839    /// because a call through a bound or through `dyn Trait` is checked
2840    /// against the trait's signature and dispatched to this one.
2841    fn check_conformance_signatures(&mut self) {
2842        // Only the conformances this module declares: one it merely imported
2843        // was checked where it was written, and its methods are not this
2844        // module's to fix.
2845        let conformances: Vec<(String, String, String, String)> = self
2846            .module
2847            .conformances
2848            .values()
2849            .map(|conformance| {
2850                let (trait_key, type_key) = conformance_key(self.module, conformance);
2851                (
2852                    trait_key,
2853                    type_key,
2854                    conformance.trait_name.clone(),
2855                    conformance.type_name.clone(),
2856                )
2857            })
2858            .collect();
2859        for (trait_key, type_key, trait_name, written_type) in conformances {
2860            let Some(entry) = self.trait_entry(&trait_key) else {
2861                continue;
2862            };
2863            let type_name = written_type;
2864            let trait_decl = entry.decl.clone();
2865            for method in &trait_decl.methods {
2866                let key = (type_key.clone(), method.name.node.clone());
2867                let Some(found) = self.methods.get(&key).cloned() else {
2868                    continue;
2869                };
2870                let Some(declared) = self.traits[&trait_key].get(&method.name.node).cloned() else {
2871                    continue;
2872                };
2873                let Some(reason) = signature_difference(&declared, &found) else {
2874                    continue;
2875                };
2876                let span = self.module.methods[&(type_name.clone(), method.name.node.clone())]
2877                    .decl
2878                    .name
2879                    .span;
2880                self.diagnostics.push(
2881                    Diagnostic::error(
2882                        CONFORMANCE_SIGNATURE,
2883                        format!(
2884                            "`{type_name}.{}` does not match the signature `{trait_name}` declares: {reason}",
2885                            method.name.node
2886                        ),
2887                    )
2888                    .at(span)
2889                    .label(
2890                        method.name.span,
2891                        format!("`{trait_name}` declares {}", trait_signature(&declared, &method.name.node)),
2892                    )
2893                    .rule("A conformance's method has exactly the signature its trait declares, because a call through a bound or through `dyn Trait` is checked against the trait and dispatched to the conformance.")
2894                    .help(format!(
2895                        "write `{}`",
2896                        trait_signature(&declared, &method.name.node)
2897                    )),
2898                );
2899            }
2900        }
2901    }
2902
2903    /// Checks one function's or method's body against its declared return
2904    /// type.
2905    ///
2906    /// A function with no `->` returns `Unit`, so its body's value must be
2907    /// `Unit` too.
2908    fn check_body(&mut self, decl: &FnDecl, sig: &FnSig) {
2909        self.body_mark = self.diagnostics.len();
2910        self.record_signature(decl, sig);
2911        self.type_params = sig.generics.clone();
2912        self.bounds = sig.bounds.clone();
2913        self.ret = sig.ret.clone();
2914        self.ret_span = sig.ret_span;
2915        self.ret_stated = true;
2916        self.scopes.push(BTreeMap::new());
2917        if let Some(receiver) = &sig.receiver {
2918            // `var self` is the one receiver a body may write through, and
2919            // it is written at the declaration exactly as a `var` parameter
2920            // is.
2921            let is_var = decl.receiver.is_some_and(|receiver| receiver.is_var);
2922            self.declare("self", receiver.clone(), is_var);
2923        }
2924        for param in &sig.params {
2925            let ty = if param.variadic {
2926                Ty::Array(Box::new(param.ty.clone()))
2927            } else {
2928                param.ty.clone()
2929            };
2930            self.declare(&param.name, ty, param.is_var);
2931        }
2932        for (param, declared) in decl.params.iter().zip(&sig.params) {
2933            if let Some(default) = &param.default {
2934                let expected = Expected::new(
2935                    declared.ty.clone(),
2936                    param.name.span,
2937                    format!("this parameter is `{}`", declared.ty),
2938                );
2939                self.expr(default, Some(&expected));
2940            }
2941        }
2942        let expected = Expected::new(
2943            sig.ret.clone(),
2944            sig.ret_span,
2945            if decl.return_type.is_some() {
2946                format!("the declared return type is `{}`", sig.ret)
2947            } else {
2948                "this function declares no return type, so it returns `()`".to_string()
2949            },
2950        );
2951        self.block(&decl.body, Some(&expected));
2952        // The body is over, so every use a binding could have had, it has
2953        // had. See `Checker::finish_inference`.
2954        self.finish_inference();
2955        self.scopes.pop();
2956        self.type_params.clear();
2957        self.bounds.clear();
2958    }
2959
2960    // ------------------------------------------------------ declarations
2961
2962    fn struct_sig(&mut self, decl: &StructDecl, opaque: bool) -> StructSig {
2963        let outer = std::mem::take(&mut self.type_params);
2964        self.reject_bounds(&decl.generics, "struct");
2965        let generics = self.enter_generics(&decl.generics);
2966        let fields = decl
2967            .fields
2968            .iter()
2969            .map(|field| ParamSig {
2970                name: field.name.node.clone(),
2971                ty: self.resolve(&field.ty),
2972                variadic: false,
2973                has_default: false,
2974                is_var: false,
2975                span: field.name.span,
2976            })
2977            .collect();
2978        self.type_params = outer;
2979        StructSig {
2980            generics,
2981            fields,
2982            opaque,
2983        }
2984    }
2985
2986    fn enum_sig(&mut self, decl: &EnumDecl) -> EnumSig {
2987        let outer = std::mem::take(&mut self.type_params);
2988        self.reject_bounds(&decl.generics, "enum");
2989        let generics = self.enter_generics(&decl.generics);
2990        let cases = decl
2991            .cases
2992            .iter()
2993            .map(|case| CaseSig {
2994                name: case.name.node.clone(),
2995                payload: case.payload.iter().map(|ty| self.resolve(ty)).collect(),
2996                span: case.name.span,
2997            })
2998            .collect();
2999        self.type_params = outer;
3000        EnumSig { generics, cases }
3001    }
3002
3003    // -------------------------------------------- recursive value layouts
3004    //
3005    // ADR 0035. A Cove value is a run of consecutive words laid out where
3006    // the value is, which is what makes an assignment a word-range copy and
3007    // is why no sharing bit is needed to keep one from becoming an alias. A
3008    // declaration that contains itself has no finite width under that model,
3009    // and the three ways of rescuing it — box it where the cycle is found,
3010    // deep-copy the box on assignment, copy it on write — each decide the
3011    // language's semantics from a representation. So the checker refuses the
3012    // declaration instead, and a program that wants a cycle writes an
3013    // indirection the reader can see.
3014    //
3015    // The analysis is a graph over declarations, not over uses: it runs once
3016    // per module, in `prepare`, and costs nothing per call site.
3017
3018    /// Reports every struct or enum of this module whose value layout would
3019    /// contain itself.
3020    ///
3021    /// The graph is over the module's *own* declarations, and that loses
3022    /// nothing: a cycle that left the module would need the module it left
3023    /// for to reach back, and resolution already refuses a package whose
3024    /// modules import in a cycle. An imported declaration is still read —
3025    /// `Cell<Node>` has to be followed into `Cell` to find the `Node` — but
3026    /// it is never a node of the graph.
3027    ///
3028    /// One declaration is reported per cycle. The rest of the cycle's
3029    /// members are named in the message and labelled at their own fields, and
3030    /// reporting each of them again would say the same thing as many times as
3031    /// the cycle is long.
3032    fn check_layout_cycles(&mut self) {
3033        let visible: Vec<String> = self
3034            .structs
3035            .keys()
3036            .chain(self.enums.keys())
3037            .cloned()
3038            .collect();
3039        let params = self.layout_parameters(&visible);
3040        let declared: Vec<String> = self
3041            .module
3042            .structs
3043            .keys()
3044            .chain(self.module.enums.keys())
3045            .cloned()
3046            .collect();
3047        // A declaration proved finite once is finite for every later root,
3048        // so the walk visits each declaration a bounded number of times.
3049        let mut finite: BTreeSet<String> = BTreeSet::new();
3050        let mut reported: BTreeSet<String> = BTreeSet::new();
3051        for name in &declared {
3052            if finite.contains(name) || reported.contains(name) {
3053                continue;
3054            }
3055            let mut path = vec![name.clone()];
3056            let mut steps: Vec<LayoutStep> = Vec::new();
3057            let found = self.layout_cycle(name, &params, &mut path, &mut steps, &mut finite);
3058            let Some(cycle) = found else {
3059                finite.insert(name.clone());
3060                continue;
3061            };
3062            reported.extend(cycle.iter().map(|step| step.owner.clone()));
3063            let diagnostic = self.layout_cycle_diagnostic(&cycle);
3064            self.diagnostics.push(diagnostic);
3065        }
3066    }
3067
3068    /// Which type parameters each visible declaration holds by value.
3069    ///
3070    /// This is a least fixed point because the answer for one declaration is
3071    /// the answer for the ones it holds: `Pair<T> { first: Wrap<T> }` holds
3072    /// its parameter exactly when `Wrap` holds its own. Starting from "holds
3073    /// none" and growing to a fixed point can only under-report, and it can
3074    /// only under-report for a declaration that is part of a cycle — which is
3075    /// the thing being looked for, and is reported by the walk below whatever
3076    /// this says about it.
3077    fn layout_parameters(&self, visible: &[String]) -> LayoutParams {
3078        let mut params: LayoutParams = visible
3079            .iter()
3080            .map(|name| (name.clone(), BTreeSet::new()))
3081            .collect();
3082        loop {
3083            let mut changed = false;
3084            for name in visible {
3085                let generics = self.layout_generics(name);
3086                if generics.is_empty() {
3087                    continue;
3088                }
3089                let mut reach = InlineReach::default();
3090                for member in self.layout_members(name) {
3091                    inline_reach(&member.ty, &params, &mut reach);
3092                }
3093                let held: BTreeSet<usize> = generics
3094                    .iter()
3095                    .enumerate()
3096                    .filter(|(_, param)| reach.params.contains(*param))
3097                    .map(|(position, _)| position)
3098                    .collect();
3099                let entry = params.entry(name.clone()).or_default();
3100                if !held.is_subset(entry) {
3101                    entry.extend(held);
3102                    changed = true;
3103                }
3104            }
3105            if !changed {
3106                return params;
3107            }
3108        }
3109    }
3110
3111    /// The first cycle reachable from `key`, as the steps that close it.
3112    ///
3113    /// `path` is the declarations entered and not yet left, and `steps` the
3114    /// edges between them, so `steps[i]` leaves `path[i]`. Reaching a
3115    /// declaration already on the path is the cycle, and the steps from where
3116    /// it was entered are the whole of it.
3117    ///
3118    /// It terminates because a declaration is entered at most once per path
3119    /// and there are finitely many; nothing here instantiates a type, so no
3120    /// type term grows.
3121    fn layout_cycle(
3122        &self,
3123        key: &str,
3124        params: &LayoutParams,
3125        path: &mut Vec<String>,
3126        steps: &mut Vec<LayoutStep>,
3127        finite: &mut BTreeSet<String>,
3128    ) -> Option<Vec<LayoutStep>> {
3129        for member in self.layout_members(key) {
3130            let mut reach = InlineReach::default();
3131            inline_reach(&member.ty, params, &mut reach);
3132            for target in reach.declarations {
3133                if !self.module.structs.contains_key(&target)
3134                    && !self.module.enums.contains_key(&target)
3135                {
3136                    continue;
3137                }
3138                let step = LayoutStep {
3139                    owner: key.to_string(),
3140                    member: member.label.clone(),
3141                    reaches: target.clone(),
3142                    span: member.span,
3143                };
3144                if let Some(entered) = path.iter().position(|name| *name == target) {
3145                    let mut cycle = steps[entered..].to_vec();
3146                    cycle.push(step);
3147                    return Some(cycle);
3148                }
3149                if finite.contains(&target) {
3150                    continue;
3151                }
3152                path.push(target.clone());
3153                steps.push(step);
3154                let found = self.layout_cycle(&target, params, path, steps, finite);
3155                steps.pop();
3156                path.pop();
3157                if found.is_some() {
3158                    return found;
3159                }
3160                finite.insert(target);
3161            }
3162        }
3163        None
3164    }
3165
3166    /// The type parameters the declaration `key` binds.
3167    fn layout_generics(&self, key: &str) -> Vec<Arc<str>> {
3168        if let Some(sig) = self.structs.get(key) {
3169            return sig.generics.clone();
3170        }
3171        if let Some(sig) = self.enums.get(key) {
3172            return sig.generics.clone();
3173        }
3174        Vec::new()
3175    }
3176
3177    /// Every field and every case payload of the declaration `key`.
3178    ///
3179    /// The span is the member's written *type* where this module declares it,
3180    /// since that is what a correction rewrites, and the member's name
3181    /// otherwise — an imported declaration is read for its types and never
3182    /// pointed at, because the cycle being reported is not its module's.
3183    fn layout_members(&self, key: &str) -> Vec<LayoutMember> {
3184        let mut members = Vec::new();
3185        if let Some(sig) = self.structs.get(key) {
3186            let decl = self.module.structs.get(key).map(|entry| &entry.decl);
3187            for (position, field) in sig.fields.iter().enumerate() {
3188                members.push(LayoutMember {
3189                    ty: field.ty.clone(),
3190                    label: format!("field `{}`", field.name),
3191                    span: decl
3192                        .and_then(|decl| decl.fields.get(position))
3193                        .map_or(field.span, |field| field.ty.span),
3194                });
3195            }
3196        }
3197        if let Some(sig) = self.enums.get(key) {
3198            let decl = self.module.enums.get(key).map(|entry| &entry.decl);
3199            for (position, case) in sig.cases.iter().enumerate() {
3200                for (index, payload) in case.payload.iter().enumerate() {
3201                    members.push(LayoutMember {
3202                        ty: payload.clone(),
3203                        label: format!("case `{}`", case.name),
3204                        span: decl
3205                            .and_then(|decl| decl.cases.get(position))
3206                            .and_then(|case| case.payload.get(index))
3207                            .map_or(case.span, |payload| payload.span),
3208                    });
3209                }
3210            }
3211        }
3212        members
3213    }
3214
3215    /// The one diagnostic ADR 0035 asks for.
3216    ///
3217    /// It is the only place a reader learns the rule, so it says three
3218    /// things: which declaration has no finite width, which member closes the
3219    /// cycle — every step of it, labelled where the type is written, when the
3220    /// cycle is longer than one — and what to write instead.
3221    fn layout_cycle_diagnostic(&self, cycle: &[LayoutStep]) -> Diagnostic {
3222        let start = cycle[0].owner.clone();
3223        let closing = &cycle[cycle.len() - 1];
3224        let message = if cycle.len() == 1 {
3225            format!(
3226                "`{start}` contains itself by value, through {}",
3227                closing.member
3228            )
3229        } else {
3230            let mut names: Vec<String> = cycle
3231                .iter()
3232                .map(|step| format!("`{}`", step.owner))
3233                .collect();
3234            names.push(format!("`{start}`"));
3235            format!("`{start}` contains itself by value: {}", names.join(" -> "))
3236        };
3237        let mut diagnostic = Diagnostic::error(LAYOUT_CYCLE, message)
3238            .at(self.layout_declaration_span(&start).unwrap_or(closing.span));
3239        for step in cycle {
3240            diagnostic = diagnostic.label(
3241                step.span,
3242                format!(
3243                    "{} puts `{}` inside `{}`",
3244                    step.member, step.reaches, step.owner
3245                ),
3246            );
3247        }
3248        diagnostic.rule(LAYOUT_CYCLE_RULE).help(format!(
3249            "break the cycle by holding one of its steps behind a reference: `Array<{start}>`, `Vector<{start}>` and `Shared<{start}>` are each one word, so a cycle that passes through one has a finite width"
3250        ))
3251    }
3252
3253    /// Where this module declares `name`, for the diagnostic's primary span.
3254    fn layout_declaration_span(&self, name: &str) -> Option<Span> {
3255        if let Some(entry) = self.module.structs.get(name) {
3256            return Some(entry.decl.name.span);
3257        }
3258        Some(self.module.enums.get(name)?.decl.name.span)
3259    }
3260
3261    /// The signature of a free function, or of a method of `receiver_type`.
3262    ///
3263    /// A method's type parameters are the ones its type declares. Resolution
3264    /// does not record an `impl` block's own parameter list, so an `impl`
3265    /// that renames its type's parameters is not supported.
3266    fn fn_sig(&mut self, decl: &FnDecl, receiver_type: Option<&str>) -> FnSig {
3267        let mut type_generics: Vec<GenericParam> = Vec::new();
3268        if let Some(type_name) = receiver_type {
3269            // The type may be one this module imported, when the method
3270            // comes from a conformance declared here for another module's
3271            // type, so its declaration is looked up where it lives.
3272            if let Some(owner) = self.declaring_module(type_name) {
3273                if let Some(entry) = owner.structs.get(type_name) {
3274                    type_generics.extend(entry.decl.generics.iter().cloned());
3275                } else if let Some(entry) = owner.enums.get(type_name) {
3276                    type_generics.extend(entry.decl.generics.iter().cloned());
3277                }
3278            }
3279        }
3280        let mut names = type_generics.clone();
3281        names.extend(decl.generics.iter().cloned());
3282        let outer = self.type_params.clone();
3283        let generics = self.enter_generics(&names);
3284        let bounds = self.bounds_of(&decl.generics);
3285        let owner_arity = type_generics.len();
3286
3287        // ADR 0004: a declaration's parameters are written, not inferred —
3288        // unlike a lambda's, which shares this same `Param` node but takes
3289        // its types from the expected type at its call site, a declaration
3290        // has no call site to infer from. `param_sig` still maps the missing
3291        // type to `Ty::recovery()` below, so this is one error rather than a
3292        // cascade through every call the parameter appears in.
3293        for param in &decl.params {
3294            if param.ty.is_none() {
3295                self.diagnostics.push(
3296                    Diagnostic::error(
3297                        MISSING_PARAMETER_TYPE,
3298                        format!("parameter `{}` has no declared type", param.name.node),
3299                    )
3300                    .at(param.span)
3301                    .rule("A declaration's parameters are written: only a lambda's infer, from the expected type at its call site.")
3302                    .help(format!("write `{}: <type>`", param.name.node)),
3303                );
3304            }
3305        }
3306        self.check_variadic_shape(&decl.params);
3307
3308        let params = decl
3309            .params
3310            .iter()
3311            .map(|param| self.param_sig(param))
3312            .collect::<Vec<_>>();
3313        let ret = match &decl.return_type {
3314            Some(ty) => self.resolve(ty),
3315            None => Ty::Unit,
3316        };
3317        let ret_span = match &decl.return_type {
3318            Some(ty) => ty.span,
3319            None => decl.name.span,
3320        };
3321        let receiver = receiver_type
3322            .filter(|_| decl.receiver.is_some())
3323            .map(|name| {
3324                let args: Vec<Ty> = generics
3325                    .iter()
3326                    .take(owner_arity)
3327                    .map(|p| Ty::Param(p.clone()))
3328                    .collect();
3329                self.nominal(name, args)
3330            });
3331        self.type_params = outer;
3332        FnSig {
3333            generics,
3334            bounds,
3335            params,
3336            ret,
3337            ret_span,
3338            is_async: decl.is_async,
3339            receiver,
3340            receiver_is_var: decl.receiver.is_some_and(|receiver| receiver.is_var),
3341        }
3342    }
3343
3344    /// A parameter's declared type. Its default value is checked with the
3345    /// body, in [`Checker::check_body`], where every signature in the module
3346    /// is known and the other parameters are in scope.
3347    fn param_sig(&mut self, param: &Param) -> ParamSig {
3348        let ty = match &param.ty {
3349            Some(ty) => self.resolve(ty),
3350            None => Ty::recovery(),
3351        };
3352        ParamSig {
3353            name: param.name.node.clone(),
3354            ty,
3355            variadic: param.variadic,
3356            has_default: param.default.is_some(),
3357            // A variadic parameter is an immutable `Array<T>` inside the
3358            // body whatever stands in front of it, which is the
3359            // `Place::binding(_, false)` `bind_params` builds for one.
3360            is_var: param.is_var && !param.variadic,
3361            span: param.span,
3362        }
3363    }
3364
3365    /// Refuses the two shapes a variadic parameter can be written in that
3366    /// nothing gave a meaning to.
3367    ///
3368    /// Where a parameter stands in the list, and whether it was written with
3369    /// a default, are read off the parameter list this pass already walks to
3370    /// build a [`ParamSig`] — which is what [ADR 0021] says makes them the
3371    /// checker's to decide rather than a backend's.
3372    ///
3373    /// **Standing anywhere but last.** A variadic parameter is the `Array<T>`
3374    /// of the arguments no earlier parameter took, so a parameter after it
3375    /// could only be filled by an argument it had already collected. The two
3376    /// evaluators disagreed about which: `Interpreter::assign_labels`
3377    /// gathers the left-over arguments only when the *last* parameter is
3378    /// variadic, while `bind_params` wraps *any* variadic slot in an
3379    /// `Array`, so `fn f(items: Int..., tail: String)` bound `items` to an
3380    /// array of at most one element. Neither reading was chosen, and the
3381    /// rule that makes the least language is that there is nothing here to
3382    /// read.
3383    ///
3384    /// **Written with a default.** A variadic parameter given no arguments
3385    /// is the empty `Array<T>`, which is already the whole answer to what
3386    /// omitting it means. A default would be a second answer to that
3387    /// question, and it is one nothing can reach: `bind_params` tests
3388    /// `variadic` before `default` and `continue`s, and
3389    /// [`Checker::match_arguments`] does the same, so the expression was
3390    /// checked, could carry side effects a reader expects, and was
3391    /// unreachable by construction.
3392    ///
3393    /// [ADR 0021]: https://github.com/myuon/cove/blob/main/docs/adr/0021-places-are-a-static-fact.md
3394    fn check_variadic_shape(&mut self, params: &[Param]) {
3395        for (index, param) in params.iter().enumerate() {
3396            if !param.variadic {
3397                continue;
3398            }
3399            if index + 1 != params.len() {
3400                self.diagnostics.push(
3401                    Diagnostic::error(
3402                        VARIADIC_POSITION,
3403                        format!(
3404                            "parameter `{}` is variadic, so it must be the last one",
3405                            param.name.node
3406                        ),
3407                    )
3408                    .at(param.span)
3409                    .rule("A variadic parameter is the last one its declaration writes: it collects every argument the parameters before it did not take.")
3410                    .help(format!(
3411                        "move `{}` to the end of the parameter list",
3412                        param.name.node
3413                    )),
3414                );
3415            }
3416            if param.default.is_some() {
3417                self.diagnostics.push(
3418                    Diagnostic::error(
3419                        VARIADIC_DEFAULT,
3420                        format!(
3421                            "parameter `{}` is variadic, so it cannot have a default",
3422                            param.name.node
3423                        ),
3424                    )
3425                    .at(param.span)
3426                    .rule("A variadic parameter given no arguments is an empty `Array<T>`, so there is nothing left for a default to answer.")
3427                    .help(format!(
3428                        "remove the `= ...`; a call that passes nothing already gives `{}` an empty array",
3429                        param.name.node
3430                    )),
3431                );
3432            }
3433        }
3434    }
3435
3436    /// Brings `params` into scope as type parameters, on top of whatever is
3437    /// already in scope, and returns just the ones it added. Every caller
3438    /// restores the previous list when the declaration ends.
3439    fn enter_generics(&mut self, params: &[GenericParam]) -> Vec<Arc<str>> {
3440        let generics: Vec<Arc<str>> = params.iter().map(|p| p.name.node.as_str().into()).collect();
3441        self.type_params.extend(generics.iter().cloned());
3442        generics
3443    }
3444
3445    /// The traits each of `params` is bounded by, with every bound checked to
3446    /// name a trait this module declares.
3447    fn bounds_of(&mut self, params: &[GenericParam]) -> BTreeMap<Arc<str>, Vec<TraitBound>> {
3448        let mut bounds: BTreeMap<Arc<str>, Vec<TraitBound>> = BTreeMap::new();
3449        for param in params {
3450            let mut named: Vec<TraitBound> = Vec::new();
3451            for bound in &param.bounds {
3452                let Some(key) = self.trait_key(&bound.node) else {
3453                    self.diagnostics
3454                        .push(unknown_trait(&bound.node, bound.span));
3455                    continue;
3456                };
3457                if named.iter().any(|b| *b.name == *key) {
3458                    continue;
3459                }
3460                named.push(TraitBound {
3461                    name: key.as_str().into(),
3462                    span: bound.span,
3463                });
3464            }
3465            if !named.is_empty() {
3466                bounds.insert(param.name.node.as_str().into(), named);
3467            }
3468        }
3469        bounds
3470    }
3471
3472    /// Reports a bound written on a declaration whose type parameters the MVP
3473    /// never checks a bound against.
3474    ///
3475    /// A bound is checked where a type parameter is instantiated, and only a
3476    /// call site instantiates one today. A `struct`, `enum`, or `type` writes
3477    /// its arguments in a type, which this pass does not check bounds for, so
3478    /// a bound written there would be silently ignored.
3479    fn reject_bounds(&mut self, params: &[GenericParam], what: &str) {
3480        for param in params {
3481            for bound in &param.bounds {
3482                self.diagnostics.push(
3483                    Diagnostic::error(
3484                        UNSUPPORTED_BOUND,
3485                        format!(
3486                            "a bound on a {what}'s type parameter is not checked in the MVP"
3487                        ),
3488                    )
3489                    .at(bound.span)
3490                    .rule("A bound is checked where its type parameter is instantiated, and only a call site instantiates one; a `struct`, `enum`, or `type` binds its arguments in a type instead.")
3491                    .help(format!(
3492                        "write `{}` here, and bound the type parameter of the functions that operate on it",
3493                        param.name.node
3494                    )),
3495                );
3496            }
3497        }
3498    }
3499
3500    /// A struct or enum this module declares, or `Unknown` when it declares
3501    /// neither.
3502    fn nominal(&self, name: &str, args: Vec<Ty>) -> Ty {
3503        let Some(owner) = self.declaring_module(name) else {
3504            return Ty::recovery();
3505        };
3506        let key = self.key(name);
3507        if owner.structs.contains_key(name) {
3508            Ty::Struct(key.into(), args)
3509        } else if owner.enums.contains_key(name) {
3510            Ty::Enum(key.into(), args)
3511        } else {
3512            Ty::recovery()
3513        }
3514    }
3515
3516    /// The resolved module a name as written belongs to: this one when it
3517    /// declares the name, and the module a `use` imported it from otherwise.
3518    fn declaring_module(&self, name: &str) -> Option<&'a ResolvedModule> {
3519        match self.module.imports.get(name) {
3520            Some(owner) if self.module.owner_of(name) != Some(&self.module.name) => {
3521                self.program.modules.get(owner)
3522            }
3523            _ => Some(self.module),
3524        }
3525    }
3526
3527    /// The trait a canonical key names, wherever it is declared.
3528    fn trait_entry(&self, key: &str) -> Option<&'a TraitEntry> {
3529        match key.rsplit_once('.') {
3530            Some((owner, name)) => self.program.modules.get(owner)?.traits.get(name),
3531            None => self.module.traits.get(key),
3532        }
3533    }
3534
3535    /// The canonical key of the trait `name` refers to here, when this
3536    /// module declares or imports one.
3537    fn trait_key(&self, name: &str) -> Option<String> {
3538        let key = self.key(name);
3539        self.traits.contains_key(&key).then_some(key)
3540    }
3541
3542    // ---------------------------------------------------- written types
3543
3544    /// Resolves a written type against the builtins, this module's
3545    /// declarations, and the type parameters in scope.
3546    fn resolve(&mut self, ty: &Type) -> Ty {
3547        match &ty.kind {
3548            TypeKind::Unit => Ty::Unit,
3549            TypeKind::Fn {
3550                is_async,
3551                params,
3552                return_type,
3553            } => {
3554                let params = params
3555                    .iter()
3556                    .map(|param| match &param.ty {
3557                        Some(ty) => self.resolve(ty),
3558                        // The parser gives every parameter of a written
3559                        // function type a type, named or bare, so there is
3560                        // no such thing as a missing one here.
3561                        None => Ty::placeholder(),
3562                    })
3563                    .collect();
3564                let ret = match return_type {
3565                    Some(ty) => self.resolve(ty),
3566                    None => Ty::Unit,
3567                };
3568                Ty::func(*is_async, params, ret)
3569            }
3570            TypeKind::Named { path, args } => self.resolve_named(path, args, ty.span),
3571            TypeKind::Dyn(name) => {
3572                // `dyn` names a trait with a bare name, so an imported trait
3573                // is reached through a `use` of the trait itself; a module
3574                // imported whole cannot qualify one.
3575                let Some(key) = self.trait_key(&name.node) else {
3576                    self.diagnostics.push(unknown_trait(&name.node, name.span));
3577                    return Ty::recovery();
3578                };
3579                Ty::Dyn(key.as_str().into())
3580            }
3581        }
3582    }
3583
3584    fn resolve_named(&mut self, path: &[Ident], args: &[Type], span: Span) -> Ty {
3585        let arguments: Vec<Ty> = args.iter().map(|arg| self.resolve(arg)).collect();
3586        if path.len() > 1 {
3587            let head = &path[0].node;
3588            // A module imported whole makes its exported types writable
3589            // qualified, exactly as a `use` of the type would make them
3590            // writable bare.
3591            if path.len() == 2 && self.module.module_imports.contains_key(head.as_str()) {
3592                let Some(key) = self.qualified_key(head, &path[1].node, span) else {
3593                    return Ty::recovery();
3594                };
3595                return self.foreign_type(&key, arguments, span);
3596            }
3597            if self.module.host_uses.contains(head.as_str()) {
3598                if path.len() == 2 {
3599                    return self.host_named_type(head, &path[1].node, arguments.len(), span);
3600                }
3601                // A host type is written `<module>.<Name>` and nothing
3602                // longer, so a deeper path reaches past anything a schema
3603                // could describe and is left to the boundary.
3604                self.diagnostics
3605                    .push(unchecked_host_type(&join_path(path), span));
3606                return Ty::dynamic_boundary();
3607            }
3608            self.diagnostics.push(
3609                Diagnostic::error(
3610                    UNKNOWN_TYPE,
3611                    format!("`{}` names no type this module can see", join_path(path)),
3612                )
3613                .at(span)
3614                .rule("A qualified type name reaches a host module, or a module of this package imported with `use`.")
3615                .help(format!(
3616                    "add `use {}` if `{}` is a host module or a module of this package, or declare the type in this module",
3617                    path[0].node,
3618                    path[0].node
3619                )),
3620            );
3621            return Ty::recovery();
3622        }
3623
3624        let name = path[0].node.as_str();
3625        if let Some(param) = self.type_params.iter().find(|p| &***p == name).cloned() {
3626            self.check_type_arity(name, 0, arguments.len(), span);
3627            return Ty::Param(param);
3628        }
3629        if let Some(ty) = self.builtin_type(name, &arguments, span) {
3630            return ty;
3631        }
3632        if let Some(entry) = self.module.structs.get(name) {
3633            let declared = entry.decl.generics.len();
3634            self.check_type_arity(name, declared, arguments.len(), span);
3635            return Ty::Struct(name.into(), fit(arguments, declared));
3636        }
3637        if let Some(entry) = self.module.enums.get(name) {
3638            let declared = entry.decl.generics.len();
3639            self.check_type_arity(name, declared, arguments.len(), span);
3640            return Ty::Enum(name.into(), fit(arguments, declared));
3641        }
3642        if self.module.aliases.contains_key(name) {
3643            let (generics, ty) = self.alias(name);
3644            self.check_type_arity(name, generics.len(), arguments.len(), span);
3645            return expand_alias(generics, ty, arguments);
3646        }
3647        if self.is_imported(name) {
3648            let key = self.key(name);
3649            return self.foreign_type(&key, arguments, span);
3650        }
3651        self.diagnostics.push(
3652            Diagnostic::error(
3653                UNKNOWN_TYPE,
3654                format!("`{name}` names no type this module can see"),
3655            )
3656            .at(span)
3657            .rule("A module sees its own declarations, what it imports with `use`, and the builtins.")
3658            .help(format!(
3659                "declare `struct {name}`, `enum {name}`, or `type {name} = ...` in this module, or `use <module>.{name}` to import it; a type only a host knows is written `<module>.{name}` after a `use` of that module"
3660            )),
3661        );
3662        Ty::recovery()
3663    }
3664
3665    /// A type another module declares, named by its canonical key.
3666    ///
3667    /// The key is enough: the module's whole environment was brought in
3668    /// before this one was prepared, so the declaration's own signature is
3669    /// already resolved.
3670    fn foreign_type(&mut self, key: &str, arguments: Vec<Ty>, span: Span) -> Ty {
3671        let written = key.rsplit('.').next().unwrap_or(key).to_string();
3672        if let Some(sig) = self.structs.get(key) {
3673            let declared = sig.generics.len();
3674            self.check_type_arity(&written, declared, arguments.len(), span);
3675            return Ty::Struct(key.into(), fit(arguments, declared));
3676        }
3677        if let Some(sig) = self.enums.get(key) {
3678            let declared = sig.generics.len();
3679            self.check_type_arity(&written, declared, arguments.len(), span);
3680            return Ty::Enum(key.into(), fit(arguments, declared));
3681        }
3682        if let Some((generics, ty)) = self.aliases.get(key).cloned() {
3683            self.check_type_arity(&written, generics.len(), arguments.len(), span);
3684            return expand_alias(generics, ty, arguments);
3685        }
3686        // The name resolves to a declaration that is not a type, such as an
3687        // imported function. Writing one where a type belongs is a mistake
3688        // with a name, not a gap in what the checker knows.
3689        self.diagnostics.push(
3690            Diagnostic::error(UNKNOWN_TYPE, format!("`{written}` is not a type"))
3691                .at(span)
3692                .rule("A type is a struct, an enum, a type alias, a type parameter, or a builtin.")
3693                .help(format!(
3694                    "`{written}` names something else the module exports; name a type instead"
3695                )),
3696        );
3697        Ty::recovery()
3698    }
3699
3700    /// The builtin named `name`, with its arity checked.
3701    ///
3702    /// How many type arguments each builtin takes is the number of
3703    /// parameters `cove_schema::builtins` declares it binds, so `Map<K, V>`
3704    /// takes two here because it takes two there. What `Ty` each name is
3705    /// stays this crate's, since `Ty` is this crate's representation.
3706    fn builtin_type(&mut self, name: &str, args: &[Ty], span: Span) -> Option<Ty> {
3707        // `Scope` is the one builtin whose type a program never writes: a
3708        // task scope is reached through `scope name { ... }`, so naming it is
3709        // an undeclared name rather than a builtin with the wrong arity.
3710        if name == SCOPE.name {
3711            return None;
3712        }
3713        let arity = cove_schema::builtin(name)?.parameters.len();
3714        self.check_type_arity(name, arity, args.len(), span);
3715        let first = args.first().cloned().unwrap_or(Ty::recovery());
3716        let second = args.get(1).cloned().unwrap_or(Ty::recovery());
3717        Some(match name {
3718            "Unit" => Ty::Unit,
3719            "Bool" => Ty::Bool,
3720            "Int" => Ty::Int,
3721            "Float" => Ty::Float,
3722            "String" => Ty::Str,
3723            "Duration" => Ty::Duration,
3724            "Error" => Ty::Error,
3725            "Range" => Ty::Range,
3726            "Array" => Ty::Array(Box::new(first)),
3727            "Vector" => Ty::Vector(Box::new(first)),
3728            "Set" => Ty::Set(Box::new(first)),
3729            "Option" => Ty::Option(Box::new(first)),
3730            "Task" => Ty::Task(Box::new(first)),
3731            "Shared" => Ty::Shared(Box::new(self.task_safe_argument(first, span))),
3732            "Map" => Ty::Map(Box::new(first), Box::new(second)),
3733            "MapEntry" => Ty::MapEntry(Box::new(first), Box::new(second)),
3734            _ => Ty::Result(Box::new(first), Box::new(second)),
3735        })
3736    }
3737
3738    fn check_type_arity(&mut self, name: &str, expected: usize, found: usize, span: Span) {
3739        if expected == found {
3740            return;
3741        }
3742        self.diagnostics.push(
3743            Diagnostic::error(
3744                TYPE_ARGUMENTS,
3745                format!("`{name}` takes {expected} type argument(s), but {found} were written"),
3746            )
3747            .at(span)
3748            .rule("A generic type is written with exactly the arguments its declaration binds.")
3749            .help(if expected == 0 {
3750                format!("write `{name}`")
3751            } else {
3752                format!(
3753                    "write `{name}<{}>`",
3754                    (0..expected).map(|_| "_").collect::<Vec<_>>().join(", ")
3755                )
3756            }),
3757        );
3758    }
3759
3760    /// Checks the argument of a `Shared<T>` and returns it, reporting the
3761    /// first part of it that may not cross a task boundary.
3762    ///
3763    /// A `Shared` is reachable from every task it was given to, so what it
3764    /// wraps must be able to cross a boundary itself. The Language Card names
3765    /// `Shared` in the sentence that keeps a vector out of a task, and a
3766    /// `Shared<Vector<T>>` would be exactly the reach that sentence forbids.
3767    ///
3768    /// This is the static half of the rule, and a type is all it sees, so it
3769    /// answers for the type arguments a program writes. A struct whose
3770    /// *field* holds a vector is refused too, by the walk over the value
3771    /// itself in `cove_runtime::task`, which is where the whole rule lives.
3772    fn task_safe_argument(&mut self, ty: Ty, span: Span) -> Ty {
3773        if let Some(offending) = not_task_safe(&ty) {
3774            let offending = offending.to_string();
3775            let message = if offending == ty.to_string() {
3776                format!("`Shared` cannot wrap a `{offending}`, which cannot cross a task boundary")
3777            } else {
3778                format!(
3779                    "`Shared` cannot wrap `{ty}`: the `{offending}` in it cannot cross a task boundary"
3780                )
3781            };
3782            self.diagnostics.push(
3783                Diagnostic::error(TASK_SAFETY, message)
3784                .at(span)
3785                .rule(TASK_SAFETY_RULE)
3786                .help(if offending.starts_with("Vector") {
3787                    "wrap an `Array` instead, or finish the vector with `freeze()` before wrapping it"
3788                        .to_string()
3789                } else {
3790                    format!("wrap a value that may cross a task boundary; a `{offending}` may not")
3791                }),
3792            );
3793        }
3794        ty
3795    }
3796
3797    /// Expands a type alias, once per module.
3798    fn alias(&mut self, name: &str) -> (Vec<Arc<str>>, Ty) {
3799        if let Some(cached) = self.aliases.get(name) {
3800            return cached.clone();
3801        }
3802        // Only a name the module declares as an alias is expanded, which
3803        // every caller has already established.
3804        let Some(entry) = self.module.aliases.get(name) else {
3805            return (Vec::new(), Ty::placeholder());
3806        };
3807        let decl = entry.decl.clone();
3808        if self.expanding.iter().any(|n| n == name) {
3809            self.diagnostics.push(
3810                Diagnostic::error(ALIAS_CYCLE, format!("`{name}` expands to itself"))
3811                    .at(decl.name.span)
3812                    .rule("A type alias names an existing type; it cannot be defined in terms of itself.")
3813                    .help(format!(
3814                        "declare `struct {name}` or `enum {name}` instead, which may refer to itself through a field"
3815                    )),
3816            );
3817            return (Vec::new(), Ty::recovery());
3818        }
3819        self.expanding.push(name.to_string());
3820        let outer = std::mem::take(&mut self.type_params);
3821        self.reject_bounds(&decl.generics, "type alias");
3822        let generics = self.enter_generics(&decl.generics);
3823        let ty = self.resolve(&decl.ty);
3824        self.type_params = outer;
3825        self.expanding.pop();
3826        let resolved = (generics, ty);
3827        // Expanding an alias can report — a bound written on its parameters
3828        // is refused here — and the cache would then answer the second walk
3829        // without reporting again. A probe's diagnostics are discarded, so
3830        // caching from inside one would discard the diagnostic for good.
3831        if !self.probing {
3832            self.aliases.insert(name.to_string(), resolved.clone());
3833        }
3834        resolved
3835    }
3836
3837    // ------------------------------------------------------------ scopes
3838
3839    /// Brings `name` into scope, saying whether source may write the place
3840    /// it binds.
3841    ///
3842    /// Mutability is a parameter rather than a default because a default is
3843    /// how the two halves of this rule came apart in the first place: every
3844    /// site that binds a name knows which kind it is binding, and a site
3845    /// that had to be *remembered* to mark is a site that will one day be
3846    /// forgotten.
3847    /// The type a name that cannot own an inference variable is bound to.
3848    ///
3849    /// ADR 0036 draws the boundary around a *local binding*: a `let` or a
3850    /// `var` with no written type is the one thing that may take a variable
3851    /// and let its later uses settle it. Every other name a body binds — a
3852    /// lambda's parameter, a `for` binding, a name a pattern binds — has no
3853    /// such ownership to take, so what it is given is what the checker knows
3854    /// *now*: a variable an earlier use already settled stands for what it
3855    /// settled to, and one nothing has settled yet stays open and becomes an
3856    /// unconstrained unknown when the body ends.
3857    ///
3858    /// A comparison is deliberately not one of these places. A found type
3859    /// checked against an expected one keeps its variables, because that
3860    /// comparison is where a use *says* what a variable is, and a second use
3861    /// disagreeing with the first is [`INFERENCE_CONFLICT`] rather than an
3862    /// ordinary mismatch. Resolving before comparing would spell that
3863    /// disagreement `expected `String`, found `Int`` and lose the binding it
3864    /// is about.
3865    ///
3866    /// Without this a variable is opaque for the whole body even after a use
3867    /// has said what it is. `found.push(item)` settles what `found` holds,
3868    /// and `found.freeze().sorted(by: fn(a, b) { a.rank > b.rank })` still
3869    /// binds `a` and `b` to a hole, so the field read off them is a recovery
3870    /// unknown nothing ever reported — a clean check carrying a type the
3871    /// checker did in fact know.
3872    fn bound(&self, ty: Ty) -> Ty {
3873        if self.vars.is_empty() {
3874            ty
3875        } else {
3876            ty.resolved(&self.vars)
3877        }
3878    }
3879
3880    fn declare(&mut self, name: &str, ty: Ty, mutable: bool) {
3881        // The other half of the placeholder invariant `Checker::expr`
3882        // asserts: a binding's type is read by every later use of the name,
3883        // so a placeholder reaching one is a site that was wrong about
3884        // itself.
3885        debug_assert!(
3886            !ty.holds_placeholder(),
3887            "a placeholder unknown escaped into the type of `{name}`: `{ty}`"
3888        );
3889        if let Some(scope) = self.scopes.last_mut() {
3890            scope.insert(name.to_string(), Binding { ty, mutable });
3891        }
3892    }
3893
3894    fn lookup(&self, name: &str) -> Option<&Binding> {
3895        self.scopes.iter().rev().find_map(|scope| scope.get(name))
3896    }
3897
3898    /// Whether `name` reaches a binding source may write.
3899    ///
3900    /// A name is writable when the binding it reaches is a `var` *and* that
3901    /// binding belongs to the function value being checked. A capture is
3902    /// read-only whatever it was declared as — see [`Checker::capture_floor`]
3903    /// — so the depth the name was found at is part of the answer and not
3904    /// bookkeeping.
3905    fn writable(&self, name: &str) -> bool {
3906        self.scopes
3907            .iter()
3908            .enumerate()
3909            .rev()
3910            .find_map(|(depth, scope)| scope.get(name).map(|binding| (depth, binding)))
3911            .is_some_and(|(depth, binding)| binding.mutable && depth >= self.capture_floor)
3912    }
3913
3914    /// Whether `expr` is a place, and whether source may write it.
3915    ///
3916    /// **This is the definition.** A place is a name a body bound, or a
3917    /// field of a place — nothing else, and no deeper analysis. The two
3918    /// readings of it that used to exist are readings of this one:
3919    /// `Interpreter::resolve_place_opt` asks it of an `Env` at run time, and
3920    /// `cove_ir::lower`'s `Body::place_mutability` asked it of a slot table
3921    /// while lowering. Both answer what a scope stack already knows, which
3922    /// is why the question belongs here.
3923    ///
3924    /// `None` is not a place at all: a call's result, a literal, an operator
3925    /// applied to anything, or a name this body did not bind. `Some` is a
3926    /// place, `true` where source may write it and `false` where `let` made
3927    /// it read-only. A field does not ask a question of its own — it
3928    /// inherits its root's answer, exactly as `Place::field` copies
3929    /// `mutable` down from the base.
3930    ///
3931    /// A name this body did not bind answers `None` rather than a refusal:
3932    /// it is a module's declaration, or a name resolution already reported,
3933    /// and neither is this rule's to speak about. [`Checker::not_a_place`]
3934    /// is what decides that abstention, and says why it is safe.
3935    fn place_mutability(&self, expr: &Expr) -> Option<bool> {
3936        match &expr.kind {
3937            ExprKind::Ident(name) => self.lookup(name).map(|_| self.writable(name)),
3938            ExprKind::Field { base, .. } => self.place_mutability(base),
3939            _ => None,
3940        }
3941    }
3942
3943    /// The `var` arguments of a call, checked against the place rule.
3944    ///
3945    /// `Interpreter::eval_args` resolves a `var` argument to a place before
3946    /// it knows which declaration the call reaches, and refuses one that is
3947    /// not a place or is a read-only one; this is the same question asked in
3948    /// the same position, so it covers a `var` written at a call to anything
3949    /// at all.
3950    ///
3951    /// What is *not* asked here is whether the callee declared that
3952    /// parameter `var`. That is a fact about the two markings agreeing
3953    /// rather than about places, a function type carries no marking for a
3954    /// call through a value to be checked against, and the interpreter still
3955    /// answers it — see the module docs under "What the runtime keeps".
3956    fn var_arguments(&mut self, args: &[Arg]) {
3957        for arg in args.iter().filter(|arg| arg.is_var) {
3958            match self.place_mutability(&arg.value) {
3959                Some(true) => {}
3960                Some(false) => {
3961                    let place = place_text(&arg.value);
3962                    self.diagnostics.push(
3963                        Diagnostic::error(
3964                            READ_ONLY_PLACE,
3965                            format!(
3966                                "`{place}` is a read-only place, so it cannot be passed as `var`"
3967                            ),
3968                        )
3969                        .at(arg.span)
3970                        .rule("`let` creates a read-only place; `var` creates a mutable place.")
3971                        .help(format!("declare it with `var {place}`")),
3972                    );
3973                }
3974                None if Checker::not_a_place(&arg.value) => {
3975                    self.diagnostics.push(
3976                        Diagnostic::error(
3977                            NOT_A_PLACE,
3978                            "this expression is not a place, so it cannot be assigned or aliased",
3979                        )
3980                        .at(arg.value.span)
3981                        .rule("Only variables and their struct fields are places.")
3982                        .help("bind it with `var` first, then pass that binding"),
3983                    );
3984                }
3985                None => {}
3986            }
3987        }
3988    }
3989
3990    /// A method that writes through its receiver, checked against the place
3991    /// rule.
3992    ///
3993    /// The receiver of a `var self` method is the caller's own place, so it
3994    /// must be one and must be writable — `Interpreter::eval_method_call`
3995    /// asks both before it makes the alias. `freeze` is the one mutating
3996    /// builtin that tolerates a receiver which is no place at all: a
3997    /// temporary holds the only handle to its own storage, so freezing it
3998    /// answers from the temporary rather than writing anywhere, which is
3999    /// what `builtins::call_method`'s own arm does.
4000    fn mutating_receiver(&mut self, receiver: &Ty, method: &Ident, base: &Expr, span: Span) {
4001        let Some(needs_a_place) = self.mutating_method(receiver, &method.node) else {
4002            return;
4003        };
4004        match self.place_mutability(base) {
4005            Some(true) => {}
4006            Some(false) => {
4007                let place = place_text(base);
4008                self.diagnostics.push(
4009                    Diagnostic::error(
4010                        READ_ONLY_PLACE,
4011                        format!(
4012                            "`{}` takes a `var self` receiver, but `{place}` is a read-only place",
4013                            method.node
4014                        ),
4015                    )
4016                    .at(span)
4017                    .rule("`let` creates a read-only place; `var` creates a mutable place.")
4018                    .help(format!("declare it with `var {place}`")),
4019                );
4020            }
4021            None if needs_a_place && Checker::not_a_place(base) => {
4022                self.diagnostics.push(
4023                    Diagnostic::error(
4024                        NOT_A_PLACE,
4025                        format!(
4026                            "`{}` takes a `var self` receiver, but `{}` is not a place",
4027                            method.node,
4028                            place_text(base)
4029                        ),
4030                    )
4031                    .at(span)
4032                    .rule("A mutating receiver declares `var self` and mutates the caller's place.")
4033                    .help("bind the value with `var` first, then call the method on that binding"),
4034                );
4035            }
4036            None => {}
4037        }
4038    }
4039
4040    /// Whether `method` called on a receiver of type `ty` writes through it,
4041    /// and whether it needs a place even where the receiver is a temporary.
4042    ///
4043    /// `None` is *not mutating, or this pass will not say*. A receiver whose
4044    /// type is an unknown, a `Never`, or a host type is the second: the
4045    /// interpreter reaches a host resource's own operations before it
4046    /// reaches any of this, and an unknown receiver could be one.
4047    fn mutating_method(&self, ty: &Ty, method: &str) -> Option<bool> {
4048        match ty {
4049            Ty::Unknown(_) | Ty::Any | Ty::Never | Ty::Host(_) => None,
4050            Ty::Struct(name, _) | Ty::Enum(name, _) => self
4051                .methods
4052                .get(&(name.to_string(), method.to_string()))
4053                .and_then(|sig| sig.receiver_is_var.then_some(true)),
4054            // A method reached through a bound or through `dyn` dispatches
4055            // on the concrete value's own type at run time, so the receiver
4056            // is the caller's place there exactly as it is for a direct
4057            // call.
4058            Ty::Param(param) => self
4059                .bound_method(param, method)
4060                .and_then(|(trait_name, _)| {
4061                    self.mutating_trait_method(&trait_name, method)
4062                        .then_some(true)
4063                }),
4064            Ty::Dyn(trait_name) => self
4065                .mutating_trait_method(trait_name, method)
4066                .then_some(true),
4067            // A builtin type: the shared table says which of its methods
4068            // write through their receiver, and `freeze` is the one that
4069            // does not need a place to write to — it takes the storage
4070            // rather than changing it, so a temporary holding the only
4071            // handle can be frozen. The rest need somewhere for the change
4072            // to land.
4073            //
4074            // The receiver's own entry is asked and not the name alone,
4075            // because a mutating name belongs to a type: `pop` is a
4076            // `Vector`'s and no method of an `Array` at all, so
4077            // `items.pop()` on an array is told it has no such method rather
4078            // than told to find a place for a receiver it would never need.
4079            // `Interpreter::call_builtin_method`'s guard asks the same
4080            // question of the value it is holding.
4081            _ => cove_schema::builtins::builtin(&builtin_name(ty))
4082                .and_then(|entry| entry.method(method))
4083                .filter(|declared| declared.mutating)
4084                .map(|_| method != "freeze"),
4085        }
4086    }
4087
4088    /// Whether an expression that is not a place should be reported as one.
4089    ///
4090    /// An `Ident`, or a field path rooted at one, that this body did not
4091    /// bind is left alone. It names a declaration the module holds — which
4092    /// the interpreter refuses with `cannot find` from its own environment,
4093    /// a resolution answer rather than a place one — or a name that failed
4094    /// to resolve and has been reported already. Either way a second
4095    /// diagnostic here would say less than the first.
4096    ///
4097    /// Everything else — a call's result, a literal, an operator — is
4098    /// decidedly not a place, from the shape of the expression alone.
4099    fn not_a_place(expr: &Expr) -> bool {
4100        !matches!(expr.kind, ExprKind::Ident(_) | ExprKind::Field { .. })
4101    }
4102
4103    // ------------------------------------------------------- expressions
4104
4105    /// Checks a block and returns the type of its value, which is its tail
4106    /// expression's type or `Unit` when it has none.
4107    fn block(&mut self, block: &Block, expected: Option<&Expected>) -> Ty {
4108        self.scopes.push(BTreeMap::new());
4109        for stmt in &block.statements {
4110            self.stmt(stmt);
4111        }
4112        let ty = match &block.tail {
4113            Some(tail) => self.expr(tail, expected),
4114            None => {
4115                let ty = Ty::Unit;
4116                if let Some(expected) = expected {
4117                    self.expect(&ty, expected, block.span);
4118                }
4119                ty
4120            }
4121        };
4122        self.scopes.pop();
4123        ty
4124    }
4125
4126    fn stmt(&mut self, stmt: &Stmt) {
4127        match &stmt.kind {
4128            StmtKind::Let {
4129                is_var,
4130                name,
4131                ty,
4132                value,
4133            } => {
4134                // The children this initializer spawns are the ones this
4135                // binding names. Frames are pushed and popped by `scope`
4136                // within one statement, so the frame on top afterwards is
4137                // the one that was on top before.
4138                let spawned_before = self.open_scopes.last().map_or(0, |o| o.children.len());
4139                let bound = match ty {
4140                    Some(written) => {
4141                        let declared = self.resolve(written);
4142                        let expected = Expected::new(
4143                            declared.clone(),
4144                            written.span,
4145                            format!("the declared type is `{declared}`"),
4146                        );
4147                        self.expr(value, Some(&expected));
4148                        declared
4149                    }
4150                    None => {
4151                        let inferred = self.expr(value, None);
4152                        // A binding whose initializer never produces a value
4153                        // has no type to infer; stop rather than guess. Every
4154                        // use of the name is in code the initializer's
4155                        // `return` or `break` made unreachable, so there is
4156                        // nothing left to say about any of them.
4157                        if inferred == Ty::Never {
4158                            Ty::recovery()
4159                        } else {
4160                            inferred
4161                        }
4162                    }
4163                };
4164                // A binding with no written type is the one place a type may
4165                // still be settled by what comes after it. Whatever its
4166                // initializer left open is now this binding's, and its uses
4167                // are what say what it is; see `Checker::attach`.
4168                if let Some(open) = self.open_scopes.last_mut() {
4169                    for child in open.children.iter_mut().skip(spawned_before) {
4170                        child.binding = Some(name.node.clone());
4171                    }
4172                }
4173                self.attach(&bound, &name.node, name.span);
4174                self.declare(&name.node, bound, *is_var);
4175            }
4176            StmtKind::Expr(expr) => {
4177                self.expr(expr, None);
4178            }
4179            StmtKind::Item(item) => {
4180                // A local `fn` is an ordinary closure the body can call.
4181                if let ItemKind::Fn(decl) = &item.kind {
4182                    let outer_params = self.type_params.clone();
4183                    let sig = self.fn_sig(decl, None);
4184                    // A local `fn` is a declaration like any other, and a
4185                    // consumer holding one needs its boundary. `check_body`
4186                    // records that for every declaration it walks and never
4187                    // reaches this one, because a local `fn` is a statement
4188                    // rather than an item of a module — so the one kind of
4189                    // declaration written inside a body was the one kind
4190                    // whose parameters and answer nothing could read. The
4191                    // signature was already computed and thrown away.
4192                    self.record_signature(decl, &sig);
4193                    self.declare(&decl.name.node, sig.as_value(), false);
4194                    let outer_ret = std::mem::replace(&mut self.ret, sig.ret.clone());
4195                    let outer_span = std::mem::replace(&mut self.ret_span, sig.ret_span);
4196                    let outer_stated = std::mem::replace(&mut self.ret_stated, true);
4197                    // A local `fn` writes what it answers, so a `?` in it is
4198                    // checked against that and never held. Taking the stack
4199                    // all the same is what makes that a property of this
4200                    // pass rather than of the return types a program happens
4201                    // to be able to write.
4202                    let outer_tries = std::mem::take(&mut self.open_lambdas);
4203                    self.type_params.extend(sig.generics.iter().cloned());
4204                    let outer_bounds = self.bounds.clone();
4205                    self.bounds.extend(
4206                        sig.bounds
4207                            .iter()
4208                            .map(|(name, bounds)| (name.clone(), bounds.clone())),
4209                    );
4210                    // A local `fn` is built as a closure, so the names
4211                    // around it are captures and a capture is read-only.
4212                    let outer_floor = std::mem::replace(&mut self.capture_floor, self.scopes.len());
4213                    self.scopes.push(BTreeMap::new());
4214                    for param in &sig.params {
4215                        self.declare(&param.name, param.ty.clone(), param.is_var);
4216                    }
4217                    let expected = Expected::new(
4218                        sig.ret.clone(),
4219                        sig.ret_span,
4220                        format!("the declared return type is `{}`", sig.ret),
4221                    );
4222                    self.block(&decl.body, Some(&expected));
4223                    self.open_lambdas = outer_tries;
4224                    self.scopes.pop();
4225                    self.capture_floor = outer_floor;
4226                    self.bounds = outer_bounds;
4227                    self.type_params = outer_params;
4228                    self.ret_span = outer_span;
4229                    self.ret = outer_ret;
4230                    self.ret_stated = outer_stated;
4231                }
4232            }
4233        }
4234    }
4235
4236    /// Checks an expression, against `expected` when the surrounding form
4237    /// imposes one, and returns its type.
4238    ///
4239    /// An expression's type is the most observable thing this pass produces:
4240    /// it is what the next form is checked against and what a binding holding
4241    /// the value keeps. [`Unknown::Placeholder`] claims to reach neither, so
4242    /// one arriving here means a construction site was wrong about itself,
4243    /// and the assertion names it in the test suite rather than letting the
4244    /// unknown validate whatever comes next.
4245    /// Recording happens here, at the one point every expression passes
4246    /// through, so no form can be added later that forgets to. It happens
4247    /// after the type is settled and nothing in the walk reads it back, so
4248    /// what is recorded cannot change what is reported.
4249    ///
4250    /// An expression walked twice records twice, and the later record wins.
4251    /// A [`Checker::probe`] is always the earlier of the two, so the answer
4252    /// left behind is the one the real walk reached.
4253    fn expr(&mut self, expr: &Expr, expected: Option<&Expected>) -> Ty {
4254        let ty = self.expr_type(expr, expected);
4255        debug_assert!(
4256            !ty.holds_placeholder(),
4257            "a placeholder unknown escaped into the type of an expression at {:?}: `{ty}`",
4258            expr.span
4259        );
4260        self.facts.record_ty(expr.span.file, expr.id, &ty);
4261        // A type still holding an inference variable is not this
4262        // expression's final answer: the uses that come after it may say
4263        // what the variable is, and `Checker::finish_inference` writes the
4264        // fact again once they have.
4265        if ty.holds_var() {
4266            self.open_facts.push((expr.span.file, expr.id));
4267        }
4268        ty
4269    }
4270
4271    fn expr_type(&mut self, expr: &Expr, expected: Option<&Expected>) -> Ty {
4272        let span = expr.span;
4273        let ty = match &expr.kind {
4274            ExprKind::Int(_) => Ty::Int,
4275            ExprKind::Float(_) => Ty::Float,
4276            ExprKind::Bool(_) => Ty::Bool,
4277            ExprKind::Duration(_) => Ty::Duration,
4278            ExprKind::Unit => Ty::Unit,
4279            ExprKind::Str(parts) => {
4280                for part in parts {
4281                    if let StrPart::Interpolation(inner) = part {
4282                        // Interpolation renders any value, so an interpolated
4283                        // expression is checked but not constrained.
4284                        self.expr(inner, None);
4285                    }
4286                }
4287                Ty::Str
4288            }
4289            ExprKind::Ident(name) => self.ident(name, span, expected),
4290            ExprKind::ArrayLit(items) => self.array_literal(items, span, expected),
4291            ExprKind::Field { base, name } => self.field(base, name, span),
4292            ExprKind::Call {
4293                callee,
4294                generics,
4295                args,
4296                trailing,
4297            } => self.call(
4298                expr.id,
4299                callee,
4300                generics,
4301                args,
4302                trailing.as_deref(),
4303                span,
4304                expected,
4305            ),
4306            ExprKind::Unary { op, operand } => self.unary(*op, operand, span),
4307            ExprKind::Binary { op, lhs, rhs } => self.binary(*op, lhs, rhs, span),
4308            ExprKind::Assign { op, target, value } => self.assign(*op, target, value, span),
4309            ExprKind::Try(inner) => self.try_expr(inner, span),
4310            ExprKind::Await(inner) => self.await_expr(inner, span),
4311            ExprKind::Block(block) => return self.block(block, expected),
4312            ExprKind::If {
4313                condition,
4314                then_branch,
4315                else_branch,
4316            } => {
4317                return self.if_expr(
4318                    condition,
4319                    then_branch,
4320                    else_branch.as_deref(),
4321                    span,
4322                    expected,
4323                )
4324            }
4325            ExprKind::Match { scrutinee, arms } => {
4326                return self.match_expr(scrutinee, arms, span, expected)
4327            }
4328            ExprKind::For {
4329                binding,
4330                iterable,
4331                body,
4332            } => self.for_expr(binding, iterable, body),
4333            ExprKind::While { condition, body } => {
4334                self.condition(condition);
4335                self.block(body, None);
4336                Ty::Unit
4337            }
4338            ExprKind::Return(value) => {
4339                if self.ret_stated {
4340                    let expected = Expected::new(
4341                        self.ret.clone(),
4342                        self.ret_span,
4343                        format!("the declared return type is `{}`", self.ret),
4344                    );
4345                    match value {
4346                        Some(value) => {
4347                            self.expr(value, Some(&expected));
4348                        }
4349                        None => self.expect(&Ty::Unit, &expected, span),
4350                    }
4351                } else {
4352                    // A function value nothing expects takes its result from
4353                    // its body's value. An early `return` produces one
4354                    // somewhere the body's value is not, so nothing written
4355                    // anywhere says what the two have to agree on — and the
4356                    // function's own type would be read off a body that no
4357                    // longer decides it.
4358                    self.diagnostics.push(
4359                        Diagnostic::error(
4360                            LAMBDA_RETURN,
4361                            "this function value uses `return`, but nothing says what it produces",
4362                        )
4363                        .at(span)
4364                        .rule("A `return` is checked against a stated result type: a declaration writes one, and a function value takes one from the place that holds it.")
4365                        .help("give this function value to a place that declares its type, as in `let handle: fn(Int) -> String = fn(n) { ... }`, or end the body with the value instead of returning it"),
4366                    );
4367                    if let Some(value) = value {
4368                        self.expr(value, None);
4369                    }
4370                }
4371                Ty::Never
4372            }
4373            // A `break` produces no value of its own, and neither does the
4374            // loop it leaves.
4375            ExprKind::Break(value) => {
4376                // The operand is checked on its own, against no expectation,
4377                // and its value is discarded: the loop it leaves produces
4378                // `()` however it leaves. Nothing expects the operand
4379                // because there is nowhere for it to go -- a loop is
4380                // permanently `()`, decided in issue #87.
4381                if let Some(value) = value {
4382                    self.expr(value, None);
4383                }
4384                Ty::Never
4385            }
4386            ExprKind::Continue => Ty::Never,
4387            ExprKind::Lambda {
4388                is_async,
4389                params,
4390                body,
4391            } => return self.lambda(*is_async, params, body, span, expected),
4392            ExprKind::Scope { name, body } => {
4393                self.scopes.push(BTreeMap::new());
4394                self.declare(&name.node, Ty::Scope, false);
4395                self.open_scopes.push(OpenScope {
4396                    name: name.node.clone(),
4397                    children: Vec::new(),
4398                });
4399                let ty = self.block(body, expected);
4400                if let Some(open) = self.open_scopes.pop() {
4401                    self.leaving_scope(open);
4402                }
4403                self.scopes.pop();
4404                return ty;
4405            }
4406            ExprKind::Range {
4407                start,
4408                end,
4409                inclusive_end: _,
4410            } => {
4411                let bound = Expected::new(Ty::Int, span, "a range runs between two `Int`s");
4412                self.expr(start, Some(&bound));
4413                self.expr(end, Some(&bound));
4414                Ty::Range
4415            }
4416        };
4417        if let Some(expected) = expected {
4418            self.expect(&ty, expected, span);
4419        }
4420        ty
4421    }
4422
4423    /// Whether the place a value is being given to has already been
4424    /// accounted for, so a form that finds nothing there should stay quiet.
4425    ///
4426    /// The `UNCONSTRAINED` warnings all say the same thing — nothing written
4427    /// settles this type — and that is only worth saying when the silence is
4428    /// the program's. An expectation the checker itself could not state
4429    /// carries its own explanation already: an argument of a call whose
4430    /// callee was just rejected, a block whose type a schema declared `Any`,
4431    /// a call into a host module no schema describes. Repeating the
4432    /// gap underneath one of those turns one fact into two diagnostics, which
4433    /// is what the recovery classification exists to prevent.
4434    ///
4435    /// See `Unknown::is_accounted_for` for which unknowns qualify.
4436    fn accounted_for(expected: Option<&Expected>) -> bool {
4437        expected.is_some_and(|e| e.ty.is_accounted_for())
4438    }
4439
4440    /// The unknown standing for a place this pass abstained about, or a
4441    /// recovery unknown when the place has a type but not a usable one.
4442    ///
4443    /// Both are silent; keeping the kind is what lets a later reader of the
4444    /// type say which silence it came from.
4445    fn abstention_of(expected: Option<&Expected>) -> Ty {
4446        match expected.map(|e| &e.ty) {
4447            Some(Ty::Unknown(kind)) if kind.is_accounted_for() => Ty::Unknown(*kind),
4448            // A schema declaring `Any` states the abstention itself, so it
4449            // is what a form given to such a place takes.
4450            Some(Ty::Any) => Ty::Any,
4451            _ => Ty::recovery(),
4452        }
4453    }
4454
4455    /// Reports a type that does not match what the surrounding form asked
4456    /// for, pointing at the expression and labelling what imposed it.
4457    fn expect(&mut self, found: &Ty, expected: &Expected, span: Span) {
4458        // The comparison this pass was going to make anyway is also where a
4459        // local binding's open type meets a stated one, so it is read for
4460        // what it says about the variables on either side before it is
4461        // judged. It happens first because an unknown matches everything:
4462        // by the line below there is nothing left to read.
4463        self.constrain(found, &expected.ty, span);
4464        if found.matches(&expected.ty) || coerces(found, &expected.ty, &self.view()) {
4465            return;
4466        }
4467        // The one implicit conversion the language has is to `dyn Trait`, so
4468        // a value rejected there is rejected for a reason of its own: it does
4469        // not conform.
4470        let mut diagnostic = match &expected.ty {
4471            Ty::Dyn(trait_name) if !matches!(found, Ty::Dyn(_)) => Diagnostic::error(
4472                MISMATCH,
4473                format!("`{found}` does not conform to `{trait_name}`, so it is not a `{}`", expected.ty),
4474            )
4475            .at(span)
4476            .rule("A concrete value becomes a `dyn Trait` value where one is expected, and that is the only implicit conversion in the language; it requires an explicit conformance.")
4477            .help(format!("write `impl {trait_name} for {found} {{ ... }}`")),
4478            _ => {
4479                let mut diagnostic = Diagnostic::error(
4480                    MISMATCH,
4481                    format!("expected `{}`, found `{found}`", expected.ty),
4482                )
4483                .at(span)
4484                .rule("Types are nominal and the only implicit conversion is to `dyn Trait`: a value must otherwise already have the type its place asks for.");
4485                if let Some(help) = conversion_help(&expected.ty, found) {
4486                    diagnostic = diagnostic.help(help);
4487                }
4488                diagnostic
4489            }
4490        };
4491        if let Some(origin) = &expected.origin {
4492            diagnostic = diagnostic.label(origin.span, origin.label.clone());
4493        }
4494        self.diagnostics.push(diagnostic);
4495    }
4496
4497    /// A bare name: a local, a module function, a constructor, a host item,
4498    /// or a name only the host can explain.
4499    fn ident(&mut self, name: &str, span: Span, expected: Option<&Expected>) -> Ty {
4500        if let Some(binding) = self.lookup(name) {
4501            return binding.ty.clone();
4502        }
4503        if name == NONE_CASE.name {
4504            return match expected.map(|e| &e.ty) {
4505                Some(Ty::Option(inner)) => Ty::Option(inner.clone()),
4506                // `None` carries nothing, so it is the only value whose own
4507                // type its own text cannot settle.
4508                _ => {
4509                    if !Checker::accounted_for(expected) {
4510                        self.diagnostics.push(unconstrained(
4511                            "nothing says what this `None` is an `Option` of".to_string(),
4512                            format!("write the type on the place that holds it, as in `let value: Option<Int> = {name}`"),
4513                            span,
4514                        ));
4515                    }
4516                    Ty::Option(Box::new(Ty::unconstrained()))
4517                }
4518            };
4519        }
4520        if let Some(sig) = self.functions.get(&self.key(name)) {
4521            return sig.as_value();
4522        }
4523        // A host operation is a value. The interpreter has always bound one
4524        // and called it later — `Value::HostFn` is exactly that — and the
4525        // schema says what it takes and what it answers, so this is a place
4526        // where reading the schema turns something that used to be unknown
4527        // into an ordinary function type rather than into a refusal.
4528        if let Some(module) = self.module.host_items.get(name).cloned() {
4529            return self.host_operation_value(&module, name, span);
4530        }
4531        // A type or a module used as a value has no type in this system; the
4532        // forms that give it meaning (`Vector.of`, `MapEntry(key:, value:)`,
4533        // `Booking(id: 1)`, `lib.create(...)`) are understood at the call
4534        // itself. Writing one bare is a mistake with a name, so it is named
4535        // rather than turned into an unknown that would let whatever was
4536        // done with it check.
4537        if let Some(what) = self.namespace(name) {
4538            self.diagnostics.push(not_a_value(name, what, span));
4539            return Ty::recovery();
4540        }
4541        self.unresolved_name(name, span)
4542    }
4543
4544    /// `console.println` written where a value belongs, or a bare `println`
4545    /// that `use console.println` brought into scope.
4546    ///
4547    /// A host module's members are its operations and its types. An operation
4548    /// is a value — the interpreter binds one as `Value::HostFn` and calls it
4549    /// later — so it is given the function type its schema declares, which
4550    /// checks a call made through the value exactly as a direct call is
4551    /// checked. A type is not a value, for the same reason a bare `Vector` is
4552    /// not.
4553    fn host_operation_value(&mut self, module: &str, name: &str, span: Span) -> Ty {
4554        let shown = format!("{module}.{name}");
4555        let Some(schema) = self.host_schema(module) else {
4556            // No schema to read: what the host exposes under this name is
4557            // between it and the boundary, and the `use` that named the
4558            // module is where that is answered (#74).
4559            return Ty::dynamic_boundary();
4560        };
4561        let Some(operation) = schema.operation(name) else {
4562            if schema.declared_type(name).is_some() || schema.resource(name).is_some() {
4563                self.diagnostics
4564                    .push(not_a_value(&shown, Namespace::HostType, span));
4565                return Ty::recovery();
4566            }
4567            self.diagnostics.push(
4568                Diagnostic::error(
4569                    UNKNOWN_HOST_OPERATION,
4570                    format!("host module `{module}` has no operation `{name}`"),
4571                )
4572                .at(span)
4573                .rule(HOST_SCHEMA_RULE)
4574                .help(format!(
4575                    "`{module}` exposes {}",
4576                    list(&operation_names(schema.operations))
4577                )),
4578            );
4579            return Ty::recovery();
4580        };
4581        if operation.variadic {
4582            // A variadic operation has no function type in this language, so
4583            // the value cannot be given one. Cove has no variadic `fn` type
4584            // to write, which makes this the language's own gap rather than
4585            // the program's: the call through the value still runs, and the
4586            // boundary still counts the arguments. Said out loud as a note,
4587            // for the same reason a schema's `Any` is one.
4588            self.diagnostics.push(
4589                Diagnostic::note(
4590                    VARIADIC_AS_VALUE,
4591                    format!(
4592                        "`{shown}` is variadic, so this value has no function type here"
4593                    ),
4594                )
4595                .at(span)
4596                .rule("A function type in Cove names a fixed list of parameters; a Host API operation may declare a variadic one, which no `fn` type can be written for.")
4597                .help(format!(
4598                    "calling `{shown}` directly is checked against its schema; a call made through this value is checked by the boundary and by nothing here, so write `fn(value: {}) {{ {shown}(value) }}` to have one that is",
4599                    operation
4600                        .params
4601                        .first()
4602                        .map(host_ty)
4603                        .unwrap_or(Ty::Unit)
4604                )),
4605            );
4606            return Ty::unconstrained();
4607        }
4608        Ty::func(
4609            false,
4610            operation.params.iter().map(host_ty).collect(),
4611            host_ty(&operation.result),
4612        )
4613    }
4614
4615    /// The type of a name nothing in scope explains.
4616    ///
4617    /// Both cases are errors, and the case of the first letter only changes
4618    /// the correction. A capitalized name used to be assumed to come from
4619    /// the host and warned about instead; but a host reaches this module
4620    /// through `use` like everything else, so that assumption never named a
4621    /// real way for the name to arrive — it only let an unknown through to
4622    /// validate whatever the program then did with it.
4623    fn unresolved_name(&mut self, name: &str, span: Span) -> Ty {
4624        let (code, help) = if starts_uppercase(name) {
4625            (
4626                UNRESOLVED_NAME,
4627                format!(
4628                    "declare `struct {name}` or `enum {name}` in this module, `use <module>.{name}` to import it, or `use <host>` and write `<host>.{name}`"
4629                ),
4630            )
4631        } else {
4632            (
4633                UNKNOWN_NAME,
4634                format!(
4635                    "declare `let {name} = ...` before this expression, or `use <host>.{name}`"
4636                ),
4637            )
4638        };
4639        self.diagnostics.push(
4640            Diagnostic::error(code, format!("cannot find `{name}` in this scope"))
4641                .at(span)
4642                .rule("A name must be a local binding, a parameter, a declaration of this module, or something `use` imports.")
4643                .help(help),
4644        );
4645        Ty::recovery()
4646    }
4647
4648    /// What `name` names, when it names something values are reached
4649    /// *through* rather than something that is one.
4650    ///
4651    /// The order follows `Checker::ident`'s: a local binding and a
4652    /// declared function are values and have already answered by the time
4653    /// this is asked.
4654    fn namespace(&self, name: &str) -> Option<Namespace> {
4655        if self.module.structs.contains_key(name) {
4656            Some(Namespace::Struct)
4657        } else if self.module.enums.contains_key(name) {
4658            Some(Namespace::Enum)
4659        } else if self.is_imported(name) {
4660            Some(self.declared_shape(&self.key(name)))
4661        } else if cove_schema::is_builtin_type(name) || name == MAP_ENTRY.name {
4662            Some(Namespace::BuiltinType)
4663        } else if self.module.host_uses.contains(name) {
4664            Some(Namespace::HostModule)
4665        } else if self.module.module_imports.contains_key(name) {
4666            Some(Namespace::Module)
4667        } else {
4668            None
4669        }
4670    }
4671
4672    /// Whether the declaration `key` names is a struct, an enum, or something
4673    /// whose shape decides nothing about how a value of it is written.
4674    ///
4675    /// A trait and a type alias reach the last of these: neither is
4676    /// constructed and neither has cases, so the correction can only point at
4677    /// the associated functions.
4678    fn declared_shape(&self, key: &str) -> Namespace {
4679        if self.structs.contains_key(key) {
4680            Namespace::Struct
4681        } else if self.enums.contains_key(key) {
4682            Namespace::Enum
4683        } else {
4684            Namespace::Type
4685        }
4686    }
4687
4688    fn array_literal(&mut self, items: &[Expr], span: Span, expected: Option<&Expected>) -> Ty {
4689        let mut element_hint = match expected.map(|e| &e.ty) {
4690            Some(Ty::Array(inner)) => Some((**inner).clone()),
4691            _ => None,
4692        };
4693        // With no expected element type a sibling may still settle one, and
4694        // which sibling is not known until every one has been walked:
4695        // `[[], [1]]` is an `Array<Array<Int>>` and nothing in it was left
4696        // unproved. So the items are walked once with nothing reported, to
4697        // find the element type out, and then again for real against it.
4698        if element_hint.is_none() && items.len() > 1 && !self.probing {
4699            let found = self.probe(|checker| {
4700                items.iter().fold(Ty::recovery(), |element, item| {
4701                    let ty = checker.expr(item, None);
4702                    element.join(&ty)
4703                })
4704            });
4705            if !found.is_wild() {
4706                element_hint = Some(found);
4707            }
4708        }
4709        if items.is_empty() && element_hint.is_none() && !Checker::accounted_for(expected) {
4710            // An empty literal has no element to read a type off and no
4711            // expected type to be given one, so `Array<_>` is as far as the
4712            // checker gets and every element-typed operation on it after
4713            // this point is unchecked.
4714            self.diagnostics.push(unconstrained(
4715                "nothing says what this empty array holds".to_string(),
4716                "write the type on the place that holds it, as in `let items: Array<Int> = []`"
4717                    .to_string(),
4718                span,
4719            ));
4720        }
4721        let mut element = element_hint
4722            .clone()
4723            .unwrap_or_else(|| match items.is_empty() {
4724                true => Ty::unconstrained(),
4725                false => Ty::recovery(),
4726            });
4727        for item in items {
4728            let hint = element_hint
4729                .clone()
4730                .map(|ty| {
4731                    let label = format!("the array's element type is `{ty}`");
4732                    Expected::new(ty, span, label)
4733                })
4734                .or_else(|| {
4735                    (!element.is_wild()).then(|| {
4736                        Expected::new(
4737                            element.clone(),
4738                            span,
4739                            format!("the first element is `{element}`"),
4740                        )
4741                    })
4742                });
4743            let ty = self.expr(item, hint.as_ref());
4744            element = element.join(&ty);
4745        }
4746        Ty::Array(Box::new(element))
4747    }
4748
4749    /// `base.name`: an enum case, a host operation, an imported module's
4750    /// declaration, or a struct field.
4751    fn field(&mut self, base: &Expr, name: &Ident, span: Span) -> Ty {
4752        // `http.Method.Get` is three segments, so it reaches here as a field
4753        // of a field. A host module's enum has no other way to be written.
4754        if let ExprKind::Field {
4755            base: module,
4756            name: declared,
4757        } = &base.kind
4758        {
4759            if let ExprKind::Ident(head) = &module.kind {
4760                if self.lookup(head).is_none() && self.module.host_uses.contains(head.as_str()) {
4761                    if let Some(ty) = self.host_enum_case(head, &declared.node, name, span) {
4762                        return ty;
4763                    }
4764                }
4765            }
4766        }
4767        if let ExprKind::Ident(head) = &base.kind {
4768            if self.lookup(head).is_none() {
4769                let key = self.key(head);
4770                if self.enums.contains_key(&key) {
4771                    return self.enum_case(&key, name, &[], span);
4772                }
4773                if self.module.host_uses.contains(head.as_str()) {
4774                    // A host module's members are its operations and its
4775                    // types. An operation is a value and the schema says
4776                    // which one; a type is not, exactly as a bare `Vector`
4777                    // is not. A build with no schema for the module can tell
4778                    // neither, and leaves both to the boundary.
4779                    return self.host_operation_value(head, &name.node, span);
4780                }
4781                if self.module.module_imports.contains_key(head.as_str()) {
4782                    let Some(key) = self.qualified_key(head, &name.node, span) else {
4783                        return Ty::recovery();
4784                    };
4785                    // A function reached through its module is an ordinary
4786                    // value; a type is not, exactly as a bare type name is
4787                    // not.
4788                    return match self.functions.get(&key) {
4789                        Some(sig) => sig.as_value(),
4790                        None => {
4791                            let shape = self.declared_shape(&key);
4792                            self.diagnostics.push(not_a_value(
4793                                &format!("{head}.{}", name.node),
4794                                shape,
4795                                span,
4796                            ));
4797                            Ty::recovery()
4798                        }
4799                    };
4800                }
4801            }
4802        }
4803        let base_ty = self.expr(base, None);
4804        self.field_of(&base_ty, name, span)
4805    }
4806
4807    fn field_of(&mut self, base_ty: &Ty, name: &Ident, span: Span) -> Ty {
4808        match base_ty {
4809            Ty::Unknown(_) => base_ty.abstain(),
4810            // A field read off a value a schema declared `Any` is checked
4811            // at run time and by nothing before it, which
4812            // `cove::type::unconstrained_result` already said where the
4813            // value was produced.
4814            Ty::Any => Ty::Any,
4815            Ty::Struct(struct_name, args) => {
4816                // A `Ty::Struct` is only ever built from a key this table
4817                // answers, so there is no reachable program without one.
4818                let Some(sig) = self.structs.get(struct_name.as_ref()) else {
4819                    return Ty::placeholder();
4820                };
4821                let sig = sig.clone();
4822                let subst = substitution(&sig.generics, args);
4823                let usage = if self.assigned_place == Some(span) {
4824                    FieldUse::Write
4825                } else {
4826                    FieldUse::Read
4827                };
4828                if self.reject_opaque_field(struct_name, &sig, &name.node, usage, span) {
4829                    return Ty::recovery();
4830                }
4831                match sig.fields.iter().find(|f| f.name == name.node) {
4832                    Some(field) => field.ty.substitute(&subst),
4833                    None => {
4834                        let known: Vec<String> =
4835                            sig.fields.iter().map(|f| f.name.clone()).collect();
4836                        self.diagnostics.push(
4837                            Diagnostic::error(
4838                                UNKNOWN_FIELD,
4839                                format!("`{struct_name}` has no field `{}`", name.node),
4840                            )
4841                            .at(span)
4842                            .rule("A struct's fields are exactly the ones its declaration lists.")
4843                            .help(format!("`{struct_name}` declares {}", list(&known))),
4844                        );
4845                        Ty::recovery()
4846                    }
4847                }
4848            }
4849            Ty::Host(declared) => {
4850                let declared = declared.clone();
4851                self.host_field(&declared, name, span)
4852            }
4853            // The two builtin structs. Their fields are declared in
4854            // `cove_schema::builtins`, which is also where the runtime reads
4855            // what to build, so `error.message` and `entry.key` are one
4856            // description rather than a checker's and an interpreter's.
4857            Ty::MapEntry(_, _) | Ty::Error => self.builtin_field(base_ty, name, span),
4858            // A type parameter and a trait object both stand for some type
4859            // the checker cannot see, so neither has fields: only the traits
4860            // in play say what can be done with the value.
4861            abstract_ty @ (Ty::Param(_) | Ty::Dyn(_)) => {
4862                self.diagnostics.push(
4863                    Diagnostic::error(
4864                        UNKNOWN_FIELD,
4865                        format!("`{abstract_ty}` has no field `{}`", name.node),
4866                    )
4867                    .at(span)
4868                    .rule("A trait declares methods, not fields, so a value reached only through a trait has no fields; conformance is explicit and never structural.")
4869                    .help(format!(
4870                        "declare `fn {}(self) -> ...` in the trait and call `{}()`",
4871                        name.node, name.node
4872                    )),
4873                );
4874                Ty::recovery()
4875            }
4876            other => {
4877                self.diagnostics.push(
4878                    Diagnostic::error(
4879                        UNKNOWN_FIELD,
4880                        format!("`{other}` has no field `{}`", name.node),
4881                    )
4882                    .at(span)
4883                    .rule("Only a struct has fields.")
4884                    .help(format!(
4885                        "`{other}` is not a struct; call a method such as `{}()` instead, if one exists",
4886                        name.node
4887                    )),
4888                );
4889                Ty::recovery()
4890            }
4891        }
4892    }
4893
4894    /// `Enum.Case` or `Enum.Case(payload...)`.
4895    fn enum_case(&mut self, enum_name: &str, case: &Ident, args: &[Arg], span: Span) -> Ty {
4896        // As in `field_of`: the key was read off a resolved type, so the
4897        // table answers it.
4898        let Some(sig) = self.enums.get(enum_name).cloned() else {
4899            return Ty::placeholder();
4900        };
4901        let ty = Ty::Enum(
4902            enum_name.into(),
4903            sig.generics.iter().cloned().map(Ty::Param).collect(),
4904        );
4905        let Some(found) = sig.cases.iter().find(|c| c.name == case.node) else {
4906            // An associated function is only reached through a call, which is
4907            // handled before this; a bare `Enum.name` that is not a case is a
4908            // case name that does not exist.
4909            let known: Vec<String> = sig.cases.iter().map(|c| c.name.clone()).collect();
4910            self.diagnostics.push(
4911                Diagnostic::error(
4912                    UNKNOWN_CASE,
4913                    format!("`{enum_name}` has no case `{}`", case.node),
4914                )
4915                .at(span)
4916                .rule("An enum's cases are exactly the ones its declaration lists.")
4917                .help(format!("`{enum_name}` declares {}", list(&known))),
4918            );
4919            return ty;
4920        };
4921        if found.payload.len() != args.len() {
4922            self.diagnostics.push(
4923                Diagnostic::error(
4924                    PAYLOAD_ARITY,
4925                    format!(
4926                        "`{enum_name}.{}` carries {} value(s), but {} were given",
4927                        case.node,
4928                        found.payload.len(),
4929                        args.len()
4930                    ),
4931                )
4932                .at(span)
4933                .label(found.span, "declared here")
4934                .rule("An enum case carries exactly the payload its declaration writes.")
4935                .help(if found.payload.is_empty() {
4936                    format!("write `{enum_name}.{}`", case.node)
4937                } else {
4938                    format!(
4939                        "write `{enum_name}.{}({})`",
4940                        case.node,
4941                        found
4942                            .payload
4943                            .iter()
4944                            .map(Ty::to_string)
4945                            .collect::<Vec<_>>()
4946                            .join(", ")
4947                    )
4948                }),
4949            );
4950        }
4951        // A generic enum's arguments are decided by the payload it is given,
4952        // exactly as a generic function's are decided by its arguments.
4953        let generic_set: BTreeSet<Arc<str>> = sig.generics.iter().cloned().collect();
4954        let mut subst: BTreeMap<Arc<str>, Ty> = BTreeMap::new();
4955        for (arg, payload) in args.iter().zip(&found.payload) {
4956            let hint = self.open(payload, &sig.generics, &subst);
4957            let expected = Expected::new(
4958                hint.clone(),
4959                found.span,
4960                format!("this case carries a `{hint}`"),
4961            );
4962            let found_ty = self.expr(&arg.value, Some(&expected));
4963            unify(payload, &found_ty, &generic_set, &mut subst, &self.view());
4964        }
4965        for arg in args.iter().skip(found.payload.len()) {
4966            self.expr(&arg.value, None);
4967        }
4968        self.open_result(&ty, &sig.generics, &subst, span)
4969    }
4970
4971    fn unary(&mut self, op: UnaryOp, operand: &Expr, span: Span) -> Ty {
4972        let ty = self.expr(operand, None);
4973        if ty.is_wild() {
4974            return ty;
4975        }
4976        match (op, &ty) {
4977            (UnaryOp::Not, Ty::Bool) => Ty::Bool,
4978            (UnaryOp::Neg, Ty::Int) => Ty::Int,
4979            (UnaryOp::Neg, Ty::Float) => Ty::Float,
4980            (UnaryOp::Neg, Ty::Duration) => Ty::Duration,
4981            _ => {
4982                let symbol = match op {
4983                    UnaryOp::Not => "!",
4984                    UnaryOp::Neg => "-",
4985                };
4986                self.diagnostics.push(
4987                    Diagnostic::error(OPERATOR, format!("`{symbol}` is not defined for `{ty}`"))
4988                        .at(span)
4989                        .rule("There are no implicit numeric, string, or boolean conversions.")
4990                        .help(match op {
4991                            UnaryOp::Not => {
4992                                "`!` negates a `Bool`; compare instead, as in `x == 0`".to_string()
4993                            }
4994                            UnaryOp::Neg => {
4995                                "`-` negates an `Int`, a `Float`, or a `Duration`".to_string()
4996                            }
4997                        }),
4998                );
4999                Ty::recovery()
5000            }
5001        }
5002    }
5003
5004    fn binary(&mut self, op: BinaryOp, lhs: &Expr, rhs: &Expr, span: Span) -> Ty {
5005        let left = self.expr(lhs, None);
5006        let right = self.expr(rhs, None);
5007        self.binary_result(op, &left, &right, span)
5008    }
5009
5010    /// The type of `left op right`, mirroring the operators the runtime
5011    /// defines. Mixed operands are rejected: the card allows no implicit
5012    /// numeric, string, or boolean conversions, and this is that rule made
5013    /// static.
5014    fn binary_result(&mut self, op: BinaryOp, left: &Ty, right: &Ty, span: Span) -> Ty {
5015        match op {
5016            BinaryOp::And | BinaryOp::Or => {
5017                let mut ok = true;
5018                for ty in [left, right] {
5019                    if !ty.is_wild() && *ty != Ty::Bool {
5020                        ok = false;
5021                    }
5022                }
5023                if !ok {
5024                    self.operator_error(op, left, right, span, "`&&` and `||` combine two `Bool`s");
5025                }
5026                Ty::Bool
5027            }
5028            BinaryOp::Eq | BinaryOp::Ne => {
5029                if !left.matches(right) {
5030                    self.diagnostics.push(
5031                        Diagnostic::error(
5032                            OPERATOR,
5033                            format!("cannot compare `{left}` with `{right}`"),
5034                        )
5035                        .at(span)
5036                        .rule("`==` means value equality between values of the same type.")
5037                        .help(format!(
5038                            "convert one side explicitly so both are `{left}`, or compare values that already share a type"
5039                        )),
5040                    );
5041                }
5042                Ty::Bool
5043            }
5044            BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Rem => {
5045                if left.is_wild() || right.is_wild() {
5046                    return left.join(right);
5047                }
5048                if left != right {
5049                    self.operator_error(
5050                        op,
5051                        left,
5052                        right,
5053                        span,
5054                        "arithmetic combines two values of the same type",
5055                    );
5056                    return Ty::recovery();
5057                }
5058                match left {
5059                    Ty::Int | Ty::Float => left.clone(),
5060                    Ty::Duration if matches!(op, BinaryOp::Add | BinaryOp::Sub) => Ty::Duration,
5061                    Ty::Str if op == BinaryOp::Add => {
5062                        self.diagnostics.push(
5063                            Diagnostic::error(OPERATOR, "`+` is not defined for `String`")
5064                                .at(span)
5065                                .rule("There are no implicit string conversions.")
5066                                .help("use string interpolation, such as \"{left}{right}\""),
5067                        );
5068                        Ty::recovery()
5069                    }
5070                    _ => {
5071                        self.operator_error(
5072                            op,
5073                            left,
5074                            right,
5075                            span,
5076                            "arithmetic is defined for `Int`, `Float`, and (for `+` and `-`) `Duration`",
5077                        );
5078                        Ty::recovery()
5079                    }
5080                }
5081            }
5082            // `is` asks a narrower question than `==`: whether two operands
5083            // are the same shared storage, which only a handful of types
5084            // (today, only `Vector`) even have. A type mismatch is rejected
5085            // exactly like `==`; a same-typed operand that is not one of
5086            // those types is rejected too, since the Language Card says
5087            // identity is explicit "when available" — it is not silently
5088            // `false` for a type that has none.
5089            BinaryOp::Is => {
5090                if !left.matches(right) {
5091                    self.diagnostics.push(
5092                        Diagnostic::error(
5093                            OPERATOR,
5094                            format!("cannot compare the identity of `{left}` with `{right}`"),
5095                        )
5096                        .at(span)
5097                        .rule("`is` compares identity between values of the same type.")
5098                        .help(format!(
5099                            "convert one side explicitly so both are `{left}`, or compare values that already share a type"
5100                        )),
5101                    );
5102                    return Ty::Bool;
5103                }
5104                if left.is_wild() || matches!(left, Ty::Vector(_)) {
5105                    return Ty::Bool;
5106                }
5107                self.diagnostics.push(
5108                    Diagnostic::error(
5109                        OPERATOR,
5110                        format!("identity is not available for `{left}`"),
5111                    )
5112                    .at(span)
5113                    .rule("`==` means value equality. Identity, when available, is explicit.")
5114                    .help(
5115                        "`is` is defined for `Vector`; compare other values with `==`, or call `toArray()` for an independent copy",
5116                    ),
5117                );
5118                Ty::Bool
5119            }
5120            BinaryOp::Lt | BinaryOp::Le | BinaryOp::Gt | BinaryOp::Ge => {
5121                if left.is_wild() || right.is_wild() {
5122                    return Ty::Bool;
5123                }
5124                if left != right {
5125                    self.operator_error(
5126                        op,
5127                        left,
5128                        right,
5129                        span,
5130                        "an ordering compares two values of the same type",
5131                    );
5132                } else if !matches!(left, Ty::Int | Ty::Float | Ty::Duration | Ty::Str) {
5133                    self.operator_error(
5134                        op,
5135                        left,
5136                        right,
5137                        span,
5138                        "`<`, `<=`, `>`, and `>=` are defined for `Int`, `Float`, `Duration`, and `String`",
5139                    );
5140                }
5141                Ty::Bool
5142            }
5143        }
5144    }
5145
5146    fn operator_error(&mut self, op: BinaryOp, left: &Ty, right: &Ty, span: Span, help: &str) {
5147        let symbol = operator_symbol(op);
5148        self.diagnostics.push(
5149            Diagnostic::error(
5150                OPERATOR,
5151                format!("`{symbol}` is not defined for `{left}` and `{right}`"),
5152            )
5153            .at(span)
5154            .rule("There are no implicit numeric, string, or boolean conversions.")
5155            .help(help.to_string()),
5156        );
5157    }
5158
5159    fn assign(&mut self, op: Option<BinaryOp>, target: &Expr, value: &Expr, span: Span) -> Ty {
5160        if !matches!(target.kind, ExprKind::Ident(_) | ExprKind::Field { .. }) {
5161            self.diagnostics.push(
5162                Diagnostic::error(
5163                    NOT_A_PLACE,
5164                    "this expression is not a place, so it cannot be assigned",
5165                )
5166                .at(target.span)
5167                .rule("Only a binding or a field of one is a place.")
5168                .help("assign to a `var` binding, or to a field of one"),
5169            );
5170            self.expr(value, None);
5171            return Ty::Unit;
5172        }
5173        // The target is a place; whether it is a *writable* one is decided
5174        // from the binding it is rooted at. Reported before the types are
5175        // checked and the walk carries on afterwards, because an assignment
5176        // whose value is also the wrong type is two mistakes and both are
5177        // worth saying.
5178        if self.place_mutability(target) == Some(false) {
5179            let place = place_text(target);
5180            self.diagnostics.push(
5181                Diagnostic::error(
5182                    READ_ONLY_PLACE,
5183                    format!("cannot assign to `{place}`, which is a read-only place"),
5184                )
5185                .at(span)
5186                .rule("`let` creates a read-only place; `var` creates a mutable place.")
5187                .help(format!(
5188                    "declare it with `var {place}` to make it assignable"
5189                )),
5190            );
5191        }
5192        // The target is checked as the place it is, so a field refused
5193        // across an opaque boundary is refused as a write rather than as a
5194        // read. Only the target itself is the place: the value, and any
5195        // field read on the way to the place, are checked as ordinary
5196        // expressions.
5197        let outer = std::mem::replace(
5198            &mut self.assigned_place,
5199            matches!(target.kind, ExprKind::Field { .. }).then_some(target.span),
5200        );
5201        let target_ty = self.expr(target, None);
5202        self.assigned_place = outer;
5203        match op {
5204            None => {
5205                let expected = Expected::new(
5206                    target_ty.clone(),
5207                    target.span,
5208                    format!("the assigned place is `{target_ty}`"),
5209                );
5210                self.expr(value, Some(&expected));
5211            }
5212            Some(op) => {
5213                let value_ty = self.expr(value, None);
5214                let result = self.binary_result(op, &target_ty, &value_ty, span);
5215                let expected = Expected::new(
5216                    target_ty.clone(),
5217                    target.span,
5218                    format!("the assigned place is `{target_ty}`"),
5219                );
5220                self.expect(&result, &expected, span);
5221            }
5222        }
5223        Ty::Unit
5224    }
5225
5226    /// `expr?`, which returns the failure from the current function.
5227    fn try_expr(&mut self, inner: &Expr, span: Span) -> Ty {
5228        let ty = self.expr(inner, None);
5229        match &ty {
5230            Ty::Unknown(_) | Ty::Never => ty.abstain(),
5231            Ty::Any => Ty::Any,
5232            Ty::Result(ok, error) => {
5233                let (ok, error) = ((**ok).clone(), (**error).clone());
5234                // `?` returns this failure from the enclosing function, so
5235                // the function's own failure type is what this one has to
5236                // be — which makes the `?` a use that says so. `Ok(5)?`
5237                // inside `-> Result<Int, String>` is where the `String`
5238                // comes from, and without this the failure type of the
5239                // `Ok` would be a hole the `?` had already agreed with.
5240                if let Ty::Result(_, ret_error) = self.ret.clone() {
5241                    self.constrain(&error, &ret_error, span);
5242                }
5243                match self.ret.clone() {
5244                    // Nothing *written* states what this body answers — the
5245                    // checker abstained, or a schema declared the place
5246                    // `Any` — so there is no declared failure type for this
5247                    // `?` to disagree with. Inside a function value that is
5248                    // not the end of it: what such a lambda produces is what
5249                    // its body proves, and the `?` is held until the body
5250                    // has proved it. Everywhere else it is the abstention it
5251                    // looks like.
5252                    Ty::Unknown(_) | Ty::Any => self.defer_try(Some(error.clone()), span),
5253                    Ty::Result(_, ret_error) if error.matches(&ret_error) => {}
5254                    Ty::Result(_, ret_error) => self.diagnostics.push(
5255                        Diagnostic::error(
5256                            TRY_RETURN,
5257                            format!(
5258                                "`?` propagates `{error}`, but this function returns `{ret_error}` as its failure"
5259                            ),
5260                        )
5261                        .at(span)
5262                        .label(self.ret_span, format!("the declared failure type is `{ret_error}`"))
5263                        .rule("`expr?` returns the error from the current function, so the two failure types must be the same.")
5264                        .help(format!(
5265                            "map the failure first, as in `expr.mapError(fn(error) {{ ... }})?`, or declare this function `-> Result<_, {error}>`"
5266                        )),
5267                    ),
5268                    other => self.diagnostics.push(
5269                        Diagnostic::error(
5270                            TRY_RETURN,
5271                            format!("`?` needs a function that returns a `Result`, but this one returns `{other}`"),
5272                        )
5273                        .at(span)
5274                        .label(self.ret_span, format!("the declared return type is `{other}`"))
5275                        .rule("`expr?` returns the error from the current function.")
5276                        .help(format!("declare this function `-> Result<{other}, {error}>`, or handle the `Err` with `unwrapOr`")),
5277                    ),
5278                }
5279                ok
5280            }
5281            Ty::Option(inner_ty) => {
5282                let inner_ty = (**inner_ty).clone();
5283                match self.ret.clone() {
5284                    Ty::Option(_) => {}
5285                    Ty::Unknown(_) | Ty::Any => self.defer_try(None, span),
5286                    other => self.diagnostics.push(
5287                        Diagnostic::error(
5288                            TRY_RETURN,
5289                            format!("`?` on an `Option` needs a function that returns an `Option`, but this one returns `{other}`"),
5290                        )
5291                        .at(span)
5292                        .label(self.ret_span, format!("the declared return type is `{other}`"))
5293                        .rule("`expr?` returns the missing value from the current function.")
5294                        .help(format!("declare this function `-> Option<{other}>`, or handle the `None` with `unwrapOr`")),
5295                    ),
5296                }
5297                inner_ty
5298            }
5299            Ty::Task(inner_ty) => {
5300                self.diagnostics.push(
5301                    Diagnostic::error(
5302                        TRY_OPERAND,
5303                        format!(
5304                            "`?` needs a `Result` or an `Option`, but found `Task<{inner_ty}>`"
5305                        ),
5306                    )
5307                    .at(span)
5308                    .rule("`expr?` returns the error from the current function.")
5309                    .help("settle the task first, as in `task.await()?`"),
5310                );
5311                Ty::recovery()
5312            }
5313            other => {
5314                self.diagnostics.push(
5315                    Diagnostic::error(
5316                        TRY_OPERAND,
5317                        format!("`?` needs a `Result` or an `Option`, but found `{other}`"),
5318                    )
5319                    .at(span)
5320                    .rule("`expr?` returns the error from the current function.")
5321                    .help(format!("`{other}` cannot fail, so drop the `?`")),
5322                );
5323                Ty::recovery()
5324            }
5325        }
5326    }
5327
5328    /// Holds a `?` whose enclosing function has no *written* result to
5329    /// disagree with, when that function is a value whose body will decide.
5330    ///
5331    /// Every way of saying "the body decides" is waited for. A placeholder
5332    /// is a lambda no place typed at all. `Any` is a place — a Host API
5333    /// schema's parameter — that typed it by saying it states nothing about
5334    /// the result. A variable, or a type parameter nothing settled, is a
5335    /// place whose result travels *outward*: `Scope.spawn` declares
5336    /// `fn() -> T` and `Array.map` declares `fn(T) -> U`, and what fills
5337    /// that `T` is the body. [`Checker::settle_pending_tries`] answers all
5338    /// of them once the body has been walked, which is when there is
5339    /// something to answer with.
5340    ///
5341    /// Two are silences already accounted for and stay silent: a recovery
5342    /// unknown stands for a mistake reported upstream, and a dynamic
5343    /// boundary for a host module this build was shown no schema for, whose
5344    /// one diagnostic ADR 0016 puts at the `use` and nowhere else.
5345    ///
5346    /// Outside a function value there is nothing to hold this against — a
5347    /// declaration always writes what it answers — so nothing is recorded.
5348    fn defer_try(&mut self, error: Option<Ty>, span: Span) {
5349        match &self.ret {
5350            Ty::Unknown(Unknown::Recovery | Unknown::DynamicBoundary) => return,
5351            ty if ty.is_wild() => {}
5352            _ => return,
5353        }
5354        if let Some(open) = self.open_lambdas.last_mut() {
5355            open.push(PendingTry { span, error });
5356        }
5357    }
5358
5359    /// Reports every `?` in a function value's body that the value's own
5360    /// result cannot carry.
5361    ///
5362    /// `produced` is what the lambda turned out to answer: what the place
5363    /// holding it declared, where it declared anything, joined with what the
5364    /// body proved. A `?` returns from this function, so this is the type
5365    /// its failure has to fit into, and `Dashboard` — the type a
5366    /// `clock.timeout` body ends with — has nowhere to put an `Err`.
5367    ///
5368    /// A produced type that says nothing is left alone. The body proved a
5369    /// recovery unknown, or an abstention, or never finished at all, and a
5370    /// second diagnostic about a type nothing states would be a guess.
5371    fn settle_pending_tries(&mut self, pending: Vec<PendingTry>, produced: &Ty, span: Span) {
5372        // The failure a `?` propagates is a use that says what this
5373        // function value's own failure type is, exactly as it is inside a
5374        // declaration: `clock.timeout { ... ?; Ok(n) }` takes the error type
5375        // of its `Ok` from here, which is the only thing in the body that
5376        // states one.
5377        if let Ty::Result(_, produced_error) = produced {
5378            for try_expr in &pending {
5379                if let Some(error) = &try_expr.error {
5380                    self.constrain(error, produced_error, try_expr.span);
5381                }
5382            }
5383        }
5384        let produced = self.bound(produced.clone());
5385        if produced.is_wild() {
5386            return;
5387        }
5388        for PendingTry { span: at, error } in pending {
5389            let diagnostic = match (&error, &produced) {
5390                (Some(error), Ty::Result(_, produced_error)) if error.matches(produced_error) => {
5391                    continue
5392                }
5393                (None, Ty::Option(_)) => continue,
5394                (Some(error), _) => Diagnostic::error(
5395                    TRY_RETURN,
5396                    format!(
5397                        "`?` propagates `{error}`, but this function value produces `{produced}`"
5398                    ),
5399                )
5400                .at(at)
5401                .label(
5402                    span,
5403                    format!("nothing declares what this function value produces, so its body's value does: `{produced}`"),
5404                )
5405                .rule(TRY_LAMBDA_RULE)
5406                .help(format!(
5407                    "end the body with a `Result`, as in `Ok(...)`, so this function value produces `Result<{produced}, {error}>` and the `?` has an `Err` to return; then answer that failure where the value arrives"
5408                )),
5409                (None, _) => Diagnostic::error(
5410                    TRY_RETURN,
5411                    format!(
5412                        "`?` on an `Option` returns `None`, but this function value produces `{produced}`"
5413                    ),
5414                )
5415                .at(at)
5416                .label(
5417                    span,
5418                    format!("nothing declares what this function value produces, so its body's value does: `{produced}`"),
5419                )
5420                .rule(TRY_LAMBDA_RULE)
5421                .help(format!(
5422                    "end the body with an `Option`, as in `Some(...)`, so this function value produces `Option<{produced}>` and the `?` has a `None` to return; then answer the missing value where it arrives"
5423                )),
5424            };
5425            self.diagnostics.push(diagnostic);
5426        }
5427    }
5428
5429    /// Records `scope.spawn { ... }` when what the task answers is a
5430    /// `Result`.
5431    ///
5432    /// The receiver is read for the scope's name rather than the innermost
5433    /// frame, because a `spawn` may name an outer scope from inside an inner
5434    /// one. Which frame it is filed under does not change the answer — every
5435    /// scope in a body leaves through the same function — but which scope
5436    /// the diagnostic names does.
5437    fn spawned(&mut self, receiver: &Expr, ty: &Ty, span: Span) {
5438        let Ty::Task(settled) = ty else { return };
5439        let Ty::Result(_, error) = &**settled else {
5440            return;
5441        };
5442        let error = (**error).clone();
5443        let Some(open) = self.open_scopes.last_mut() else {
5444            return;
5445        };
5446        let scope = match &receiver.kind {
5447            ExprKind::Ident(name) => name.clone(),
5448            _ => open.name.clone(),
5449        };
5450        open.children.push(SpawnedChild {
5451            span,
5452            scope,
5453            binding: None,
5454            error,
5455            awaited: false,
5456        });
5457    }
5458
5459    /// Marks the child `handle` names as one the program itself settles.
5460    ///
5461    /// An awaited task is joined where the `await` is written, so scope exit
5462    /// finds it no longer running and passes over it — the failure is the
5463    /// awaiting expression's, and a `?` or a `match` on it is ordinary code.
5464    ///
5465    /// Every open frame is searched, not just the innermost, because a
5466    /// handle spawned into an outer scope may be awaited inside an inner
5467    /// one. A handle awaited where it was spawned is matched by span, which
5468    /// is what makes `await tasks.spawn { ... }` count.
5469    fn handle_awaited(&mut self, handle: &Expr) {
5470        let named = match &handle.kind {
5471            ExprKind::Ident(name) => Some(name.as_str()),
5472            _ => None,
5473        };
5474        let span = handle.span;
5475        for open in &mut self.open_scopes {
5476            for child in &mut open.children {
5477                let by_name = named.is_some() && child.binding.as_deref() == named;
5478                let by_span = child.span.file == span.file
5479                    && child.span.start >= span.start
5480                    && child.span.end <= span.end;
5481                if by_name || by_span {
5482                    child.awaited = true;
5483                }
5484            }
5485        }
5486    }
5487
5488    /// Reports every child of a `scope` being left that nothing awaits and
5489    /// whose failure the enclosing function cannot answer.
5490    ///
5491    /// A `cancel()` is not a settling: cancellation stops work that has not
5492    /// happened and does not undo work that has, so a task that finished
5493    /// with an `Err` before the request reached it is still waited for at
5494    /// scope exit and still returns. Only an `await` takes a child out of
5495    /// this.
5496    fn leaving_scope(&mut self, open: OpenScope) {
5497        for child in open.children {
5498            if child.awaited {
5499                continue;
5500            }
5501            let subject = match &child.binding {
5502                Some(name) => format!("`{name}`"),
5503                None => "this task".to_string(),
5504            };
5505            let SpawnedChild {
5506                span, scope, error, ..
5507            } = child;
5508            // Leaving the scope returns this child's failure from the
5509            // enclosing function, so the function's own failure type is what
5510            // this one has to be — the same rule `?` states, and a use that
5511            // says so. `s.spawn { ... Ok(n) }` that nothing awaits takes its
5512            // failure type from here, which is the only thing in the program
5513            // that states one.
5514            if let Ty::Result(_, ret_error) = self.ret.clone() {
5515                self.constrain(&error, &ret_error, span);
5516            }
5517            let diagnostic = match self.ret.clone() {
5518                // Nothing written says what this body answers, so there is
5519                // no failure type to disagree with.
5520                Ty::Unknown(_) | Ty::Any | Ty::Never => continue,
5521                Ty::Result(_, ret_error) if error.matches(&ret_error) => continue,
5522                Ty::Result(ret_ok, ret_error) => Diagnostic::error(
5523                    SCOPE_CHILD_FAILURE,
5524                    format!(
5525                        "nothing awaits {subject}, so leaving `{scope}` propagates its `{error}`, but this function returns `{ret_error}` as its failure"
5526                    ),
5527                )
5528                .at(span)
5529                .label(
5530                    self.ret_span,
5531                    format!("the declared failure type is `{ret_error}`"),
5532                )
5533                .rule(SCOPE_CHILD_RULE)
5534                .help(format!(
5535                    "map the failure inside the task, as in `{scope}.spawn {{ ... .mapError(fn(error) {{ ... }}) }}`, or declare this function `-> Result<{ret_ok}, {error}>`"
5536                )),
5537                other => Diagnostic::error(
5538                    SCOPE_CHILD_FAILURE,
5539                    format!(
5540                        "nothing awaits {subject}, so leaving `{scope}` propagates its `{error}`, but this function returns `{other}`"
5541                    ),
5542                )
5543                .at(span)
5544                .label(
5545                    self.ret_span,
5546                    format!("the declared return type is `{other}`"),
5547                )
5548                .rule(SCOPE_CHILD_RULE)
5549                .help(format!(
5550                    "declare this function `-> Result<{other}, {error}>`, or await {subject} and answer its `Err` here"
5551                )),
5552            };
5553            self.diagnostics.push(diagnostic);
5554        }
5555    }
5556
5557    fn await_expr(&mut self, inner: &Expr, span: Span) -> Ty {
5558        let ty = self.expr(inner, None);
5559        if matches!(ty, Ty::Task(_)) {
5560            self.handle_awaited(inner);
5561        }
5562        match &ty {
5563            Ty::Unknown(_) | Ty::Never => ty.abstain(),
5564            Ty::Any => Ty::Any,
5565            Ty::Task(inner_ty) => (**inner_ty).clone(),
5566            other => {
5567                self.diagnostics.push(
5568                    Diagnostic::error(
5569                        AWAIT_OPERAND,
5570                        format!("`await` needs a task, but found `{other}`"),
5571                    )
5572                    .at(span)
5573                    .rule("`await` settles a task. Only a task spawned into a scope, or one returned by an `async fn`, has a value to settle.")
5574                    .help("call an `async fn`, or spawn the work into a task scope, and await that handle"),
5575                );
5576                Ty::recovery()
5577            }
5578        }
5579    }
5580
5581    fn condition(&mut self, condition: &Expr) -> Ty {
5582        let ty = self.expr(condition, None);
5583        if !ty.matches(&Ty::Bool) {
5584            self.diagnostics.push(
5585                Diagnostic::error(
5586                    CONDITION,
5587                    format!("a condition must be a `Bool`, but found `{ty}`"),
5588                )
5589                .at(condition.span)
5590                .rule("There are no implicit boolean conversions.")
5591                .help(condition_help(&ty)),
5592            );
5593        }
5594        Ty::Bool
5595    }
5596
5597    /// An `if` with an `else` is an expression whose branches must agree.
5598    ///
5599    /// An `if` with no `else` is a statement: its type is `()` and the value
5600    /// of its branch is discarded, because there is no second branch to give
5601    /// the missing case a value.
5602    fn if_expr(
5603        &mut self,
5604        condition: &Expr,
5605        then_branch: &Block,
5606        else_branch: Option<&Expr>,
5607        span: Span,
5608        expected: Option<&Expected>,
5609    ) -> Ty {
5610        self.condition(condition);
5611        let Some(else_branch) = else_branch else {
5612            self.block(then_branch, None);
5613            if let Some(expected) = expected {
5614                self.expect(&Ty::Unit, expected, span);
5615            }
5616            return Ty::Unit;
5617        };
5618        // With no expectation the branches are only answerable to each other,
5619        // and either of them may be the one that says what the value is:
5620        // `if c { None } else { Some(1) }` is an `Option<Int>` and nothing in
5621        // it was left unproved. Which branch says so is not known until both
5622        // have been walked, so with nothing expected they are walked once
5623        // with nothing reported and then again against what that found.
5624        let settled = match expected {
5625            Some(_) => None,
5626            None if self.probing => None,
5627            None => self
5628                .probe(|checker| {
5629                    let then_ty = checker.block(then_branch, None);
5630                    let else_ty = checker.expr(else_branch, None);
5631                    then_ty
5632                        .matches(&else_ty)
5633                        .then(|| then_ty.join(&else_ty))
5634                        .filter(|ty| !ty.is_wild())
5635                })
5636                .map(|ty| {
5637                    let label = format!("both branches produce `{ty}`");
5638                    Expected::new(ty, span, label)
5639                }),
5640        };
5641        let hint = expected.or(settled.as_ref());
5642        let then_ty = self.block(then_branch, hint);
5643        let else_ty = self.expr(else_branch, hint);
5644        // With an expectation, both branches were already checked against it
5645        // and a disagreement was reported there; without one, the branches
5646        // are only answerable to each other.
5647        if expected.is_none() && !then_ty.matches(&else_ty) {
5648            self.branches_disagree(then_branch.span, else_branch.span, &then_ty, &else_ty);
5649        }
5650        then_ty.join(&else_ty)
5651    }
5652
5653    fn branches_disagree(&mut self, first: Span, second: Span, first_ty: &Ty, second_ty: &Ty) {
5654        self.diagnostics.push(
5655            Diagnostic::error(
5656                BRANCHES,
5657                format!("this branch produces `{second_ty}`, but the other produces `{first_ty}`"),
5658            )
5659            .at(second)
5660            .label(first, format!("this branch produces `{first_ty}`"))
5661            .rule(
5662                "Every branch of an `if` or `match` used as an expression produces the same type.",
5663            )
5664            .help(format!(
5665                "make both branches produce `{first_ty}`, or bind them separately"
5666            )),
5667        );
5668    }
5669
5670    fn match_expr(
5671        &mut self,
5672        scrutinee: &Expr,
5673        arms: &[MatchArm],
5674        span: Span,
5675        expected: Option<&Expected>,
5676    ) -> Ty {
5677        let scrutinee_ty = self.expr(scrutinee, None);
5678        let mut result: Option<(Ty, Span)> = None;
5679        for arm in arms {
5680            self.scopes.push(BTreeMap::new());
5681            self.pattern(&arm.pattern, &scrutinee_ty);
5682            let ty = self.expr(&arm.body, expected);
5683            self.scopes.pop();
5684            result = Some(match result {
5685                None => (ty, arm.body.span),
5686                Some((previous, previous_span)) => {
5687                    if expected.is_none() && !previous.matches(&ty) {
5688                        self.branches_disagree(previous_span, arm.body.span, &previous, &ty);
5689                    }
5690                    (previous.join(&ty), previous_span)
5691                }
5692            });
5693        }
5694        let _ = span;
5695        match result {
5696            Some((ty, _)) => ty,
5697            // A `match` with no arms produces nothing; resolution already
5698            // reports it as non-exhaustive.
5699            None => Ty::Never,
5700        }
5701    }
5702
5703    /// Checks a pattern against the scrutinee's type and binds its names.
5704    ///
5705    /// Case names and exhaustiveness belong to resolution, which reports them
5706    /// from the arms alone; this adds what only a type can say — that the
5707    /// pattern's enum is the scrutinee's enum, and that a payload has the
5708    /// arity and types the case declares.
5709    fn pattern(&mut self, pattern: &Pattern, scrutinee: &Ty) {
5710        match &pattern.kind {
5711            PatternKind::Wildcard => {}
5712            PatternKind::Binding(name) => {
5713                let ty = self.bound(scrutinee.clone());
5714                self.declare(name, ty, false);
5715            }
5716            PatternKind::Literal(expr) => {
5717                let ty = self.expr(expr, None);
5718                if !ty.matches(scrutinee) {
5719                    self.diagnostics.push(
5720                        Diagnostic::error(
5721                            PATTERN,
5722                            format!(
5723                                "this pattern matches `{ty}`, but the scrutinee is `{scrutinee}`"
5724                            ),
5725                        )
5726                        .at(pattern.span)
5727                        .rule("A pattern matches values of the scrutinee's type.")
5728                        .help(format!(
5729                            "write a `{scrutinee}` literal, or a binding such as `other`"
5730                        )),
5731                    );
5732                }
5733            }
5734            PatternKind::Variant { path, payload } => {
5735                self.variant_pattern(pattern.span, path, payload, scrutinee)
5736            }
5737        }
5738    }
5739
5740    fn variant_pattern(&mut self, span: Span, path: &[Ident], payload: &[Pattern], scrutinee: &Ty) {
5741        let case = path.last().expect("a variant path is never empty");
5742        let payload_types: Option<Vec<Ty>> = match scrutinee {
5743            Ty::Unknown(_) | Ty::Any | Ty::Never => None,
5744            // The language's own enums declare their cases in
5745            // `cove_schema::builtins`, and a case's payload is written in the
5746            // parameters the scrutinee binds: `Some` carries a `T`, so
5747            // `Some(n)` against an `Option<Int>` binds an `Int`. A case the
5748            // schema does not declare answers `None` here, because resolution
5749            // is what reports an arm that names one.
5750            Ty::Option(_) | Ty::Result(_, _) => builtin_case_payload(scrutinee, &case.node),
5751            Ty::Enum(name, args) => {
5752                if let [qualifier, _] = path {
5753                    if self.key(&qualifier.node) != **name {
5754                        self.diagnostics.push(
5755                            Diagnostic::error(
5756                                PATTERN,
5757                                format!(
5758                                    "this pattern matches `{}`, but the scrutinee is `{name}`",
5759                                    qualifier.node
5760                                ),
5761                            )
5762                            .at(span)
5763                            .rule("A pattern matches values of the scrutinee's type.")
5764                            .help(format!(
5765                                "write a `{name}` case, such as `{name}.{}`",
5766                                first_case_of(self.enums.get(name.as_ref()))
5767                            )),
5768                        );
5769                        None
5770                    } else {
5771                        self.case_payload(name, &case.node, args)
5772                    }
5773                } else {
5774                    self.case_payload(name, &case.node, args)
5775                }
5776            }
5777            // A host module's enum has cases and nothing inside them: the
5778            // schema writes `cases: &["Get", "Post"]` and gives them no
5779            // payload to bind.
5780            Ty::Host(declared) => match self.host_declared_type(declared) {
5781                Some(schema) if schema.cases.contains(&case.node.as_str()) => Some(Vec::new()),
5782                Some(schema) if schema.is_enum() => {
5783                    let known: Vec<String> =
5784                        schema.cases.iter().map(|c| (*c).to_string()).collect();
5785                    self.diagnostics.push(
5786                        Diagnostic::error(
5787                            UNKNOWN_CASE,
5788                            format!("`{declared}` has no case `{}`", case.node),
5789                        )
5790                        .at(span)
5791                        .rule(HOST_SCHEMA_RULE)
5792                        .help(format!("`{declared}` declares {}", list(&known))),
5793                    );
5794                    None
5795                }
5796                _ => {
5797                    self.diagnostics.push(
5798                        Diagnostic::error(
5799                            PATTERN,
5800                            format!(
5801                                "`{declared}` has no cases, so it cannot be matched by `{}`",
5802                                case.node
5803                            ),
5804                        )
5805                        .at(span)
5806                        .rule(HOST_SCHEMA_RULE)
5807                        .help(format!(
5808                            "match a `{declared}` with a binding, or read one of its fields"
5809                        )),
5810                    );
5811                    None
5812                }
5813            },
5814            other => {
5815                self.diagnostics.push(
5816                    Diagnostic::error(
5817                        PATTERN,
5818                        format!(
5819                            "`{other}` has no cases, so it cannot be matched by `{}`",
5820                            case.node
5821                        ),
5822                    )
5823                    .at(span)
5824                    .rule("A variant pattern matches an enum case.")
5825                    .help(format!(
5826                        "match a literal `{other}`, or bind the value with a name"
5827                    )),
5828                );
5829                None
5830            }
5831        };
5832
5833        let Some(types) = payload_types else {
5834            for sub in payload {
5835                self.pattern(sub, &Ty::recovery());
5836            }
5837            return;
5838        };
5839        if types.len() != payload.len() {
5840            self.diagnostics.push(
5841                Diagnostic::error(
5842                    PAYLOAD_ARITY,
5843                    format!(
5844                        "`{}` carries {} value(s), but this pattern binds {}",
5845                        case.node,
5846                        types.len(),
5847                        payload.len()
5848                    ),
5849                )
5850                .at(span)
5851                .rule("A pattern binds exactly the payload its case declares.")
5852                .help(if types.is_empty() {
5853                    format!("write `{}`", case.node)
5854                } else {
5855                    format!(
5856                        "write `{}({})`",
5857                        case.node,
5858                        types.iter().map(|_| "value").collect::<Vec<_>>().join(", ")
5859                    )
5860                }),
5861            );
5862        }
5863        for (sub, ty) in payload.iter().zip(types.iter()) {
5864            self.pattern(sub, ty);
5865        }
5866        for sub in payload.iter().skip(types.len()) {
5867            self.pattern(sub, &Ty::recovery());
5868        }
5869    }
5870
5871    /// The payload types of `case` on the enum `name`, substituted with the
5872    /// scrutinee's type arguments, or `None` when the enum has no such case —
5873    /// resolution reports that.
5874    fn case_payload(&mut self, name: &str, case: &str, args: &[Ty]) -> Option<Vec<Ty>> {
5875        let sig = self.enums.get(name)?;
5876        let subst = substitution(&sig.generics, args);
5877        let found = sig.cases.iter().find(|c| c.name == case)?;
5878        Some(
5879            found
5880                .payload
5881                .iter()
5882                .map(|ty| ty.substitute(&subst))
5883                .collect(),
5884        )
5885    }
5886
5887    fn for_expr(&mut self, binding: &Ident, iterable: &Expr, body: &Block) -> Ty {
5888        let ty = self.expr(iterable, None);
5889        let element = match &ty {
5890            Ty::Unknown(_) | Ty::Never => ty.abstain(),
5891            Ty::Any => Ty::Any,
5892            Ty::Array(inner) | Ty::Vector(inner) | Ty::Set(inner) => (**inner).clone(),
5893            Ty::Range => Ty::Int,
5894            // A `Map` iterates in ascending key order, binding each pair as
5895            // the same `MapEntry` shape `Map.of` accepts.
5896            Ty::Map(key, value) => Ty::MapEntry(key.clone(), value.clone()),
5897            other => {
5898                self.diagnostics.push(
5899                    Diagnostic::error(
5900                        ITERABLE,
5901                        format!(
5902                            "`for` iterates an `Array`, a `Vector`, a `Range`, a `Set`, or a `Map`, but found `{other}`"
5903                        ),
5904                    )
5905                    .at(iterable.span)
5906                    .rule("`for` iterates a sequence; iteration order is defined by each collection type.")
5907                    .help(iterable_help(other)),
5908                );
5909                Ty::recovery()
5910            }
5911        };
5912        self.scopes.push(BTreeMap::new());
5913        let element = self.bound(element);
5914        self.declare(&binding.node, element, false);
5915        self.block(body, None);
5916        self.scopes.pop();
5917        Ty::Unit
5918    }
5919
5920    /// A lambda takes its parameter types from the expected type at the call
5921    /// site, as ADR 0004 decides; a parameter it writes for itself is used as
5922    /// written.
5923    ///
5924    /// One shape it may not write is a variadic parameter
5925    /// ([`VARIADIC_LAMBDA`]), at any position. See the comment at the
5926    /// refusal for why, and for what it leaves undecided.
5927    fn lambda(
5928        &mut self,
5929        is_async: bool,
5930        params: &[Param],
5931        body: &Block,
5932        span: Span,
5933        expected: Option<&Expected>,
5934    ) -> Ty {
5935        let hint = match expected.map(|e| &e.ty) {
5936            // Resolved, because a parameter this lambda takes from the
5937            // expectation is a binding and not a comparison: see
5938            // `Checker::bound`.
5939            Some(Ty::Fn(func)) => match self.bound(Ty::Fn(func.clone())) {
5940                Ty::Fn(func) => Some(func),
5941                _ => Some(func.clone()),
5942            },
5943            _ => None,
5944        };
5945        // Whether anything at all says what this function value is. A
5946        // written function type says it exactly. An expected type the
5947        // checker has already abstained about — a host with no schema, a
5948        // schema's `Any` — says that nothing here is being stated, which is
5949        // an answer of its own and one reported where the abstention was
5950        // made. No expected type at all is the language gap, and it is the
5951        // only case this pass has to name.
5952        let stated = expected.is_some();
5953        // What the place holding this value says it *produces*, which is a
5954        // narrower question than what it says about the value.
5955        let stated_ret: Option<Ty> = match (hint.as_ref(), expected) {
5956            // A written or schema-declared result type, or one this pass
5957            // abstained about, which is an answer as well.
5958            (Some(func), _) if !func.ret.holds_placeholder() => Some(func.ret.clone()),
5959            // An expected function type whose own result this pass left
5960            // open: `Result.mapError`'s callback produces whatever its body
5961            // produces, and the expectation states its parameters only. So
5962            // nothing anywhere says what an early `return` in it has to
5963            // agree with, which is the gap `LAMBDA_RETURN` names.
5964            (Some(_), _) => None,
5965            // Not a function type at all. An expectation this pass abstained
5966            // about answers for the whole value, its result included; any
5967            // other one is a mismatch reported where the value is given, and
5968            // saying a second time that the result is unstated would be the
5969            // same mistake twice.
5970            (None, Some(_)) => Some(Checker::abstention_of(expected)),
5971            (None, None) => None,
5972        };
5973        if let Some(func) = &hint {
5974            if func.params.len() != params.len() {
5975                // A trailing closure parses as a lambda of no parameters,
5976                // unconditionally (`parse_trailing_closure`) — and the AST
5977                // does not otherwise record that this lambda came from that
5978                // form rather than a written `fn() { ... }`. So a lambda of
5979                // no parameters gets the help that assumes the harder case:
5980                // it cannot be fixed by adding a parameter to it, because a
5981                // trailing closure has nowhere to write one, and the fix is
5982                // to stop writing it as a trailing closure.
5983                let help = if params.is_empty() {
5984                    "a trailing closure can never declare a parameter — write it as an ordinary argument instead, as in `result.mapError(fn(error) { ... })`".to_string()
5985                } else {
5986                    format!(
5987                        "write `fn({}) {{ ... }}`",
5988                        (0..func.params.len())
5989                            .map(|i| format!("p{i}"))
5990                            .collect::<Vec<_>>()
5991                            .join(", ")
5992                    )
5993                };
5994                self.diagnostics.push(
5995                    Diagnostic::error(
5996                        ARITY,
5997                        format!(
5998                            "this function takes {} parameter(s), but {} were expected here",
5999                            params.len(),
6000                            func.params.len()
6001                        ),
6002                    )
6003                    .at(span)
6004                    .rule("A function value has exactly the parameters the place that holds it declares.")
6005                    .help(help),
6006                );
6007            }
6008        }
6009
6010        let mut param_types = Vec::with_capacity(params.len());
6011        // Everything outside this scope is a capture from here on, and
6012        // `Env::declare_capture` binds a capture read-only. See
6013        // `Checker::capture_floor`.
6014        let outer_floor = std::mem::replace(&mut self.capture_floor, self.scopes.len());
6015        self.scopes.push(BTreeMap::new());
6016        for (index, param) in params.iter().enumerate() {
6017            let ty = match &param.ty {
6018                Some(written) => self.resolve(written),
6019                // A lambda's parameters are the one kind the language
6020                // infers, and the only thing they are inferred from is the
6021                // expected type at the place the value is given to. With no
6022                // such place there is nothing to infer from, and the body is
6023                // then checked against nothing wherever it uses the
6024                // parameter.
6025                None => match hint.as_ref().and_then(|f| f.params.get(index)) {
6026                    Some(ty) => ty.clone(),
6027                    None if stated => Checker::abstention_of(expected),
6028                    None => {
6029                        self.diagnostics.push(unconstrained(
6030                            format!("nothing says what `{}` is", param.name.node),
6031                            format!(
6032                                "write the type, as in `{}: <type>`, or give this function value to a place that declares one",
6033                                param.name.node
6034                            ),
6035                            param.span,
6036                        ));
6037                        Ty::recovery()
6038                    }
6039                },
6040            };
6041            // A function value's parameters are its function type's, and
6042            // ADR 0016 says a function type in Cove names a fixed list of
6043            // them — the same rule `cove::type::variadic_as_value` states
6044            // from the other side, where a variadic host operation is used
6045            // as a value and no `fn` type can be written for it. A `...`
6046            // here asks for a parameter list that is a run-time fact: how
6047            // many arguments it gathers is decided at the call, and a call
6048            // through a value has no declaration in reach to gather
6049            // against.
6050            //
6051            // Which is to say this leans toward "a closure's parameter list
6052            // is fixed", because that is what the rest of the language
6053            // already says and it is the smaller of the two languages. What
6054            // a variadic parameter on a function value should *mean* is not
6055            // settled here, and the other reading — teach a function type to
6056            // carry variadicity, so that a call through a value gathers — is
6057            // still open; it needs ADR 0016's decision revisited, and
6058            // nothing below stands in its way. Issue #168 is where both are
6059            // written down.
6060            //
6061            // The parameter binds a recovery unknown rather than what was
6062            // written, so that this is one diagnostic and not a cascade
6063            // through every use of the name in the body — the same reason
6064            // `MISSING_PARAMETER_TYPE` does it.
6065            let ty = if param.variadic {
6066                self.diagnostics.push(
6067                    Diagnostic::error(
6068                        VARIADIC_LAMBDA,
6069                        format!(
6070                            "parameter `{}` is variadic, so it cannot be written on a function value",
6071                            param.name.node
6072                        ),
6073                    )
6074                    .at(param.span)
6075                    .rule("A variadic parameter is written on a declaration: a function value has exactly the parameters its function type names, and a function type names a fixed list of them.")
6076                    .help(format!(
6077                        "remove the `...` and give `{}` an `Array` type, passing one at the call; or declare an `fn`, which a call reaches by name and can gather arguments for",
6078                        param.name.node
6079                    )),
6080                );
6081                Ty::recovery()
6082            } else {
6083                ty
6084            };
6085            param_types.push(ty.clone());
6086            self.declare(&param.name.node, ty, param.is_var);
6087        }
6088
6089        // The expected type decides the result only when it has one to give;
6090        // otherwise the body does.
6091        let declared_ret = stated_ret.clone().filter(|ty| !ty.is_wild());
6092        let outer_ret = std::mem::replace(
6093            &mut self.ret,
6094            stated_ret.clone().unwrap_or_else(Ty::placeholder),
6095        );
6096        let outer_span = std::mem::replace(&mut self.ret_span, span);
6097        let outer_stated = std::mem::replace(&mut self.ret_stated, stated_ret.is_some());
6098        self.open_lambdas.push(Vec::new());
6099        let expected_body = stated_ret.clone().map(|ty| match ty.is_wild() {
6100            // An abstention passed on rather than dropped: a body given to a
6101            // place this pass said nothing about is not asked to state a type
6102            // nothing outside it stated either.
6103            true => Expected::abstained(ty),
6104            false => {
6105                let label = format!("this function value produces `{ty}`");
6106                Expected::new(ty, span, label)
6107            }
6108        });
6109        let body_ty = self.block(body, expected_body.as_ref());
6110        // Popped here, next to the `ret` this pass is putting back, but not
6111        // answered until the produced type below exists — which is the whole
6112        // reason these were kept rather than judged where they were written.
6113        let pending = self.open_lambdas.pop().unwrap_or_default();
6114        self.ret = outer_ret;
6115        self.ret_span = outer_span;
6116        self.ret_stated = outer_stated;
6117        self.scopes.pop();
6118        self.capture_floor = outer_floor;
6119
6120        // What the place holding this value said about its result stands,
6121        // and what it left open the body answers: a callback passed to
6122        // `retry<T>` is given the place's `Result<_, Error>` and produces a
6123        // `Result<Booking, Error>`, and the value's type is both. Where the
6124        // two disagree about a type the place *did* state, `Ty::join` keeps
6125        // the place's and the disagreement is already reported against the
6126        // body.
6127        let produced = match declared_ret {
6128            Some(declared) => declared.join(&body_ty),
6129            None => body_ty,
6130        };
6131        self.settle_pending_tries(pending, &produced, span);
6132        let value = Ty::func(is_async, param_types, produced);
6133        // A function value given to a place that is not a function type is a
6134        // mismatch like any other, and this is where it is reported.
6135        // `Checker::expr` hands the expectation to this method rather than
6136        // checking the result against it afterwards, because a lambda *reads*
6137        // the expectation to type its parameters; so the check that skips is
6138        // made here, for exactly the expectations a lambda could not read. An
6139        // expected function type is left alone — a disagreeing one has
6140        // already been reported against the parameters and the body, which
6141        // says where it disagrees — and so is an unknown, which agrees with
6142        // everything by construction.
6143        if let Some(expected) = expected {
6144            if !matches!(expected.ty, Ty::Fn(_)) && !expected.ty.is_wild() {
6145                self.expect(&value, expected, span);
6146            }
6147        }
6148        value
6149    }
6150
6151    // -------------------------------------------------------------- calls
6152
6153    /// A call, resolved the way the interpreter resolves one: a local
6154    /// binding, then a declaration of this module, then a host item, then a
6155    /// builtin.
6156    ///
6157    /// `id` names the call expression itself rather than any of its parts,
6158    /// because that is what a resolved target is recorded against: a
6159    /// consumer holding the call is asking which declaration it reaches.
6160    #[allow(clippy::too_many_arguments)]
6161    fn call(
6162        &mut self,
6163        id: ExprId,
6164        callee: &Expr,
6165        generics: &[Type],
6166        args: &[Arg],
6167        trailing: Option<&Expr>,
6168        span: Span,
6169        expected: Option<&Expected>,
6170    ) -> Ty {
6171        // Before the callee is resolved, exactly as `Interpreter::eval_args`
6172        // aliases a `var` argument before it knows what it is calling.
6173        self.var_arguments(args);
6174        match &callee.kind {
6175            ExprKind::Ident(name) if self.lookup(name).is_none() => {
6176                self.call_named(name, generics, args, trailing, span, callee.span, expected)
6177            }
6178            ExprKind::Field { base, name } => {
6179                if let ExprKind::Ident(head) = &base.kind {
6180                    if self.lookup(head).is_none() {
6181                        if let Some(ty) =
6182                            self.call_qualified(id, head, name, args, trailing, span, expected)
6183                        {
6184                            return ty;
6185                        }
6186                    }
6187                }
6188                let receiver = self.expr(base, None);
6189                self.mutating_receiver(&receiver, name, base, span);
6190                // `handle.await()` and `await handle` mean the same thing,
6191                // and they unwrap a `Task` through two different paths, so
6192                // both have to say so. `Scope.spawn` is read on the way out
6193                // instead, because what it answers is what decides whether
6194                // there is anything to record.
6195                if matches!(receiver, Ty::Task(_)) && name.node == "await" {
6196                    self.handle_awaited(base);
6197                }
6198                let ty = self.method_call(id, &receiver, name, args, trailing, span);
6199                if matches!(receiver, Ty::Scope) && name.node == "spawn" {
6200                    self.spawned(base, &ty, span);
6201                }
6202                ty
6203            }
6204            _ => {
6205                let callee_ty = self.expr(callee, None);
6206                self.call_value(&callee_ty, args, trailing, span, callee.span)
6207            }
6208        }
6209    }
6210
6211    /// `name(...)` where `name` is not a local binding.
6212    #[allow(clippy::too_many_arguments)]
6213    fn call_named(
6214        &mut self,
6215        name: &str,
6216        generics: &[Type],
6217        args: &[Arg],
6218        trailing: Option<&Expr>,
6219        span: Span,
6220        callee_span: Span,
6221        expected: Option<&Expected>,
6222    ) -> Ty {
6223        let key = self.key(name);
6224        if let Some(sig) = self.functions.get(&key).cloned() {
6225            let explicit = generics.iter().map(|ty| self.resolve(ty)).collect();
6226            return self.call_signature(&sig, &format!("`{name}`"), explicit, args, trailing, span);
6227        }
6228        if let Some(sig) = self.structs.get(&key).cloned() {
6229            return self.struct_init(&key, &sig, args, trailing, span, expected);
6230        }
6231        if self.enums.contains_key(&key) {
6232            let cases = first_case_of(self.enums.get(&key));
6233            self.diagnostics.push(
6234                Diagnostic::error(NOT_CALLABLE, format!("`{name}` is an enum, not a function"))
6235                    .at(callee_span)
6236                    .rule("An enum value is one of its cases; the enum itself is not callable.")
6237                    .help(format!("name a case, such as `{name}.{cases}`")),
6238            );
6239            self.check_args_freely(args, trailing);
6240            return Ty::recovery();
6241        }
6242        // `use console.println` makes `println(...)` the same call as
6243        // `console.println(...)`, so it is checked against the same schema
6244        // entry.
6245        if let Some(module) = self.module.host_items.get(name).cloned() {
6246            return self.host_call(&module, name, args, trailing, span);
6247        }
6248        if name == MAP_ENTRY.name {
6249            return self.map_entry(args, trailing, span);
6250        }
6251        if let Some(ty) = self.assertion(name, args, trailing, span) {
6252            return ty;
6253        }
6254        if let Some(ty) = self.constructor(name, args, trailing, span, expected) {
6255            return ty;
6256        }
6257        if name == NONE_CASE.name {
6258            self.diagnostics.push(
6259                Diagnostic::error(NOT_CALLABLE, "`None` is a value, not a call")
6260                    .at(callee_span)
6261                    .rule("`None` is the empty case of `Option`, which carries nothing.")
6262                    .help("write `None`"),
6263            );
6264            self.check_args_freely(args, trailing);
6265            return Ty::Option(Box::new(Ty::recovery()));
6266        }
6267        self.check_args_freely(args, trailing);
6268        self.unresolved_name(name, callee_span)
6269    }
6270
6271    /// `assert(condition)` and `assertEqual(actual, expected)`.
6272    ///
6273    /// These are builtins rather than a library because a failure message
6274    /// names the source text of the condition, which only the compiler has.
6275    /// Both report failure as an ordinary `Err`, so `?` works on them inside
6276    /// a test and a failing assertion is an expected failure rather than a
6277    /// panic.
6278    ///
6279    /// The signature comes from `cove_schema::builtins::FREE_BUILTINS`, which
6280    /// the runtime dispatches out of as well, so an assertion cannot take one
6281    /// number of arguments here and another there.
6282    fn assertion(
6283        &mut self,
6284        name: &str,
6285        args: &[Arg],
6286        trailing: Option<&Expr>,
6287        span: Span,
6288    ) -> Option<Ty> {
6289        let schema = free_builtin(name, FreeBuiltinKind::Assertion)?;
6290        let supplied: Vec<&Expr> = args.iter().map(|arg| &arg.value).chain(trailing).collect();
6291        // An assertion answers `Unit`, so a parameter of its own that
6292        // nothing settles reaches no expression's type and no binding: there
6293        // is nothing for a later use to fill and nothing downstream to be
6294        // handed. A constructor is the opposite, which is why that one opens
6295        // variables and this one does not.
6296        let open = vec![Ty::unconstrained(); schema.generics.len()];
6297        let mut bindings = FreeBindings::new(schema, open);
6298        if supplied.len() == schema.arity() {
6299            self.free_arguments(schema, &supplied, &mut bindings, span);
6300        } else {
6301            // An assertion given the wrong number of arguments is told that
6302            // and nothing else: which argument was meant to be which is no
6303            // longer a question with an answer.
6304            self.diagnostics.push(
6305                free_arity(schema, supplied.len(), span)
6306                    .rule(
6307                        "`assert` checks one condition; `assertEqual` compares one pair of values.",
6308                    )
6309                    .help(format!(
6310                        "write `{name}({})`",
6311                        schema
6312                            .params
6313                            .iter()
6314                            .map(|param| param.name)
6315                            .collect::<Vec<_>>()
6316                            .join(", ")
6317                    )),
6318            );
6319            self.check_args_freely(args, trailing);
6320        }
6321        Some(bindings.open(&schema.result))
6322    }
6323
6324    /// `Ok(v)`, `Err(e)`, `Some(v)`, `Error("message")`, and `Shared(value)`.
6325    ///
6326    /// Which names these are, what each carries, and what each produces are
6327    /// the shared table's; what a call site adds is the type it expects,
6328    /// which is the only thing that can say what the `E` of an `Ok` is.
6329    fn constructor(
6330        &mut self,
6331        name: &str,
6332        args: &[Arg],
6333        trailing: Option<&Expr>,
6334        span: Span,
6335        expected: Option<&Expected>,
6336    ) -> Option<Ty> {
6337        let schema = free_builtin(name, FreeBuiltinKind::Constructor)?;
6338        let open: Vec<Ty> = schema
6339            .generics
6340            .iter()
6341            .map(|_| self.fresh_var(span))
6342            .collect();
6343        let mut bindings = FreeBindings::new(schema, open);
6344        let opened = bindings.open(&schema.result);
6345        self.produced(&opened);
6346        if let Some(hint) = expected.map(|e| &e.ty) {
6347            // The expectation settles the variables and the table both. The
6348            // table is what the arguments are checked against; the variables
6349            // are what a later use of the binding reads, and the two saying
6350            // different things is how a hole gets reported after something
6351            // had already filled it.
6352            self.constrain(&opened, hint, span);
6353            bindings.read_off(&schema.result, hint, span);
6354        }
6355        let mut supplied: Vec<&Expr> = args.iter().map(|arg| &arg.value).collect();
6356        if let Some(trailing) = trailing {
6357            supplied.push(trailing);
6358        }
6359        if supplied.len() != schema.arity() {
6360            self.diagnostics.push(
6361                free_arity(schema, supplied.len(), span)
6362                    .rule("A constructor carries exactly one value.")
6363                    .help(format!("write `{name}(value)`")),
6364            );
6365        }
6366        // Unlike an assertion, a constructor still checks the payload it was
6367        // given: there is only one parameter, so a wrong count says nothing
6368        // about which value was meant for it.
6369        self.free_arguments(schema, &supplied, &mut bindings, span);
6370        Some(bindings.open(&schema.result))
6371    }
6372
6373    /// Checks a free builtin's arguments against the parameters it declares.
6374    ///
6375    /// A parameter whose type is already settled — by the type the call site
6376    /// expects, or by an argument that came before it — is what its argument
6377    /// is checked against. One that is not is settled *by* its argument,
6378    /// which is how `Ok(1)` decides it makes a `Result<Int, _>` and how
6379    /// `assertEqual`'s first argument decides what its second one must be.
6380    fn free_arguments(
6381        &mut self,
6382        schema: &'static FreeBuiltinSchema,
6383        supplied: &[&Expr],
6384        bindings: &mut FreeBindings,
6385        span: Span,
6386    ) {
6387        for (index, value) in supplied.iter().enumerate() {
6388            let Some(param) = schema.params.get(index) else {
6389                // An argument the signature has no parameter for is still
6390                // checked, so a mistake inside it is reported next to the
6391                // arity rather than after it is fixed.
6392                self.expr(value, None);
6393                continue;
6394            };
6395            let declared = bindings.open(&param.ty);
6396            if declared.is_wild() {
6397                let found = self.expr(value, None);
6398                // See `free_builtin_call`: what the argument says settles
6399                // the variable as well as the table.
6400                self.constrain(&found, &declared, value.span);
6401                // What a `Shared` wraps must be task-safe, so the payload is
6402                // checked here as well as where a `Shared<T>` is written as a
6403                // type.
6404                let found = if matches!(schema.result, BuiltinType::Shared(_)) {
6405                    self.task_safe_argument(found, span)
6406                } else {
6407                    found
6408                };
6409                bindings.bind(&param.ty, found, value.span);
6410            } else {
6411                let reason = free_builtin_reason(schema, param, &declared);
6412                let expected = Expected::new(declared, bindings.origin(&param.ty, span), reason);
6413                self.expr(value, Some(&expected));
6414            }
6415        }
6416    }
6417
6418    /// `head.name(...)` where `head` is not a local binding: a host
6419    /// operation, an enum case, an associated function, or a method reached
6420    /// through its type's name.
6421    #[allow(clippy::too_many_arguments)]
6422    fn call_qualified(
6423        &mut self,
6424        id: ExprId,
6425        head: &str,
6426        name: &Ident,
6427        args: &[Arg],
6428        trailing: Option<&Expr>,
6429        span: Span,
6430        expected: Option<&Expected>,
6431    ) -> Option<Ty> {
6432        if self.module.host_uses.contains(head) {
6433            return Some(self.host_call(head, &name.node, args, trailing, span));
6434        }
6435        // A module imported whole answers a qualified call with whatever it
6436        // exports under that name: a function to call, or a struct to
6437        // initialize.
6438        if self.module.module_imports.contains_key(head) {
6439            let Some(key) = self.qualified_key(head, &name.node, span) else {
6440                self.check_args_freely(args, trailing);
6441                return Some(Ty::recovery());
6442            };
6443            if let Some(sig) = self.functions.get(&key).cloned() {
6444                return Some(self.call_signature(
6445                    &sig,
6446                    &format!("`{head}.{}`", name.node),
6447                    Vec::new(),
6448                    args,
6449                    trailing,
6450                    span,
6451                ));
6452            }
6453            if let Some(sig) = self.structs.get(&key).cloned() {
6454                return Some(self.struct_init(&key, &sig, args, trailing, span, expected));
6455            }
6456            // The module exports the name, but as something no call reaches:
6457            // an enum, a trait, or an alias.
6458            self.diagnostics.push(
6459                Diagnostic::error(
6460                    NOT_CALLABLE,
6461                    format!("`{head}.{}` is not a function", name.node),
6462                )
6463                .at(span)
6464                .rule("A qualified call reaches a function the named module exports, or a struct it declares.")
6465                .help(format!(
6466                    "`{head}` exports `{}` as something else; name a case or a method of it instead",
6467                    name.node
6468                )),
6469            );
6470            self.check_args_freely(args, trailing);
6471            return Some(Ty::recovery());
6472        }
6473        let key = self.key(head);
6474        if let Some(sig) = self.enums.get(&key).cloned() {
6475            let is_case = sig.cases.iter().any(|c| c.name == name.node);
6476            if !is_case {
6477                if let Some(sig) = self.methods.get(&(key.clone(), name.node.clone())).cloned() {
6478                    self.record_target(id, span.file, &key, &name.node);
6479                    self.check_receiver(&sig, &key, &name.node, span, false);
6480                    return Some(self.call_signature(
6481                        &sig,
6482                        &format!("`{head}.{}`", name.node),
6483                        Vec::new(),
6484                        args,
6485                        trailing,
6486                        span,
6487                    ));
6488                }
6489            }
6490            return Some(self.enum_case(&key, name, args, span));
6491        }
6492        if self.structs.contains_key(&key) {
6493            if let Some(sig) = self.methods.get(&(key.clone(), name.node.clone())).cloned() {
6494                self.record_target(id, span.file, &key, &name.node);
6495                self.check_receiver(&sig, &key, &name.node, span, false);
6496                return Some(self.call_signature(
6497                    &sig,
6498                    &format!("`{head}.{}`", name.node),
6499                    Vec::new(),
6500                    args,
6501                    trailing,
6502                    span,
6503                ));
6504            }
6505            let known = self.known_members(&key);
6506            self.diagnostics.push(
6507                Diagnostic::error(
6508                    UNKNOWN_ASSOCIATED,
6509                    format!("`{head}` has no associated function `{}`", name.node),
6510                )
6511                .at(span)
6512                .rule("An associated function is declared in the type's `impl` block.")
6513                .help(format!("`{head}` declares {known}")),
6514            );
6515            self.check_args_freely(args, trailing);
6516            return Some(Ty::recovery());
6517        }
6518        if cove_schema::is_builtin_type(head) {
6519            return Some(self.builtin_associated(head, name, args, trailing, span, expected));
6520        }
6521        None
6522    }
6523
6524    // --------------------------------------------------------- host calls
6525    //
6526    // ADR 0001 asks for one description of each Host API operation's
6527    // argument, result, and error types, "shared by the compiler, runtime,
6528    // and CLI". `cove-schema` is that description and this is the compiler's
6529    // half of reading it: a call reaching a host module is checked against
6530    // the same entry `HostRegistry::dispatch` will check it against, except
6531    // that here the mistake still has a span to point at.
6532    //
6533    // What the checker cannot do is see a host it does not ship. An
6534    // embedding registers its modules at run time, so a module named in no
6535    // shipped schema is left exactly where it was — unchecked, and said to be
6536    // — and the boundary is what holds such a host to its word.
6537
6538    /// `http.fetch(...)`, `http.Route(...)`, or `println(...)` reached
6539    /// through `use console.println`.
6540    fn host_call(
6541        &mut self,
6542        module: &str,
6543        name: &str,
6544        args: &[Arg],
6545        trailing: Option<&Expr>,
6546        span: Span,
6547    ) -> Ty {
6548        let Some(schema) = self.host_schema(module) else {
6549            // A module no schema describes — neither a shipped one nor one
6550            // the embedder handed over. Its operations are between the host
6551            // that registered it and the boundary, which is the one thing
6552            // `cove check` cannot do for a program.
6553            //
6554            // Nothing is reported *here*. The fact is about the `use` that
6555            // named the module and about the compilation that was not shown
6556            // it, not about this call: no edit to `module.name` can fix it,
6557            // and the remedy — handing the module's `ModuleSchema` to the
6558            // compiler — is one thing to say however many calls a program
6559            // makes. `cove::resolve::unchecked_host` puts that warning at
6560            // the `use`, where the remedy is.
6561            //
6562            // What the arguments are given is the abstention itself, so a
6563            // callback into such a host — the shape an embedding is written
6564            // in — is not asked to state a type nothing on this side stated.
6565            self.check_args_abstained(args, trailing, Ty::dynamic_boundary());
6566            return Ty::dynamic_boundary();
6567        };
6568        if let Some(operation) = schema.operation(name) {
6569            return self.call_host_operation(
6570                operation,
6571                &format!("{module}.{name}"),
6572                args,
6573                trailing,
6574                span,
6575            );
6576        }
6577        if let Some(declared) = schema.declared_type(name) {
6578            if !declared.is_enum() {
6579                return self.host_type_init(module, declared, args, trailing, span);
6580            }
6581            self.diagnostics.push(
6582                Diagnostic::error(
6583                    NOT_CALLABLE,
6584                    format!("`{module}.{name}` is a host enum, not a function"),
6585                )
6586                .at(span)
6587                .rule(HOST_SCHEMA_RULE)
6588                .help(format!(
6589                    "name a case, such as `{module}.{name}.{}`",
6590                    declared.cases.first().copied().unwrap_or("Case")
6591                )),
6592            );
6593            self.check_args_freely(args, trailing);
6594            return Ty::Host(format!("{module}.{name}").into());
6595        }
6596        if schema.resource(name).is_some() {
6597            self.diagnostics.push(
6598                Diagnostic::error(
6599                    NOT_CALLABLE,
6600                    format!("`{module}.{name}` is a host resource, not a function"),
6601                )
6602                .at(span)
6603                .rule("A host resource is opened by an operation of its module, which hands back a handle to it.")
6604                .help(format!(
6605                    "call the operation that opens one, such as {}",
6606                    list(&operation_names(schema.operations))
6607                )),
6608            );
6609            self.check_args_freely(args, trailing);
6610            return Ty::recovery();
6611        }
6612        self.diagnostics.push(
6613            Diagnostic::error(
6614                UNKNOWN_HOST_OPERATION,
6615                format!("host module `{module}` has no operation `{name}`"),
6616            )
6617            .at(span)
6618            .rule(HOST_SCHEMA_RULE)
6619            .help(format!(
6620                "`{module}` exposes {}",
6621                list(&operation_names(schema.operations))
6622            )),
6623        );
6624        self.check_args_freely(args, trailing);
6625        Ty::recovery()
6626    }
6627
6628    /// Checks a call against one operation's declared signature.
6629    ///
6630    /// A host operation's parameters have types and no names, so they are
6631    /// named by position: the diagnostic for the second one reads "argument
6632    /// `#2`", and the runtime's own message for the same mistake counts the
6633    /// same way.
6634    fn call_host_operation(
6635        &mut self,
6636        operation: &'static OperationSchema,
6637        shown: &str,
6638        args: &[Arg],
6639        trailing: Option<&Expr>,
6640        span: Span,
6641    ) -> Ty {
6642        let supplied = args.len() + usize::from(trailing.is_some());
6643        // A spread argument stands for a sequence whose length is not known
6644        // here, so it is the one call whose arity cannot be counted; the
6645        // boundary counts it when the values exist.
6646        let spread = args.iter().any(|arg| arg.spread);
6647        if !spread && !operation.accepts(supplied) {
6648            self.diagnostics.push(
6649                Diagnostic::error(
6650                    ARITY,
6651                    format!(
6652                        "`{shown}` takes {}, but {supplied} were given",
6653                        operation.expected_arity()
6654                    ),
6655                )
6656                .at(span)
6657                .rule(HOST_SCHEMA_RULE)
6658                .help(declared_signature(shown, operation)),
6659            );
6660            self.check_args_freely(args, trailing);
6661            // The call was just rejected, so it produces nothing to say
6662            // anything about: noting that its result is unconstrained would
6663            // be a second diagnostic about a call that will never run.
6664            return host_ty(&operation.result);
6665        }
6666        let last = operation.params.len().saturating_sub(1);
6667        let params: Vec<ParamSig> = operation
6668            .params
6669            .iter()
6670            .enumerate()
6671            .map(|(index, declared)| {
6672                // A variadic parameter answers for every argument from its
6673                // own position onwards, so it is named the way the signature
6674                // writes it: `#1...`, not `#1`.
6675                let variadic = operation.variadic && index == last;
6676                ParamSig {
6677                    name: format!("#{}{}", index + 1, if variadic { "..." } else { "" }),
6678                    ty: host_ty(declared),
6679                    variadic,
6680                    has_default: false,
6681                    is_var: false,
6682                    span,
6683                }
6684            })
6685            .collect();
6686        self.match_arguments(
6687            &params,
6688            &[],
6689            BTreeMap::new(),
6690            args,
6691            trailing,
6692            span,
6693            &format!("`{shown}`"),
6694            "argument",
6695        );
6696        self.host_result(operation, shown, span)
6697    }
6698
6699    /// The type a host operation's result is here, saying so where the
6700    /// schema declared it `Any`.
6701    ///
6702    /// `Any` in a parameter costs nothing: the operation accepts every
6703    /// value, so there was no check to skip. `Any` in a result is the other
6704    /// half of the same promise, and it does cost something — from the call
6705    /// onwards the program holds a value whose type no schema stated — so
6706    /// the call says which of the two it is rather than leaving a silent
6707    /// unknown to spread.
6708    fn host_result(&mut self, operation: &'static OperationSchema, shown: &str, span: Span) -> Ty {
6709        if contains_any(&operation.result) {
6710            self.diagnostics.push(
6711                Diagnostic::note(
6712                    UNCONSTRAINED_RESULT,
6713                    format!(
6714                        "`{shown}` declares its result `{}`, so nothing here says what this call produced",
6715                        operation.result
6716                    ),
6717                )
6718                .at(span)
6719                .rule("A Host API operation declares `Any` where its meaning does not depend on the type of a value: the schema promises to carry the value, not to describe it.")
6720                .help(format!(
6721                    "whatever the program does with the result of `{shown}` is checked at run time and by nothing here; {}",
6722                    declared_signature(shown, operation)
6723                )),
6724            );
6725        }
6726        host_ty(&operation.result)
6727    }
6728
6729    /// `http.Route(method: ..., path: ..., handler: ...)`: a host type
6730    /// initialized from Cove source, exactly as a struct is.
6731    ///
6732    /// This is the one place a host type's *fields* are checked. The boundary
6733    /// checks a declared type by name only — ADR 0013's amendment says why —
6734    /// so what is checked here is that the program built the value the schema
6735    /// describes, not that the host did.
6736    fn host_type_init(
6737        &mut self,
6738        module: &str,
6739        declared: &'static TypeSchema,
6740        args: &[Arg],
6741        trailing: Option<&Expr>,
6742        span: Span,
6743    ) -> Ty {
6744        let params: Vec<ParamSig> = declared
6745            .fields
6746            .iter()
6747            .map(|field| ParamSig {
6748                name: field.name.to_string(),
6749                ty: host_ty(&field.ty),
6750                variadic: false,
6751                has_default: false,
6752                is_var: false,
6753                span,
6754            })
6755            .collect();
6756        self.match_arguments(
6757            &params,
6758            &[],
6759            BTreeMap::new(),
6760            args,
6761            trailing,
6762            span,
6763            &format!("`{module}.{}`", declared.name),
6764            "the field",
6765        );
6766        Ty::Host(format!("{module}.{}", declared.name).into())
6767    }
6768
6769    /// `http.Request` written as a type.
6770    fn host_named_type(&mut self, module: &str, name: &str, arguments: usize, span: Span) -> Ty {
6771        let qualified = format!("{module}.{name}");
6772        let Some(schema) = self.host_schema(module) else {
6773            self.diagnostics.push(unchecked_host_type(&qualified, span));
6774            return Ty::dynamic_boundary();
6775        };
6776        if !schema.declares_type(name) {
6777            let mut known: Vec<String> = schema
6778                .types
6779                .iter()
6780                .map(|declared| declared.name.to_string())
6781                .collect();
6782            known.extend(
6783                schema
6784                    .resources
6785                    .iter()
6786                    .map(|resource| resource.name.to_string()),
6787            );
6788            self.diagnostics.push(
6789                Diagnostic::error(
6790                    UNKNOWN_HOST_TYPE,
6791                    format!("host module `{module}` declares no type `{name}`"),
6792                )
6793                .at(span)
6794                .rule(HOST_SCHEMA_RULE)
6795                .help(if known.is_empty() {
6796                    format!("`{module}` declares no types of its own")
6797                } else {
6798                    format!("`{module}` declares {}", list(&known))
6799                }),
6800            );
6801            return Ty::recovery();
6802        }
6803        // A host type takes no arguments, because the schema has none to
6804        // give it.
6805        self.check_type_arity(&qualified, 0, arguments, span);
6806        Ty::Host(qualified.into())
6807    }
6808
6809    /// `http.Method.Get`, if `module` is a host module whose schema declares
6810    /// `declared` as an enum. `None` leaves the expression to be read the way
6811    /// it was before.
6812    fn host_enum_case(
6813        &mut self,
6814        module: &str,
6815        declared: &str,
6816        case: &Ident,
6817        span: Span,
6818    ) -> Option<Ty> {
6819        let schema = self.host_schema(module)?.declared_type(declared)?;
6820        if !schema.is_enum() {
6821            return None;
6822        }
6823        let qualified: Arc<str> = format!("{module}.{declared}").into();
6824        if !schema.cases.contains(&case.node.as_str()) {
6825            let known: Vec<String> = schema.cases.iter().map(|c| (*c).to_string()).collect();
6826            self.diagnostics.push(
6827                Diagnostic::error(
6828                    UNKNOWN_CASE,
6829                    format!("`{qualified}` has no case `{}`", case.node),
6830                )
6831                .at(span)
6832                .rule(HOST_SCHEMA_RULE)
6833                .help(format!("`{qualified}` declares {}", list(&known))),
6834            );
6835        }
6836        Some(Ty::Host(qualified))
6837    }
6838
6839    /// `error.message` and `entry.key`: a field of a builtin struct, typed
6840    /// from the shared table.
6841    ///
6842    /// The runtime builds both of these as ordinary struct values and has
6843    /// always served a read of their fields. What it had no way to tell the
6844    /// checker was what those fields are called, so `Error` was opaque here
6845    /// and answered that it had no `message` at all; declaring the fields in
6846    /// `cove_schema::builtins` is what closed that.
6847    fn builtin_field(&mut self, base_ty: &Ty, name: &Ident, span: Span) -> Ty {
6848        // Only `MapEntry` and `Error` reach here, and the table declares
6849        // both.
6850        let Some(schema) = builtin_schema_of(base_ty) else {
6851            return Ty::placeholder();
6852        };
6853        let bound = receiver_binding(schema, base_ty);
6854        match schema.field(&name.node) {
6855            Some(field) => builtin_ty(&field.ty, &bound, Some(base_ty)),
6856            None => {
6857                let known: Vec<String> = schema.fields.iter().map(|f| f.name.to_string()).collect();
6858                self.diagnostics.push(
6859                    Diagnostic::error(
6860                        UNKNOWN_FIELD,
6861                        format!("`{}` has no field `{}`", schema.name, name.node),
6862                    )
6863                    .at(span)
6864                    .rule("A builtin struct's fields are exactly the ones the language defines.")
6865                    .help(format!(
6866                        "`{}` declares {}",
6867                        schema.name,
6868                        list(&known)
6869                    )),
6870                );
6871                Ty::recovery()
6872            }
6873        }
6874    }
6875
6876    /// `request.path`: a field of a host type, typed from the schema.
6877    fn host_field(&mut self, declared: &str, name: &Ident, span: Span) -> Ty {
6878        let Some(schema) = self.host_declared_type(declared) else {
6879            // A resource keeps its state on the far side of the boundary, so
6880            // there is nothing in it to read: everything it answers, it
6881            // answers as an operation.
6882            self.diagnostics.push(
6883                Diagnostic::error(
6884                    UNKNOWN_FIELD,
6885                    format!("`{declared}` has no field `{}`", name.node),
6886                )
6887                .at(span)
6888                .rule("A host resource is a name for something the host keeps, so it has operations rather than fields.")
6889                .help(format!("call an operation on it, such as `{}()`", name.node)),
6890            );
6891            return Ty::recovery();
6892        };
6893        match schema.fields.iter().find(|f| f.name == name.node) {
6894            Some(field) => {
6895                // The other end of the `Any` promise. A schema may declare a
6896                // *field* `Any` as readily as a result — `http.Route.handler`
6897                // is one — and reading it leaves the program holding a value
6898                // no schema described, exactly as calling an `Any`-result
6899                // operation does. Same fact, same note.
6900                if contains_any(&field.ty) {
6901                    self.diagnostics.push(
6902                        Diagnostic::note(
6903                            UNCONSTRAINED_FIELD,
6904                            format!(
6905                                "`{declared}` declares `{}` as `{}`, so nothing here says what this field holds",
6906                                name.node, field.ty
6907                            ),
6908                        )
6909                        .at(span)
6910                        .rule("A Host API schema declares `Any` where its meaning does not depend on the type of a value: the schema promises to carry the value, not to describe it.")
6911                        .help(format!(
6912                            "whatever the program does with `{}.{}` is checked at run time and by nothing here",
6913                            declared, name.node
6914                        )),
6915                    );
6916                }
6917                host_ty(&field.ty)
6918            }
6919            None => {
6920                let known: Vec<String> = schema.fields.iter().map(|f| f.name.to_string()).collect();
6921                self.diagnostics.push(
6922                    Diagnostic::error(
6923                        UNKNOWN_FIELD,
6924                        format!("`{declared}` has no field `{}`", name.node),
6925                    )
6926                    .at(span)
6927                    .rule(HOST_SCHEMA_RULE)
6928                    .help(if known.is_empty() {
6929                        format!("`{declared}` carries no fields")
6930                    } else {
6931                        format!("`{declared}` declares {}", list(&known))
6932                    }),
6933                );
6934                Ty::recovery()
6935            }
6936        }
6937    }
6938
6939    /// `server.handle(routes)`: an operation called on a host resource
6940    /// handle, checked against the same schema a module's operation is.
6941    fn host_method_call(
6942        &mut self,
6943        declared: &str,
6944        name: &Ident,
6945        args: &[Arg],
6946        trailing: Option<&Expr>,
6947        span: Span,
6948    ) -> Ty {
6949        if let Some(resource) = self.host_resource(declared) {
6950            if let Some(operation) = resource.operation(&name.node) {
6951                return self.call_host_operation(
6952                    operation,
6953                    &format!("{declared}.{}", name.node),
6954                    args,
6955                    trailing,
6956                    span,
6957                );
6958            }
6959            self.diagnostics.push(
6960                Diagnostic::error(
6961                    UNKNOWN_HOST_OPERATION,
6962                    format!("`{declared}` has no operation `{}`", name.node),
6963                )
6964                .at(span)
6965                .rule(HOST_SCHEMA_RULE)
6966                .help(format!(
6967                    "`{declared}` answers {}",
6968                    list(&operation_names(resource.operations))
6969                )),
6970            );
6971            self.check_args_freely(args, trailing);
6972            return Ty::recovery();
6973        }
6974        self.diagnostics.push(
6975            Diagnostic::error(
6976                UNKNOWN_HOST_OPERATION,
6977                format!("`{declared}` has no operation `{}`", name.node),
6978            )
6979            .at(span)
6980            .rule("A host type that is plain data has fields; only a host resource answers operations.")
6981            .help(format!("read a field, such as `.{}`", name.node)),
6982        );
6983        self.check_args_freely(args, trailing);
6984        Ty::recovery()
6985    }
6986
6987    /// `Vector.of(...)`, `Map.of(...)`, `Set.of(...)`, `Int.parse(...)`.
6988    ///
6989    /// The signatures come from [`cove_schema::builtins`], the same table the
6990    /// runtime's `call_associated` dispatches out of. A spread argument is
6991    /// left to the runtime, which rejects one in any of these calls.
6992    #[allow(clippy::too_many_arguments)]
6993    fn builtin_associated(
6994        &mut self,
6995        type_name: &str,
6996        name: &Ident,
6997        args: &[Arg],
6998        trailing: Option<&Expr>,
6999        span: Span,
7000        expected: Option<&Expected>,
7001    ) -> Ty {
7002        // An associated function is called on the type, so nothing binds the
7003        // receiver's parameters: the `T` of `Vector.of(items: T...)` is the
7004        // signature's own, unified at the call site.
7005        let declared = cove_schema::builtin(type_name)
7006            .and_then(|schema| schema.associated_function(&name.node));
7007        let Some(declared) = declared else {
7008            self.diagnostics.push(
7009                Diagnostic::error(
7010                    UNKNOWN_ASSOCIATED,
7011                    format!("`{type_name}` has no associated function `{}`", name.node),
7012                )
7013                .at(span)
7014                .rule(format!(
7015                    "A builtin type's associated functions are {}.",
7016                    builtin_associated_functions()
7017                ))
7018                .help(format!(
7019                    "`{type_name}` has no `{}`; construct the value another way",
7020                    name.node
7021                )),
7022            );
7023            self.check_args_freely(args, trailing);
7024            return Ty::recovery();
7025        };
7026        let sig = builtin_sig(declared, &[], &[], None);
7027        let what = format!("`{type_name}.{}`", name.node);
7028        let mut subst = self.builtin_arguments(&sig, &what, args, trailing, span);
7029        self.settle_from_expectation(&sig, &mut subst, expected);
7030        // `Vector.of()`, `Set.of()` and `Map.of()` are the empty collection
7031        // literals, and an empty one has no argument to read its element
7032        // type off. If the place that holds it did not say either, the
7033        // *uses* of the binding that holds it do — `var log = Vector.of()`
7034        // followed by `log.push(text)` is a `Vector<String>` — and a
7035        // variable is what carries the question that far. Issue #240
7036        // decided it there rather than here, so this is not a rule about
7037        // empty collections: it is `Checker::open_result`, which every call
7038        // whose result mentions a type parameter nothing settled goes
7039        // through. A binding whose uses settle nothing is reported once, at
7040        // the binding, by `Checker::finish_inference`.
7041        self.open_result(&sig.ret, &sig.generics, &subst, span)
7042    }
7043
7044    /// The type parameters the place holding this value settles, for the
7045    /// ones its arguments did not.
7046    ///
7047    /// `Vector.of()` has no argument to read its `T` off, and a declared
7048    /// return type, a `let` annotation, a parameter, a field or an argument
7049    /// position states it. Reading it back off the expected type is the step
7050    /// [`FreeBindings::read_off`] takes for `Ok(1)`, and it is [`unify`]
7051    /// here because a builtin's signature has already become a [`Ty`]: the
7052    /// result type is matched against what the call site asked for, and the
7053    /// parameters that meet a type there are bound to it.
7054    ///
7055    /// An argument is still what settles a parameter it mentions. This runs
7056    /// after [`Checker::builtin_arguments`] and only ever adds bindings, so
7057    /// `Vector.of(1, 2)` in a place expecting a `Vector<String>` is the same
7058    /// mismatch it always was rather than an argument checked against the
7059    /// place. And the whole match is discarded unless it succeeds, so a
7060    /// half-read expectation cannot settle one parameter out of two.
7061    fn settle_from_expectation(
7062        &mut self,
7063        sig: &BuiltinSig,
7064        subst: &mut BTreeMap<Arc<str>, Ty>,
7065        expected: Option<&Expected>,
7066    ) {
7067        if sig.generics.iter().all(|g| subst.contains_key(g)) {
7068            return;
7069        }
7070        let Some(expected) = expected else {
7071            return;
7072        };
7073        let generics: BTreeSet<Arc<str>> = sig.generics.iter().cloned().collect();
7074        let mut found = subst.clone();
7075        if unify(&sig.ret, &expected.ty, &generics, &mut found, &self.view()) {
7076            *subst = found;
7077        }
7078    }
7079
7080    /// `MapEntry(key: ..., value: ...)`: a synthesized labeled call, exactly
7081    /// like a declared struct's initializer, that exists so `Map.of` has a
7082    /// call-shaped way to write the pairs it collects.
7083    ///
7084    /// Its labels are the fields [`MAP_ENTRY`] declares, which is also what
7085    /// the interpreter assigns the arguments to, so a call and the value it
7086    /// builds cannot come apart.
7087    fn map_entry(&mut self, args: &[Arg], trailing: Option<&Expr>, span: Span) -> Ty {
7088        // There is no receiver here, so the entry's own `K` and `V` are what
7089        // the call site settles, the way a generic function's are.
7090        let bound = BTreeMap::new();
7091        let sig = BuiltinSig {
7092            generics: MAP_ENTRY
7093                .parameters
7094                .iter()
7095                .map(|name| Arc::from(*name))
7096                .collect(),
7097            params: MAP_ENTRY
7098                .fields
7099                .iter()
7100                .map(|field| (field.name, builtin_ty(&field.ty, &bound, None)))
7101                .collect(),
7102            variadic: false,
7103            ret: Ty::MapEntry(
7104                Box::new(Ty::Param("K".into())),
7105                Box::new(Ty::Param("V".into())),
7106            ),
7107        };
7108        self.call_builtin(&sig, "`MapEntry`", args, trailing, span)
7109    }
7110
7111    /// The type arguments the place holding this value states, when it
7112    /// states any: `let t: Tagged<String> = Tagged(n: 1)` settles `T` even
7113    /// though no field mentions it.
7114    fn expected_arguments(name: &str, expected: Option<&Expected>) -> Vec<Ty> {
7115        match expected.map(|e| &e.ty) {
7116            Some(Ty::Struct(other, args)) if other.as_ref() == name => args.clone(),
7117            _ => Vec::new(),
7118        }
7119    }
7120
7121    /// `Type(field: value, ...)`, the synthesized labeled call the card
7122    /// describes.
7123    #[allow(clippy::too_many_arguments)]
7124    fn struct_init(
7125        &mut self,
7126        name: &str,
7127        sig: &StructSig,
7128        args: &[Arg],
7129        trailing: Option<&Expr>,
7130        span: Span,
7131        expected: Option<&Expected>,
7132    ) -> Ty {
7133        // A refusal ends the diagnosis. Matching the arguments against
7134        // fields this module may not name would answer the question it was
7135        // just refused — the labels it guessed wrong would come back as
7136        // `known labels: raw, count`, and a field it left out would be
7137        // reported against the declaring module's source. The arguments
7138        // themselves are still checked, since a mistake inside one is a
7139        // mistake either way, and the result is still this struct.
7140        if self.reject_opaque_construction(name, sig, span) {
7141            self.check_args_freely(args, trailing);
7142            return Ty::Struct(name.into(), vec![Ty::recovery(); sig.generics.len()]);
7143        }
7144        let generics: Vec<Arc<str>> = sig.generics.clone();
7145        let stated = Checker::expected_arguments(name, expected);
7146        let subst = self.match_arguments(
7147            &sig.fields,
7148            &generics,
7149            BTreeMap::new(),
7150            args,
7151            trailing,
7152            span,
7153            &format!("`{name}`"),
7154            "the field",
7155        );
7156        let arguments = generics
7157            .iter()
7158            .enumerate()
7159            .map(|(index, g)| {
7160                // The fields were just checked, which is what settles the
7161                // parameters they mention; one no field mentions can only be
7162                // settled by the place the value is given to.
7163                if let Some(ty) = subst.get(g) {
7164                    return ty.clone();
7165                }
7166                if let Some(ty) = stated.get(index).filter(|ty| !ty.is_wild()) {
7167                    return ty.clone();
7168                }
7169                // Nothing settles it, and the value carries it anyway: every
7170                // later use of this binding at that parameter's position is
7171                // checked against nothing. That is the same gap an empty
7172                // array literal and a bare `None` leave, and it is named the
7173                // same way rather than left to spread as a silent unknown.
7174                if !Checker::accounted_for(expected) {
7175                    self.diagnostics.push(unconstrained(
7176                        format!("nothing says what `{g}` is in `{name}<{g}>`"),
7177                        format!(
7178                            "write the type on the place that holds it, as in `let value: {name}<Int> = ...`, or give the value to a place that declares one"
7179                        ),
7180                        span,
7181                    ));
7182                }
7183                Ty::unconstrained()
7184            })
7185            .collect();
7186        Ty::Struct(name.into(), arguments)
7187    }
7188
7189    /// Checks a call against a declared signature, unifying the callee's type
7190    /// parameters at the call site and substituting them into the result.
7191    fn call_signature(
7192        &mut self,
7193        sig: &FnSig,
7194        what: &str,
7195        explicit: Vec<Ty>,
7196        args: &[Arg],
7197        trailing: Option<&Expr>,
7198        span: Span,
7199    ) -> Ty {
7200        let mut subst: BTreeMap<Arc<str>, Ty> = BTreeMap::new();
7201        for (param, ty) in sig.generics.iter().zip(explicit) {
7202            subst.insert(param.clone(), ty);
7203        }
7204        let subst = self.match_arguments(
7205            &sig.params,
7206            &sig.generics,
7207            subst,
7208            args,
7209            trailing,
7210            span,
7211            what,
7212            "the parameter",
7213        );
7214        self.check_bounds(sig, &subst, what, span);
7215        let ret = self.open_result(&sig.ret, &sig.generics, &subst, span);
7216        if sig.is_async {
7217            // An `async fn` is called like any other function and produces a
7218            // task; its value is reachable only through `await`.
7219            Ty::Task(Box::new(ret))
7220        } else {
7221            ret
7222        }
7223    }
7224
7225    /// Calls a value of function type.
7226    fn call_value(
7227        &mut self,
7228        callee: &Ty,
7229        args: &[Arg],
7230        trailing: Option<&Expr>,
7231        span: Span,
7232        callee_span: Span,
7233    ) -> Ty {
7234        match callee {
7235            Ty::Unknown(_) | Ty::Never => {
7236                self.check_args_freely(args, trailing);
7237                callee.abstain()
7238            }
7239            Ty::Any => {
7240                self.check_args_freely(args, trailing);
7241                Ty::Any
7242            }
7243            Ty::Fn(func) => {
7244                let params: Vec<ParamSig> = func
7245                    .params
7246                    .iter()
7247                    .enumerate()
7248                    .map(|(index, ty)| ParamSig {
7249                        name: format!("#{index}"),
7250                        ty: ty.clone(),
7251                        variadic: false,
7252                        has_default: false,
7253                        // A function type has no marking to read. See
7254                        // `Checker::var_arguments` for what this pass does
7255                        // and does not decide about a call through a value.
7256                        is_var: false,
7257                        span: callee_span,
7258                    })
7259                    .collect();
7260                self.match_arguments(
7261                    &params,
7262                    &[],
7263                    BTreeMap::new(),
7264                    args,
7265                    trailing,
7266                    span,
7267                    "this function value",
7268                    "the parameter",
7269                );
7270                if func.is_async {
7271                    Ty::Task(Box::new(func.ret.clone()))
7272                } else {
7273                    func.ret.clone()
7274                }
7275            }
7276            other => {
7277                self.diagnostics.push(
7278                    Diagnostic::error(NOT_CALLABLE, format!("`{other}` is not a function"))
7279                        .at(callee_span)
7280                        .rule("Only a function value can be called.")
7281                        .help(format!(
7282                            "`{other}` is a value, not a function; remove the argument list"
7283                        )),
7284                );
7285                self.check_args_freely(args, trailing);
7286                Ty::recovery()
7287            }
7288        }
7289    }
7290
7291    /// Matches call-site arguments to parameters by position and by label,
7292    /// checking each against the parameter's type and binding the callee's
7293    /// type parameters as it goes.
7294    ///
7295    /// Labels are parameter names, so a labeled argument goes to the
7296    /// parameter it names. Their *order* is the runtime's rule, not this
7297    /// one's.
7298    #[allow(clippy::too_many_arguments)]
7299    fn match_arguments(
7300        &mut self,
7301        params: &[ParamSig],
7302        generics: &[Arc<str>],
7303        mut subst: BTreeMap<Arc<str>, Ty>,
7304        args: &[Arg],
7305        trailing: Option<&Expr>,
7306        span: Span,
7307        what: &str,
7308        role: &str,
7309    ) -> BTreeMap<Arc<str>, Ty> {
7310        let variadic_last = params.last().is_some_and(|p| p.variadic);
7311        let mut slots: Vec<Option<&Arg>> = vec![None; params.len()];
7312        let mut rest: Vec<&Arg> = Vec::new();
7313        let mut next = 0usize;
7314        let mut labeled = false;
7315        // One mistake, one diagnostic: a label that names no parameter has
7316        // already been reported, so the parameter it failed to fill is not
7317        // reported as missing too.
7318        let mut mislabeled = false;
7319        let generic_set: BTreeSet<Arc<str>> = generics.iter().cloned().collect();
7320
7321        for arg in args {
7322            match &arg.label {
7323                Some(label) => {
7324                    labeled = true;
7325                    match params.iter().position(|p| p.name == label.node) {
7326                        Some(index) => {
7327                            // A label whose parameter stands before one an
7328                            // earlier argument already filled. The same
7329                            // label twice lands here too, and is left to the
7330                            // missing-argument report the parameter it never
7331                            // filled already earns: one mistake, one
7332                            // diagnostic.
7333                            if index < next && slots[index].is_none() {
7334                                let order: Vec<&str> =
7335                                    params.iter().map(|p| p.name.as_str()).collect();
7336                                self.diagnostics.push(
7337                                    Diagnostic::error(
7338                                        LABEL_ORDER,
7339                                        format!(
7340                                            "{what} was given the label `{}` out of declaration order",
7341                                            label.node
7342                                        ),
7343                                    )
7344                                    .at(arg.span)
7345                                    .rule("Labeled arguments appear in declaration order, so argument order matches parameter order.")
7346                                    .help(format!(
7347                                        "write the arguments in this order: {}",
7348                                        order.join(", ")
7349                                    )),
7350                                );
7351                            }
7352                            slots[index] = Some(arg);
7353                            next = index + 1;
7354                        }
7355                        None => {
7356                            let known: Vec<String> =
7357                                params.iter().map(|p| p.name.clone()).collect();
7358                            self.diagnostics.push(
7359                                Diagnostic::error(
7360                                    UNKNOWN_LABEL,
7361                                    format!("{what} has no parameter labeled `{}`", label.node),
7362                                )
7363                                .at(arg.span)
7364                                .rule("Argument labels are parameter names and part of the API contract.")
7365                                .help(format!("known labels: {}", list(&known))),
7366                            );
7367                            self.expr(&arg.value, None);
7368                            mislabeled = true;
7369                        }
7370                    }
7371                }
7372                // The runtime rejects a positional argument after a labeled
7373                // one; there is no parameter to check this one against.
7374                None if labeled => {
7375                    self.expr(&arg.value, None);
7376                }
7377                None if variadic_last && next + 1 >= params.len() => rest.push(arg),
7378                None if next < params.len() => {
7379                    slots[next] = Some(arg);
7380                    next += 1;
7381                }
7382                None => {
7383                    self.diagnostics.push(
7384                        Diagnostic::error(
7385                            ARITY,
7386                            format!(
7387                                "{what} takes {} argument(s), but more were given",
7388                                params.len()
7389                            ),
7390                        )
7391                        .at(arg.span)
7392                        .rule("A call passes exactly the arguments the declaration binds.")
7393                        .help(format!(
7394                            "{what} declares {}",
7395                            list(&params.iter().map(|p| p.name.clone()).collect::<Vec<_>>())
7396                        )),
7397                    );
7398                    self.expr(&arg.value, None);
7399                }
7400            }
7401        }
7402
7403        // A trailing closure fills the first parameter still empty, which is
7404        // the variadic one when the signature ends in `...`.
7405        let trailing_slot = trailing.and_then(|_| {
7406            if variadic_last {
7407                None
7408            } else {
7409                slots.iter().position(Option::is_none)
7410            }
7411        });
7412        if let Some(trailing) = trailing {
7413            match trailing_slot.and_then(|index| params.get(index).map(|p| (index, p))) {
7414                Some((index, param)) => {
7415                    let param = param.clone();
7416                    let expected = param.ty.substitute(&subst);
7417                    let hint = self.open(&expected, generics, &subst);
7418                    let found = self.trailing_type(trailing, Some(&hint));
7419                    self.check_argument(
7420                        &found,
7421                        &hint,
7422                        &expected,
7423                        trailing.span,
7424                        &param,
7425                        &generic_set,
7426                        &mut subst,
7427                        role,
7428                    );
7429                    slots[index] = None;
7430                }
7431                None => {
7432                    let ty = self.trailing_type(trailing, None);
7433                    if variadic_last {
7434                        if let Some(param) = params.last() {
7435                            let param = param.clone();
7436                            let element = param.ty.substitute(&subst);
7437                            let hint = self.open(&element, generics, &subst);
7438                            self.check_argument(
7439                                &ty,
7440                                &hint,
7441                                &element,
7442                                trailing.span,
7443                                &param,
7444                                &generic_set,
7445                                &mut subst,
7446                                role,
7447                            );
7448                        }
7449                    } else {
7450                        self.diagnostics.push(
7451                            Diagnostic::error(
7452                                ARITY,
7453                                format!(
7454                                    "{what} takes {} argument(s), but a trailing closure was given too",
7455                                    params.len()
7456                                ),
7457                            )
7458                            .at(trailing.span)
7459                            .rule("A trailing closure is the call's last argument.")
7460                            .help("remove the trailing closure, or pass it in place of an argument"),
7461                        );
7462                    }
7463                }
7464            }
7465        }
7466
7467        for (index, param) in params.iter().enumerate() {
7468            if param.variadic {
7469                let element = param.ty.substitute(&subst);
7470                let mut supplied: Vec<&Arg> = rest.clone();
7471                if let Some(arg) = slots[index] {
7472                    supplied.insert(0, arg);
7473                }
7474                for arg in supplied {
7475                    self.variadic_argument(
7476                        arg,
7477                        &element,
7478                        param,
7479                        generics,
7480                        &generic_set,
7481                        &mut subst,
7482                        role,
7483                    );
7484                }
7485                continue;
7486            }
7487            let Some(arg) = slots[index] else {
7488                if !param.has_default && trailing_slot != Some(index) && !mislabeled {
7489                    self.diagnostics.push(
7490                        Diagnostic::error(
7491                            MISSING_ARGUMENT,
7492                            format!("{what} needs {role} `{}`", param.name),
7493                        )
7494                        .at(span)
7495                        .label(param.span, format!("`{}` is `{}`", param.name, param.ty))
7496                        .rule("A call passes every parameter that has no default.")
7497                        .help(format!("pass `{}: <{}>`", param.name, param.ty)),
7498                    );
7499                }
7500                continue;
7501            };
7502            let expected = param.ty.substitute(&subst);
7503            let hint = self.open(&expected, generics, &subst);
7504            let hint_expected = Expected::new(
7505                hint.clone(),
7506                param.span,
7507                format!("{role} `{}` is `{}`", param.name, param.ty),
7508            );
7509            let found = self.expr(&arg.value, Some(&hint_expected));
7510            self.check_argument(
7511                &found,
7512                &hint,
7513                &expected,
7514                arg.span,
7515                param,
7516                &generic_set,
7517                &mut subst,
7518                role,
7519            );
7520        }
7521        subst
7522    }
7523
7524    /// Binds the callee's type parameters from one argument, and reports the
7525    /// mismatch the expectation could not: an expectation is checked against
7526    /// `hint`, in which every unbound type parameter is `Unknown`, so only
7527    /// unification can tell that two uses of the same parameter disagree.
7528    #[allow(clippy::too_many_arguments)]
7529    fn check_argument(
7530        &mut self,
7531        found: &Ty,
7532        hint: &Ty,
7533        expected: &Ty,
7534        span: Span,
7535        param: &ParamSig,
7536        generics: &BTreeSet<Arc<str>>,
7537        subst: &mut BTreeMap<Arc<str>, Ty>,
7538        role: &str,
7539    ) {
7540        // The other half of `Checker::expect`: a variadic argument and a
7541        // trailing closure are checked here and nowhere else, so this is
7542        // where a use of that shape says what a binding's open type is.
7543        self.constrain(found, hint, span);
7544        // A generic parameter is bound from what the checker already knows
7545        // about `found`, not only from what `found`'s own written form
7546        // states: `items` read from a binding that took its type from
7547        // `Vector.of()` and a later `push` is still `Array<a>` here — the
7548        // binding's stored type is rewritten only at the end of the body —
7549        // even though `a` was settled several statements ago. `unify` binds
7550        // a type parameter by inserting `found` verbatim, so an argument in
7551        // that shape looked exactly as unconstrained as one that really was,
7552        // and a later argument — a closure whose parameter type is this
7553        // same still-open generic — was asked to settle a decision the
7554        // array had already made. `Checker::bound` is the existing read of
7555        // "what does the checker already know", used everywhere a name that
7556        // cannot itself own a variable is bound from one; a generic
7557        // parameter is exactly such a name, so the same read applies here.
7558        let resolved = self.bound(found.clone());
7559        let unified = unify(expected, &resolved, generics, subst, &self.view());
7560        if !unified && found.matches(hint) {
7561            let expected = expected.substitute(subst);
7562            self.report_argument(found, &expected, span, param, role);
7563        }
7564    }
7565
7566    /// A signature type with every type parameter still unbound replaced by
7567    /// an unconstrained unknown, so it can be used as an expectation without
7568    /// pretending the call site has decided what the parameter is.
7569    ///
7570    /// The unknown is [`Ty::unconstrained`] rather than a placeholder because
7571    /// it *is* read: an argument is checked against it, and a lambda takes
7572    /// its parameter types from it. What it says is exactly what
7573    /// "unconstrained" means — nothing read so far states this type — and
7574    /// saying so is what keeps a form given to such a place from being asked
7575    /// to explain a silence that is not its own.
7576    fn open(&self, ty: &Ty, generics: &[Arc<str>], subst: &BTreeMap<Arc<str>, Ty>) -> Ty {
7577        if generics.is_empty() {
7578            return ty.clone();
7579        }
7580        let map: BTreeMap<Arc<str>, Ty> = generics
7581            .iter()
7582            .map(|g| {
7583                (
7584                    g.clone(),
7585                    subst.get(g).cloned().unwrap_or(Ty::unconstrained()),
7586                )
7587            })
7588            .collect();
7589        ty.substitute(&map)
7590    }
7591
7592    // ------------------------------------------------- local inference
7593
7594    /// A *call's result*, with every type parameter neither the arguments
7595    /// nor the call site settled replaced by a fresh inference variable.
7596    ///
7597    /// This is [`Checker::open`] with an identity kept for each hole, and
7598    /// the difference between the two is the difference between a place
7599    /// being checked *now* and a type being carried *forward*. An argument
7600    /// checked against an opened parameter is finished with the moment the
7601    /// argument is walked, so nothing would ever read a variable back out of
7602    /// it. A call's result is what a binding holds and what every later use
7603    /// of that binding is checked against, so it is the one position where
7604    /// leaving the hole open costs nothing and closing it costs the rest of
7605    /// the body: `Vector.of()` is a `Vector<a>` until `log.push(text)` says
7606    /// what `a` is.
7607    ///
7608    /// It is used at the four places a call produces a value —
7609    /// [`Checker::call_signature`], [`Checker::call_builtin`],
7610    /// [`Checker::builtin_associated`] and [`Checker::enum_case`] — so a
7611    /// generic declaration, a builtin method, a builtin associated function
7612    /// and a generic enum case all reach the same inference rather than each
7613    /// getting one.
7614    fn open_result(
7615        &mut self,
7616        ty: &Ty,
7617        generics: &[Arc<str>],
7618        subst: &BTreeMap<Arc<str>, Ty>,
7619        at: Span,
7620    ) -> Ty {
7621        if generics.is_empty() {
7622            return ty.clone();
7623        }
7624        let map: BTreeMap<Arc<str>, Ty> = generics
7625            .iter()
7626            .map(|generic| {
7627                let ty = match subst.get(generic) {
7628                    Some(settled) => settled.clone(),
7629                    None => self.fresh_var(at),
7630                };
7631                (generic.clone(), ty)
7632            })
7633            .collect();
7634        let opened = ty.substitute(&map);
7635        self.produced(&opened);
7636        opened
7637    }
7638
7639    /// Tells every variable in `ty` that `ty` is what the call it came out
7640    /// of produced.
7641    ///
7642    /// A variable a binding takes shows the binding's type in its
7643    /// diagnostic; one no binding takes has only this. `Result<Int, _>`
7644    /// says which hole is open where `_` alone says nothing.
7645    fn produced(&mut self, ty: &Ty) {
7646        for id in ty.vars() {
7647            if let Some(var) = self.vars.get_mut(id as usize) {
7648                var.produced = ty.clone();
7649            }
7650        }
7651    }
7652
7653    /// A variable nothing has said anything about yet.
7654    fn fresh_var(&mut self, at: Span) -> Ty {
7655        self.vars.push(TyVar {
7656            owner: None,
7657            solved: None,
7658            conflicted: false,
7659            spoken_for: None,
7660            abstained: None,
7661            at,
7662            produced: Ty::Unknown(Unknown::Var(self.vars.len() as u32)),
7663            probed: self.probing,
7664        });
7665        Ty::var((self.vars.len() - 1) as u32)
7666    }
7667
7668    /// Gives every variable in `ty` to the binding that now holds it.
7669    ///
7670    /// This is the boundary the language draws. A `let` or a `var` with no
7671    /// written type is the one place a type may still be settled by what
7672    /// comes *after* it; a parameter, a return type, and a public
7673    /// declaration state their types where they are written, and none of
7674    /// them reaches here. A variable already owned keeps its first owner, so
7675    /// `var a = Vector.of()` followed by `var b = a` names `a` when nothing
7676    /// settles the type the two of them share.
7677    fn attach(&mut self, ty: &Ty, name: &str, span: Span) {
7678        // A probe walks a tree and throws away what it reported; a binding
7679        // it declares is walked again for real straight after. Giving a
7680        // probe's variable an owner would leave a second, unsettled claim
7681        // on the same `let`, and the report at the end of the body cannot
7682        // tell it from the real one.
7683        if self.probing {
7684            return;
7685        }
7686        for id in ty.vars() {
7687            if let Some(var) = self.vars.get_mut(id as usize) {
7688                if var.owner.is_none() {
7689                    var.owner = Some(Owned {
7690                        name: name.to_string(),
7691                        span,
7692                        ty: ty.clone(),
7693                    });
7694                }
7695            }
7696        }
7697    }
7698
7699    /// Reads what a use says about the variables in the type it meets.
7700    ///
7701    /// Every place a found type is compared with an expected one runs
7702    /// through here first, so `log.push(text)`, `takesLines(log)`,
7703    /// `log = other` and `return log` are one rule and not four: the
7704    /// comparison the checker was going to make anyway is walked in
7705    /// parallel, and wherever a variable stands opposite a type that is not
7706    /// itself a variable or an unknown, that is what the variable is.
7707    ///
7708    /// A variable standing opposite another variable settles nothing. Two
7709    /// open types meeting say only that they are the same, which is a fact
7710    /// this pass has nowhere to keep and no program yet needs — a union
7711    /// would be the general answer, and the day one is needed the shape of
7712    /// it is [`TyVar::solved`] pointing at another variable rather than at a
7713    /// type.
7714    fn constrain(&mut self, found: &Ty, expected: &Ty, span: Span) {
7715        // A probe walks a tree to find one type out and its diagnostics are
7716        // thrown away; what it reads about a variable would not be, so it
7717        // reads nothing.
7718        if self.vars.is_empty() || self.probing {
7719            return;
7720        }
7721        // A place that abstained answers for every variable given to it, at
7722        // any depth: `Ok(())` written in a callback a schema declared `Any`
7723        // leaves its error type open, and what states that error type is the
7724        // schema's own `Any`. See `TyVar::abstained`.
7725        for (open, place) in [(found, expected), (expected, found)] {
7726            if let Some(abstention) = place.abstention() {
7727                for id in open.vars() {
7728                    if let Some(var) = self.vars.get_mut(id as usize) {
7729                        if var.abstained.is_none() {
7730                            var.abstained = Some(abstention.clone());
7731                        }
7732                    }
7733                }
7734            }
7735        }
7736        match (found, expected) {
7737            (Ty::Unknown(Unknown::Var(id)), other) | (other, Ty::Unknown(Unknown::Var(id))) => {
7738                self.settle_var(*id, other, span)
7739            }
7740            (Ty::Array(a), Ty::Array(b))
7741            | (Ty::Vector(a), Ty::Vector(b))
7742            | (Ty::Set(a), Ty::Set(b))
7743            | (Ty::Option(a), Ty::Option(b))
7744            | (Ty::Task(a), Ty::Task(b))
7745            | (Ty::Shared(a), Ty::Shared(b)) => self.constrain(a, b, span),
7746            (Ty::Map(ak, av), Ty::Map(bk, bv))
7747            | (Ty::MapEntry(ak, av), Ty::MapEntry(bk, bv))
7748            | (Ty::Result(ak, av), Ty::Result(bk, bv)) => {
7749                self.constrain(ak, bk, span);
7750                self.constrain(av, bv, span);
7751            }
7752            (Ty::Struct(a, aargs), Ty::Struct(b, bargs))
7753            | (Ty::Enum(a, aargs), Ty::Enum(b, bargs))
7754                if a == b && aargs.len() == bargs.len() =>
7755            {
7756                for (a, b) in aargs.iter().zip(bargs) {
7757                    self.constrain(a, b, span);
7758                }
7759            }
7760            (Ty::Fn(a), Ty::Fn(b))
7761                if a.is_async == b.is_async && a.params.len() == b.params.len() =>
7762            {
7763                for (a, b) in a.params.iter().zip(&b.params) {
7764                    self.constrain(a, b, span);
7765                }
7766                self.constrain(&a.ret, &b.ret, span);
7767            }
7768            _ => {}
7769        }
7770    }
7771
7772    /// Settles one variable, or reports the use that disagrees with what
7773    /// settled it first.
7774    ///
7775    /// Nothing is read off an unknown or a `Never`, which say nothing, or
7776    /// off a type that still holds a variable of its own, which would make
7777    /// one open type stand for another. The first use to say something wins
7778    /// and every later one is checked against it, so which use is *named* as
7779    /// the settling one is the first in source order — the same order the
7780    /// program is read in.
7781    fn settle_var(&mut self, id: u32, ty: &Ty, span: Span) {
7782        if ty.is_wild() {
7783            return;
7784        }
7785        if ty.holds_var() {
7786            if let Some(var) = self.vars.get_mut(id as usize) {
7787                if var.spoken_for.is_none() {
7788                    var.spoken_for = Some((ty.clone(), span));
7789                }
7790            }
7791            return;
7792        }
7793        let Some(var) = self.vars.get(id as usize) else {
7794            return;
7795        };
7796        let Some((settled, first)) = var.solved.clone() else {
7797            self.vars[id as usize].solved = Some((ty.clone(), span));
7798            return;
7799        };
7800        if settled.matches(ty) || var.conflicted {
7801            return;
7802        }
7803        // A variable no binding took is one the language says nothing about:
7804        // it was an unconstrained unknown before this inference existed, and
7805        // an unconstrained unknown agrees with everything. Only a binding's
7806        // own type is a claim two uses can be held to.
7807        let Some(owner) = var.owner.clone() else {
7808            self.vars[id as usize].conflicted = true;
7809            return;
7810        };
7811        self.vars[id as usize].conflicted = true;
7812        // Both constraints are shown as the whole type the binding would
7813        // have, because that is the type the program is arguing about: the
7814        // variable on its own is an element type or a payload, and a
7815        // diagnostic naming `String` against `Int` would not say where in
7816        // `log` they sit.
7817        let holds = owner.ty.settled(&self.vars);
7818        self.vars[id as usize].solved = Some((ty.clone(), span));
7819        let needs = owner.ty.settled(&self.vars);
7820        self.vars[id as usize].solved = Some((settled, first));
7821        let name = owner.name;
7822        self.diagnostics.push(
7823            Diagnostic::error(
7824                INFERENCE_CONFLICT,
7825                format!("`{name}` was settled as `{holds}`, but this use needs `{needs}`"),
7826            )
7827            .at(span)
7828            .label(first, format!("settled as `{holds}` here"))
7829            .label(owner.span, format!("`{name}` is declared with no written type"))
7830            .rule("A binding whose initializer leaves a type open takes that type from its uses, and every use of it means the same type.")
7831            .help(format!(
7832                "write the type on the binding, as in `{name}: {holds}`, and correct whichever use disagrees"
7833            )),
7834        );
7835    }
7836
7837    /// Settles every variable the body just checked minted, and writes the
7838    /// facts that were recorded while they were still open.
7839    ///
7840    /// The end of a body is the end of the inference scope, and it is the
7841    /// last moment a use could have arrived: a binding is gone by then and a
7842    /// declaration that comes after cannot see it. So a variable nothing
7843    /// settled is where the program left a type nobody stated, and this is
7844    /// where it is refused.
7845    ///
7846    /// Every one is refused, not only the ones a binding took. A variable a
7847    /// `let` holds is asked for the annotation by name; one that came out of
7848    /// a call written in the middle of an expression is asked at the call,
7849    /// because there is no name to ask about; and one a use described in
7850    /// terms of itself — `v.push(v)` — is [`RECURSIVE_TYPE`], because the
7851    /// type it asks for exists and cannot be written. Leaving any of them
7852    /// unrefused would leave a checked program holding a type nothing
7853    /// settles, which is the one thing `Facts` promises it does not.
7854    ///
7855    /// Every fact is written again from here rather than left as it was,
7856    /// which is what the promise in [`Facts`] rests on: a consumer reading a
7857    /// type after the check finished sees what the uses settled, and never a
7858    /// variable.
7859    fn finish_inference(&mut self) {
7860        // A variable nothing said anything real about, given to a place that
7861        // said it need not: the place's own answer is the answer, and no
7862        // annotation is asked for. Done before the reports below so that
7863        // both they and the facts written after them read one table.
7864        for index in 0..self.vars.len() {
7865            if self.vars[index].solved.is_some() {
7866                continue;
7867            }
7868            if let Some(abstention) = self.vars[index].abstained.clone() {
7869                let at = self.vars[index].at;
7870                self.vars[index].solved = Some((abstention, at));
7871            }
7872        }
7873        // A body with an error in it is asked for no annotations. Every
7874        // report below says the program did not state a type, and after a
7875        // mistake the checker no longer knows whether it was the program
7876        // that did not state it or the mistake that stopped it being read.
7877        let stopped = self.diagnostics[self.body_mark.min(self.diagnostics.len())..]
7878            .iter()
7879            .any(|item| item.severity == Severity::Error);
7880        // One report per place, not one per variable: `Map.of()` leaves two
7881        // open and a reader is missing one annotation, not two.
7882        let mut reported: BTreeSet<(cove_diag::FileId, u32)> = BTreeSet::new();
7883        for index in 0..self.vars.len() {
7884            let var = &self.vars[index];
7885            // A probe walks a tree and throws away what it reported; the
7886            // real walk of the same tree mints its own variables straight
7887            // after, and those are the ones a reader is told about.
7888            if stopped || var.probed || var.solved.is_some() || var.conflicted {
7889                continue;
7890            }
7891            let owner = var.owner.clone();
7892            let at = owner.as_ref().map_or(var.at, |owner| owner.span);
7893            if !reported.insert((at.file, at.start)) {
7894                continue;
7895            }
7896            if let Some((asked, use_span)) = var.spoken_for.clone() {
7897                let holds = asked.settled(&self.vars);
7898                let subject = match &owner {
7899                    Some(owner) => format!("`{}`", owner.name),
7900                    None => "this value".to_string(),
7901                };
7902                self.diagnostics.push(
7903                    Diagnostic::error(
7904                        RECURSIVE_TYPE,
7905                        format!("this use makes {subject} hold a `{holds}`, which holds itself"),
7906                    )
7907                    .at(use_span)
7908                    .label(at, format!("{subject} is declared with no written type"))
7909                    .rule("A type the checker infers is a type the program could have written, and a type that contains itself is written by declaring one.")
7910                    .help(
7911                        "declare a struct or an enum for the thing that repeats and hold that, as in `struct Node { next: Vector<Node> }`",
7912                    ),
7913                );
7914                continue;
7915            }
7916            match &owner {
7917                Some(owner) => {
7918                    let shown = owner.ty.settled(&self.vars);
7919                    let name = &owner.name;
7920                    self.diagnostics.push(unconstrained(
7921                        format!("nothing says what the `_` in `{name}: {shown}` is"),
7922                        format!(
7923                            "write the type on the binding, as in `{name}: {shown}` with the `_` filled in, or use `{name}` in a way that says what it holds"
7924                        ),
7925                        at,
7926                    ));
7927                }
7928                // A value no binding holds has no name to ask about, so the
7929                // correction is to give it one that states the type.
7930                None => {
7931                    let shown = self.vars[index].produced.settled(&self.vars);
7932                    self.diagnostics.push(unconstrained(
7933                    format!("nothing says what the `_` in `{shown}` is"),
7934                    format!(
7935                        "bind this value first, with the type written, as in `let value: {shown} = ...` with the `_` filled in"
7936                    ),
7937                    at,
7938                ));
7939                }
7940            }
7941        }
7942        for (file, id) in std::mem::take(&mut self.open_facts) {
7943            let Some(ty) = self.facts.ty(file, id).cloned() else {
7944                continue;
7945            };
7946            let settled = ty.settled(&self.vars);
7947            debug_assert!(
7948                !settled.holds_var(),
7949                "an inference variable escaped into a fact: `{settled}`"
7950            );
7951            self.facts.record_ty(file, id, &settled);
7952        }
7953        self.vars.clear();
7954    }
7955
7956    /// One argument passed to a variadic parameter, which is an `Array<T>`
7957    /// inside the callee: each ordinary argument is a `T`, and a spread
7958    /// argument is a sequence of them.
7959    #[allow(clippy::too_many_arguments)]
7960    fn variadic_argument(
7961        &mut self,
7962        arg: &Arg,
7963        element: &Ty,
7964        param: &ParamSig,
7965        generics: &[Arc<str>],
7966        generic_set: &BTreeSet<Arc<str>>,
7967        subst: &mut BTreeMap<Arc<str>, Ty>,
7968        role: &str,
7969    ) {
7970        if arg.spread {
7971            let ty = self.expr(&arg.value, None);
7972            let spread_element = match &ty {
7973                Ty::Array(inner) | Ty::Vector(inner) => (**inner).clone(),
7974                Ty::Unknown(_) | Ty::Never => ty.abstain(),
7975                Ty::Any => Ty::Any,
7976                other => {
7977                    self.diagnostics.push(
7978                        Diagnostic::error(
7979                            MISMATCH,
7980                            format!("`...` spreads an `Array` or a `Vector`, but found `{other}`"),
7981                        )
7982                        .at(arg.span)
7983                        .label(param.span, format!("`{}` is variadic", param.name))
7984                        .rule("A variadic parameter is an `Array<T>`, so a spread argument must be a sequence of `T`.")
7985                        .help(format!("pass the value directly, as in `f(<{other}>)`")),
7986                    );
7987                    return;
7988                }
7989            };
7990            if !unify(element, &spread_element, generic_set, subst, &self.view()) {
7991                self.diagnostics.push(
7992                    Diagnostic::error(
7993                        MISMATCH,
7994                        format!("expected `{element}`, found `{spread_element}`"),
7995                    )
7996                    .at(arg.span)
7997                    .label(param.span, format!("`{}` is `{element}...`", param.name))
7998                    .rule("A variadic parameter is an `Array<T>`; every spread element is a `T`.")
7999                    .help(format!("spread a sequence of `{element}`")),
8000                );
8001            }
8002            return;
8003        }
8004        let hint = self.open(element, generics, subst);
8005        let hint_expected = Expected::new(
8006            hint.clone(),
8007            param.span,
8008            format!("{role} `{}` is `{}`", param.name, param.ty),
8009        );
8010        let found = self.expr(&arg.value, Some(&hint_expected));
8011        self.check_argument(
8012            &found,
8013            &hint,
8014            element,
8015            arg.span,
8016            param,
8017            generic_set,
8018            subst,
8019            role,
8020        );
8021    }
8022
8023    fn report_argument(
8024        &mut self,
8025        found: &Ty,
8026        expected: &Ty,
8027        span: Span,
8028        param: &ParamSig,
8029        role: &str,
8030    ) {
8031        if found.matches(expected) {
8032            return;
8033        }
8034        let mut diagnostic = Diagnostic::error(
8035            MISMATCH,
8036            format!("expected `{expected}`, found `{found}`"),
8037        )
8038        .at(span)
8039        .label(param.span, format!("{role} `{}` is `{}`", param.name, param.ty))
8040        .rule("Types are nominal and there are no implicit conversions: an argument must already have the parameter's type.");
8041        if let Some(help) = conversion_help(expected, found) {
8042            diagnostic = diagnostic.help(help);
8043        }
8044        self.diagnostics.push(diagnostic);
8045    }
8046
8047    /// A trailing block is a closure argument: `tasks.spawn { ... }` is a
8048    /// function of no parameters.
8049    fn trailing_type(&mut self, trailing: &Expr, expected: Option<&Ty>) -> Ty {
8050        match &trailing.kind {
8051            ExprKind::Block(block) => {
8052                let ret = match expected {
8053                    Some(Ty::Fn(func)) => Some(func.ret.clone()),
8054                    // A block given to a place this pass abstained about is
8055                    // a body with an explanation of its own, made where the
8056                    // abstention was. Passing it down is what keeps an empty
8057                    // array or a bare `None` inside `clock.timeout(1s) { .. }`
8058                    // from being asked to state a type nothing outside it
8059                    // stated either.
8060                    Some(ty) if ty.is_accounted_for() => Some(ty.clone()),
8061                    _ => None,
8062                };
8063                let hint = ret.clone().map(|ty| match ty.is_wild() {
8064                    true => Expected::abstained(ty),
8065                    false => {
8066                        let label = format!("the trailing closure produces `{ty}`");
8067                        Expected::new(ty, trailing.span, label)
8068                    }
8069                });
8070                let ty = self.block(block, hint.as_ref());
8071                Ty::func(
8072                    false,
8073                    Vec::new(),
8074                    ret.filter(|ty| !ty.is_wild()).unwrap_or(ty),
8075                )
8076            }
8077            _ => {
8078                let hint = expected.cloned().map(|ty| match ty.is_accounted_for() {
8079                    true => Expected::abstained(ty),
8080                    false => {
8081                        let label = format!("the trailing argument is `{ty}`");
8082                        Expected::new(ty, trailing.span, label)
8083                    }
8084                });
8085                self.expr(trailing, hint.as_ref())
8086            }
8087        }
8088    }
8089
8090    /// Checks every argument of a call whose callee has no signature, so an
8091    /// error inside one is still reported.
8092    fn check_args_freely(&mut self, args: &[Arg], trailing: Option<&Expr>) {
8093        self.check_args_abstained(args, trailing, Ty::recovery());
8094    }
8095
8096    /// Walks every argument of a call this pass has stopped checking,
8097    /// against an unknown that says why.
8098    ///
8099    /// Each argument is still walked, because a mistake inside one is a
8100    /// mistake wherever the call went wrong. What it is *not* is walked
8101    /// against nothing: a place typed by an unknown the checker has already
8102    /// accounted for is a place with an explanation, and giving the argument
8103    /// that explanation is what stops one rejected call from also reporting
8104    /// the empty array, the bare `None`, and the unannotated lambda
8105    /// parameter it happened to be written with.
8106    ///
8107    /// The two callers are the two reasons a call stops being checked: an
8108    /// error already reported about it ([`Ty::recovery`]), and a host module
8109    /// no schema describes ([`Ty::dynamic_boundary`]).
8110    fn check_args_abstained(&mut self, args: &[Arg], trailing: Option<&Expr>, why: Ty) {
8111        let expected = Expected::abstained(why.clone());
8112        for arg in args {
8113            self.expr(&arg.value, Some(&expected));
8114        }
8115        if let Some(trailing) = trailing {
8116            self.trailing_type(trailing, Some(&why));
8117        }
8118    }
8119
8120    // ----------------------------------------------------------- traits
8121
8122    /// What a conformance question needs to be answered: the module's
8123    /// declared conformances, plus the bounds of the type parameters in
8124    /// scope, since a bounded parameter conforms to the traits it is bounded
8125    /// by.
8126    fn view(&self) -> ConformanceView<'_> {
8127        ConformanceView {
8128            declared: &self.conformances,
8129            bounds: &self.bounds,
8130        }
8131    }
8132
8133    /// Checks every bound of `sig` against the types its call site chose.
8134    ///
8135    /// A bound is checked here, at the call, because that is where a type
8136    /// parameter is instantiated; inside the body the parameter is rigid and
8137    /// its bound is a fact rather than an obligation.
8138    fn check_bounds(
8139        &mut self,
8140        sig: &FnSig,
8141        subst: &BTreeMap<Arc<str>, Ty>,
8142        what: &str,
8143        span: Span,
8144    ) {
8145        for (param, bounds) in &sig.bounds {
8146            let Some(ty) = subst.get(param) else {
8147                continue;
8148            };
8149            if ty.is_wild() {
8150                continue;
8151            }
8152            for bound in bounds {
8153                if conforms(ty, &bound.name, &self.view()) {
8154                    continue;
8155                }
8156                // `dyn Trait` is a type, not a type parameter, so it never
8157                // stands in for one even when it names the very same trait.
8158                let (message, help) = if let Ty::Dyn(trait_name) = ty {
8159                    (
8160                        format!("`dyn {trait_name}` cannot be used as a type argument"),
8161                        format!(
8162                            "pass a concrete value that conforms to `{}`, or declare the parameter as `dyn {}` instead of `{param}`",
8163                            bound.name, bound.name
8164                        ),
8165                    )
8166                } else {
8167                    (
8168                        format!("`{ty}` does not conform to `{}`", bound.name),
8169                        format!("write `impl {} for {ty} {{ ... }}`", bound.name),
8170                    )
8171                };
8172                self.diagnostics.push(
8173                    Diagnostic::error(UNSATISFIED_BOUND, message)
8174                        .at(span)
8175                        .label(
8176                            bound.span,
8177                            format!("{what} requires `{param}: {}`", bound.name),
8178                        )
8179                        .rule("A type argument must conform to every trait its type parameter is bounded by, and conformance is explicit: only an `impl Trait for Type` block declares one.")
8180                        .help(help),
8181                );
8182            }
8183        }
8184    }
8185
8186    /// Whether the trait method named `method` declares a `var self`
8187    /// receiver.
8188    fn mutating_trait_method(&self, trait_name: &str, method: &str) -> bool {
8189        self.trait_entry(trait_name)
8190            .and_then(|entry| entry.method(method))
8191            .and_then(|method| method.receiver)
8192            .is_some_and(|receiver| receiver.is_var)
8193    }
8194
8195    /// The trait among `T`'s bounds that declares `method`, with its
8196    /// signature.
8197    fn bound_method(&self, param: &str, method: &str) -> Option<(Arc<str>, FnSig)> {
8198        for bound in self.bounds.get(param)? {
8199            if let Some(sig) = self.traits.get(&*bound.name).and_then(|m| m.get(method)) {
8200                return Some((bound.name.clone(), sig.clone()));
8201            }
8202        }
8203        None
8204    }
8205
8206    /// A method call on a value whose type is the type parameter `param`.
8207    ///
8208    /// Resolution goes through the parameter's bounds: a parameter with no
8209    /// bound has no operations at all, which is the whole reason a bound is
8210    /// written.
8211    fn param_method_call(
8212        &mut self,
8213        param: &Arc<str>,
8214        name: &Ident,
8215        args: &[Arg],
8216        trailing: Option<&Expr>,
8217        span: Span,
8218    ) -> Ty {
8219        if let Some((trait_name, sig)) = self.bound_method(param, &name.node) {
8220            return self.call_signature(
8221                &sig,
8222                &format!("`{trait_name}.{}`", name.node),
8223                Vec::new(),
8224                args,
8225                trailing,
8226                span,
8227            );
8228        }
8229        let diagnostic = match self.bounds.get(param) {
8230            None => Diagnostic::error(
8231                UNBOUNDED_PARAMETER,
8232                format!("`{param}` has no bound, so it has no method `{}`", name.node),
8233            )
8234            .rule("A method call on a type parameter resolves through the parameter's bounds; an unbounded parameter's values can only be moved, not inspected.")
8235            .help(format!(
8236                "bound the parameter, as in `<{param}: SomeTrait>`, and declare `{}` in that trait",
8237                name.node
8238            )),
8239            Some(bounds) => {
8240                let names: Vec<String> = bounds.iter().map(|b| b.name.to_string()).collect();
8241                Diagnostic::error(
8242                    UNKNOWN_METHOD,
8243                    format!(
8244                        "no trait `{param}` is bounded by declares a method `{}`",
8245                        name.node
8246                    ),
8247                )
8248                .rule("A method call on a type parameter resolves through the parameter's bounds.")
8249                .help(format!(
8250                    "`{param}` is bounded by {}; declare `{}` in one of them, or add another bound",
8251                    list(&names),
8252                    name.node
8253                ))
8254            }
8255        };
8256        self.diagnostics.push(diagnostic.at(span));
8257        self.check_args_freely(args, trailing);
8258        Ty::recovery()
8259    }
8260
8261    /// A method call on a `dyn Trait` value.
8262    ///
8263    /// Only the trait's `self`-taking methods are reachable: an associated
8264    /// function has no receiver to dispatch on, so a trait object cannot
8265    /// find an implementation for it.
8266    fn dyn_method_call(
8267        &mut self,
8268        trait_name: &Arc<str>,
8269        name: &Ident,
8270        args: &[Arg],
8271        trailing: Option<&Expr>,
8272        span: Span,
8273    ) -> Ty {
8274        let sig = self
8275            .traits
8276            .get(&**trait_name)
8277            .and_then(|methods| methods.get(&name.node))
8278            .cloned();
8279        let Some(sig) = sig else {
8280            let known: Vec<String> = self
8281                .traits
8282                .get(&**trait_name)
8283                .map(|methods| methods.keys().cloned().collect())
8284                .unwrap_or_default();
8285            self.diagnostics.push(
8286                Diagnostic::error(
8287                    UNKNOWN_METHOD,
8288                    format!("`{trait_name}` has no method `{}`", name.node),
8289                )
8290                .at(span)
8291                .rule("A call on a `dyn Trait` value reaches the trait's methods and nothing else: the concrete type is not known here.")
8292                .help(if known.is_empty() {
8293                    format!("`{trait_name}` declares no methods")
8294                } else {
8295                    format!("`{trait_name}` declares {}", list(&known))
8296                }),
8297            );
8298            self.check_args_freely(args, trailing);
8299            return Ty::recovery();
8300        };
8301        if sig.receiver.is_none() {
8302            self.diagnostics.push(
8303                Diagnostic::error(
8304                    DYN_ASSOCIATED,
8305                    format!(
8306                        "`{trait_name}.{}` takes no `self`, so it cannot be called through `dyn {trait_name}`",
8307                        name.node
8308                    ),
8309                )
8310                .at(span)
8311                .rule("Only a trait method whose first parameter is `self` may be called through `dyn Trait`: an associated function has no receiver to dispatch on.")
8312                .help(format!(
8313                    "call it on a concrete type, as in `SomeType.{}(...)`, or give it a `self` parameter",
8314                    name.node
8315                )),
8316            );
8317            self.check_args_freely(args, trailing);
8318            return Ty::recovery();
8319        }
8320        // Conversion to `dyn Trait` produces a value, exactly as assignment
8321        // and argument passing do, so a mutation made through the trait
8322        // object could not be observed by whatever the value came from.
8323        if self.mutating_trait_method(trait_name, &name.node) {
8324            self.diagnostics.push(
8325                Diagnostic::error(
8326                    DYN_MUTATING,
8327                    format!(
8328                        "`{trait_name}.{}` takes `var self`, so it cannot be called through `dyn {trait_name}`",
8329                        name.node
8330                    ),
8331                )
8332                .at(span)
8333                .rule("A concrete value becomes a `dyn Trait` value by conversion, and a conversion produces a value; a mutating receiver needs the caller's own place, which a converted value is not.")
8334                .help(format!(
8335                    "call `{}` on the concrete value before converting it, or declare the method with `self`",
8336                    name.node
8337                )),
8338            );
8339            self.check_args_freely(args, trailing);
8340            return Ty::recovery();
8341        }
8342        self.call_signature(
8343            &sig,
8344            &format!("`{trait_name}.{}`", name.node),
8345            Vec::new(),
8346            args,
8347            trailing,
8348            span,
8349        )
8350    }
8351
8352    // ------------------------------------------------------------ methods
8353
8354    /// Records that the call `id` reaches the method `method` declared on
8355    /// the type `key` names.
8356    ///
8357    /// `key` is a canonical name — bare for a type this module declares, and
8358    /// `module.Name` for one it meets through an import — so splitting it is
8359    /// what turns "the name this checker files it under" into "the
8360    /// declaration", which is what a consumer needs and what is the same
8361    /// answer read from anywhere in the package.
8362    ///
8363    /// The split is at the **last** dot, because a module's name may hold one
8364    /// and a type's name may not: `module_opaque.account.Account` is the type
8365    /// `Account` of the module `module_opaque.account`, and splitting at the
8366    /// first dot would file it under `module_opaque` as a type called
8367    /// `account.Account`, which nothing declares.
8368    /// Records the boundary of the declaration whose body is about to be
8369    /// checked.
8370    ///
8371    /// The types are `sig`'s own — the ones this checker resolved for *this*
8372    /// declaration and is about to check the body against — rather than a
8373    /// second reading of `decl`'s annotations. That is the whole point:
8374    /// [`crate::facts`] exists so that a consumer and the checker cannot
8375    /// disagree, and a re-derivation here would be exactly the disagreement
8376    /// it prevents.
8377    ///
8378    /// A variadic parameter is recorded as what it was written as rather
8379    /// than as the `Array<T>` the body sees, because a call supplies the
8380    /// element and the array is what the callee makes of them. Which of the
8381    /// two questions [`Signature::params`] answers is stated on the field
8382    /// itself, where a consumer reads it, rather than only here.
8383    ///
8384    /// Recording is not deciding: this is called before the walk and read by
8385    /// nothing during it, so no diagnostic depends on it.
8386    fn record_signature(&mut self, decl: &FnDecl, sig: &FnSig) {
8387        self.facts.record_signature(
8388            decl.span.file,
8389            decl.span,
8390            Signature {
8391                receiver: sig.receiver.clone(),
8392                params: sig.params.iter().map(|param| param.ty.clone()).collect(),
8393                ret: sig.ret.clone(),
8394            },
8395        );
8396    }
8397
8398    /// Records the boundary of a struct declaration's initializer.
8399    ///
8400    /// `Point(x: 0.0, y: 1.0)` is a call, and the thing it calls is a
8401    /// signature this checker synthesizes out of the declaration's fields —
8402    /// which is why [`ParamSig`] documents itself as covering one. Recording
8403    /// it here is what publishes a struct's *resolved* field types, in
8404    /// declaration order, to anything downstream that holds a value to the
8405    /// declaration rather than reading a field out of one.
8406    ///
8407    /// The types are the declaration's own, so a generic struct's field is
8408    /// recorded as the `Ty::Param` it was written as; a consumer holding a
8409    /// use completes it with [`Ty::instantiate`]. Recording is not deciding,
8410    /// exactly as for [`Checker::record_signature`].
8411    fn record_struct_signature(&mut self, decl: &StructDecl, sig: &StructSig) {
8412        let ret = Ty::Struct(
8413            self.key(&decl.name.node).into(),
8414            sig.generics.iter().cloned().map(Ty::Param).collect(),
8415        );
8416        self.facts.record_signature(
8417            decl.span.file,
8418            decl.span,
8419            Signature {
8420                receiver: None,
8421                params: sig.fields.iter().map(|field| field.ty.clone()).collect(),
8422                ret,
8423            },
8424        );
8425    }
8426
8427    /// The same for each of an enum's cases, whose payload types a case
8428    /// expression is checked against.
8429    ///
8430    /// One record per case rather than one per enum, because a case is what a
8431    /// program names and a value carries: `Verdict.Drop(reason)` is the call,
8432    /// and the case's own span is what a consumer holding the declaration
8433    /// already has to key by.
8434    fn record_case_signatures(&mut self, decl: &EnumDecl, sig: &EnumSig) {
8435        let ret = Ty::Enum(
8436            self.key(&decl.name.node).into(),
8437            sig.generics.iter().cloned().map(Ty::Param).collect(),
8438        );
8439        for (case, declared) in decl.cases.iter().zip(&sig.cases) {
8440            self.facts.record_signature(
8441                case.span.file,
8442                case.span,
8443                Signature {
8444                    receiver: None,
8445                    params: declared.payload.clone(),
8446                    ret: ret.clone(),
8447                },
8448            );
8449        }
8450    }
8451
8452    fn record_target(&mut self, id: ExprId, file: FileId, key: &str, method: &str) {
8453        let (module, type_name) = match key.rsplit_once('.') {
8454            Some((module, name)) => (module.to_string(), name.to_string()),
8455            None => (self.module.name.clone(), key.to_string()),
8456        };
8457        self.facts.record_target(
8458            file,
8459            id,
8460            MethodTarget {
8461                module,
8462                type_name,
8463                method: method.to_string(),
8464            },
8465        );
8466    }
8467
8468    fn method_call(
8469        &mut self,
8470        id: ExprId,
8471        receiver: &Ty,
8472        name: &Ident,
8473        args: &[Arg],
8474        trailing: Option<&Expr>,
8475        span: Span,
8476    ) -> Ty {
8477        match receiver {
8478            Ty::Unknown(_) | Ty::Never => {
8479                self.check_args_freely(args, trailing);
8480                return receiver.abstain();
8481            }
8482            // A method called on a value a schema declared `Any` is
8483            // dispatched by the boundary at run time, and what it answers is
8484            // as unstated as the receiver was.
8485            Ty::Any => {
8486                self.check_args_freely(args, trailing);
8487                return Ty::Any;
8488            }
8489            Ty::Struct(type_name, type_args) | Ty::Enum(type_name, type_args) => {
8490                let key = (type_name.to_string(), name.node.clone());
8491                if let Some(sig) = self.methods.get(&key).cloned() {
8492                    self.record_target(id, span.file, type_name, &name.node);
8493                    self.check_receiver(&sig, type_name, &name.node, span, true);
8494                    let generics = self.declared_generics(type_name);
8495                    let subst = substitution(&generics, type_args);
8496                    let sig = FnSig {
8497                        generics: sig
8498                            .generics
8499                            .iter()
8500                            .filter(|g| !generics.contains(g))
8501                            .cloned()
8502                            .collect(),
8503                        params: sig
8504                            .params
8505                            .iter()
8506                            .map(|p| ParamSig {
8507                                ty: p.ty.substitute(&subst),
8508                                ..p.clone()
8509                            })
8510                            .collect(),
8511                        ret: sig.ret.substitute(&subst),
8512                        ..sig
8513                    };
8514                    return self.call_signature(
8515                        &sig,
8516                        &format!("`{type_name}.{}`", name.node),
8517                        Vec::new(),
8518                        args,
8519                        trailing,
8520                        span,
8521                    );
8522                }
8523                let known = self.known_members(type_name);
8524                self.diagnostics.push(
8525                    Diagnostic::error(
8526                        UNKNOWN_METHOD,
8527                        format!("`{type_name}` has no method `{}`", name.node),
8528                    )
8529                    .at(span)
8530                    .rule("A method is declared in its type's `impl` block.")
8531                    .help(format!("`{type_name}` declares {known}")),
8532                );
8533                self.check_args_freely(args, trailing);
8534                return Ty::recovery();
8535            }
8536            Ty::Param(param) => {
8537                let param = param.clone();
8538                return self.param_method_call(&param, name, args, trailing, span);
8539            }
8540            Ty::Dyn(trait_name) => {
8541                let trait_name = trait_name.clone();
8542                return self.dyn_method_call(&trait_name, name, args, trailing, span);
8543            }
8544            Ty::Host(declared) => {
8545                let declared = declared.clone();
8546                return self.host_method_call(&declared, name, args, trailing, span);
8547            }
8548            _ => {}
8549        }
8550
8551        if let (Ty::Result(ok, error), "mapError") = (receiver, name.node.as_str()) {
8552            return self.map_error(ok, error, args, trailing, span);
8553        }
8554
8555        // `Snapshot` is the one trait a closure, a task, a task scope, and a
8556        // synchronized value never conform to: none has an independent
8557        // mutable graph this side of a lock to copy. `builtin_method` would
8558        // otherwise report this as an ordinary unknown method, which does not
8559        // say why.
8560        if name.node == "snapshot"
8561            && matches!(
8562                receiver,
8563                Ty::Fn(_) | Ty::Task(_) | Ty::Scope | Ty::Shared(_)
8564            )
8565        {
8566            self.diagnostics
8567                .push(no_snapshot_conformance(receiver, span));
8568            self.check_args_freely(args, trailing);
8569            return Ty::recovery();
8570        }
8571
8572        match builtin_method(receiver, &name.node) {
8573            Some(sig) => {
8574                let what = format!("`{}.{}`", builtin_name(receiver), name.node);
8575                self.call_builtin(&sig, &what, args, trailing, span)
8576            }
8577            None => {
8578                self.diagnostics
8579                    .push(unknown_builtin_method(receiver, &name.node, span));
8580                self.check_args_freely(args, trailing);
8581                Ty::recovery()
8582            }
8583        }
8584    }
8585
8586    /// `result.mapError(fn(error) { ... })`, which replaces a `Result`'s
8587    /// failure with whatever its callback produces.
8588    ///
8589    /// The callback's declared type is `fn(E) -> F`, matched exactly like
8590    /// any other callback in the language — there is no exception for a
8591    /// callback that ignores the error.
8592    fn map_error(
8593        &mut self,
8594        ok: &Ty,
8595        error: &Ty,
8596        args: &[Arg],
8597        trailing: Option<&Expr>,
8598        span: Span,
8599    ) -> Ty {
8600        let callback: Option<&Expr> = match (args.first(), trailing) {
8601            (Some(arg), None) => Some(&arg.value),
8602            (None, Some(trailing)) => Some(trailing),
8603            _ => None,
8604        };
8605        let count = args.len() + usize::from(trailing.is_some());
8606        if count != 1 {
8607            self.diagnostics.push(
8608                Diagnostic::error(
8609                    ARITY,
8610                    format!("`Result.mapError` takes 1 argument, but {count} were given"),
8611                )
8612                .at(span)
8613                .rule("`mapError` replaces a failure with the value its one callback produces.")
8614                .help("write `result.mapError(fn(error) { ... })`"),
8615            );
8616        }
8617        let Some(callback) = callback else {
8618            self.check_args_freely(args, trailing);
8619            return Ty::Result(Box::new(ok.clone()), Box::new(Ty::recovery()));
8620        };
8621        let expected = Ty::func(
8622            false,
8623            vec![error.clone()],
8624            // The callback's own result is what replaces the failure type,
8625            // so the expectation states the parameters and leaves the result
8626            // to the body.
8627            Ty::placeholder(),
8628        );
8629        let found = self.trailing_type(callback, Some(&expected));
8630        let replacement = match &found {
8631            Ty::Fn(func) => func.ret.clone(),
8632            _ => Ty::recovery(),
8633        };
8634        Ty::Result(Box::new(ok.clone()), Box::new(replacement))
8635    }
8636
8637    /// Checks a call against a builtin signature, which binds no generics of
8638    /// its own beyond those already substituted into it.
8639    fn call_builtin(
8640        &mut self,
8641        sig: &BuiltinSig,
8642        what: &str,
8643        args: &[Arg],
8644        trailing: Option<&Expr>,
8645        span: Span,
8646    ) -> Ty {
8647        let subst = self.builtin_arguments(sig, what, args, trailing, span);
8648        self.open_result(&sig.ret, &sig.generics, &subst, span)
8649    }
8650
8651    /// The arguments of a builtin call, checked against the parameters, and
8652    /// what they settled the signature's own type parameters to.
8653    ///
8654    /// Split out from [`Checker::call_builtin`] so that an associated
8655    /// function can look at the bindings before its result is opened: an
8656    /// empty `Vector.of()` settles nothing here and the place that holds it
8657    /// is what says what it holds. See
8658    /// [`Checker::settle_from_expectation`].
8659    fn builtin_arguments(
8660        &mut self,
8661        sig: &BuiltinSig,
8662        what: &str,
8663        args: &[Arg],
8664        trailing: Option<&Expr>,
8665        span: Span,
8666    ) -> BTreeMap<Arc<str>, Ty> {
8667        let last = sig.params.len().saturating_sub(1);
8668        let params: Vec<ParamSig> = sig
8669            .params
8670            .iter()
8671            .enumerate()
8672            .map(|(index, (name, ty))| ParamSig {
8673                name: (*name).to_string(),
8674                ty: ty.clone(),
8675                variadic: sig.variadic && index == last,
8676                has_default: false,
8677                is_var: false,
8678                span,
8679            })
8680            .collect();
8681        self.match_arguments(
8682            &params,
8683            &sig.generics,
8684            BTreeMap::new(),
8685            args,
8686            trailing,
8687            span,
8688            what,
8689            "the parameter",
8690        )
8691    }
8692
8693    /// Reports a method called as an associated function, or an associated
8694    /// function called on a value.
8695    ///
8696    /// A method's first parameter is its receiver, written `self` or `var
8697    /// self`; an associated function has none. Which one a declaration is,
8698    /// is part of its type.
8699    fn check_receiver(
8700        &mut self,
8701        sig: &FnSig,
8702        type_name: &str,
8703        name: &str,
8704        span: Span,
8705        given: bool,
8706    ) {
8707        match (sig.receiver.is_some(), given) {
8708            (true, false) => self.diagnostics.push(
8709                Diagnostic::error(
8710                    RECEIVER,
8711                    format!("`{type_name}.{name}` is a method and needs a receiver"),
8712                )
8713                .at(span)
8714                .rule("A method is called on a value; only an associated function is called on its type.")
8715                .help(format!(
8716                    "call it on a value, as in `value.{name}(...)`, or declare `fn {name}()` without `self`"
8717                )),
8718            ),
8719            (false, true) => self.diagnostics.push(
8720                Diagnostic::error(
8721                    RECEIVER,
8722                    format!("`{type_name}.{name}` takes no receiver"),
8723                )
8724                .at(span)
8725                .rule("An associated function is called on its type; only a method is called on a value.")
8726                .help(format!("write `{type_name}.{name}(...)`")),
8727            ),
8728            _ => {}
8729        }
8730    }
8731
8732    /// The type parameters a struct or enum declares.
8733    fn declared_generics(&self, name: &str) -> Vec<Arc<str>> {
8734        if let Some(sig) = self.structs.get(name) {
8735            return sig.generics.clone();
8736        }
8737        if let Some(sig) = self.enums.get(name) {
8738            return sig.generics.clone();
8739        }
8740        Vec::new()
8741    }
8742
8743    /// The methods and cases a diagnostic can suggest for `type_name`.
8744    fn known_members(&self, type_name: &str) -> String {
8745        let mut names: Vec<String> = self
8746            .methods
8747            .keys()
8748            .filter(|(owner, _)| owner == type_name)
8749            .map(|(_, name)| name.clone())
8750            .collect();
8751        if let Some(sig) = self.enums.get(type_name) {
8752            names.extend(sig.cases.iter().map(|c| c.name.clone()));
8753        }
8754        if names.is_empty() {
8755            format!("no methods; declare one in `impl {type_name}`")
8756        } else {
8757            list(&names)
8758        }
8759    }
8760}
8761
8762// ------------------------------------------------------------- entry shape
8763
8764/// Checks every `[run.<name>]` entry against the shape the host boundary
8765/// calls: no parameters or one `Array<String>` of process arguments, and a
8766/// value the host can report.
8767fn check_entries(
8768    package: &Package,
8769    checked: &BTreeMap<&str, Checker<'_>>,
8770    diagnostics: &mut Vec<Diagnostic>,
8771) {
8772    for run in package.config.runs.values() {
8773        let Some((module_name, entry)) = run.entry_parts() else {
8774            continue;
8775        };
8776        let Some(checker) = checked.get(module_name) else {
8777            continue;
8778        };
8779        let Some(sig) = checker.functions.get(entry) else {
8780            continue;
8781        };
8782        let Some(function) = checker.module.functions.get(entry) else {
8783            continue;
8784        };
8785        let name_span = function.decl.name.span;
8786
8787        if sig.params.len() > 1 {
8788            diagnostics.push(
8789                Diagnostic::error(
8790                    ENTRY,
8791                    format!(
8792                        "entry `{}` declares {} parameters",
8793                        run.entry,
8794                        sig.params.len()
8795                    ),
8796                )
8797                .at(name_span)
8798                .rule("An entry function takes either no parameters or one `Array<String>` of process arguments.")
8799                .help(format!(
8800                    "write `fn {entry}()` or `fn {entry}(args: Array<String>)`"
8801                )),
8802            );
8803        } else if let Some(param) = sig.params.first() {
8804            let expected = Ty::Array(Box::new(Ty::Str));
8805            if !param.ty.matches(&expected) {
8806                diagnostics.push(
8807                    Diagnostic::error(
8808                        ENTRY,
8809                        format!(
8810                            "entry `{}` takes `{}`, but the host passes `Array<String>`",
8811                            run.entry, param.ty
8812                        ),
8813                    )
8814                    .at(param.span)
8815                    .rule("An entry function's one parameter is the process arguments, an `Array<String>`.")
8816                    .help(format!("write `fn {entry}(args: Array<String>)`")),
8817                );
8818            }
8819        }
8820
8821        if !matches!(
8822            sig.ret,
8823            Ty::Unit | Ty::Result(_, _) | Ty::Unknown(_) | Ty::Any
8824        ) {
8825            diagnostics.push(
8826                Diagnostic::error(
8827                    ENTRY,
8828                    format!(
8829                        "entry `{}` returns `{}`, which the host cannot report",
8830                        run.entry, sig.ret
8831                    ),
8832                )
8833                .at(sig.ret_span)
8834                .rule("The host reports an entry's failure through its `Err`, so an entry returns `()` or a `Result`.")
8835                .help(format!(
8836                    "write `fn {entry}(...) -> Result<{}, Error>`",
8837                    sig.ret
8838                )),
8839            );
8840        }
8841    }
8842}
8843
8844// -------------------------------------------------------------- unification
8845
8846/// Unifies a parameter type with an argument type, binding the callee's own
8847/// type parameters in `subst`.
8848///
8849/// This is the whole of ADR 0004's "unify at the call site, substitute into
8850/// the signature": a type parameter binds to the first type it meets and
8851/// must match every later one, and nothing else is inferred.
8852fn unify(
8853    param: &Ty,
8854    arg: &Ty,
8855    generics: &BTreeSet<Arc<str>>,
8856    subst: &mut BTreeMap<Arc<str>, Ty>,
8857    view: &ConformanceView<'_>,
8858) -> bool {
8859    if coerces(arg, param, view) {
8860        return true;
8861    }
8862    if let Ty::Param(name) = param {
8863        if generics.contains(name) {
8864            return match subst.get(name) {
8865                Some(bound) => bound.matches(arg),
8866                None => {
8867                    if !arg.is_wild() {
8868                        subst.insert(name.clone(), arg.clone());
8869                    }
8870                    true
8871                }
8872            };
8873        }
8874    }
8875    if param.is_wild() || arg.is_wild() {
8876        return true;
8877    }
8878    match (param, arg) {
8879        (Ty::Array(a), Ty::Array(b))
8880        | (Ty::Vector(a), Ty::Vector(b))
8881        | (Ty::Set(a), Ty::Set(b))
8882        | (Ty::Option(a), Ty::Option(b))
8883        | (Ty::Task(a), Ty::Task(b))
8884        | (Ty::Shared(a), Ty::Shared(b)) => unify(a, b, generics, subst, view),
8885        (Ty::Map(ak, av), Ty::Map(bk, bv))
8886        | (Ty::MapEntry(ak, av), Ty::MapEntry(bk, bv))
8887        | (Ty::Result(ak, av), Ty::Result(bk, bv)) => {
8888            unify(ak, bk, generics, subst, view) && unify(av, bv, generics, subst, view)
8889        }
8890        (Ty::Struct(a, aargs), Ty::Struct(b, bargs)) | (Ty::Enum(a, aargs), Ty::Enum(b, bargs)) => {
8891            a == b
8892                && aargs.len() == bargs.len()
8893                && aargs
8894                    .iter()
8895                    .zip(bargs)
8896                    .all(|(a, b)| unify(a, b, generics, subst, view))
8897        }
8898        (Ty::Fn(a), Ty::Fn(b)) => {
8899            a.is_async == b.is_async
8900                && a.params.len() == b.params.len()
8901                && a.params
8902                    .iter()
8903                    .zip(&b.params)
8904                    .all(|(a, b)| unify(a, b, generics, subst, view))
8905                && unify(&a.ret, &b.ret, generics, subst, view)
8906        }
8907        (param, arg) => param.matches(arg),
8908    }
8909}
8910
8911/// Everything needed to answer "does this type conform to this trait?".
8912///
8913/// Conformance is explicit, so `declared` is the complete set of `(trait,
8914/// type)` pairs the module has an `impl Trait for Type` block for. `bounds`
8915/// adds the type parameters currently in scope, which conform to whatever
8916/// they are bounded by.
8917struct ConformanceView<'c> {
8918    declared: &'c BTreeSet<(String, String)>,
8919    bounds: &'c BTreeMap<Arc<str>, Vec<TraitBound>>,
8920}
8921
8922/// Whether `ty` conforms to the trait named `trait_name`.
8923///
8924/// `Unknown` and `Never` conform to everything, for the same reason they
8925/// match everything: the checker has abstained and must not turn its own
8926/// silence into an error.
8927fn conforms(ty: &Ty, trait_name: &str, view: &ConformanceView<'_>) -> bool {
8928    match ty {
8929        Ty::Unknown(_) | Ty::Any | Ty::Never => true,
8930        Ty::Struct(name, _) | Ty::Enum(name, _) => view
8931            .declared
8932            .contains(&(trait_name.to_string(), name.to_string())),
8933        // A type parameter conforms to exactly the traits it is bounded by,
8934        // which is what lets one bounded function call another.
8935        Ty::Param(name) => view
8936            .bounds
8937            .get(name)
8938            .is_some_and(|bounds| bounds.iter().any(|b| &*b.name == trait_name)),
8939        // A `dyn Trait` value is not a type parameter and never stands in for
8940        // one, so it satisfies no bound — not even its own trait's.
8941        _ => false,
8942    }
8943}
8944
8945/// Whether a value of type `found` may be used where `expected` is written.
8946///
8947/// This is the language's only implicit conversion, and it is deliberately
8948/// narrow: a concrete value becomes a `dyn Trait` value when it conforms to
8949/// that trait, and nothing else converts. In particular the conversion does
8950/// not run in reverse (a `dyn Trait` is not a concrete type), does not chain
8951/// through another trait, and does not reach inside a generic argument —
8952/// `Array<Booking>` is not an `Array<dyn Display>`, because `Array` is
8953/// invariant like every other generic type. Writing `[booking, receipt]`
8954/// where an `Array<dyn Display>` is expected does work, because each element
8955/// is checked against `dyn Display` on its own.
8956fn coerces(found: &Ty, expected: &Ty, view: &ConformanceView<'_>) -> bool {
8957    let Ty::Dyn(trait_name) = expected else {
8958        return false;
8959    };
8960    !matches!(found, Ty::Dyn(_)) && conforms(found, trait_name, view)
8961}
8962
8963/// A name written after `dyn` or after `:` in a bound that names no trait.
8964fn unknown_trait(name: &str, span: Span) -> Diagnostic {
8965    Diagnostic::error(UNKNOWN_TRAIT, format!("`{name}` is not a trait"))
8966        .at(span)
8967        .rule("`dyn` and a type parameter's bound both name a trait the module declares; there are no module-to-module imports yet.")
8968        .help(format!(
8969            "declare `trait {name} {{ ... }}` in this module, or name a trait that exists"
8970        ))
8971}
8972
8973/// How a conformance's method differs from the signature its trait declares,
8974/// or `None` when the two agree.
8975fn signature_difference(declared: &FnSig, found: &FnSig) -> Option<String> {
8976    if declared.receiver.is_some() != found.receiver.is_some() {
8977        return Some(if declared.receiver.is_some() {
8978            "it takes no `self`".to_string()
8979        } else {
8980            "it takes a `self` the trait does not declare".to_string()
8981        });
8982    }
8983    if declared.is_async != found.is_async {
8984        return Some(if declared.is_async {
8985            "it is not `async`".to_string()
8986        } else {
8987            "it is `async`".to_string()
8988        });
8989    }
8990    if declared.params.len() != found.params.len() {
8991        return Some(format!(
8992            "it takes {} parameter(s), not {}",
8993            found.params.len(),
8994            declared.params.len()
8995        ));
8996    }
8997    for (want, got) in declared.params.iter().zip(&found.params) {
8998        if want.name != got.name {
8999            return Some(format!(
9000                "its parameter `{}` is named `{}` in the trait",
9001                got.name, want.name
9002            ));
9003        }
9004        if !want.ty.matches(&got.ty) {
9005            return Some(format!(
9006                "its parameter `{}` is `{}`, not `{}`",
9007                got.name, got.ty, want.ty
9008            ));
9009        }
9010    }
9011    if !declared.ret.matches(&found.ret) {
9012        return Some(format!(
9013            "it returns `{}`, not `{}`",
9014            found.ret, declared.ret
9015        ));
9016    }
9017    None
9018}
9019
9020/// A trait method's signature, written the way it would be declared.
9021fn trait_signature(sig: &FnSig, name: &str) -> String {
9022    let mut out = String::new();
9023    if sig.is_async {
9024        out.push_str("async ");
9025    }
9026    out.push_str("fn ");
9027    out.push_str(name);
9028    out.push('(');
9029    let mut entries: Vec<String> = Vec::new();
9030    if sig.receiver.is_some() {
9031        entries.push("self".to_string());
9032    }
9033    entries.extend(
9034        sig.params
9035            .iter()
9036            .map(|param| format!("{}: {}", param.name, param.ty)),
9037    );
9038    out.push_str(&entries.join(", "));
9039    out.push(')');
9040    if sig.ret != Ty::Unit {
9041        out.push_str(&format!(" -> {}", sig.ret));
9042    }
9043    out
9044}
9045
9046/// Pairs a declaration's type parameters with the arguments a use of it was
9047/// written with.
9048///
9049/// A short argument list means the arity was already reported, so the
9050/// padding is a recovery unknown: the diagnostic exists and this stands
9051/// where the argument the program did not write would have.
9052fn substitution(generics: &[Arc<str>], args: &[Ty]) -> BTreeMap<Arc<str>, Ty> {
9053    generics
9054        .iter()
9055        .cloned()
9056        .zip(
9057            args.iter()
9058                .cloned()
9059                .chain(std::iter::repeat(Ty::recovery())),
9060        )
9061        .collect()
9062}
9063
9064/// Substitutes the arguments a type alias was written with into the type it
9065/// expands to.
9066fn expand_alias(generics: Vec<Arc<str>>, ty: Ty, arguments: Vec<Ty>) -> Ty {
9067    let subst = generics
9068        .into_iter()
9069        .zip(
9070            fit(arguments, 0)
9071                .into_iter()
9072                .chain(std::iter::repeat(Ty::recovery())),
9073        )
9074        .collect();
9075    ty.substitute(&subst)
9076}
9077
9078/// Truncates or pads `args` to `arity`, so a type written with the wrong
9079/// number of arguments still has a shape the rest of the pass can use.
9080fn fit(mut args: Vec<Ty>, arity: usize) -> Vec<Ty> {
9081    args.truncate(arity);
9082    while args.len() < arity {
9083        args.push(Ty::recovery());
9084    }
9085    args
9086}
9087
9088// ----------------------------------------------------------------- builtins
9089
9090/// A builtin method's or associated function's signature.
9091struct BuiltinSig {
9092    /// Type parameters this signature binds, unified at the call site just
9093    /// like a declared function's.
9094    generics: Vec<Arc<str>>,
9095    params: Vec<(&'static str, Ty)>,
9096    /// Whether the last parameter takes the rest of the arguments, as
9097    /// `Vector.of(items: T...)` does.
9098    variadic: bool,
9099    ret: Ty,
9100}
9101
9102// ---------------------------------------------------------- the host schema
9103
9104/// The Language Card sentence a Host API diagnostic quotes.
9105///
9106/// The schema is one description and both ends read it, so both ends say the
9107/// same thing about a call that does not fit: this is the compiler's wording
9108/// of the rule `cove_runtime::host` states at the boundary.
9109const HOST_SCHEMA_RULE: &str = "A Host API operation's argument, result, and error types come from its schema, which the compiler, the runtime, and the CLI all read.";
9110
9111/// The type a Host API schema's type is, here.
9112///
9113/// The two vocabularies are the same one written twice, so the translation is
9114/// mechanical except at the ends. [`cove_schema::HostType::Any`] becomes
9115/// [`Ty::Any`]: an operation that declares `Any` is one whose meaning does
9116/// not depend on which value it was given — the work `clock.timeout` bounds
9117/// — and that is a statement the schema made rather than something the
9118/// checker failed to find out, so it is a type here and not an unknown.
9119/// `Checker::host_result` notes it at the call when it is a result rather
9120/// than a parameter. [`cove_schema::HostType::Named`] becomes
9121/// [`Ty::Host`], which is nominal and compared by the name the schema wrote.
9122fn host_ty(declared: &HostType) -> Ty {
9123    match declared {
9124        HostType::Unit => Ty::Unit,
9125        HostType::Bool => Ty::Bool,
9126        HostType::Int => Ty::Int,
9127        HostType::String => Ty::Str,
9128        HostType::Duration => Ty::Duration,
9129        HostType::Error => Ty::Error,
9130        HostType::Array(item) => Ty::Array(Box::new(host_ty(item))),
9131        HostType::Set(item) => Ty::Set(Box::new(host_ty(item))),
9132        HostType::Map(key, value) => Ty::Map(Box::new(host_ty(key)), Box::new(host_ty(value))),
9133        HostType::Option(some) => Ty::Option(Box::new(host_ty(some))),
9134        HostType::Result(ok, error) => Ty::Result(Box::new(host_ty(ok)), Box::new(host_ty(error))),
9135        HostType::Named(name) => Ty::Host((*name).into()),
9136        HostType::Any => Ty::Any,
9137    }
9138}
9139
9140/// The dotted name a place is written with in source, for a diagnostic.
9141///
9142/// The same rendering `Interpreter::describe_place` produces, because a
9143/// place refused here is a place that expression would have been refused as
9144/// there, and the words a reader has seen for years are the words to keep.
9145/// Anything that is not a name or a field of one renders as `this
9146/// expression`, which is how a receiver that is no place at all reads in a
9147/// sentence.
9148fn place_text(expr: &Expr) -> String {
9149    match &expr.kind {
9150        ExprKind::Ident(name) => name.clone(),
9151        ExprKind::Field { base, name } => format!("{}.{}", place_text(base), name.node),
9152        _ => "this expression".to_string(),
9153    }
9154}
9155
9156/// The signature the schema declares, qualified the way the call was named,
9157/// which is word for word what the boundary's own diagnostic quotes.
9158fn declared_signature(shown: &str, operation: &OperationSchema) -> String {
9159    let owner = match shown.rsplit_once('.') {
9160        Some((owner, _)) => owner,
9161        None => shown,
9162    };
9163    format!(
9164        "the Host API schema declares `{owner}.{}`",
9165        operation.signature()
9166    )
9167}
9168
9169/// The names of the operations in one table, for a diagnostic that has to
9170/// list what does exist.
9171fn operation_names(operations: &'static [OperationSchema]) -> Vec<String> {
9172    operations
9173        .iter()
9174        .map(|entry| entry.name.to_string())
9175        .collect()
9176}
9177
9178/// What a name that is not a value is instead.
9179///
9180/// This is an enum rather than the sentence it prints because the sentence
9181/// and the correction have to agree: a module is reached *into* and a type is
9182/// made *of*, and choosing between those by comparing the printed words is
9183/// how one of them came to offer a correction the language does not have.
9184#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9185enum Namespace {
9186    /// A struct, whether this module declares it or `use` reaches it: a
9187    /// value of one is *constructed*.
9188    Struct,
9189    /// An enum, likewise: a value of one is one of its *cases*.
9190    Enum,
9191    /// `Vector`, `Map`, `MapEntry`: a type the language defines, whose values
9192    /// come from the associated functions it declares.
9193    BuiltinType,
9194    /// A type a host module declares, such as `http.Request`.
9195    HostType,
9196    /// A type whose shape the site reporting it does not have to hand.
9197    Type,
9198    /// A host module named by `use`, such as `console`.
9199    HostModule,
9200    /// Another module of the package, imported whole.
9201    Module,
9202}
9203
9204impl Namespace {
9205    /// How the diagnostic names it: `` `Vector` is a builtin type ``.
9206    fn what(self) -> &'static str {
9207        match self {
9208            Namespace::Struct => "a struct",
9209            Namespace::Enum => "an enum",
9210            Namespace::BuiltinType => "a builtin type",
9211            Namespace::HostType => "a host type",
9212            Namespace::Type => "a type",
9213            Namespace::HostModule => "a host module",
9214            Namespace::Module => "a module",
9215        }
9216    }
9217
9218    /// The correction, which has to name a form the language actually has.
9219    ///
9220    /// This is the whole reason the kind is an enum. Choosing between these
9221    /// by comparing the printed noun is how one of them came to offer
9222    /// `console.println.<name>(...)`, which is not a Cove form at all.
9223    fn correction(self, name: &str) -> String {
9224        match self {
9225            Namespace::Struct => {
9226                format!("construct one, as in `{name}(field: value)`, or name a value instead")
9227            }
9228            Namespace::Enum => {
9229                format!("name one of its cases, as in `{name}.<case>`, or name a value instead")
9230            }
9231            Namespace::BuiltinType | Namespace::Type => format!(
9232                "call an associated function of it, as in `{name}.<name>(...)`, or name a value instead"
9233            ),
9234            Namespace::HostType => format!(
9235                "construct one, as in `{name}(field: value)`, or call the operation that answers one"
9236            ),
9237            Namespace::HostModule | Namespace::Module => {
9238                format!("name something in it, as in `{name}.<name>(...)`, or name a value instead")
9239            }
9240        }
9241    }
9242}
9243
9244/// A type or a module written where a value belongs.
9245///
9246/// Each of these is a name a value can be reached *through*, and the forms
9247/// that reach one — `Vector.of(1)`, `console.println("x")`, `Booking(id: 1)`
9248/// — say so at the call. Bare, it is not a value and has no type, which used
9249/// to be an unknown and is now a mistake with a name.
9250///
9251/// A host *operation* is deliberately not here: it is a value, typed from its
9252/// schema by `Checker::host_operation_value`.
9253fn not_a_value(name: &str, what: Namespace, span: Span) -> Diagnostic {
9254    let help = what.correction(name);
9255    Diagnostic::error(
9256        NOT_A_VALUE,
9257        format!("`{name}` is {}, not a value", what.what()),
9258    )
9259    .at(span)
9260    .rule("A value is a literal, a binding, a call, or a constructed struct or enum case. A type and a module are names other forms read; neither is a value on its own.")
9261    .help(help)
9262}
9263
9264/// Nothing written anywhere settles a type the checker was asked to infer.
9265///
9266/// This is the language gap the checker can neither fill nor excuse: the
9267/// program itself is missing the annotation, and nothing downstream can act
9268/// on the type it left open.
9269///
9270/// ADR 0016 made this a warning, on the reading that the value is still
9271/// usable and the operations not depending on the missing type are still
9272/// checked. That reading was the interpreter's. A type nothing settles has
9273/// no width and no layout, so it is not a soft spot in a program that runs —
9274/// it is a program a backend cannot place a value for, and `cove check`
9275/// reporting nothing worse than a warning about it would be reporting that
9276/// the program is ready to run. The correction is still always available,
9277/// which is what `help` says; what changed is that leaving it uncorrected is
9278/// no longer a program.
9279fn unconstrained(message: String, help: String, span: Span) -> Diagnostic {
9280    Diagnostic::error(UNCONSTRAINED, message)
9281        .at(span)
9282        .rule("A type the checker infers is inferred from something written: a value, an annotation, or the type of the place the value is given to.")
9283        .help(help)
9284}
9285
9286/// Whether a declared host type is, or contains, [`HostType::Any`].
9287fn contains_any(declared: &HostType) -> bool {
9288    match declared {
9289        HostType::Any => true,
9290        HostType::Array(inner) | HostType::Set(inner) | HostType::Option(inner) => {
9291            contains_any(inner)
9292        }
9293        HostType::Map(key, value) | HostType::Result(key, value) => {
9294            contains_any(key) || contains_any(value)
9295        }
9296        _ => false,
9297    }
9298}
9299
9300/// A type reached through a host module no schema describes.
9301///
9302/// This is the warning that used to greet every host type. It is now what
9303/// greets only the ones the checker genuinely cannot answer for: an
9304/// embedding may register any module it likes, and one whose schema the
9305/// compiler was not handed is checked by the boundary at run time and by
9306/// nothing before it.
9307fn unchecked_host_type(shown: &str, span: Span) -> Diagnostic {
9308    Diagnostic::warning(
9309        HOST_TYPE,
9310        format!("`{shown}` comes from a host module no Host API schema describes, so values of it are unchecked"),
9311    )
9312    .at(span)
9313    .rule("A Host API's types come from its schema; the checker reads the shipped schemas and any an embedder supplies.")
9314    .help("the checker treats this type as unknown; every operation on it is left to the runtime, which holds the host to the schema it registered with")
9315}
9316
9317/// The builtin type `receiver` is one of, when it is one.
9318///
9319/// `MapEntry` and `Error` are here for their *fields* rather than their
9320/// methods: both are builtin structs that answer no methods at all, and what
9321/// the table says about them is what they carry.
9322///
9323/// `pub(crate)` because `unique::creates` reads it too, to turn a method
9324/// call's already-settled receiver type into the schema entry that answers
9325/// whether the call is fresh — the same mapping this module uses to check
9326/// the call in the first place, read back rather than re-derived.
9327pub(crate) fn builtin_schema_of(receiver: &Ty) -> Option<&'static BuiltinSchema> {
9328    let name = match receiver {
9329        Ty::Unit => "Unit",
9330        Ty::Bool => "Bool",
9331        Ty::Int => "Int",
9332        Ty::Float => "Float",
9333        Ty::Str => "String",
9334        Ty::Duration => "Duration",
9335        Ty::Error => "Error",
9336        Ty::Range => "Range",
9337        Ty::Array(_) => "Array",
9338        Ty::Vector(_) => "Vector",
9339        Ty::Map(_, _) => "Map",
9340        Ty::MapEntry(_, _) => "MapEntry",
9341        Ty::Set(_) => "Set",
9342        Ty::Option(_) => "Option",
9343        Ty::Result(_, _) => "Result",
9344        Ty::Task(_) => "Task",
9345        Ty::Shared(_) => "Shared",
9346        Ty::Scope => "Scope",
9347        _ => return None,
9348    };
9349    cove_schema::builtin(name)
9350}
9351
9352/// The type arguments `receiver` was written with, in the order the schema
9353/// declares its parameters.
9354///
9355/// This is what binds the `T` of `Array<T>.get` to the element type of the
9356/// array the call was made on.
9357fn receiver_arguments(receiver: &Ty) -> Vec<Ty> {
9358    match receiver {
9359        Ty::Array(item)
9360        | Ty::Vector(item)
9361        | Ty::Set(item)
9362        | Ty::Option(item)
9363        | Ty::Task(item)
9364        | Ty::Shared(item) => vec![(**item).clone()],
9365        Ty::Map(left, right) | Ty::MapEntry(left, right) | Ty::Result(left, right) => {
9366            vec![(**left).clone(), (**right).clone()]
9367        }
9368        _ => Vec::new(),
9369    }
9370}
9371
9372/// The type a builtin schema's type is, here.
9373///
9374/// The scalars translate the way [`host_ty`] translates a host's, and the
9375/// three variants the host vocabulary does not have are the whole reason
9376/// there are two vocabularies. [`BuiltinType::Param`] is a name the receiver
9377/// binds -- read off `bound`, so `Array<Int>.get` answers `Option<Int>` -- or,
9378/// when the signature binds it itself, a [`Ty::Param`] for the call site to
9379/// unify like any other. [`BuiltinType::SelfType`] is the receiver, which is
9380/// what `snapshot` answers. [`BuiltinType::Fn`] is an ordinary function type,
9381/// since a builtin that takes a callback takes an ordinary closure.
9382fn builtin_ty(declared: &BuiltinType, bound: &BTreeMap<&str, Ty>, receiver: Option<&Ty>) -> Ty {
9383    let nested = |inner: &BuiltinType| Box::new(builtin_ty(inner, bound, receiver));
9384    match declared {
9385        BuiltinType::Unit => Ty::Unit,
9386        BuiltinType::Bool => Ty::Bool,
9387        BuiltinType::Int => Ty::Int,
9388        BuiltinType::Float => Ty::Float,
9389        BuiltinType::String => Ty::Str,
9390        BuiltinType::Error => Ty::Error,
9391        BuiltinType::Duration => Ty::Duration,
9392        BuiltinType::Array(item) => Ty::Array(nested(item)),
9393        BuiltinType::Vector(item) => Ty::Vector(nested(item)),
9394        BuiltinType::Set(item) => Ty::Set(nested(item)),
9395        BuiltinType::Map(key, value) => Ty::Map(nested(key), nested(value)),
9396        BuiltinType::MapEntry(key, value) => Ty::MapEntry(nested(key), nested(value)),
9397        BuiltinType::Option(some) => Ty::Option(nested(some)),
9398        BuiltinType::Result(ok, error) => Ty::Result(nested(ok), nested(error)),
9399        BuiltinType::Task(inner) => Ty::Task(nested(inner)),
9400        BuiltinType::Shared(inner) => Ty::Shared(nested(inner)),
9401        BuiltinType::Fn(params, ret) => Ty::func(
9402            false,
9403            params
9404                .iter()
9405                .map(|param| builtin_ty(param, bound, receiver))
9406                .collect(),
9407            builtin_ty(ret, bound, receiver),
9408        ),
9409        BuiltinType::Param(name) => bound
9410            .get(name)
9411            .cloned()
9412            .unwrap_or_else(|| Ty::Param((*name).into())),
9413        // Only an associated function is opened with no receiver, and the
9414        // schema's own tests hold one to naming no `Self`.
9415        BuiltinType::SelfType => receiver.cloned().unwrap_or(Ty::placeholder()),
9416    }
9417}
9418
9419/// The free builtin `name` describes itself with, when it is one of `kind`.
9420///
9421/// The kind is asked for because the two are reached separately: an assertion
9422/// is dispatched through the path that carries its arguments' source text,
9423/// and a constructor through the one that reads the type the call site
9424/// expects.
9425fn free_builtin(name: &str, kind: FreeBuiltinKind) -> Option<&'static FreeBuiltinSchema> {
9426    cove_schema::free_builtin(name).filter(|schema| schema.kind == kind)
9427}
9428
9429/// What a free builtin's call has settled its type parameters to, and where.
9430///
9431/// A free builtin binds every parameter it names itself — there is no
9432/// receiver to read one off — and exactly two things can settle one: the type
9433/// the call site expects, and an argument. An unsettled parameter is
9434/// [`Ty::unconstrained`] rather than a [`Ty::Param`], because nothing declared
9435/// it for a call site to instantiate: `Ok(1)` written where nothing expects
9436/// a `Result` genuinely does not know what its error type is, and what
9437/// settles it is the place the value is given to.
9438///
9439/// It is an *unconstrained* unknown and not a placeholder because it does
9440/// escape: `Ok(1)` in a place that expects nothing produces a
9441/// `Result<Int, _>` the program goes on holding. That is one of the two
9442/// admitted holes in what a clean check guarantees, named in the module
9443/// documentation above.
9444///
9445/// The spans are here because a diagnostic points at whatever settled the
9446/// parameter it is complaining about: `assertEqual("a", 1)` says the `1`
9447/// should have been a `String` and points at the `"a"` that decided so.
9448struct FreeBindings {
9449    types: BTreeMap<&'static str, Ty>,
9450    origins: BTreeMap<&'static str, Span>,
9451}
9452
9453impl FreeBindings {
9454    /// Every parameter `schema` binds, each open and each with an identity.
9455    ///
9456    /// `open` is one fresh inference variable per generic, in the order
9457    /// `schema.generics` lists them. They used to be unconstrained unknowns
9458    /// minted here, which is why `Ok(1)` in a place expecting no `Result`
9459    /// produced a `Result<Int, _>` that nothing could ever settle and
9460    /// nothing ever reported — ADR 0016 named it as one of the two silences
9461    /// a clean check does not cover. A variable is the same hole with a
9462    /// number on it: a later use of the binding can fill it, and if none
9463    /// does, `Checker::finish_inference` says so where the value was
9464    /// written.
9465    fn new(schema: &'static FreeBuiltinSchema, open: Vec<Ty>) -> FreeBindings {
9466        FreeBindings {
9467            types: schema.generics.iter().copied().zip(open).collect(),
9468            origins: BTreeMap::new(),
9469        }
9470    }
9471
9472    /// `declared`, with every parameter settled so far substituted in.
9473    fn open(&self, declared: &BuiltinType) -> Ty {
9474        builtin_ty(declared, &self.types, None)
9475    }
9476
9477    /// Settles the parameter `declared` names, when it names one bare.
9478    ///
9479    /// A parameter mentioned inside a larger type is not settled by an
9480    /// argument, because no free builtin declares one that way and reading a
9481    /// type back out of a value's type is unification the checker does not do
9482    /// here.
9483    ///
9484    /// A type that says nothing settles nothing. Writing one here would
9485    /// replace the parameter's open variable with a hole that has no
9486    /// identity, and the argument that comes after — or the use that comes
9487    /// after the whole call — would then have nothing left to settle:
9488    /// `retry`'s callback is expected to answer `Result<T, Error>` with `T`
9489    /// not yet known, and it is `Ok(booking)` that says what `T` is.
9490    fn bind(&mut self, declared: &BuiltinType, ty: Ty, at: Span) {
9491        if ty.is_wild() {
9492            return;
9493        }
9494        if let BuiltinType::Param(name) = declared {
9495            self.types.insert(name, ty);
9496            self.origins.insert(name, at);
9497        }
9498    }
9499
9500    /// Reads the parameters of `declared` off `actual`, as far as the two
9501    /// have the same shape.
9502    ///
9503    /// This is how the type a call site expects reaches a constructor's
9504    /// payload: `Result<T, E>` against `Result<Int, Error>` settles both, and
9505    /// `Result<T, E>` against something that is not a `Result` settles
9506    /// neither, leaving the argument to say what it can.
9507    fn read_off(&mut self, declared: &BuiltinType, actual: &Ty, at: Span) {
9508        match (declared, actual) {
9509            (BuiltinType::Param(_), _) => self.bind(declared, actual.clone(), at),
9510            (BuiltinType::Array(inner), Ty::Array(ty))
9511            | (BuiltinType::Vector(inner), Ty::Vector(ty))
9512            | (BuiltinType::Set(inner), Ty::Set(ty))
9513            | (BuiltinType::Option(inner), Ty::Option(ty))
9514            | (BuiltinType::Task(inner), Ty::Task(ty))
9515            | (BuiltinType::Shared(inner), Ty::Shared(ty)) => self.read_off(inner, ty, at),
9516            (BuiltinType::Map(key, value), Ty::Map(left, right))
9517            | (BuiltinType::MapEntry(key, value), Ty::MapEntry(left, right))
9518            | (BuiltinType::Result(key, value), Ty::Result(left, right)) => {
9519                self.read_off(key, left, at);
9520                self.read_off(value, right, at);
9521            }
9522            _ => {}
9523        }
9524    }
9525
9526    /// Where the parameter `declared` names was settled, or `fallback` when
9527    /// it was settled by the call site rather than by an argument.
9528    fn origin(&self, declared: &BuiltinType, fallback: Span) -> Span {
9529        match declared {
9530            BuiltinType::Param(name) => self.origins.get(name).copied().unwrap_or(fallback),
9531            _ => fallback,
9532        }
9533    }
9534}
9535
9536/// A free builtin was given the wrong number of arguments.
9537///
9538/// The rule and the correction are the caller's, because they are what the
9539/// two kinds do not share: a constructor carries a value and an assertion
9540/// checks one.
9541fn free_arity(schema: &FreeBuiltinSchema, found: usize, span: Span) -> Diagnostic {
9542    Diagnostic::error(
9543        ARITY,
9544        match schema.kind {
9545            FreeBuiltinKind::Constructor => format!(
9546                "`{}` takes {} argument, but {found} were given",
9547                schema.name,
9548                schema.arity()
9549            ),
9550            FreeBuiltinKind::Assertion => format!(
9551                "`{}` takes {} argument(s), but {found} were given",
9552                schema.name,
9553                schema.arity()
9554            ),
9555        },
9556    )
9557    .at(span)
9558}
9559
9560/// What a diagnostic says a free builtin's parameter is for.
9561///
9562/// The sentence is the checker's rather than the table's: the table says what
9563/// a call takes, and this says why, which is prose no other crate reads.
9564fn free_builtin_reason(schema: &FreeBuiltinSchema, param: &ParamSchema, ty: &Ty) -> String {
9565    match schema.kind {
9566        FreeBuiltinKind::Constructor => format!("`{}` carries a `{ty}`", schema.name),
9567        // An assertion either checks one value against a type it declares or
9568        // compares a pair against each other, and its one parameter or its
9569        // two are what say which.
9570        FreeBuiltinKind::Assertion if schema.arity() == 1 => {
9571            format!("`{}` checks a `{ty}` {}", schema.name, param.name)
9572        }
9573        FreeBuiltinKind::Assertion => {
9574            format!("`{}` compares two values of one type", schema.name)
9575        }
9576    }
9577}
9578
9579/// One schema signature, opened for the receiver it was reached through.
9580///
9581/// `parameters` and `arguments` are the receiver's, paired positionally; an
9582/// associated function is called on the type and passes both empty.
9583fn builtin_sig(
9584    method: &'static MethodSchema,
9585    parameters: &'static [&'static str],
9586    arguments: &[Ty],
9587    receiver: Option<&Ty>,
9588) -> BuiltinSig {
9589    let bound: BTreeMap<&str, Ty> = parameters
9590        .iter()
9591        .copied()
9592        .zip(arguments.iter().cloned())
9593        .collect();
9594    BuiltinSig {
9595        generics: method
9596            .generics
9597            .iter()
9598            .map(|generic| Arc::from(*generic))
9599            .collect(),
9600        params: method
9601            .params
9602            .iter()
9603            .map(|param| (param.name, builtin_ty(&param.ty, &bound, receiver)))
9604            .collect(),
9605        variadic: method.variadic,
9606        ret: builtin_ty(&method.result, &bound, receiver),
9607    }
9608}
9609
9610/// What a builtin's own type parameters stand for in `receiver`.
9611///
9612/// `Map<String, Int>` binds `K` to `String` and `V` to `Int`, which is what
9613/// opens a method's signature, a case's payload, and a field's type alike.
9614fn receiver_binding<'a>(schema: &'a BuiltinSchema, receiver: &Ty) -> BTreeMap<&'a str, Ty> {
9615    schema
9616        .parameters
9617        .iter()
9618        .copied()
9619        .zip(receiver_arguments(receiver))
9620        .collect()
9621}
9622
9623/// The types a builtin enum's case binds, read off the scrutinee, or `None`
9624/// when the enum declares no such case.
9625///
9626/// This is the same opening [`builtin_sig`] does, with a case's payload where
9627/// a signature's parameters would be: `Ok` carries the `T` of the `Result<T,
9628/// E>` the `match` is over, so one description of what `Ok` carries serves
9629/// both the pattern's binding here and the value the interpreter builds.
9630fn builtin_case_payload(scrutinee: &Ty, case: &str) -> Option<Vec<Ty>> {
9631    let schema = builtin_schema_of(scrutinee)?;
9632    let case = schema.case(case)?;
9633    let bound = receiver_binding(schema, scrutinee);
9634    Some(
9635        case.payload
9636            .iter()
9637            .map(|ty| builtin_ty(ty, &bound, Some(scrutinee)))
9638            .collect(),
9639    )
9640}
9641
9642/// The signature of a builtin method, or `None` when the receiver has no such
9643/// method.
9644///
9645/// The table is [`cove_schema::builtins`], which the runtime dispatches out of
9646/// as well: there is one list of what a builtin type answers to, and this is
9647/// the compiler reading it.
9648fn builtin_method(receiver: &Ty, name: &str) -> Option<BuiltinSig> {
9649    let schema = builtin_schema_of(receiver)?;
9650    let method = schema.method(name)?;
9651    Some(builtin_sig(
9652        method,
9653        schema.parameters,
9654        &receiver_arguments(receiver),
9655        Some(receiver),
9656    ))
9657}
9658
9659/// Every associated function the builtin types declare, qualified, as a
9660/// diagnostic reads them out.
9661fn builtin_associated_functions() -> String {
9662    let names: Vec<String> = cove_schema::builtins::builtins()
9663        .iter()
9664        .flat_map(|entry| {
9665            entry
9666                .associated
9667                .iter()
9668                .map(|method| format!("`{}.{}`", entry.name, method.name))
9669        })
9670        .collect();
9671    match names.split_last() {
9672        Some((last, [])) => last.clone(),
9673        Some((last, rest)) => format!("{}, and {last}", rest.join(", ")),
9674        None => "nothing".to_string(),
9675    }
9676}
9677
9678/// The name a builtin type answers to in a diagnostic.
9679fn builtin_name(ty: &Ty) -> String {
9680    match ty {
9681        Ty::Array(_) => "Array".to_string(),
9682        Ty::Vector(_) => "Vector".to_string(),
9683        Ty::Option(_) => "Option".to_string(),
9684        Ty::Result(_, _) => "Result".to_string(),
9685        Ty::Task(_) => "Task".to_string(),
9686        Ty::Shared(_) => "Shared".to_string(),
9687        Ty::Map(_, _) => "Map".to_string(),
9688        Ty::Set(_) => "Set".to_string(),
9689        Ty::MapEntry(_, _) => "MapEntry".to_string(),
9690        other => other.to_string(),
9691    }
9692}
9693
9694/// `value.snapshot()` on a type ADR 0001 excludes by name: a closure, a
9695/// task, or a task scope.
9696fn no_snapshot_conformance(receiver: &Ty, span: Span) -> Diagnostic {
9697    let what = match receiver {
9698        Ty::Fn(_) => "closures",
9699        Ty::Task(_) => "tasks",
9700        Ty::Shared(_) => "synchronized values",
9701        _ => "task scopes",
9702    };
9703    Diagnostic::error(
9704        UNKNOWN_METHOD,
9705        format!("`{receiver}` does not implement `Snapshot`"),
9706    )
9707    .at(span)
9708    .rule(format!(
9709        "Closures, synchronized values, and Host resources do not implement `Snapshot` by default; {what} have no independent mutable graph to copy."
9710    ))
9711    .help("a struct or enum conforms explicitly with `impl Snapshot for Type`")
9712}
9713
9714fn unknown_builtin_method(receiver: &Ty, name: &str, span: Span) -> Diagnostic {
9715    let type_name = builtin_name(receiver);
9716    // Who is taught the spelling is derived rather than listed: a receiver
9717    // that declares `length` is a receiver a program might have written
9718    // `count()` on. The two ends used to keep a list each and had drifted by
9719    // two types, so a `Map` was taught the spelling at run time and told
9720    // nothing by `cove check`.
9721    if name == "count" && cove_schema::builtins::declares_length(&type_name) {
9722        return Diagnostic::error(
9723            UNKNOWN_METHOD,
9724            format!("`{type_name}` has no method `count`; Cove spells the number of elements `length()`"),
9725        )
9726        .at(span)
9727        .rule("Every sequence reports its element count as `length()`; there is no `count()`.")
9728        .help("write `length()` instead of `count()`");
9729    }
9730    let known = builtin_methods_of(receiver);
9731    Diagnostic::error(
9732        UNKNOWN_METHOD,
9733        format!("`{type_name}` has no method `{name}`"),
9734    )
9735    .at(span)
9736    .rule("A builtin type's methods are exactly the ones the language defines.")
9737    .help(if known.is_empty() {
9738        format!("`{type_name}` has no methods")
9739    } else {
9740        format!("`{type_name}` has {}", list(&known))
9741    })
9742}
9743
9744/// Every method name a builtin receiver answers to, for a diagnostic's help.
9745///
9746/// This used to be a hand-written list of candidate names filtered through
9747/// [`builtin_method`], which is a third copy of the table and had drifted
9748/// like the other two: it had never gained `mapError`, `cancel`, `lock`, or
9749/// `spawn`, so a `Result` whose method was misspelled was told it had two
9750/// methods when it has three. Reading the schema's own order removes both the
9751/// copy and the omission.
9752fn builtin_methods_of(receiver: &Ty) -> Vec<String> {
9753    builtin_schema_of(receiver)
9754        .map(|schema| {
9755            schema
9756                .methods
9757                .iter()
9758                .map(|method| method.name.to_string())
9759                .collect()
9760        })
9761        .unwrap_or_default()
9762}
9763
9764// ------------------------------------------------------------------- prose
9765
9766fn operator_symbol(op: BinaryOp) -> &'static str {
9767    match op {
9768        BinaryOp::Add => "+",
9769        BinaryOp::Sub => "-",
9770        BinaryOp::Mul => "*",
9771        BinaryOp::Div => "/",
9772        BinaryOp::Rem => "%",
9773        BinaryOp::Eq => "==",
9774        BinaryOp::Ne => "!=",
9775        BinaryOp::Lt => "<",
9776        BinaryOp::Le => "<=",
9777        BinaryOp::Gt => ">",
9778        BinaryOp::Ge => ">=",
9779        BinaryOp::Is => "is",
9780        BinaryOp::And => "&&",
9781        BinaryOp::Or => "||",
9782    }
9783}
9784
9785fn starts_uppercase(name: &str) -> bool {
9786    name.chars().next().is_some_and(char::is_uppercase)
9787}
9788
9789fn join_path(path: &[Ident]) -> String {
9790    path.iter()
9791        .map(|segment| segment.node.as_str())
9792        .collect::<Vec<_>>()
9793        .join(".")
9794}
9795
9796fn list(items: &[String]) -> String {
9797    if items.is_empty() {
9798        return "nothing".to_string();
9799    }
9800    items
9801        .iter()
9802        .map(|item| format!("`{item}`"))
9803        .collect::<Vec<_>>()
9804        .join(", ")
9805}
9806
9807fn first_case_of(sig: Option<&EnumSig>) -> String {
9808    sig.and_then(|sig| sig.cases.first())
9809        .map(|case| case.name.clone())
9810        .unwrap_or_else(|| "Case".to_string())
9811}
9812
9813/// The correction for a mismatch, when the language offers exactly one.
9814fn conversion_help(expected: &Ty, found: &Ty) -> Option<String> {
9815    Some(match (expected, found) {
9816        (Ty::Str, _) => {
9817            format!("interpolate the `{found}`, as in \"{{value}}\", to make a `String`")
9818        }
9819        (Ty::Int, Ty::Str) => {
9820            "parse the `String` with `Int.parse(text)`, which returns a `Result<Int, Error>`"
9821                .to_string()
9822        }
9823        (Ty::Option(inner), other) if inner.matches(other) => {
9824            format!("wrap it, as in `Some(value)`, to make an `Option<{inner}>`")
9825        }
9826        (Ty::Result(ok, _), other) if ok.matches(other) => {
9827            format!("wrap it, as in `Ok(value)`, to make a `Result<{ok}, _>`")
9828        }
9829        (other, Ty::Option(inner)) if other.matches(inner) => {
9830            format!(
9831                "unwrap it, as in `value.unwrapOr(<{other}>)`, which always produces a `{other}`"
9832            )
9833        }
9834        (other, Ty::Result(ok, _)) if other.matches(ok) => {
9835            format!(
9836                "unwrap it, as in `value.unwrapOr(<{other}>)`, which always produces a `{other}`"
9837            )
9838        }
9839        (Ty::Array(element), Ty::Vector(other)) if element.matches(other) => {
9840            "finish the vector, as in `vector.freeze()` or `vector.toArray()`".to_string()
9841        }
9842        (Ty::Float, Ty::Int) | (Ty::Int, Ty::Float) => {
9843            format!("write the literal as a `{expected}`; Cove converts nothing implicitly")
9844        }
9845        _ => return None,
9846    })
9847}
9848
9849fn condition_help(ty: &Ty) -> String {
9850    match ty {
9851        Ty::Option(_) => "compare it, as in `value.isSome()`".to_string(),
9852        Ty::Int | Ty::Float => format!("compare it, as in `value != 0`; a `{ty}` is not a `Bool`"),
9853        _ => format!("compare it, so the condition is a `Bool` rather than a `{ty}`"),
9854    }
9855}
9856
9857fn iterable_help(ty: &Ty) -> String {
9858    match ty {
9859        Ty::Option(inner) => {
9860            format!("match the `Option`, or write `for x in [value.unwrapOr(<{inner}>)]`")
9861        }
9862        Ty::Int => "write a range, as in `0..<n`".to_string(),
9863        Ty::MapEntry(_, _) => {
9864            "iterate the `Map` itself; `for` already binds each pair as a `MapEntry`".to_string()
9865        }
9866        _ => format!("build an `Array`, a `Vector`, or a `Range` from the `{ty}` first"),
9867    }
9868}
9869
9870#[cfg(test)]
9871mod tests {
9872    use super::*;
9873    use crate::config::Config;
9874    use crate::package::{Module, Unit};
9875    use crate::resolve::resolve;
9876    use cove_diag::{Severity, SourceMap};
9877    use std::path::{Path, PathBuf};
9878
9879    /// Type-checks one module written inline, without touching the
9880    /// filesystem, and returns everything it reported.
9881    fn diagnostics_of(source: &str) -> Vec<Diagnostic> {
9882        diagnostics_with(source, Config::default())
9883    }
9884
9885    fn diagnostics_with(source: &str, config: Config) -> Vec<Diagnostic> {
9886        let mut sources = SourceMap::new();
9887        let path = PathBuf::from("main.cove");
9888        let file = sources.add(path.clone(), source);
9889        let ast = cove_syntax::parse_file(&sources, file).expect("test source parses");
9890        let mut modules = BTreeMap::new();
9891        modules.insert(
9892            "main".to_string(),
9893            Module {
9894                name: "main".to_string(),
9895                dir: PathBuf::from("main"),
9896                units: vec![Unit { file, path, ast }],
9897            },
9898        );
9899        let package = Package {
9900            root: PathBuf::new(),
9901            config,
9902            modules,
9903        };
9904        let program = resolve(&package).expect("test source resolves");
9905        check(&package, &program)
9906    }
9907
9908    /// Type-checks several modules written inline, so one can `use` another.
9909    fn diagnostics_of_modules(modules: &[(&str, &str)]) -> Vec<Diagnostic> {
9910        let mut sources = SourceMap::new();
9911        let mut map = BTreeMap::new();
9912        for (name, source) in modules {
9913            let path = PathBuf::from(format!("{name}.cove"));
9914            let file = sources.add(path.clone(), *source);
9915            let ast = cove_syntax::parse_file(&sources, file).expect("test source parses");
9916            map.insert(
9917                (*name).to_string(),
9918                Module {
9919                    name: (*name).to_string(),
9920                    dir: PathBuf::from(*name),
9921                    units: vec![Unit { file, path, ast }],
9922                },
9923            );
9924        }
9925        let package = Package {
9926            root: PathBuf::new(),
9927            config: Config::default(),
9928            modules: map,
9929        };
9930        let program = resolve(&package).expect("test package resolves");
9931        check(&package, &program)
9932    }
9933
9934    #[track_caller]
9935    fn accepts_modules(modules: &[(&str, &str)]) {
9936        let errors: Vec<Diagnostic> = diagnostics_of_modules(modules)
9937            .into_iter()
9938            .filter(|d| d.severity == Severity::Error)
9939            .collect();
9940        assert!(
9941            errors.is_empty(),
9942            "expected no errors, found: {}",
9943            errors
9944                .iter()
9945                .map(|d| format!("{}: {}", d.code, d.message))
9946                .collect::<Vec<_>>()
9947                .join("; ")
9948        );
9949    }
9950
9951    #[track_caller]
9952    fn rejects_modules(modules: &[(&str, &str)]) -> Diagnostic {
9953        let mut errors: Vec<Diagnostic> = diagnostics_of_modules(modules)
9954            .into_iter()
9955            .filter(|d| d.severity == Severity::Error)
9956            .collect();
9957        assert_eq!(
9958            errors.len(),
9959            1,
9960            "expected exactly one error, found: {}",
9961            errors
9962                .iter()
9963                .map(|d| format!("{}: {}", d.code, d.message))
9964                .collect::<Vec<_>>()
9965                .join("; ")
9966        );
9967        errors.remove(0)
9968    }
9969
9970    fn errors_of(source: &str) -> Vec<Diagnostic> {
9971        diagnostics_of(source)
9972            .into_iter()
9973            .filter(|d| d.severity == Severity::Error)
9974            .collect()
9975    }
9976
9977    fn warnings_of(source: &str) -> Vec<Diagnostic> {
9978        diagnostics_of(source)
9979            .into_iter()
9980            .filter(|d| d.severity == Severity::Warning)
9981            .collect()
9982    }
9983
9984    fn notes_of(source: &str) -> Vec<Diagnostic> {
9985        diagnostics_of(source)
9986            .into_iter()
9987            .filter(|d| d.severity == Severity::Note)
9988            .collect()
9989    }
9990
9991    /// Asserts that `source` produces exactly one warning, and returns it.
9992    #[track_caller]
9993    fn warns(source: &str) -> Diagnostic {
9994        accepts(source);
9995        let mut warnings = warnings_of(source);
9996        assert_eq!(
9997            warnings.len(),
9998            1,
9999            "expected exactly one warning, found: {}",
10000            warnings
10001                .iter()
10002                .map(|d| format!("{}: {}", d.code, d.message))
10003                .collect::<Vec<_>>()
10004                .join("; ")
10005        );
10006        warnings.remove(0)
10007    }
10008
10009    /// Asserts that `source` checks, showing what was reported when it does
10010    /// not.
10011    #[track_caller]
10012    fn accepts(source: &str) {
10013        let errors = errors_of(source);
10014        assert!(
10015            errors.is_empty(),
10016            "expected no errors, found: {}",
10017            errors
10018                .iter()
10019                .map(|d| format!("{}: {}", d.code, d.message))
10020                .collect::<Vec<_>>()
10021                .join("; ")
10022        );
10023    }
10024
10025    /// Asserts that `source` produces exactly one error, and returns it.
10026    #[track_caller]
10027    fn rejects(source: &str) -> Diagnostic {
10028        let mut errors = errors_of(source);
10029        assert_eq!(
10030            errors.len(),
10031            1,
10032            "expected exactly one error, found: {}",
10033            errors
10034                .iter()
10035                .map(|d| format!("{}: {}", d.code, d.message))
10036                .collect::<Vec<_>>()
10037                .join("; ")
10038        );
10039        errors.remove(0)
10040    }
10041
10042    #[test]
10043    fn accepts_a_test_of_the_shape_the_runner_calls() {
10044        accepts("test fn passes() -> Result<Unit, Error> {\n  Ok(())\n}\n");
10045    }
10046
10047    #[test]
10048    fn rejects_a_test_that_declares_a_parameter() {
10049        let error = rejects("test fn passes(n: Int) -> Result<Unit, Error> {\n  Ok(())\n}\n");
10050        assert_eq!(error.code, TEST);
10051        assert!(error.message.contains("declares 1 parameter(s)"));
10052        assert_eq!(
10053            error.help.as_deref(),
10054            Some("write `test fn passes() -> Result<Unit, Error>`")
10055        );
10056    }
10057
10058    #[test]
10059    fn rejects_a_test_that_returns_something_else() {
10060        for source in [
10061            "test fn passes() -> Int {\n  1\n}\n",
10062            "test fn passes() {\n}\n",
10063            "test fn passes() -> Result<Int, Error> {\n  Ok(1)\n}\n",
10064        ] {
10065            let error = rejects(source);
10066            assert_eq!(error.code, TEST, "{source}");
10067            assert!(
10068                error
10069                    .message
10070                    .contains("a test returns `Result<Unit, Error>`"),
10071                "{}",
10072                error.message
10073            );
10074        }
10075    }
10076
10077    #[test]
10078    fn rejects_an_async_test() {
10079        let error = rejects("test async fn passes() -> Result<Unit, Error> {\n  Ok(())\n}\n");
10080        assert_eq!(error.code, TEST);
10081        assert!(error.message.contains("is `async`"));
10082    }
10083
10084    #[test]
10085    fn assert_takes_a_bool_and_produces_a_result() {
10086        accepts("test fn passes() -> Result<Unit, Error> {\n  assert(1 == 1)?\n  Ok(())\n}\n");
10087        let error =
10088            rejects("test fn passes() -> Result<Unit, Error> {\n  assert(1)?\n  Ok(())\n}\n");
10089        assert_eq!(error.code, MISMATCH);
10090    }
10091
10092    #[test]
10093    fn assert_equal_compares_two_values_of_one_type() {
10094        accepts(
10095            "test fn passes() -> Result<Unit, Error> {\n  assertEqual(1 + 1, 2)?\n  Ok(())\n}\n",
10096        );
10097        let error = rejects(
10098            "test fn passes() -> Result<Unit, Error> {\n  assertEqual(1, \"1\")?\n  Ok(())\n}\n",
10099        );
10100        assert_eq!(error.code, MISMATCH);
10101    }
10102
10103    #[test]
10104    fn an_assertion_takes_the_number_of_arguments_it_declares() {
10105        let error =
10106            rejects("test fn passes() -> Result<Unit, Error> {\n  assert()?\n  Ok(())\n}\n");
10107        assert_eq!(error.code, ARITY);
10108        let error =
10109            rejects("test fn passes() -> Result<Unit, Error> {\n  assertEqual(1)?\n  Ok(())\n}\n");
10110        assert_eq!(error.code, ARITY);
10111    }
10112
10113    #[test]
10114    fn a_declaration_of_the_same_name_wins_over_the_assertion_builtin() {
10115        // The module's own `assert` answers first, exactly as it does for
10116        // every other builtin the checker knows.
10117        accepts(
10118            "fn assert(message: String) -> Result<Unit, Error> {\n  Ok(())\n}\n\n             test fn passes() -> Result<Unit, Error> {\n  assert(\"anything\")?\n  Ok(())\n}\n",
10119        );
10120    }
10121
10122    /// Wraps `body` in an entry function, the shape most of these tests need.
10123    fn in_main(body: &str) -> String {
10124        format!(
10125            "use console.println\n\nexport fn main() -> Result<Unit, Error> {{\n{body}\n  Ok(())\n}}\n"
10126        )
10127    }
10128
10129    #[track_caller]
10130    fn accepts_body(body: &str) {
10131        accepts(&in_main(body));
10132    }
10133
10134    #[track_caller]
10135    fn rejects_body(body: &str) -> Diagnostic {
10136        rejects(&in_main(body))
10137    }
10138
10139    // ------------------------------------------------------- accepted
10140
10141    #[test]
10142    fn accepts_the_card_s_greeting_program() {
10143        accepts(
10144            "\
10145use console.println
10146
10147export fn greet(name: String) -> String {
10148  \"Hello, {name}!\"
10149}
10150
10151export fn main(args: Array<String>) -> Result<Unit, Error> {
10152  let name = args.get(0).unwrapOr(\"world\")
10153  console.println(greet(name))?
10154  Ok(())
10155}
10156",
10157        );
10158    }
10159
10160    #[test]
10161    fn infers_a_let_from_its_initializer() {
10162        accepts_body("  let n = 1\n  let doubled = n * 2\n  println(\"{doubled}\")?");
10163    }
10164
10165    #[test]
10166    fn checks_a_written_let_annotation() {
10167        accepts_body("  let n: Int = 1\n  println(\"{n}\")?");
10168        let error = rejects_body("  let n: Int = \"one\"");
10169        assert_eq!(error.code, MISMATCH);
10170        assert_eq!(error.message, "expected `Int`, found `String`");
10171        assert_eq!(error.rule.unwrap(), "Types are nominal and the only implicit conversion is to `dyn Trait`: a value must otherwise already have the type its place asks for.");
10172        assert_eq!(
10173            error.help.unwrap(),
10174            "parse the `String` with `Int.parse(text)`, which returns a `Result<Int, Error>`"
10175        );
10176    }
10177
10178    #[test]
10179    fn an_array_literal_takes_its_element_type_from_its_elements() {
10180        accepts_body("  let items = [1, 2]\n  let first: Option<Int> = items.get(0)");
10181        let error = rejects_body("  let items = [1, \"two\"]");
10182        assert_eq!(error.code, MISMATCH);
10183        assert_eq!(error.message, "expected `Int`, found `String`");
10184    }
10185
10186    #[test]
10187    fn an_empty_array_literal_has_no_element_type_to_infer() {
10188        // Nothing says what the elements are, and the operations that do
10189        // not depend on the element type are not enough: a value of a type
10190        // with a hole in it is a value no backend can place. The gap is an
10191        // error of its own, pinned with the other unknowns.
10192        let error =
10193            rejects_body("  let empty = []\n  println(\"{empty.length()} {empty.isEmpty()}\")?");
10194        assert_eq!(error.code, UNCONSTRAINED);
10195    }
10196
10197    #[test]
10198    fn a_later_method_call_settles_what_an_empty_collection_holds() {
10199        // `Vector.of()` has nothing to read an element type off, and
10200        // `push` is what says it. The declared return type proves the
10201        // element type reached the rest of the body: `Array<_>` agreed with
10202        // every declaration before this existed, and `Array<String>`
10203        // disagrees with `Array<Int>`.
10204        accepts(
10205            "\
10206fn build(text: String) -> Array<String> {
10207  var log = Vector.of()
10208  log.push(text)
10209  log.freeze()
10210}
10211",
10212        );
10213        let error = rejects(
10214            "\
10215fn build(text: String) -> Array<Int> {
10216  var log = Vector.of()
10217  log.push(text)
10218  log.freeze()
10219}
10220",
10221        );
10222        // The return type is a use as much as the `push` is, and the two
10223        // disagree, so the report is about the binding rather than about
10224        // the last expression that touched it.
10225        assert_eq!(error.code, INFERENCE_CONFLICT);
10226        assert_eq!(
10227            error.message,
10228            "`log` was settled as `Vector<String>`, but this use needs `Vector<Int>`"
10229        );
10230    }
10231
10232    #[test]
10233    fn every_empty_collection_takes_its_type_from_its_uses() {
10234        // One mechanism, not one rule per collection: `Set`, `Map` and a
10235        // generic declaration of the package's own reach the same
10236        // inference, because each is a call whose result mentions a type
10237        // parameter its arguments did not settle.
10238        accepts(
10239            "\
10240fn build(text: String, n: Int) -> Int {
10241  var names = Set.of()
10242  names = names.inserted(text)
10243  var counts = Map.of()
10244  counts = counts.inserted(text, n)
10245  names.length() + counts.length()
10246}
10247",
10248        );
10249        // `toArray()` rather than `freeze()` because the two questions are
10250        // separate: what settles `log`'s element type is the same either
10251        // way, and `cove_sema::unique` will not let a `freeze()` consume
10252        // storage a *call* produced, however fresh that call's answer is.
10253        accepts(
10254            "\
10255fn empty<T>() -> Vector<T> {
10256  Vector.of()
10257}
10258
10259fn build(text: String) -> Array<String> {
10260  var log = empty()
10261  log.push(text)
10262  log.toArray()
10263}
10264",
10265        );
10266    }
10267
10268    #[test]
10269    fn an_argument_position_settles_what_a_binding_holds() {
10270        accepts(
10271            "\
10272fn count(lines: Vector<String>) -> Int {
10273  lines.length()
10274}
10275
10276fn build(text: String) -> Int {
10277  var log = Vector.of()
10278  count(log)
10279  log.push(text)
10280  count(log)
10281}
10282",
10283        );
10284        let error = rejects(
10285            "\
10286fn count(lines: Vector<String>) -> Int {
10287  lines.length()
10288}
10289
10290fn build(n: Int) -> Int {
10291  var log = Vector.of()
10292  count(log)
10293  log.push(n)
10294  0
10295}
10296",
10297        );
10298        assert_eq!(error.code, INFERENCE_CONFLICT);
10299        assert_eq!(
10300            error.message,
10301            "`log` was settled as `Vector<String>`, but this use needs `Vector<Int>`"
10302        );
10303    }
10304
10305    // ---- issue #265: a generic call reads the whole argument list
10306
10307    #[test]
10308    fn a_generic_parameter_is_bound_from_an_argument_a_binding_only_just_settled() {
10309        // `items` is `Array<a>` here in exactly the same way `log` is
10310        // `Vector<a>` two tests up — the binding's stored type is not
10311        // rewritten until the end of the body — but `a` was settled by the
10312        // `push` calls above it. Before this was fixed, a generic call's
10313        // own unification saw only the still-open `a` and never bound `T`
10314        // to it, so neither the array's element type nor the closure's
10315        // parameter was ever pinned down and `result` came out as a type
10316        // nothing settled.
10317        accepts(
10318            "\
10319fn myFilter<T>(items: Array<T>, keep: fn(item: T) -> Bool) -> Array<T> {
10320  var out = Vector.of()
10321  for item in items {
10322    if keep(item) {
10323      out.push(item)
10324    }
10325  }
10326  out.freeze()
10327}
10328
10329fn build() -> Int {
10330  var v = Vector.of()
10331  v.push(1)
10332  v.push(2)
10333  let items = v.freeze()
10334  let result = myFilter(items, fn(item) { item % 2 == 0 })
10335  result.length()
10336}
10337",
10338        );
10339    }
10340
10341    #[test]
10342    fn an_annotated_closure_parameter_still_settles_a_generic_call_alone() {
10343        // The rescue the issue names as already working, kept working: the
10344        // closure states its own parameter type, which settles `T` without
10345        // any help from `items`.
10346        accepts(
10347            "\
10348fn myFilter<T>(items: Array<T>, keep: fn(item: T) -> Bool) -> Array<T> {
10349  var out = Vector.of()
10350  for item in items {
10351    if keep(item) {
10352      out.push(item)
10353    }
10354  }
10355  out.freeze()
10356}
10357
10358fn build() -> Int {
10359  var v = Vector.of()
10360  v.push(1)
10361  v.push(2)
10362  let items = v.freeze()
10363  let result = myFilter(items, fn(item: Int) { item % 2 == 0 })
10364  result.length()
10365}
10366",
10367        );
10368    }
10369
10370    #[test]
10371    fn a_generic_call_still_unconstrained_reads_as_before() {
10372        // `items` here is never settled by anything at all — not by an
10373        // earlier use, not by an annotation on it or on the closure — so
10374        // reading what the checker already knows about it finds nothing to
10375        // read, exactly as ADR 0038 requires: a type nothing settles is
10376        // still refused, with the same diagnostic as before this fix.
10377        let error = rejects(
10378            "\
10379fn myFilter<T>(items: Array<T>, keep: fn(item: T) -> Bool) -> Array<T> {
10380  var out = Vector.of()
10381  for item in items {
10382    if keep(item) {
10383      out.push(item)
10384    }
10385  }
10386  out.freeze()
10387}
10388
10389fn build() -> Int {
10390  let items = Vector.of().freeze()
10391  let result = myFilter(items, fn(item: Int) { item == item })
10392  result.length()
10393}
10394",
10395        );
10396        assert_eq!(error.code, UNCONSTRAINED);
10397        assert_eq!(
10398            error.message,
10399            "nothing says what the `_` in `items: Array<_>` is"
10400        );
10401    }
10402
10403    #[test]
10404    fn two_type_parameters_are_settled_from_different_arguments() {
10405        // Neither argument alone determines both `T` and `U`: `items`
10406        // settles `T` and says nothing about `U`, and `transform` settles
10407        // `U` only once `T` is known, because its own parameter is
10408        // unannotated and takes its type from the call. The two settle the
10409        // call together.
10410        accepts(
10411            "\
10412fn myMap<T, U>(items: Array<T>, transform: fn(item: T) -> U) -> Array<U> {
10413  var out = Vector.of()
10414  for item in items {
10415    out.push(transform(item))
10416  }
10417  out.freeze()
10418}
10419
10420fn build() -> Int {
10421  var v = Vector.of()
10422  v.push(1)
10423  v.push(2)
10424  let items = v.freeze()
10425  let result = myMap(items, fn(item) { \"{item}\" })
10426  result.length()
10427}
10428",
10429        );
10430    }
10431
10432    #[test]
10433    fn an_assignment_settles_what_a_binding_holds() {
10434        // `toArray()`, because `log = lines` gives `log` storage the caller
10435        // is still holding and `cove_sema::unique` refuses to `freeze()`
10436        // that — correctly, and for a reason that has nothing to do with
10437        // what this test is about.
10438        accepts(
10439            "\
10440fn build(lines: Vector<String>) -> Array<String> {
10441  var log = Vector.of()
10442  log = lines
10443  log.toArray()
10444}
10445",
10446        );
10447        let error = rejects(
10448            "\
10449fn build(lines: Vector<String>) -> Array<Int> {
10450  var log = Vector.of()
10451  log = lines
10452  log.freeze()
10453}
10454",
10455        );
10456        assert_eq!(error.code, INFERENCE_CONFLICT);
10457        assert_eq!(
10458            error.message,
10459            "`log` was settled as `Vector<String>`, but this use needs `Vector<Int>`"
10460        );
10461    }
10462
10463    #[test]
10464    fn two_uses_that_disagree_are_an_error_naming_both() {
10465        let error = rejects(
10466            "\
10467fn build(text: String, n: Int) -> Int {
10468  var log = Vector.of()
10469  log.push(text)
10470  log.push(n)
10471  log.length()
10472}
10473",
10474        );
10475        assert_eq!(error.code, INFERENCE_CONFLICT);
10476        assert_eq!(
10477            error.message,
10478            "`log` was settled as `Vector<String>`, but this use needs `Vector<Int>`"
10479        );
10480        assert_eq!(error.rule.unwrap(), "A binding whose initializer leaves a type open takes that type from its uses, and every use of it means the same type.");
10481        assert_eq!(
10482            error.help.unwrap(),
10483            "write the type on the binding, as in `log: Vector<String>`, and correct whichever use disagrees"
10484        );
10485        // Both constraints are pointed at, and the binding that has neither.
10486        assert_eq!(error.labels.len(), 2);
10487    }
10488
10489    #[test]
10490    fn a_third_use_does_not_report_the_same_disagreement_again() {
10491        let errors = errors_of(
10492            "\
10493fn build(text: String, n: Int) -> Int {
10494  var log = Vector.of()
10495  log.push(text)
10496  log.push(n)
10497  log.push(n)
10498  log.length()
10499}
10500",
10501        );
10502        assert_eq!(errors.len(), 1, "found: {errors:?}");
10503    }
10504
10505    #[test]
10506    fn a_binding_nothing_settles_asks_for_the_annotation() {
10507        let error = rejects(
10508            "\
10509fn build() -> Int {
10510  var log = Vector.of()
10511  log.length()
10512}
10513",
10514        );
10515        assert_eq!(error.code, UNCONSTRAINED);
10516        assert_eq!(
10517            error.message,
10518            "nothing says what the `_` in `log: Vector<_>` is"
10519        );
10520        assert_eq!(error.rule.unwrap(), "A type the checker infers is inferred from something written: a value, an annotation, or the type of the place the value is given to.");
10521        assert_eq!(
10522            error.help.unwrap(),
10523            "write the type on the binding, as in `log: Vector<_>` with the `_` filled in, or use `log` in a way that says what it holds"
10524        );
10525    }
10526
10527    /// A value no binding holds is asked at the value, because there is no
10528    /// name to ask about.
10529    #[test]
10530    fn a_value_no_binding_holds_is_asked_where_it_is_written() {
10531        let error = rejects(
10532            "\
10533fn build() -> Int {
10534  Vector.of().length()
10535}
10536",
10537        );
10538        assert_eq!(error.code, UNCONSTRAINED);
10539        assert_eq!(error.message, "nothing says what the `_` in `Vector<_>` is");
10540        assert_eq!(
10541            error.help.unwrap(),
10542            "bind this value first, with the type written, as in `let value: Vector<_> = ...` with the `_` filled in"
10543        );
10544    }
10545
10546    #[test]
10547    fn a_written_annotation_settles_it_without_any_use() {
10548        // The other half of the rule: what the program states, it states,
10549        // and the inference has nothing left to do.
10550        assert!(warnings_of(
10551            "\
10552fn build() -> Int {
10553  var log: Vector<String> = Vector.of()
10554  log.length()
10555}
10556"
10557        )
10558        .is_empty());
10559    }
10560
10561    #[test]
10562    fn inference_does_not_reach_across_a_declaration() {
10563        // Two bindings of the same name in two declarations are two
10564        // variables, settled apart. Were they one, the second `push` would
10565        // disagree with the first.
10566        accepts(
10567            "\
10568fn first(text: String) -> Int {
10569  var log = Vector.of()
10570  log.push(text)
10571  log.length()
10572}
10573
10574fn second(n: Int) -> Int {
10575  var log = Vector.of()
10576  log.push(n)
10577  log.length()
10578}
10579",
10580        );
10581        assert!(warnings_of(
10582            "\
10583fn first(text: String) -> Int {
10584  var log = Vector.of()
10585  log.push(text)
10586  log.length()
10587}
10588
10589fn second(n: Int) -> Int {
10590  var log = Vector.of()
10591  log.push(n)
10592  log.length()
10593}
10594"
10595        )
10596        .is_empty());
10597    }
10598
10599    #[test]
10600    fn a_vector_that_holds_itself_is_refused() {
10601        // `v.push(v)` says what `v` holds in terms of `v` itself. The type
10602        // it asks for is `μX. Vector<X>` — regular and finitely
10603        // representable, and with no surface syntax, because recursion here
10604        // is nominal and this inference is structural. So the constraint is
10605        // read exactly and then cannot be kept, and what the program is
10606        // left holding is a type nothing settles.
10607        //
10608        // It used to be carried silently, which made it the one way a clean
10609        // `cove check` handed a backend a `Vector<_>`. The remedy is a
10610        // declared type, which is what `tests/e2e/gc_cycles` writes.
10611        let error = rejects(
10612            "\
10613fn churn() {
10614  var v = Vector.of()
10615  v.push(v)
10616}
10617",
10618        );
10619        assert_eq!(error.code, RECURSIVE_TYPE);
10620        assert_eq!(
10621            error.message,
10622            "this use makes `v` hold a `Vector<_>`, which holds itself"
10623        );
10624        assert_eq!(error.rule.unwrap(), "A type the checker infers is a type the program could have written, and a type that contains itself is written by declaring one.");
10625        assert_eq!(
10626            error.help.unwrap(),
10627            "declare a struct or an enum for the thing that repeats and hold that, as in `struct Node { next: Vector<Node> }`"
10628        );
10629    }
10630
10631    /// The declared form the refusal points at, which is what the corpus
10632    /// writes instead.
10633    #[test]
10634    fn a_cycle_through_a_declared_type_is_accepted() {
10635        accepts(
10636            "\
10637struct Node {
10638  next: Vector<Node>
10639}
10640
10641fn churn() {
10642  var v: Vector<Node> = Vector.of()
10643  v.push(Node(next: v))
10644}
10645",
10646        );
10647    }
10648
10649    #[test]
10650    fn a_use_inside_a_nested_block_settles_the_binding() {
10651        // The inference scope is the body, not the statement: a use inside
10652        // a loop, an `if`, or any other nested block is a use like any
10653        // other, and this is the shape the corpus is written in.
10654        accepts(
10655            "\
10656fn build(lines: Array<String>) -> Array<String> {
10657  var log = Vector.of()
10658  for line in lines {
10659    log.push(line)
10660  }
10661  log.freeze()
10662}
10663",
10664        );
10665    }
10666
10667    #[test]
10668    fn a_vector_grows_and_freezes_into_an_array() {
10669        accepts(
10670            "\
10671fn build(upTo: Int) -> Array<Int> {
10672  var building = Vector.of(1)
10673  for n in 1..upTo {
10674    building.push(n)
10675  }
10676  building.freeze()
10677}
10678",
10679        );
10680        let error = rejects(
10681            "\
10682fn build() -> Array<String> {
10683  var building = Vector.of(1)
10684  building.freeze()
10685}
10686",
10687        );
10688        assert_eq!(error.code, MISMATCH);
10689        assert_eq!(
10690            error.message,
10691            "expected `Array<String>`, found `Array<Int>`"
10692        );
10693    }
10694
10695    #[test]
10696    fn snapshot_returns_the_receiver_s_own_type_for_every_builtin_value() {
10697        accepts_body(
10698            "\
10699  let n: Int = 1.snapshot()
10700  let s: String = \"a\".snapshot()
10701  let arr: Array<Int> = [1, 2].snapshot()
10702  var v: Vector<Int> = Vector.of(1).snapshot()
10703  println(\"{n} {s} {arr} {v}\")?
10704",
10705        );
10706    }
10707
10708    #[test]
10709    fn rejects_snapshot_on_a_closure() {
10710        let error = rejects_body(
10711            "\
10712  let handler = fn(x: Int) { x }
10713  println(\"{handler.snapshot()}\")?
10714",
10715        );
10716        assert_eq!(error.code, UNKNOWN_METHOD);
10717        assert_eq!(
10718            error.message,
10719            "`fn(Int) -> Int` does not implement `Snapshot`"
10720        );
10721        assert!(error.rule.unwrap().contains("Closures"));
10722    }
10723
10724    #[test]
10725    fn a_vector_push_takes_the_element_type() {
10726        let error = rejects(
10727            "\
10728fn build() -> Array<Int> {
10729  var building = Vector.of(1)
10730  building.push(\"two\")
10731  building.freeze()
10732}
10733",
10734        );
10735        assert_eq!(error.code, MISMATCH);
10736        assert_eq!(error.message, "expected `Int`, found `String`");
10737    }
10738
10739    /// `Result.unwrapOr` is `Option.unwrapOr`'s sibling, so the two are
10740    /// checked together: the fallback is the type inside, the result is that
10741    /// type, and the error type is not named by either half of the
10742    /// signature.
10743    #[test]
10744    fn unwrap_or_takes_the_type_inside_on_both_option_and_result() {
10745        accepts_body(
10746            "  let found: Int = [1].get(0).unwrapOr(0)\n\
10747             \x20 let parsed: Int = Int.parse(\"1\").unwrapOr(0)\n\
10748             \x20 let mapped: Int = Int.parse(\"1\").mapError(fn(error) { \"bad\" }).unwrapOr(0)",
10749        );
10750        let error = rejects_body("  Int.parse(\"1\").unwrapOr(\"zero\")");
10751        assert_eq!(error.code, MISMATCH);
10752        assert_eq!(error.message, "expected `Int`, found `String`");
10753        let error = rejects_body("  let n: String = Int.parse(\"1\").unwrapOr(0)");
10754        assert_eq!(error.code, MISMATCH);
10755        assert_eq!(error.message, "expected `String`, found `Int`");
10756    }
10757
10758    /// A `Result` where its own `Ok` type was expected now has the same one
10759    /// correction an `Option` has, because it now has the same method.
10760    #[test]
10761    fn a_result_where_its_ok_type_belongs_is_told_about_unwrap_or() {
10762        let error = rejects_body("  let n: Int = Int.parse(\"1\")");
10763        assert_eq!(error.code, MISMATCH);
10764        assert_eq!(
10765            error.help.unwrap(),
10766            "unwrap it, as in `value.unwrapOr(<Int>)`, which always produces a `Int`"
10767        );
10768    }
10769
10770    /// `Int.parse` is one argument and decimal, and `Int.parseRadix` is two
10771    /// and is not. That `parse` keeps its arity is the point of their being
10772    /// two functions, so it is what this checks first.
10773    #[test]
10774    fn int_parse_and_parse_radix_are_two_signatures() {
10775        accepts_body(
10776            "  let decimal: Result<Int, Error> = Int.parse(\"12\")\n\
10777             \x20 let hex: Result<Int, Error> = Int.parseRadix(\"ff\", 16)",
10778        );
10779        let error = rejects_body("  Int.parse(\"ff\", 16)");
10780        assert_eq!(error.code, ARITY);
10781        let error = rejects_body("  Int.parseRadix(\"ff\")");
10782        assert_eq!(error.code, MISSING_ARGUMENT);
10783        let error = rejects_body("  Int.parseRadix(\"ff\", \"16\")");
10784        assert_eq!(error.code, MISMATCH);
10785        assert_eq!(error.message, "expected `Int`, found `String`");
10786    }
10787
10788    /// A character is a `String` of length 1, so this answers a `String` and
10789    /// not some type of its own — and a `Result`, because a number that names
10790    /// no character is a failure the caller handles.
10791    #[test]
10792    fn from_code_point_answers_a_result_of_string() {
10793        accepts_body(
10794            "  let character: Result<String, Error> = String.fromCodePoint(65)\n\
10795             \x20 let letter: String = String.fromCodePoint(65).unwrapOr(\"?\")",
10796        );
10797        let error = rejects_body("  String.fromCodePoint(\"A\")");
10798        assert_eq!(error.code, MISMATCH);
10799        assert_eq!(error.message, "expected `Int`, found `String`");
10800        let error = rejects_body("  let letter: String = String.fromCodePoint(65)");
10801        assert_eq!(error.code, MISMATCH);
10802        assert_eq!(
10803            error.message,
10804            "expected `String`, found `Result<String, Error>`"
10805        );
10806    }
10807
10808    #[test]
10809    fn checks_every_map_operation() {
10810        accepts_body(
10811            "  let ages = Map.of(MapEntry(key: \"Alice\", value: 30))\n\
10812             \x20 let found: Option<Int> = ages.get(\"Alice\")\n\
10813             \x20 let has: Bool = ages.contains(\"Bob\")\n\
10814             \x20 let n: Int = ages.length()\n\
10815             \x20 let empty: Bool = ages.isEmpty()\n\
10816             \x20 let names: Array<String> = ages.keys()\n\
10817             \x20 let numbers: Array<Int> = ages.values()\n\
10818             \x20 let more: Map<String, Int> = ages.inserted(\"Carol\", 41)\n\
10819             \x20 let fewer: Map<String, Int> = ages.removed(\"Alice\")",
10820        );
10821        let error =
10822            rejects_body("  let ages = Map.of(MapEntry(key: \"Alice\", value: 30))\n  ages.get(1)");
10823        assert_eq!(error.code, MISMATCH);
10824        assert_eq!(error.message, "expected `String`, found `Int`");
10825    }
10826
10827    #[test]
10828    fn checks_every_set_operation() {
10829        accepts_body(
10830            "  let tags = Set.of(\"a\", \"b\")\n\
10831             \x20 let has: Bool = tags.contains(\"a\")\n\
10832             \x20 let n: Int = tags.length()\n\
10833             \x20 let empty: Bool = tags.isEmpty()\n\
10834             \x20 let items: Array<String> = tags.toArray()\n\
10835             \x20 let bigger: Set<String> = tags.inserted(\"c\")\n\
10836             \x20 let smaller: Set<String> = tags.removed(\"a\")",
10837        );
10838        let error = rejects_body("  let tags = Set.of(\"a\")\n  tags.contains(1)");
10839        assert_eq!(error.code, MISMATCH);
10840        assert_eq!(error.message, "expected `String`, found `Int`");
10841    }
10842
10843    #[test]
10844    fn map_of_collects_map_entries() {
10845        let error = rejects_body("  let ages = Map.of(1)");
10846        assert_eq!(error.code, MISMATCH);
10847        assert_eq!(error.message, "expected `MapEntry<_, _>`, found `Int`");
10848
10849        let error = rejects_body(
10850            "  let ages = Map.of(MapEntry(key: \"a\", value: 1), MapEntry(key: 2, value: 3))",
10851        );
10852        assert_eq!(error.code, MISMATCH);
10853        assert_eq!(
10854            error.message,
10855            "expected `MapEntry<String, Int>`, found `MapEntry<Int, Int>`"
10856        );
10857    }
10858
10859    #[test]
10860    fn a_map_entry_carries_a_key_and_a_value() {
10861        accepts_body(
10862            "  let entry = MapEntry(key: \"a\", value: 1)\n\
10863             \x20 let key: String = entry.key\n\
10864             \x20 let value: Int = entry.value",
10865        );
10866        let error = rejects_body("  let entry = MapEntry(key: \"a\", value: 1)\n  entry.other");
10867        assert_eq!(error.code, UNKNOWN_FIELD);
10868        assert_eq!(error.message, "`MapEntry` has no field `other`");
10869        assert_eq!(
10870            error.rule.unwrap(),
10871            "A builtin struct's fields are exactly the ones the language defines."
10872        );
10873        assert_eq!(error.help.unwrap(), "`MapEntry` declares `key`, `value`");
10874    }
10875
10876    /// The runtime builds an `Error` with a `message` and has always served a
10877    /// read of it; the checker used to answer that `Error` had no such field
10878    /// and suggest a method `Error` does not have. One table is what let the
10879    /// two agree.
10880    #[test]
10881    fn an_error_carries_a_message() {
10882        accepts_body("  let message: String = Error(\"boom\").message");
10883        accepts_body(
10884            "  let outcome: Result<Int, Error> = Err(Error(\"boom\"))\n\
10885             \x20 match outcome {\n\
10886             \x20   Ok(n) => n,\n\
10887             \x20   Err(failure) => failure.message.length()\n\
10888             \x20 }",
10889        );
10890        let error = rejects_body("  let code = Error(\"boom\").code");
10891        assert_eq!(error.code, UNKNOWN_FIELD);
10892        assert_eq!(error.message, "`Error` has no field `code`");
10893        assert_eq!(
10894            error.rule.unwrap(),
10895            "A builtin struct's fields are exactly the ones the language defines."
10896        );
10897        assert_eq!(error.help.unwrap(), "`Error` declares `message`");
10898    }
10899
10900    /// An `Error`'s message is a `String`, so using it as anything else is
10901    /// the ordinary mismatch rather than an unknown field.
10902    #[test]
10903    fn an_error_s_message_is_a_string() {
10904        let error = rejects_body("  let code: Int = Error(\"boom\").message");
10905        assert_eq!(error.code, MISMATCH);
10906        assert_eq!(error.message, "expected `Int`, found `String`");
10907    }
10908
10909    #[test]
10910    fn a_map_iterates_map_entries_and_a_set_its_elements() {
10911        accepts_body(
10912            "  let ages = Map.of(MapEntry(key: \"a\", value: 1))\n\
10913             \x20 for entry in ages {\n\
10914             \x20   let key: String = entry.key\n\
10915             \x20   let value: Int = entry.value\n\
10916             \x20 }\n\
10917             \x20 for tag in Set.of(\"a\") {\n\
10918             \x20   let element: String = tag\n\
10919             \x20 }",
10920        );
10921        let error = rejects_body(
10922            "  let ages = Map.of(MapEntry(key: \"a\", value: 1))\n\
10923             \x20 for entry in ages {\n\
10924             \x20   let key: Int = entry.key\n\
10925             \x20 }",
10926        );
10927        assert_eq!(error.code, MISMATCH);
10928        assert_eq!(error.message, "expected `Int`, found `String`");
10929    }
10930
10931    #[test]
10932    fn checks_every_range_operation() {
10933        accepts_body(
10934            "  let range = 0..<3\n\
10935             \x20 let n: Int = range.length()\n\
10936             \x20 let empty: Bool = range.isEmpty()\n\
10937             \x20 let has: Bool = range.contains(1)",
10938        );
10939        let error = rejects_body("  let range = 0..<3\n  range.contains(\"one\")");
10940        assert_eq!(error.code, MISMATCH);
10941        assert_eq!(error.message, "expected `Int`, found `String`");
10942    }
10943
10944    #[test]
10945    fn checks_struct_initialization_and_field_access() {
10946        accepts(
10947            "\
10948struct Point { x: Int, y: Int }
10949
10950fn sum(point: Point) -> Int {
10951  point.x + point.y
10952}
10953
10954fn origin() -> Point {
10955  Point(x: 0, y: 0)
10956}
10957",
10958        );
10959    }
10960
10961    #[test]
10962    fn rejects_a_struct_field_of_the_wrong_type() {
10963        let error = rejects(
10964            "\
10965struct Point { x: Int, y: Int }
10966
10967fn origin() -> Point {
10968  Point(x: 0, y: \"zero\")
10969}
10970",
10971        );
10972        assert_eq!(error.code, MISMATCH);
10973        assert_eq!(error.message, "expected `Int`, found `String`");
10974        assert_eq!(error.labels[0].message, "the field `y` is `Int`");
10975    }
10976
10977    #[test]
10978    fn rejects_a_missing_struct_field() {
10979        let error = rejects(
10980            "\
10981struct Point { x: Int, y: Int }
10982
10983fn origin() -> Point {
10984  Point(x: 0)
10985}
10986",
10987        );
10988        assert_eq!(error.code, MISSING_ARGUMENT);
10989        assert_eq!(error.message, "`Point` needs the field `y`");
10990        assert_eq!(
10991            error.rule.unwrap(),
10992            "A call passes every parameter that has no default."
10993        );
10994        assert_eq!(error.help.unwrap(), "pass `y: <Int>`");
10995    }
10996
10997    #[test]
10998    fn rejects_a_field_the_struct_does_not_declare() {
10999        let error = rejects(
11000            "\
11001struct Point { x: Int, y: Int }
11002
11003fn z(point: Point) -> Int {
11004  point.z
11005}
11006",
11007        );
11008        assert_eq!(error.code, UNKNOWN_FIELD);
11009        assert_eq!(error.message, "`Point` has no field `z`");
11010        assert_eq!(
11011            error.rule.unwrap(),
11012            "A struct's fields are exactly the ones its declaration lists."
11013        );
11014        assert_eq!(error.help.unwrap(), "`Point` declares `x`, `y`");
11015    }
11016
11017    #[test]
11018    fn checks_enum_construction_and_match_payloads() {
11019        accepts(
11020            "\
11021enum Status {
11022  Pending
11023  Active(Int)
11024}
11025
11026fn describe(status: Status) -> String {
11027  match status {
11028    Status.Pending => \"pending\"
11029    Status.Active(since) => \"active since {since}\"
11030  }
11031}
11032
11033fn active() -> Status {
11034  Status.Active(7)
11035}
11036",
11037        );
11038    }
11039
11040    #[test]
11041    fn rejects_an_enum_payload_of_the_wrong_type() {
11042        let error = rejects(
11043            "\
11044enum Status {
11045  Active(Int)
11046}
11047
11048fn active() -> Status {
11049  Status.Active(\"now\")
11050}
11051",
11052        );
11053        assert_eq!(error.code, MISMATCH);
11054        assert_eq!(error.message, "expected `Int`, found `String`");
11055    }
11056
11057    #[test]
11058    fn rejects_an_enum_payload_of_the_wrong_arity() {
11059        let error = rejects(
11060            "\
11061enum Status {
11062  Active(Int)
11063}
11064
11065fn active() -> Status {
11066  Status.Active(1, 2)
11067}
11068",
11069        );
11070        assert_eq!(error.code, PAYLOAD_ARITY);
11071        assert_eq!(
11072            error.message,
11073            "`Status.Active` carries 1 value(s), but 2 were given"
11074        );
11075        assert_eq!(
11076            error.rule.unwrap(),
11077            "An enum case carries exactly the payload its declaration writes."
11078        );
11079        assert_eq!(error.help.unwrap(), "write `Status.Active(Int)`");
11080    }
11081
11082    #[test]
11083    fn rejects_a_case_the_enum_does_not_declare() {
11084        let error = rejects(
11085            "\
11086enum Status {
11087  Pending
11088}
11089
11090fn active() -> Status {
11091  Status.Active
11092}
11093",
11094        );
11095        assert_eq!(error.code, UNKNOWN_CASE);
11096        assert_eq!(error.message, "`Status` has no case `Active`");
11097        assert_eq!(
11098            error.rule.unwrap(),
11099            "An enum's cases are exactly the ones its declaration lists."
11100        );
11101        assert_eq!(error.help.unwrap(), "`Status` declares `Pending`");
11102    }
11103
11104    #[test]
11105    fn rejects_a_pattern_from_another_enum() {
11106        let error = rejects(
11107            "\
11108enum Suit {
11109  Hearts
11110}
11111
11112enum Card {
11113  Blank
11114}
11115
11116fn name(card: Card) -> String {
11117  match card {
11118    Suit.Hearts => \"hearts\"
11119    _ => \"other\"
11120  }
11121}
11122",
11123        );
11124        assert_eq!(error.code, PATTERN);
11125        assert_eq!(
11126            error.message,
11127            "this pattern matches `Suit`, but the scrutinee is `Card`"
11128        );
11129        assert_eq!(
11130            error.rule.unwrap(),
11131            "A pattern matches values of the scrutinee's type."
11132        );
11133        assert_eq!(
11134            error.help.unwrap(),
11135            "write a `Card` case, such as `Card.Blank`"
11136        );
11137    }
11138
11139    #[test]
11140    fn rejects_a_literal_pattern_of_another_type() {
11141        let error = rejects(
11142            "\
11143fn name(n: Int) -> String {
11144  match n {
11145    \"one\" => \"one\"
11146    _ => \"other\"
11147  }
11148}
11149",
11150        );
11151        assert_eq!(error.code, PATTERN);
11152        assert_eq!(
11153            error.message,
11154            "this pattern matches `String`, but the scrutinee is `Int`"
11155        );
11156        assert_eq!(
11157            error.help.unwrap(),
11158            "write a `Int` literal, or a binding such as `other`"
11159        );
11160    }
11161
11162    #[test]
11163    fn checks_methods_and_associated_functions() {
11164        accepts(
11165            "\
11166struct Counter { hits: Int }
11167
11168impl Counter {
11169  fn start() -> Counter {
11170    Counter(hits: 0)
11171  }
11172
11173  fn hit(var self) {
11174    self.hits += 1
11175  }
11176
11177  fn describe(self) -> String {
11178    \"{self.hits}\"
11179  }
11180}
11181
11182fn run() -> String {
11183  var counter = Counter.start()
11184  counter.hit()
11185  counter.describe()
11186}
11187",
11188        );
11189    }
11190
11191    #[test]
11192    fn a_method_needs_a_receiver_and_an_associated_function_takes_none() {
11193        let source = "\
11194struct Counter { hits: Int }
11195
11196impl Counter {
11197  fn start() -> Counter {
11198    Counter(hits: 0)
11199  }
11200
11201  fn describe(self) -> String {
11202    \"{self.hits}\"
11203  }
11204}
11205";
11206        let error = rejects(&format!(
11207            "{source}\nfn run() -> String {{\n  Counter.describe()\n}}\n"
11208        ));
11209        assert_eq!(error.code, RECEIVER);
11210        assert_eq!(
11211            error.message,
11212            "`Counter.describe` is a method and needs a receiver"
11213        );
11214        assert_eq!(
11215            error.rule.unwrap(),
11216            "A method is called on a value; only an associated function is called on its type."
11217        );
11218        assert_eq!(
11219            error.help.unwrap(),
11220            "call it on a value, as in `value.describe(...)`, or declare `fn describe()` without `self`"
11221        );
11222
11223        let error = rejects(&format!(
11224            "{source}\nfn run(counter: Counter) -> Counter {{\n  counter.start()\n}}\n"
11225        ));
11226        assert_eq!(error.code, RECEIVER);
11227        assert_eq!(error.message, "`Counter.start` takes no receiver");
11228        assert_eq!(error.help.unwrap(), "write `Counter.start(...)`");
11229    }
11230
11231    #[test]
11232    fn rejects_a_method_the_type_does_not_declare() {
11233        let error = rejects(
11234            "\
11235struct Counter { hits: Int }
11236
11237impl Counter {
11238  fn describe(self) -> String {
11239    \"{self.hits}\"
11240  }
11241}
11242
11243fn run(counter: Counter) -> String {
11244  counter.report()
11245}
11246",
11247        );
11248        assert_eq!(error.code, UNKNOWN_METHOD);
11249        assert_eq!(error.message, "`Counter` has no method `report`");
11250        assert_eq!(
11251            error.rule.unwrap(),
11252            "A method is declared in its type's `impl` block."
11253        );
11254        assert_eq!(error.help.unwrap(), "`Counter` declares `describe`");
11255    }
11256
11257    #[test]
11258    fn rejects_an_associated_function_the_type_does_not_declare() {
11259        let error = rejects(
11260            "\
11261struct Counter { hits: Int }
11262
11263fn run() -> Counter {
11264  Counter.start()
11265}
11266",
11267        );
11268        assert_eq!(error.code, UNKNOWN_ASSOCIATED);
11269        assert_eq!(
11270            error.message,
11271            "`Counter` has no associated function `start`"
11272        );
11273        assert_eq!(
11274            error.help.unwrap(),
11275            "`Counter` declares no methods; declare one in `impl Counter`"
11276        );
11277    }
11278
11279    #[test]
11280    fn count_is_spelled_length() {
11281        let error = rejects_body("  let items = [1]\n  println(\"{items.count()}\")?");
11282        assert_eq!(error.code, UNKNOWN_METHOD);
11283        assert_eq!(
11284            error.message,
11285            "`Array` has no method `count`; Cove spells the number of elements `length()`"
11286        );
11287        assert_eq!(
11288            error.rule.unwrap(),
11289            "Every sequence reports its element count as `length()`; there is no `count()`."
11290        );
11291        assert_eq!(error.help.unwrap(), "write `length()` instead of `count()`");
11292    }
11293
11294    /// Every receiver that answers `length()` is told so, which is what the
11295    /// runtime already did: `Map` and `Set` used to be taught the spelling at
11296    /// run time and told nothing here.
11297    #[test]
11298    fn every_sequence_is_told_that_count_is_spelled_length() {
11299        let receivers = [
11300            ("Array", "let items = [1]\n  items"),
11301            ("Vector", "var items = Vector.of(1)\n  items"),
11302            ("String", "let text = \"ab\"\n  text"),
11303            ("Range", "let span = 0..<3\n  span"),
11304            (
11305                "Map",
11306                "let ages = Map.of(MapEntry(key: \"a\", value: 1))\n  ages",
11307            ),
11308            ("Set", "let seen = Set.of(1)\n  seen"),
11309        ];
11310        for (type_name, receiver) in receivers {
11311            let error = rejects_body(&format!("  {receiver}.count()"));
11312            assert_eq!(error.code, UNKNOWN_METHOD, "{type_name}");
11313            assert_eq!(
11314                error.message,
11315                format!(
11316                    "`{type_name}` has no method `count`; Cove spells the number of elements `length()`"
11317                )
11318            );
11319            assert_eq!(
11320                error.help.unwrap(),
11321                "write `length()` instead of `count()`",
11322                "{type_name}"
11323            );
11324        }
11325    }
11326
11327    // ------------------------------ walking a sequence with a closure
11328
11329    /// A callback's own parameters come from the receiver's element type,
11330    /// with nothing written, and its body is checked in them.
11331    ///
11332    /// This is the signature a higher-order builtin is most easily got
11333    /// wrong: the closure is written at the call site with no types on it,
11334    /// so everything it is held to comes from the shared table by way of the
11335    /// receiver.
11336    #[test]
11337    fn a_callbacks_parameters_come_from_the_element_type() {
11338        accepts_body(
11339            "  let words = [\"a\", \"bb\"]\n  \
11340             let lengths = words.map(fn(w) { w.length() })\n  \
11341             let long = words.filter(fn(w) { w.length() > 1 })\n  \
11342             let total = words.fold(0, fn(t, w) { t + w.length() })\n  \
11343             let ordered = words.sorted(by: fn(a, b) { a < b })",
11344        );
11345        let error = rejects_body("  let words = [\"a\"]\n  let n = words.map(fn(w) { w + 1 })");
11346        assert_eq!(error.code, OPERATOR);
11347        assert_eq!(error.message, "`+` is not defined for `String` and `Int`");
11348    }
11349
11350    /// What a walk answers is read off the callback, and it is an `Array`
11351    /// whichever sequence the walk started from.
11352    #[test]
11353    fn a_walk_answers_an_array_of_what_its_callback_produced() {
11354        for (receiver, answer) in [
11355            ("let items = [1, 2]", "Array<String>"),
11356            ("var items = Vector.of(1, 2)", "Array<String>"),
11357        ] {
11358            let error = rejects_body(&format!(
11359                "  {receiver}\n  let n: Int = items.map(fn(v) {{ \"{{v}}\" }})"
11360            ));
11361            assert_eq!(error.code, MISMATCH);
11362            assert_eq!(error.message, format!("expected `Int`, found `{answer}`"));
11363        }
11364        let error = rejects_body(
11365            "  let items = [1, 2]\n  let n: Int = items.sorted(by: fn(a, b) { a < b })",
11366        );
11367        assert_eq!(error.message, "expected `Int`, found `Array<Int>`");
11368        let error = rejects_body(
11369            "  var items = Vector.of(1, 2)\n  let n: Int = items.filter(fn(v) { v > 1 })",
11370        );
11371        assert_eq!(error.message, "expected `Int`, found `Array<Int>`");
11372    }
11373
11374    /// `fold`'s accumulator is settled by `initial`, so a `step` that answers
11375    /// something else is a mismatch and not a second accumulator type.
11376    #[test]
11377    fn folds_accumulator_is_the_type_its_initial_value_has() {
11378        accepts_body(
11379            "  let items = [1, 2]\n  let text = items.fold(\"\", fn(t, n) { \"{t}{n}\" })",
11380        );
11381        let error =
11382            rejects_body("  let items = [1, 2]\n  let n = items.fold(0, fn(t, v) { \"{t}\" })");
11383        assert_eq!(error.code, MISMATCH);
11384        assert_eq!(error.message, "expected `Int`, found `String`");
11385    }
11386
11387    /// A callback of the wrong arity is reported against the shape the
11388    /// signature declares, at the closure rather than at the call.
11389    #[test]
11390    fn a_callback_takes_the_parameters_its_builtin_declares() {
11391        let error =
11392            rejects_body("  let items = [2, 1]\n  let n = items.sorted(by: fn(a) { true })");
11393        assert_eq!(error.code, ARITY);
11394        assert_eq!(
11395            error.message,
11396            "this function takes 1 parameter(s), but 2 were expected here"
11397        );
11398        let error = rejects_body("  let items = [2, 1]\n  let n = items.map(fn(a, b) { a })");
11399        assert_eq!(error.code, ARITY);
11400        assert_eq!(
11401            error.message,
11402            "this function takes 2 parameter(s), but 1 were expected here"
11403        );
11404    }
11405
11406    /// `filter` and `sorted` declare a `Bool` result, so a callback that
11407    /// answers anything else is refused — which is also what makes a `?`
11408    /// inside one a check-time mismatch rather than a runtime surprise.
11409    #[test]
11410    fn a_predicate_callback_must_answer_a_bool() {
11411        let error = rejects_body("  let items = [1, 2]\n  let n = items.filter(fn(v) { v })");
11412        assert_eq!(error.code, MISMATCH);
11413        assert_eq!(error.message, "expected `Bool`, found `Int`");
11414        let error =
11415            rejects_body("  let items = [2, 1]\n  let n = items.sorted(by: fn(a, b) { a - b })");
11416        assert_eq!(error.code, MISMATCH);
11417        assert_eq!(error.message, "expected `Bool`, found `Int`");
11418    }
11419
11420    // -------------------- membership, position, and part of a sequence
11421
11422    /// `contains`, `indexOf`, and `slice` read the same on either sequence,
11423    /// and each answers what the shared table says.
11424    ///
11425    /// The element parameter is where these are got wrong: it is the
11426    /// receiver's own `T`, so a `contains` of the wrong type is a mismatch
11427    /// rather than a `false`, which is the whole reason a sequence's
11428    /// membership is checked and a `Map`'s `Any` key would not be.
11429    #[test]
11430    fn a_sequence_answers_membership_position_and_a_part_of_itself() {
11431        for receiver in ["let items = [1, 2]", "var items = Vector.of(1, 2)"] {
11432            accepts_body(&format!(
11433                "  {receiver}\n  \
11434                 let held: Bool = items.contains(1)\n  \
11435                 let at: Option<Int> = items.indexOf(2)\n  \
11436                 let first: Array<Int> = items.slice(0, 1)"
11437            ));
11438            let error = rejects_body(&format!("  {receiver}\n  let n = items.contains(\"1\")"));
11439            assert_eq!(error.code, MISMATCH);
11440            assert_eq!(error.message, "expected `Int`, found `String`");
11441            let error = rejects_body(&format!("  {receiver}\n  let n: Int = items.indexOf(1)"));
11442            assert_eq!(error.message, "expected `Int`, found `Option<Int>`");
11443            let error = rejects_body(&format!("  {receiver}\n  let n = items.slice(0)"));
11444            assert_eq!(error.code, MISSING_ARGUMENT);
11445        }
11446    }
11447
11448    /// A `Set` answers membership and nothing about a position, because a
11449    /// set has none to answer about.
11450    ///
11451    /// The ascending order a `Set` and a `Map` are stored in is the
11452    /// collection's, not a caller's: `toArray()` is where a program takes
11453    /// that ordering as its own, and what it answers has both.
11454    #[test]
11455    fn an_unordered_collection_answers_membership_and_not_a_position() {
11456        accepts_body("  let seen = Set.of(1, 2)\n  let held: Bool = seen.contains(1)");
11457        accepts_body(
11458            "  let seen = Set.of(1, 2)\n  let at: Option<Int> = seen.toArray().indexOf(1)",
11459        );
11460        let error = rejects_body("  let seen = Set.of(1, 2)\n  let n = seen.indexOf(1)");
11461        assert_eq!(error.code, UNKNOWN_METHOD);
11462        assert_eq!(error.message, "`Set` has no method `indexOf`");
11463        let error = rejects_body(
11464            "  let ages = Map.of(MapEntry(key: \"a\", value: 1))\n  let n = ages.slice(0, 1)",
11465        );
11466        assert_eq!(error.message, "`Map` has no method `slice`");
11467    }
11468
11469    /// `set` replaces an element, so it takes the receiver's own element
11470    /// type and answers what was there.
11471    #[test]
11472    fn a_vector_replaces_an_element_with_one_of_its_own_type() {
11473        accepts_body("  var items = Vector.of(1, 2)\n  let was: Option<Int> = items.set(0, 9)");
11474        let error = rejects_body("  var items = Vector.of(1, 2)\n  let n = items.set(0, \"9\")");
11475        assert_eq!(error.code, MISMATCH);
11476        assert_eq!(error.message, "expected `Int`, found `String`");
11477        let error = rejects_body("  var items = Vector.of(1, 2)\n  let n = items.set(\"0\", 9)");
11478        assert_eq!(error.message, "expected `Int`, found `String`");
11479        let error = rejects_body("  var items = Vector.of(1, 2)\n  let n: Int = items.set(0, 9)");
11480        assert_eq!(error.message, "expected `Int`, found `Option<Int>`");
11481        // An `Array` is immutable, so it has no such method to reach at all
11482        // — however the receiver was bound. The place rule asks the shared
11483        // table what *this* receiver declares rather than asking the name,
11484        // so a `let` array is told it has no `set` rather than told to be a
11485        // `var` first.
11486        for receiver in ["var items = [1, 2]", "let items = [1, 2]"] {
11487            let error = rejects_body(&format!("  {receiver}\n  let n = items.set(0, 9)"));
11488            assert_eq!(error.code, UNKNOWN_METHOD);
11489            assert_eq!(error.message, "`Array` has no method `set`");
11490        }
11491    }
11492
11493    /// `pop` and `remove` take an element back out, so both answer the
11494    /// receiver's own element type inside an `Option`, and `remove` takes
11495    /// the index by the name `get` and `set` already call it.
11496    #[test]
11497    fn a_vector_answers_what_it_took_out() {
11498        accepts_body(
11499            "  var items = Vector.of(1, 2)\n  \
11500             let last: Option<Int> = items.pop()\n  \
11501             let first: Option<Int> = items.remove(0)",
11502        );
11503        let error = rejects_body("  var items = Vector.of(1, 2)\n  let n: Int = items.pop()");
11504        assert_eq!(error.code, MISMATCH);
11505        assert_eq!(error.message, "expected `Int`, found `Option<Int>`");
11506        let error = rejects_body("  var items = Vector.of(1, 2)\n  let n = items.remove(\"0\")");
11507        assert_eq!(error.message, "expected `Int`, found `String`");
11508        // An `Array` is immutable and a `Set`'s removal answers a new set,
11509        // so neither has these; and `Vector` has no `removed`, because a
11510        // past participle would say it answered a new collection.
11511        for receiver in ["let items = [1, 2]", "var items = [1, 2]"] {
11512            let error = rejects_body(&format!("  {receiver}\n  let n = items.pop()"));
11513            assert_eq!(error.code, UNKNOWN_METHOD);
11514            assert_eq!(error.message, "`Array` has no method `pop`");
11515        }
11516        let error = rejects_body("  var items = Vector.of(1, 2)\n  let n = items.removed(0)");
11517        assert_eq!(error.message, "`Vector` has no method `removed`");
11518        // There is no `clear`: emptying a vector is `pop` in a loop, or a
11519        // rebinding.
11520        let error = rejects_body("  var items = Vector.of(1, 2)\n  items.clear()");
11521        assert_eq!(error.message, "`Vector` has no method `clear`");
11522    }
11523
11524    /// `pop` and `remove` mutate, so their receivers are under exactly the
11525    /// place rule `push` and `set` are under.
11526    #[test]
11527    fn rejects_a_removal_on_a_read_only_place_and_on_no_place() {
11528        for call in ["pop()", "remove(0)"] {
11529            let error = rejects(&format!(
11530                "fn run() -> Int {{\n  let items = Vector.of(1)\n  let n = items.{call}\n  0\n}}\n"
11531            ));
11532            assert_eq!(error.code, READ_ONLY_PLACE);
11533            assert!(
11534                error.message.ends_with("but `items` is a read-only place"),
11535                "{}",
11536                error.message
11537            );
11538            let error = rejects(&format!(
11539                "fn run() -> Int {{\n  let n = Vector.of(1).{call}\n  0\n}}\n"
11540            ));
11541            assert_eq!(error.code, NOT_A_PLACE);
11542        }
11543    }
11544
11545    /// `toVector` answers a growable copy of an array, and it is on `Array`
11546    /// only: an independent vector from a vector is `snapshot()`.
11547    #[test]
11548    fn an_array_answers_a_growable_copy_of_itself() {
11549        accepts_body("  let items = [1, 2]\n  var building: Vector<Int> = items.toVector()");
11550        let error = rejects_body("  let items = [1, 2]\n  let n: Array<Int> = items.toVector()");
11551        assert_eq!(error.code, MISMATCH);
11552        assert_eq!(error.message, "expected `Array<Int>`, found `Vector<Int>`");
11553        let error = rejects_body("  var items = Vector.of(1, 2)\n  let n = items.toVector()");
11554        assert_eq!(error.code, UNKNOWN_METHOD);
11555        assert_eq!(error.message, "`Vector` has no method `toVector`");
11556    }
11557
11558    /// `set` mutates, so its receiver is the caller's place under exactly
11559    /// the rule `push`'s receiver is under.
11560    #[test]
11561    fn rejects_set_on_a_read_only_place_and_on_no_place() {
11562        let error = rejects(
11563            "fn run() -> Int {\n  let items = Vector.of(1)\n  items.set(0, 2)\n  items.length()\n}\n",
11564        );
11565        assert_eq!(error.code, READ_ONLY_PLACE);
11566        assert_eq!(
11567            error.message,
11568            "`set` takes a `var self` receiver, but `items` is a read-only place"
11569        );
11570        assert_eq!(error.help.unwrap(), "declare it with `var items`");
11571        let error = rejects("fn run() -> Int {\n  Vector.of(1).set(0, 2)\n  0\n}\n");
11572        assert_eq!(error.code, NOT_A_PLACE);
11573        assert_eq!(
11574            error.message,
11575            "`set` takes a `var self` receiver, but `this expression` is not a place"
11576        );
11577    }
11578
11579    // ------------------------------------ building and reading a duration
11580
11581    /// A `Duration` is built from a number in any of the six units a literal
11582    /// is written in, and read back in the same six.
11583    #[test]
11584    fn a_duration_is_built_from_a_count_and_read_back_as_one() {
11585        accepts_body(
11586            "  let timeout: Duration = Duration.millis(250)\n  \
11587             let whole: Duration = Duration.nanos(1) + Duration.micros(1) + \
11588             Duration.seconds(1) + Duration.minutes(1) + Duration.hours(1)\n  \
11589             let back: Int = timeout.millis()\n  \
11590             let coarse: Int = whole.seconds()",
11591        );
11592        // The builder takes an `Int`; a `Duration` is what it answers rather
11593        // than what it takes.
11594        let error = rejects_body("  let d = Duration.millis(1s)");
11595        assert_eq!(error.code, MISMATCH);
11596        assert_eq!(error.message, "expected `Int`, found `Duration`");
11597        let error = rejects_body("  let n: Int = Duration.seconds(1)");
11598        assert_eq!(error.message, "expected `Int`, found `Duration`");
11599        let error = rejects_body("  let d = 1s\n  let n: Duration = d.seconds()");
11600        assert_eq!(error.message, "expected `Duration`, found `Int`");
11601    }
11602
11603    /// A unit no literal suffix names is not a unit, in either direction.
11604    #[test]
11605    fn a_duration_has_only_the_units_a_literal_is_written_in() {
11606        let error = rejects_body("  let d = Duration.weeks(1)");
11607        assert_eq!(error.code, UNKNOWN_ASSOCIATED);
11608        assert_eq!(
11609            error.message,
11610            "`Duration` has no associated function `weeks`"
11611        );
11612        let error = rejects_body("  let d = 1s\n  let n = d.weeks()");
11613        assert_eq!(error.code, UNKNOWN_METHOD);
11614        assert_eq!(error.message, "`Duration` has no method `weeks`");
11615        assert_eq!(
11616            error.help.unwrap(),
11617            "`Duration` has `nanos`, `micros`, `millis`, `seconds`, `minutes`, `hours`, `snapshot`"
11618        );
11619    }
11620
11621    /// A receiver that is not a sequence has none of the four.
11622    #[test]
11623    fn only_a_sequence_walks_with_a_closure() {
11624        let error = rejects_body("  let ages = Set.of(1, 2)\n  let n = ages.map(fn(v) { v })");
11625        assert_eq!(error.code, UNKNOWN_METHOD);
11626        assert_eq!(error.message, "`Set` has no method `map`");
11627    }
11628
11629    /// A receiver that reports no element count is told what it does have
11630    /// instead, because `count()` teaches nothing about an `Option`.
11631    #[test]
11632    fn a_receiver_that_has_no_length_is_not_taught_the_spelling() {
11633        let error = rejects_body("  let value = Some(1)\n  let n = value.count()");
11634        assert_eq!(error.code, UNKNOWN_METHOD);
11635        assert_eq!(error.message, "`Option` has no method `count`");
11636    }
11637
11638    #[test]
11639    fn rejects_a_builtin_method_that_does_not_exist() {
11640        let error = rejects_body("  println(\"{\"text\".scream()}\")?");
11641        assert_eq!(error.code, UNKNOWN_METHOD);
11642        assert_eq!(error.message, "`String` has no method `scream`");
11643        assert_eq!(
11644            error.help.unwrap(),
11645            "`String` has `length`, `isEmpty`, `words`, `chars`, `split`, `join`, `slice`, \
11646             `trim`, `contains`, `startsWith`, `endsWith`, `indexOf`, `replace`, `toUpper`, \
11647             `toLower`, `byteLength`, `byteAt`, `codePointAtByte`, `sliceBytes`, \
11648             `snapshot`"
11649        );
11650    }
11651
11652    /// The help lists what the shared table declares, all of it, in the
11653    /// order the table declares it. The hand-written candidate list it
11654    /// replaced had never gained `mapError`, so a `Result` used to be told
11655    /// it had two methods when it has four; `unwrapOr` reads between the
11656    /// queries and `mapError` here because that is where `Option` puts it.
11657    #[test]
11658    fn the_methods_a_diagnostic_lists_are_the_ones_the_table_declares() {
11659        let error = rejects_body("  let outcome = Ok(1)\n  println(\"{outcome.unwrap()}\")?");
11660        assert_eq!(error.code, UNKNOWN_METHOD);
11661        assert_eq!(error.message, "`Result` has no method `unwrap`");
11662        assert_eq!(
11663            error.help.unwrap(),
11664            "`Result` has `isOk`, `isError`, `unwrapOr`, `mapError`"
11665        );
11666    }
11667
11668    /// `lock` is a `Shared`'s only operation, and the help says so rather
11669    /// than claiming a `Shared` has no methods at all.
11670    #[test]
11671    fn a_shared_is_told_that_lock_is_what_it_has() {
11672        let error = rejects_body("  let counts = Shared(1)\n  let value = counts.get()");
11673        assert_eq!(error.help.unwrap(), "`Shared` has `lock`");
11674    }
11675
11676    /// The rule sentence reads the associated functions out of the table
11677    /// rather than restating them, so a new one cannot go unmentioned.
11678    #[test]
11679    fn an_unknown_associated_function_names_the_ones_that_exist() {
11680        let error = rejects_body("  let items = Array.of(1)");
11681        assert_eq!(error.code, UNKNOWN_ASSOCIATED);
11682        assert_eq!(error.message, "`Array` has no associated function `of`");
11683        assert_eq!(
11684            error.rule.unwrap(),
11685            "A builtin type's associated functions are `Vector.of`, `Map.of`, `Set.of`, `String.fromCodePoint`, `Int.parse`, `Int.parseRadix`, `Float.parse`, `Duration.nanos`, `Duration.micros`, `Duration.millis`, `Duration.seconds`, `Duration.minutes`, and `Duration.hours`."
11686        );
11687    }
11688
11689    // ------------------------------------------------------ calls
11690
11691    #[test]
11692    fn checks_an_argument_against_its_parameter() {
11693        let error = rejects(
11694            "\
11695fn greet(name: String) -> String {
11696  name
11697}
11698
11699fn run() -> String {
11700  greet(42)
11701}
11702",
11703        );
11704        assert_eq!(error.code, MISMATCH);
11705        assert_eq!(error.message, "expected `String`, found `Int`");
11706        assert_eq!(error.labels[0].message, "the parameter `name` is `String`");
11707        assert_eq!(
11708            error.help.unwrap(),
11709            "interpolate the `Int`, as in \"{value}\", to make a `String`"
11710        );
11711    }
11712
11713    #[test]
11714    fn rejects_too_many_arguments() {
11715        let error = rejects(
11716            "\
11717fn greet(name: String) -> String {
11718  name
11719}
11720
11721fn run() -> String {
11722  greet(\"a\", \"b\")
11723}
11724",
11725        );
11726        assert_eq!(error.code, ARITY);
11727        assert_eq!(
11728            error.message,
11729            "`greet` takes 1 argument(s), but more were given"
11730        );
11731        assert_eq!(
11732            error.rule.unwrap(),
11733            "A call passes exactly the arguments the declaration binds."
11734        );
11735        assert_eq!(error.help.unwrap(), "`greet` declares `name`");
11736    }
11737
11738    #[test]
11739    fn rejects_a_label_that_names_no_parameter() {
11740        let error = rejects(
11741            "\
11742fn between(low: Int, high: Int) -> Int {
11743  high - low
11744}
11745
11746fn run() -> Int {
11747  between(low: 1, top: 2)
11748}
11749",
11750        );
11751        assert_eq!(error.code, UNKNOWN_LABEL);
11752        assert_eq!(error.message, "`between` has no parameter labeled `top`");
11753        assert_eq!(
11754            error.rule.unwrap(),
11755            "Argument labels are parameter names and part of the API contract."
11756        );
11757        assert_eq!(error.help.unwrap(), "known labels: `low`, `high`");
11758    }
11759
11760    #[test]
11761    fn labels_bind_arguments_to_the_parameters_they_name() {
11762        accepts(
11763            "\
11764fn between(low: Int, high: Int) -> Int {
11765  high - low
11766}
11767
11768fn run() -> Int {
11769  between(low: 1, high: 2)
11770}
11771",
11772        );
11773    }
11774
11775    #[test]
11776    fn rejects_labels_that_stand_out_of_declaration_order() {
11777        let error = rejects(
11778            "\
11779fn between(low: Int, high: Int) -> Int {
11780  high - low
11781}
11782
11783fn run() -> Int {
11784  between(high: 2, low: 1)
11785}
11786",
11787        );
11788        assert_eq!(error.code, LABEL_ORDER);
11789        assert_eq!(
11790            error.message,
11791            "`between` was given the label `low` out of declaration order"
11792        );
11793        assert_eq!(
11794            error.rule.unwrap(),
11795            "Labeled arguments appear in declaration order, so argument order matches parameter order."
11796        );
11797        assert_eq!(
11798            error.help.unwrap(),
11799            "write the arguments in this order: low, high"
11800        );
11801    }
11802
11803    /// A struct's synthesized initializer takes its labels in declaration
11804    /// order exactly as a declared function does, which is the half of this
11805    /// rule a reader is most likely to meet.
11806    #[test]
11807    fn rejects_a_struct_initializer_whose_labels_are_out_of_order() {
11808        let error = rejects(
11809            "\
11810struct Point {
11811  x: Int
11812  y: Int
11813}
11814
11815fn run() -> Point {
11816  Point(y: 20, x: 10)
11817}
11818",
11819        );
11820        assert_eq!(error.code, LABEL_ORDER);
11821        assert_eq!(
11822            error.message,
11823            "`Point` was given the label `x` out of declaration order"
11824        );
11825    }
11826
11827    /// The same label twice is reported once, as the parameter it left
11828    /// unfilled, rather than twice.
11829    #[test]
11830    fn a_label_written_twice_is_one_diagnostic() {
11831        let error = rejects(
11832            "\
11833fn between(low: Int, high: Int) -> Int {
11834  high - low
11835}
11836
11837fn run() -> Int {
11838  between(low: 1, low: 2)
11839}
11840",
11841        );
11842        assert_eq!(error.code, MISSING_ARGUMENT);
11843    }
11844
11845    // ------------------------------------------------------------- places
11846
11847    // A place is a name a body bound, or a field of one, and `let` makes a
11848    // read-only place. ADR 0021 is why these are here rather than at run
11849    // time; the wording is the interpreter's, because it is what a person
11850    // reading Cove errors has always seen.
11851
11852    #[test]
11853    fn rejects_an_assignment_to_a_let_binding() {
11854        let error = rejects("fn run() -> Int {\n  let x = 1\n  x = 2\n  x\n}\n");
11855        assert_eq!(error.code, READ_ONLY_PLACE);
11856        assert_eq!(
11857            error.message,
11858            "cannot assign to `x`, which is a read-only place"
11859        );
11860        assert_eq!(
11861            error.rule.unwrap(),
11862            "`let` creates a read-only place; `var` creates a mutable place."
11863        );
11864        assert_eq!(
11865            error.help.unwrap(),
11866            "declare it with `var x` to make it assignable"
11867        );
11868    }
11869
11870    /// An ordinary parameter is a read-only place too: it receives a shallow
11871    /// copy, and only `var` names the caller's own storage.
11872    #[test]
11873    fn rejects_an_assignment_to_a_parameter_that_is_not_var() {
11874        let error = rejects("fn run(n: Int) -> Int {\n  n = 2\n  n\n}\n");
11875        assert_eq!(error.code, READ_ONLY_PLACE);
11876        assert_eq!(
11877            error.message,
11878            "cannot assign to `n`, which is a read-only place"
11879        );
11880    }
11881
11882    /// A field of a read-only place is a read-only place: the walk asks the
11883    /// root and a field inherits its answer.
11884    #[test]
11885    fn rejects_an_assignment_to_a_field_of_a_let_binding() {
11886        let error = rejects(
11887            "struct P {\n  x: Int\n}\n\nfn run() -> Int {\n  let p = P(x: 1)\n  p.x = 2\n  p.x\n}\n",
11888        );
11889        assert_eq!(error.code, READ_ONLY_PLACE);
11890        assert_eq!(
11891            error.message,
11892            "cannot assign to `p.x`, which is a read-only place"
11893        );
11894    }
11895
11896    /// A `var` binding, a `var` parameter, and a field of either are the
11897    /// places source may write.
11898    #[test]
11899    fn accepts_a_write_to_a_var_binding_and_to_its_fields() {
11900        accepts(
11901            "struct P {\n  x: Int\n}\n\nfn bump(var n: Int) {\n  n += 1\n}\n\nfn run() -> Int {\n  var p = P(x: 1)\n  p.x = 2\n  var n = 0\n  n += 1\n  bump(var n)\n  p.x + n\n}\n",
11902        );
11903    }
11904
11905    /// A closure holds a *copy* of what it captured, so a captured `var` is
11906    /// a read-only place inside it — which is the `Place::binding(value,
11907    /// false)` `Env::declare_capture` builds, read here instead.
11908    #[test]
11909    fn rejects_an_assignment_to_a_captured_var_binding() {
11910        let error = rejects(
11911            "fn run() -> Int {\n  var count = 0\n  let bump = fn() {\n    count = count + 1\n  }\n  count\n}\n",
11912        );
11913        assert_eq!(error.code, READ_ONLY_PLACE);
11914        assert_eq!(
11915            error.message,
11916            "cannot assign to `count`, which is a read-only place"
11917        );
11918    }
11919
11920    /// A local `fn` is built as a closure too, so the same rule reaches it.
11921    #[test]
11922    fn rejects_an_assignment_to_a_var_captured_by_a_local_fn() {
11923        let error = rejects(
11924            "fn run() -> Int {\n  var count = 0\n  fn bump() {\n    count = count + 1\n  }\n  count\n}\n",
11925        );
11926        assert_eq!(error.code, READ_ONLY_PLACE);
11927    }
11928
11929    #[test]
11930    fn rejects_a_var_argument_that_is_a_read_only_place() {
11931        let error = rejects(
11932            "fn bump(var n: Int) {\n  n += 1\n}\n\nfn run() -> Int {\n  let total = 1\n  bump(var total)\n  total\n}\n",
11933        );
11934        assert_eq!(error.code, READ_ONLY_PLACE);
11935        assert_eq!(
11936            error.message,
11937            "`total` is a read-only place, so it cannot be passed as `var`"
11938        );
11939    }
11940
11941    #[test]
11942    fn rejects_a_var_argument_that_is_not_a_place() {
11943        let error = rejects(
11944            "fn bump(var n: Int) {\n  n += 1\n}\n\nfn run() -> Int {\n  bump(var 1 + 2)\n  0\n}\n",
11945        );
11946        assert_eq!(error.code, NOT_A_PLACE);
11947        assert_eq!(
11948            error.message,
11949            "this expression is not a place, so it cannot be assigned or aliased"
11950        );
11951        assert_eq!(
11952            error.rule.unwrap(),
11953            "Only variables and their struct fields are places."
11954        );
11955    }
11956
11957    #[test]
11958    fn rejects_push_on_a_read_only_place() {
11959        let error = rejects(
11960            "fn run() -> Int {\n  let items = Vector.of(1)\n  items.push(2)\n  items.length()\n}\n",
11961        );
11962        assert_eq!(error.code, READ_ONLY_PLACE);
11963        assert_eq!(
11964            error.message,
11965            "`push` takes a `var self` receiver, but `items` is a read-only place"
11966        );
11967        assert_eq!(error.help.unwrap(), "declare it with `var items`");
11968    }
11969
11970    #[test]
11971    fn rejects_push_on_a_receiver_that_is_not_a_place() {
11972        let error = rejects("fn run() -> () {\n  Vector.of(1).push(2)\n}\n");
11973        assert_eq!(error.code, NOT_A_PLACE);
11974        assert_eq!(
11975            error.message,
11976            "`push` takes a `var self` receiver, but `this expression` is not a place"
11977        );
11978        assert_eq!(
11979            error.rule.unwrap(),
11980            "A mutating receiver declares `var self` and mutates the caller's place."
11981        );
11982    }
11983
11984    /// `freeze` is the one mutating builtin that tolerates a receiver which
11985    /// is no place at all: a temporary holds the only handle to its own
11986    /// storage, so freezing it answers from the temporary. It still needs a
11987    /// *writable* place when it has one.
11988    #[test]
11989    fn freeze_needs_a_writable_place_only_when_it_has_one() {
11990        accepts("fn run() -> Int {\n  Vector.of(1).freeze().length()\n}\n");
11991        let error =
11992            rejects("fn run() -> Int {\n  let v = Vector.of(1)\n  v.freeze().length()\n}\n");
11993        assert_eq!(error.code, READ_ONLY_PLACE);
11994        assert_eq!(
11995            error.message,
11996            "`freeze` takes a `var self` receiver, but `v` is a read-only place"
11997        );
11998    }
11999
12000    /// A declared `var self` method is the same question asked of a
12001    /// declaration rather than of a builtin.
12002    #[test]
12003    fn rejects_a_var_self_method_on_a_read_only_place() {
12004        let error = rejects(
12005            "struct Counter {\n  value: Int\n}\n\nimpl Counter {\n  fn bump(var self) {\n    self.value += 1\n  }\n}\n\nfn run() -> Int {\n  let counter = Counter(value: 1)\n  counter.bump()\n  counter.value\n}\n",
12006        );
12007        assert_eq!(error.code, READ_ONLY_PLACE);
12008        assert_eq!(
12009            error.message,
12010            "`bump` takes a `var self` receiver, but `counter` is a read-only place"
12011        );
12012    }
12013
12014    /// A `lock` closure that does not declare `var` receives a copy, and the
12015    /// `var self` method that would change it is refused, because a copy is
12016    /// not the place the value lives in.
12017    #[test]
12018    fn rejects_a_mutating_method_on_a_lock_closures_copy() {
12019        let source = "struct Counter {\n  value: Int\n}\n\nimpl Counter {\n  fn bump(var self) {\n    self.value += 1\n  }\n}\n\nfn run() -> () {\n  let shared = Shared(Counter(value: 0))\n  shared.lock(fn(value) {\n    value.bump()\n  })\n}\n";
12020        let error = rejects(source);
12021        assert_eq!(error.code, READ_ONLY_PLACE);
12022        assert_eq!(
12023            error.message,
12024            "`bump` takes a `var self` receiver, but `value` is a read-only place"
12025        );
12026        accepts(&source.replace("fn(value)", "fn(var value)"));
12027    }
12028
12029    /// A receiver whose type nothing settled is left alone. The interpreter
12030    /// reaches a host resource's own operations before it reaches any of
12031    /// this, so a name that means `push` there might not mean it here.
12032    #[test]
12033    fn abstains_about_a_mutating_method_on_an_unknown_receiver() {
12034        accepts(
12035            "use unknownhost.open\n\nfn run() -> () {\n  let handle = open()\n  handle.push(1)\n}\n",
12036        );
12037    }
12038
12039    #[test]
12040    fn a_parameter_with_a_default_may_be_omitted() {
12041        accepts(
12042            "\
12043fn measure(value: Int, unit: String = \"m\") -> String {
12044  \"{value}{unit}\"
12045}
12046
12047fn run() -> String {
12048  measure(3)
12049}
12050",
12051        );
12052        let error = rejects(
12053            "\
12054fn measure(value: Int, unit: String = 1) -> String {
12055  \"{value}{unit}\"
12056}
12057",
12058        );
12059        assert_eq!(error.code, MISMATCH);
12060        assert_eq!(error.message, "expected `String`, found `Int`");
12061    }
12062
12063    #[test]
12064    fn checks_a_variadic_parameter_and_its_spread() {
12065        accepts(
12066            "\
12067fn joinAll(separator: String, items: String...) -> Int {
12068  items.length()
12069}
12070
12071fn run() -> Int {
12072  let ready = [\"x\"]
12073  joinAll(\"-\", \"a\", ...ready)
12074}
12075",
12076        );
12077        let error = rejects(
12078            "\
12079fn joinAll(items: String...) -> Int {
12080  items.length()
12081}
12082
12083fn run() -> Int {
12084  joinAll(\"a\", 2)
12085}
12086",
12087        );
12088        assert_eq!(error.code, MISMATCH);
12089        assert_eq!(error.message, "expected `String`, found `Int`");
12090    }
12091
12092    #[test]
12093    fn a_declaration_parameter_without_a_type_is_refused() {
12094        // ADR 0004: a declaration's parameters are written, not inferred.
12095        // `x` has no expected type to fall back on the way a lambda's would.
12096        let error = rejects(
12097            "\
12098fn double(x) -> Int {
12099  x + x
12100}
12101",
12102        );
12103        assert_eq!(error.code, MISSING_PARAMETER_TYPE);
12104        assert_eq!(error.message, "parameter `x` has no declared type");
12105        assert_eq!(
12106            error.rule.unwrap(),
12107            "A declaration's parameters are written: only a lambda's infer, from the expected type at its call site."
12108        );
12109        assert_eq!(error.help.unwrap(), "write `x: <type>`");
12110    }
12111
12112    #[test]
12113    fn a_lambda_parameter_without_a_type_still_infers() {
12114        // The same `Param` node, and the same missing `: Type`, is not
12115        // refused here *with that code*: a lambda has an expected type to
12116        // infer from, and `checks_a_lambda_...` tests already cover it, but
12117        // this pins the point next to the declaration it is not. A lambda
12118        // passed where no type is expected is `UNCONSTRAINED` — nothing
12119        // said what `n` is — and not `MISSING_PARAMETER_TYPE`, which is
12120        // about a *declaration*, where the type is written and not
12121        // inferred.
12122        let error = rejects_body("  let double = fn(n) { n + n }\n  println(\"{double(1)}\")?");
12123        assert_eq!(error.code, UNCONSTRAINED);
12124    }
12125
12126    #[test]
12127    fn rejects_a_spread_of_the_wrong_element_type() {
12128        let error = rejects(
12129            "\
12130fn joinAll(items: String...) -> Int {
12131  items.length()
12132}
12133
12134fn run() -> Int {
12135  joinAll(...[1, 2])
12136}
12137",
12138        );
12139        assert_eq!(error.code, MISMATCH);
12140        assert_eq!(error.message, "expected `String`, found `Int`");
12141        assert_eq!(
12142            error.rule.unwrap(),
12143            "A variadic parameter is an `Array<T>`; every spread element is a `T`."
12144        );
12145        assert_eq!(error.help.unwrap(), "spread a sequence of `String`");
12146    }
12147
12148    #[test]
12149    fn rejects_calling_something_that_is_not_a_function() {
12150        let error = rejects_body("  let n = 1\n  println(\"{n(2)}\")?");
12151        assert_eq!(error.code, NOT_CALLABLE);
12152        assert_eq!(error.message, "`Int` is not a function");
12153        assert_eq!(error.rule.unwrap(), "Only a function value can be called.");
12154    }
12155
12156    #[test]
12157    fn rejects_calling_an_enum_rather_than_a_case() {
12158        let error = rejects(
12159            "\
12160enum Status {
12161  Pending
12162}
12163
12164fn run() -> Status {
12165  Status(1)
12166}
12167",
12168        );
12169        assert_eq!(error.code, NOT_CALLABLE);
12170        assert_eq!(error.message, "`Status` is an enum, not a function");
12171        assert_eq!(error.help.unwrap(), "name a case, such as `Status.Pending`");
12172    }
12173
12174    // -------------------------------------------------------- traits
12175
12176    /// The trait, two conforming types, and one that does not conform, which
12177    /// every trait test below builds on.
12178    const TRAITS: &str = "\
12179/// Renders itself.
12180trait Display {
12181  /// The full form.
12182  fn describe(self) -> String
12183
12184  /// A short form, defaulting to the full one.
12185  fn label(self) -> String { self.describe() }
12186}
12187
12188/// A booking.
12189struct Booking(id: Int)
12190
12191/// A receipt.
12192struct Receipt(total: Int)
12193
12194/// Conforms to nothing.
12195struct Ticket(seat: Int)
12196
12197impl Display for Booking {
12198  fn describe(self) -> String { \"booking\" }
12199  fn label(self) -> String { \"#\" }
12200}
12201
12202impl Display for Receipt {
12203  fn describe(self) -> String { \"receipt\" }
12204}
12205";
12206
12207    fn with_traits(source: &str) -> String {
12208        format!("{TRAITS}\n{source}")
12209    }
12210
12211    #[track_caller]
12212    fn accepts_with_traits(source: &str) {
12213        accepts(&with_traits(source));
12214    }
12215
12216    #[track_caller]
12217    fn rejects_with_traits(source: &str) -> Diagnostic {
12218        rejects(&with_traits(source))
12219    }
12220
12221    #[test]
12222    fn a_bound_makes_the_trait_s_methods_callable_on_a_type_parameter() {
12223        accepts_with_traits(
12224            "fn render<T: Display>(value: T) -> String {\n  \"{value.label()}: {value.describe()}\"\n}\n\nfn run() -> String {\n  render(Booking(id: 1))\n}\n",
12225        );
12226    }
12227
12228    #[test]
12229    fn rejects_a_type_argument_that_does_not_conform_to_the_bound() {
12230        let error = rejects_with_traits(
12231            "fn render<T: Display>(value: T) -> String {\n  value.describe()\n}\n\nfn run() -> String {\n  render(Ticket(seat: 1))\n}\n",
12232        );
12233        assert_eq!(error.code, UNSATISFIED_BOUND);
12234        assert_eq!(error.message, "`Ticket` does not conform to `Display`");
12235        assert_eq!(error.labels[0].message, "`render` requires `T: Display`");
12236        assert_eq!(
12237            error.help.as_deref(),
12238            Some("write `impl Display for Ticket { ... }`")
12239        );
12240    }
12241
12242    #[test]
12243    fn several_bounds_are_all_checked_and_all_searched_for_a_method() {
12244        let source = "\
12245/// Names itself.
12246trait Named {
12247  /// The name.
12248  fn name(self) -> String
12249}
12250
12251/// Weighs itself.
12252trait Weighed {
12253  /// The weight.
12254  fn weight(self) -> Int
12255}
12256
12257/// A crate.
12258struct Crate(label: String, kilos: Int)
12259
12260/// A pebble, which is named but not weighed.
12261struct Pebble(label: String)
12262
12263impl Named for Crate {
12264  fn name(self) -> String { self.label }
12265}
12266
12267impl Weighed for Crate {
12268  fn weight(self) -> Int { self.kilos }
12269}
12270
12271impl Named for Pebble {
12272  fn name(self) -> String { self.label }
12273}
12274
12275fn tag<T: Named + Weighed>(item: T) -> String {
12276  \"{item.name()}({item.weight()})\"
12277}
12278
12279fn ok() -> String {
12280  tag(Crate(label: \"a\", kilos: 3))
12281}
12282";
12283        accepts(source);
12284        let error = rejects(&format!(
12285            "{source}\nfn bad() -> String {{\n  tag(Pebble(label: \"b\"))\n}}\n"
12286        ));
12287        assert_eq!(error.code, UNSATISFIED_BOUND);
12288        assert_eq!(error.message, "`Pebble` does not conform to `Weighed`");
12289    }
12290
12291    #[test]
12292    fn rejects_a_method_call_on_an_unbounded_type_parameter() {
12293        let error =
12294            rejects_with_traits("fn render<T>(value: T) -> String {\n  value.describe()\n}\n");
12295        assert_eq!(error.code, UNBOUNDED_PARAMETER);
12296        assert_eq!(
12297            error.message,
12298            "`T` has no bound, so it has no method `describe`"
12299        );
12300    }
12301
12302    #[test]
12303    fn rejects_a_method_no_bound_of_the_parameter_declares() {
12304        let error =
12305            rejects_with_traits("fn render<T: Display>(value: T) -> Int {\n  value.total()\n}\n");
12306        assert_eq!(error.code, UNKNOWN_METHOD);
12307        assert_eq!(
12308            error.message,
12309            "no trait `T` is bounded by declares a method `total`"
12310        );
12311    }
12312
12313    #[test]
12314    fn one_bounded_function_may_call_another() {
12315        accepts_with_traits(
12316            "fn render<T: Display>(value: T) -> String {\n  value.describe()\n}\n\nfn shout<U: Display>(value: U) -> String {\n  render(value)\n}\n",
12317        );
12318    }
12319
12320    #[test]
12321    fn a_conforming_value_is_accepted_where_dyn_is_expected() {
12322        accepts_with_traits(
12323            "fn show(value: dyn Display) -> String {\n  value.describe()\n}\n\nfn run() -> String {\n  show(Booking(id: 1))\n}\n",
12324        );
12325    }
12326
12327    #[test]
12328    fn rejects_a_value_that_does_not_conform_where_dyn_is_expected() {
12329        let error = rejects_with_traits(
12330            "fn show(value: dyn Display) -> String {\n  value.describe()\n}\n\nfn run() -> String {\n  show(Ticket(seat: 1))\n}\n",
12331        );
12332        assert_eq!(error.code, MISMATCH);
12333        assert_eq!(
12334            error.message,
12335            "`Ticket` does not conform to `Display`, so it is not a `dyn Display`"
12336        );
12337    }
12338
12339    #[test]
12340    fn an_array_of_dyn_mixes_conforming_types_element_by_element() {
12341        // The conversion applies to each element on its own; the array type
12342        // itself is invariant, so `Array<Booking>` is still not an
12343        // `Array<dyn Display>`.
12344        accepts_with_traits(
12345            "fn run() -> Array<dyn Display> {\n  [Booking(id: 1), Receipt(total: 2)]\n}\n",
12346        );
12347        let error = rejects_with_traits(
12348            "fn run(bookings: Array<Booking>) -> Array<dyn Display> {\n  bookings\n}\n",
12349        );
12350        assert_eq!(error.code, MISMATCH);
12351        assert_eq!(
12352            error.message,
12353            "expected `Array<dyn Display>`, found `Array<Booking>`"
12354        );
12355    }
12356
12357    #[test]
12358    fn dyn_is_not_a_type_parameter_and_satisfies_no_bound() {
12359        let error = rejects_with_traits(
12360            "fn render<T: Display>(value: T) -> String {\n  value.describe()\n}\n\nfn run(value: dyn Display) -> String {\n  render(value)\n}\n",
12361        );
12362        assert_eq!(error.code, UNSATISFIED_BOUND);
12363        assert_eq!(
12364            error.message,
12365            "`dyn Display` cannot be used as a type argument"
12366        );
12367    }
12368
12369    #[test]
12370    fn a_dyn_value_does_not_convert_back_to_its_concrete_type() {
12371        let error = rejects_with_traits("fn run(value: dyn Display) -> Booking {\n  value\n}\n");
12372        assert_eq!(error.code, MISMATCH);
12373        assert_eq!(error.message, "expected `Booking`, found `dyn Display`");
12374    }
12375
12376    #[test]
12377    fn only_the_trait_s_methods_are_reachable_through_dyn() {
12378        let source = format!(
12379            "{TRAITS}\nimpl Booking {{\n  /// The identifier.\n  fn id(self) -> Int {{ self.id }}\n}}\n\nfn run(value: dyn Display) -> Int {{\n  value.id()\n}}\n"
12380        );
12381        let error = rejects(&source);
12382        assert_eq!(error.code, UNKNOWN_METHOD);
12383        assert_eq!(error.message, "`Display` has no method `id`");
12384        assert_eq!(
12385            error.help.as_deref(),
12386            Some("`Display` declares `describe`, `label`")
12387        );
12388    }
12389
12390    #[test]
12391    fn an_associated_function_is_not_callable_through_dyn() {
12392        let source = "\
12393/// Renders itself.
12394trait Display {
12395  /// The full form.
12396  fn describe(self) -> String
12397
12398  /// Builds one.
12399  fn blank() -> Int
12400}
12401
12402/// A booking.
12403struct Booking(id: Int)
12404
12405impl Display for Booking {
12406  fn describe(self) -> String { \"booking\" }
12407  fn blank() -> Int { 0 }
12408}
12409
12410fn run(value: dyn Display) -> Int {
12411  value.blank()
12412}
12413";
12414        let error = rejects(source);
12415        assert_eq!(error.code, DYN_ASSOCIATED);
12416        assert_eq!(
12417            error.message,
12418            "`Display.blank` takes no `self`, so it cannot be called through `dyn Display`"
12419        );
12420    }
12421
12422    #[test]
12423    fn a_mutating_method_is_not_callable_through_dyn() {
12424        let source = "\
12425/// Counts.
12426trait Bump {
12427  /// Adds one.
12428  fn bump(var self)
12429}
12430
12431/// A counter.
12432struct Counter(hits: Int)
12433
12434impl Bump for Counter {
12435  fn bump(var self) { self.hits += 1 }
12436}
12437
12438fn run(var value: dyn Bump) {
12439  value.bump()
12440}
12441";
12442        let error = rejects(source);
12443        assert_eq!(error.code, DYN_MUTATING);
12444        assert_eq!(
12445            error.message,
12446            "`Bump.bump` takes `var self`, so it cannot be called through `dyn Bump`"
12447        );
12448    }
12449
12450    #[test]
12451    fn a_mutating_method_is_callable_through_a_bound() {
12452        // Through a bound the receiver is still the caller's own place, so
12453        // the restriction that `dyn` imposes does not apply.
12454        accepts(
12455            "\
12456/// Counts.
12457trait Bump {
12458  /// Adds one.
12459  fn bump(var self)
12460}
12461
12462/// A counter.
12463struct Counter(hits: Int)
12464
12465impl Bump for Counter {
12466  fn bump(var self) { self.hits += 1 }
12467}
12468
12469fn run<T: Bump>(var value: T) {
12470  value.bump()
12471}
12472",
12473        );
12474    }
12475
12476    #[test]
12477    fn a_trait_method_call_is_checked_against_the_trait_s_signature() {
12478        let error = rejects_with_traits(
12479            "fn render<T: Display>(value: T) -> String {\n  value.describe(1)\n}\n",
12480        );
12481        assert_eq!(error.code, ARITY);
12482    }
12483
12484    #[test]
12485    fn rejects_a_conformance_whose_method_has_the_wrong_signature() {
12486        let source = "\
12487/// Renders itself.
12488trait Display {
12489  /// The full form.
12490  fn describe(self) -> String
12491}
12492
12493/// A booking.
12494struct Booking(id: Int)
12495
12496impl Display for Booking {
12497  fn describe(self) -> Int { 1 }
12498}
12499";
12500        let error = rejects(source);
12501        assert_eq!(error.code, CONFORMANCE_SIGNATURE);
12502        assert_eq!(
12503            error.message,
12504            "`Booking.describe` does not match the signature `Display` declares: it returns `Int`, not `String`"
12505        );
12506        assert_eq!(
12507            error.help.as_deref(),
12508            Some("write `fn describe(self) -> String`")
12509        );
12510    }
12511
12512    #[test]
12513    fn a_default_body_sees_its_trait_and_nothing_of_the_conforming_type() {
12514        // Checked once against `Self: Summary`, not once per conformance, so
12515        // a default body cannot reach a conforming type's fields even when
12516        // every implementor happens to have one by that name.
12517        let source = "\
12518/// Renders itself.
12519trait Summary {
12520  /// The tag.
12521  fn tag(self) -> Int
12522
12523  /// A line, which reaches for a field no trait declares.
12524  fn line(self) -> String { \"{self.id}\" }
12525}
12526
12527/// A booking.
12528struct Booking(id: Int)
12529
12530impl Summary for Booking {
12531  fn tag(self) -> Int { self.id }
12532}
12533";
12534        let error = rejects(source);
12535        assert_eq!(error.code, UNKNOWN_FIELD);
12536        assert_eq!(error.message, "`Self` has no field `id`");
12537    }
12538
12539    #[test]
12540    fn a_default_body_may_call_the_trait_s_own_methods() {
12541        accepts_with_traits("fn run(value: Booking) -> String {\n  value.label()\n}\n");
12542    }
12543
12544    #[test]
12545    fn a_default_body_is_reported_once_however_many_types_conform() {
12546        let source = "\
12547/// Renders itself.
12548trait Summary {
12549  /// The tag.
12550  fn tag(self) -> Int
12551
12552  /// A line whose body does not type-check.
12553  fn line(self) -> String { self.tag() }
12554}
12555
12556/// A booking.
12557struct Booking(id: Int)
12558
12559/// A receipt.
12560struct Receipt(cents: Int)
12561
12562impl Summary for Booking {
12563  fn tag(self) -> Int { self.id }
12564}
12565
12566impl Summary for Receipt {
12567  fn tag(self) -> Int { self.cents }
12568}
12569";
12570        let error = rejects(source);
12571        assert_eq!(error.code, MISMATCH);
12572        assert_eq!(error.message, "expected `String`, found `Int`");
12573    }
12574
12575    #[test]
12576    fn rejects_a_dyn_or_a_bound_that_names_no_trait() {
12577        let error = rejects("fn run(value: dyn Missing) {\n}\n");
12578        assert_eq!(error.code, UNKNOWN_TRAIT);
12579        let error = rejects("fn run<T: Missing>(value: T) {\n}\n");
12580        assert_eq!(error.code, UNKNOWN_TRAIT);
12581    }
12582
12583    #[test]
12584    fn rejects_a_bound_where_the_mvp_never_checks_one() {
12585        let source = with_traits("struct Box<T: Display>(value: T)\n");
12586        let error = rejects(&source);
12587        assert_eq!(error.code, UNSUPPORTED_BOUND);
12588        assert_eq!(
12589            error.message,
12590            "a bound on a struct's type parameter is not checked in the MVP"
12591        );
12592    }
12593
12594    // ------------------------------------------------------ generics
12595
12596    #[test]
12597    fn unifies_a_type_parameter_at_the_call_site() {
12598        accepts(
12599            "\
12600fn first<T>(items: Array<T>, fallback: T) -> T {
12601  items.get(0).unwrapOr(fallback)
12602}
12603
12604fn run() -> Int {
12605  first([1, 2], 0)
12606}
12607",
12608        );
12609    }
12610
12611    #[test]
12612    fn rejects_a_type_parameter_used_at_two_types() {
12613        let error = rejects(
12614            "\
12615fn pair<T>(left: T, right: T) -> T {
12616  left
12617}
12618
12619fn run() -> Int {
12620  pair(1, \"two\")
12621}
12622",
12623        );
12624        assert_eq!(error.code, MISMATCH);
12625        assert_eq!(error.message, "expected `Int`, found `String`");
12626    }
12627
12628    #[test]
12629    fn substitutes_a_type_parameter_into_the_result() {
12630        let error = rejects(
12631            "\
12632fn identity<T>(value: T) -> T {
12633  value
12634}
12635
12636fn run() -> String {
12637  identity(1)
12638}
12639",
12640        );
12641        assert_eq!(error.code, MISMATCH);
12642        assert_eq!(error.message, "expected `String`, found `Int`");
12643    }
12644
12645    #[test]
12646    fn checks_a_generic_struct_s_fields_through_its_arguments() {
12647        accepts(
12648            "\
12649struct Box<T> { value: T }
12650
12651fn unwrap(box: Box<Int>) -> Int {
12652  box.value
12653}
12654",
12655        );
12656        let error = rejects(
12657            "\
12658struct Box<T> { value: T }
12659
12660fn unwrap(box: Box<String>) -> Int {
12661  box.value
12662}
12663",
12664        );
12665        assert_eq!(error.code, MISMATCH);
12666        assert_eq!(error.message, "expected `Int`, found `String`");
12667    }
12668
12669    #[test]
12670    fn a_generic_enum_takes_its_arguments_from_its_payload() {
12671        accepts(
12672            "\
12673enum Slot<T> {
12674  Full(T)
12675  Empty
12676}
12677
12678fn run() -> Slot<Int> {
12679  Slot.Full(1)
12680}
12681",
12682        );
12683        let error = rejects(
12684            "\
12685enum Slot<T> {
12686  Full(T)
12687  Empty
12688}
12689
12690fn run() -> Slot<Int> {
12691  Slot.Full(\"one\")
12692}
12693",
12694        );
12695        assert_eq!(error.code, MISMATCH);
12696        assert_eq!(error.message, "expected `Slot<Int>`, found `Slot<String>`");
12697    }
12698
12699    #[test]
12700    fn a_generic_type_s_method_sees_its_arguments() {
12701        accepts(
12702            "\
12703struct Slot<T> { value: T }
12704
12705impl Slot {
12706  fn get(self) -> T {
12707    self.value
12708  }
12709}
12710
12711fn run(slot: Slot<Int>) -> Int {
12712  slot.get()
12713}
12714",
12715        );
12716        let error = rejects(
12717            "\
12718struct Slot<T> { value: T }
12719
12720impl Slot {
12721  fn get(self) -> T {
12722    self.value
12723  }
12724}
12725
12726fn run(slot: Slot<String>) -> Int {
12727  slot.get()
12728}
12729",
12730        );
12731        assert_eq!(error.code, MISMATCH);
12732        assert_eq!(error.message, "expected `Int`, found `String`");
12733    }
12734
12735    #[test]
12736    fn rejects_the_wrong_number_of_type_arguments() {
12737        let error = rejects("fn run(items: Array<Int, String>) -> Int {\n  1\n}\n");
12738        assert_eq!(error.code, TYPE_ARGUMENTS);
12739        assert_eq!(
12740            error.message,
12741            "`Array` takes 1 type argument(s), but 2 were written"
12742        );
12743        assert_eq!(
12744            error.rule.unwrap(),
12745            "A generic type is written with exactly the arguments its declaration binds."
12746        );
12747        assert_eq!(error.help.unwrap(), "write `Array<_>`");
12748    }
12749
12750    // ------------------------------------------------------ lambdas
12751
12752    #[test]
12753    fn a_lambda_takes_its_parameter_types_from_the_expected_type() {
12754        accepts(
12755            "\
12756fn apply(value: Int, transform: fn(Int) -> Int) -> Int {
12757  transform(value)
12758}
12759
12760fn run() -> Int {
12761  apply(5, fn(n) { n + 1 })
12762}
12763",
12764        );
12765    }
12766
12767    #[test]
12768    fn rejects_a_lambda_whose_result_does_not_fit() {
12769        let error = rejects(
12770            "\
12771fn apply(value: Int, transform: fn(Int) -> Int) -> Int {
12772  transform(value)
12773}
12774
12775fn run() -> Int {
12776  apply(5, fn(n) { \"{n}\" })
12777}
12778",
12779        );
12780        assert_eq!(error.code, MISMATCH);
12781        assert_eq!(error.message, "expected `Int`, found `String`");
12782    }
12783
12784    #[test]
12785    fn rejects_a_lambda_with_the_wrong_number_of_parameters() {
12786        let error = rejects(
12787            "\
12788fn apply(transform: fn(Int) -> Int) -> Int {
12789  transform(1)
12790}
12791
12792fn run() -> Int {
12793  apply(fn(a, b) { a })
12794}
12795",
12796        );
12797        assert_eq!(error.code, ARITY);
12798        assert_eq!(
12799            error.message,
12800            "this function takes 2 parameter(s), but 1 were expected here"
12801        );
12802        assert_eq!(error.help.unwrap(), "write `fn(p0) { ... }`");
12803    }
12804
12805    #[test]
12806    fn a_lambda_with_no_expected_type_infers_nothing_about_its_parameters() {
12807        // Nothing says what `n` is, so the checker abstains rather than
12808        // guessing, and the body is still walked so that a mistake in it is
12809        // reported too. The gap is an error of its own, pinned with the
12810        // other unknowns.
12811        let error = rejects_body("  let double = fn(n) { n * 2 }\n  println(\"{double(4)}\")?");
12812        assert_eq!(error.code, UNCONSTRAINED);
12813    }
12814
12815    #[test]
12816    fn checks_a_function_value_s_arguments() {
12817        let error = rejects(
12818            "\
12819fn apply(transform: fn(Int) -> Int) -> Int {
12820  transform(\"one\")
12821}
12822",
12823        );
12824        assert_eq!(error.code, MISMATCH);
12825        assert_eq!(error.message, "expected `Int`, found `String`");
12826    }
12827
12828    // ------------------------------------------------- operators
12829
12830    #[test]
12831    fn rejects_mixed_arithmetic() {
12832        let error = rejects_body("  println(\"{1 + 1.0}\")?");
12833        assert_eq!(error.code, OPERATOR);
12834        assert_eq!(error.message, "`+` is not defined for `Int` and `Float`");
12835        assert_eq!(
12836            error.rule.unwrap(),
12837            "There are no implicit numeric, string, or boolean conversions."
12838        );
12839        assert_eq!(
12840            error.help.unwrap(),
12841            "arithmetic combines two values of the same type"
12842        );
12843    }
12844
12845    #[test]
12846    fn rejects_mixed_equality() {
12847        let error = rejects_body("  println(\"{1 == \"1\"}\")?");
12848        assert_eq!(error.code, OPERATOR);
12849        assert_eq!(error.message, "cannot compare `Int` with `String`");
12850        assert_eq!(
12851            error.rule.unwrap(),
12852            "`==` means value equality between values of the same type."
12853        );
12854        assert_eq!(
12855            error.help.unwrap(),
12856            "convert one side explicitly so both are `Int`, or compare values that already share a type"
12857        );
12858    }
12859
12860    #[test]
12861    fn is_compares_the_identity_of_two_vectors() {
12862        accepts_body(
12863            "\
12864  var a = Vector.of(1, 2)
12865  var b = a
12866  println(\"{a is b}\")?
12867",
12868        );
12869    }
12870
12871    #[test]
12872    fn rejects_is_between_different_types() {
12873        let error = rejects_body("  println(\"{Vector.of(1) is Vector.of(\"x\")}\")?");
12874        assert_eq!(error.code, OPERATOR);
12875        assert_eq!(
12876            error.message,
12877            "cannot compare the identity of `Vector<Int>` with `Vector<String>`"
12878        );
12879        assert_eq!(
12880            error.rule.unwrap(),
12881            "`is` compares identity between values of the same type."
12882        );
12883    }
12884
12885    #[test]
12886    fn rejects_is_on_a_value_type() {
12887        let error = rejects_body("  println(\"{1 is 1}\")?");
12888        assert_eq!(error.code, OPERATOR);
12889        assert_eq!(error.message, "identity is not available for `Int`");
12890        assert_eq!(
12891            error.rule.unwrap(),
12892            "`==` means value equality. Identity, when available, is explicit."
12893        );
12894    }
12895
12896    #[test]
12897    fn rejects_adding_two_strings() {
12898        let error = rejects_body("  println(\"{\"a\" + \"b\"}\")?");
12899        assert_eq!(error.code, OPERATOR);
12900        assert_eq!(error.message, "`+` is not defined for `String`");
12901        assert_eq!(
12902            error.rule.unwrap(),
12903            "There are no implicit string conversions."
12904        );
12905        assert_eq!(
12906            error.help.unwrap(),
12907            "use string interpolation, such as \"{left}{right}\""
12908        );
12909    }
12910
12911    #[test]
12912    fn accepts_duration_arithmetic_and_comparison() {
12913        accepts_body("  println(\"{1s + 500ms} {1s > 999ms}\")?");
12914        let error = rejects_body("  println(\"{1s * 2s}\")?");
12915        assert_eq!(error.code, OPERATOR);
12916        assert_eq!(
12917            error.message,
12918            "`*` is not defined for `Duration` and `Duration`"
12919        );
12920    }
12921
12922    #[test]
12923    fn rejects_negating_a_string() {
12924        let error = rejects_body("  println(\"{-\"a\"}\")?");
12925        assert_eq!(error.code, OPERATOR);
12926        assert_eq!(error.message, "`-` is not defined for `String`");
12927        assert_eq!(
12928            error.help.unwrap(),
12929            "`-` negates an `Int`, a `Float`, or a `Duration`"
12930        );
12931    }
12932
12933    #[test]
12934    fn rejects_a_non_bool_operand_of_and() {
12935        let error = rejects_body("  println(\"{1 && true}\")?");
12936        assert_eq!(error.code, OPERATOR);
12937        assert_eq!(error.message, "`&&` is not defined for `Int` and `Bool`");
12938        assert_eq!(error.help.unwrap(), "`&&` and `||` combine two `Bool`s");
12939    }
12940
12941    #[test]
12942    fn rejects_ordering_two_bools() {
12943        let error = rejects_body("  println(\"{true < false}\")?");
12944        assert_eq!(error.code, OPERATOR);
12945        assert_eq!(error.message, "`<` is not defined for `Bool` and `Bool`");
12946    }
12947
12948    #[test]
12949    fn rejects_a_non_bool_condition() {
12950        let error = rejects_body("  if 1 {\n    println(\"never\")?\n  }");
12951        assert_eq!(error.code, CONDITION);
12952        assert_eq!(
12953            error.message,
12954            "a condition must be a `Bool`, but found `Int`"
12955        );
12956        assert_eq!(
12957            error.rule.unwrap(),
12958            "There are no implicit boolean conversions."
12959        );
12960        assert_eq!(
12961            error.help.unwrap(),
12962            "compare it, as in `value != 0`; a `Int` is not a `Bool`"
12963        );
12964    }
12965
12966    // ------------------------------------------------- control flow
12967
12968    #[test]
12969    fn an_if_with_no_else_is_a_statement() {
12970        accepts_body("  var seen = 0\n  if true {\n    seen = 1\n  }\n  println(\"{seen}\")?");
12971        // Its value is `()` whatever the branch produces, so binding it and
12972        // using it as an `Int` is an error.
12973        let error = rejects_body("  let n: Int = if true { 1 }");
12974        assert_eq!(error.code, MISMATCH);
12975        assert_eq!(error.message, "expected `Int`, found `()`");
12976    }
12977
12978    #[test]
12979    fn if_branches_must_agree() {
12980        accepts_body("  let n = if true { 1 } else { 2 }\n  println(\"{n}\")?");
12981        let error = rejects_body("  let n = if true { 1 } else { \"two\" }");
12982        assert_eq!(error.code, BRANCHES);
12983        assert_eq!(
12984            error.message,
12985            "this branch produces `String`, but the other produces `Int`"
12986        );
12987        assert_eq!(
12988            error.rule.unwrap(),
12989            "Every branch of an `if` or `match` used as an expression produces the same type."
12990        );
12991        assert_eq!(
12992            error.help.unwrap(),
12993            "make both branches produce `Int`, or bind them separately"
12994        );
12995    }
12996
12997    #[test]
12998    fn every_loop_is_unit_and_a_break_operand_is_discarded() {
12999        // Every loop can reach its end without breaking, and there is
13000        // nothing at that end to produce but `()`, so the loop is `()` and a
13001        // `break` operand is checked on its own and its value discarded --
13002        // the rule an `if` with no `else` already follows. That a loop never
13003        // carries a value is settled, not pending: issue #87 decided it.
13004        accepts_body("  let ran = for value in [1, 2] {\n    value\n  }\n  println(\"{ran}\")?");
13005        accepts_body(
13006            "  let ran = for value in [1, 2] {\n    break value\n  }\n  println(\"{ran}\")?",
13007        );
13008        accepts_body(
13009            "  var seen = 0\n  let ran = while seen < 2 {\n    seen += 1\n    break seen\n  }\n  println(\"{ran}\")?",
13010        );
13011        // `while true` is an ordinary `while`: nothing about the condition
13012        // makes it a form the two passes have to treat specially.
13013        accepts_body("  let ran = while true {\n    break 1\n  }\n  println(\"{ran}\")?");
13014        // Two `break`s out of one loop are checked separately, because
13015        // neither of them says what the loop produces.
13016        accepts_body(
13017            "  let ran = while true {\n    if true {\n      break 1\n    }\n    break \"two\"\n  }\n  println(\"{ran}\")?",
13018        );
13019        // A binding that asks the loop for anything but `()` is a mismatch,
13020        // whatever the `break`s carry.
13021        let error = rejects_body("  let n: Int = while true {\n    break 1\n  }");
13022        assert_eq!(error.code, MISMATCH);
13023        assert_eq!(error.message, "expected `Int`, found `()`");
13024        let error = rejects_body("  let n: Int = for value in [1, 2] {\n    break value\n  }");
13025        assert_eq!(error.code, MISMATCH);
13026        // The operand is still checked, so a mistake inside it is reported.
13027        let error = rejects_body("  for value in [1, 2] {\n    break value + \"a\"\n  }");
13028        assert_eq!(error.code, OPERATOR);
13029    }
13030
13031    #[test]
13032    fn match_arms_must_agree() {
13033        let error = rejects(
13034            "\
13035fn name(n: Int) -> String {
13036  let value = match n {
13037    0 => \"zero\"
13038    _ => 1
13039  }
13040  \"{value}\"
13041}
13042",
13043        );
13044        assert_eq!(error.code, BRANCHES);
13045        assert_eq!(
13046            error.message,
13047            "this branch produces `Int`, but the other produces `String`"
13048        );
13049    }
13050
13051    #[test]
13052    fn a_return_never_disagrees_with_a_branch() {
13053        accepts(
13054            "\
13055fn label(n: Int) -> String {
13056  match n {
13057    0 => return \"zero\"
13058    _ => \"other\"
13059  }
13060}
13061",
13062        );
13063    }
13064
13065    #[test]
13066    fn checks_return_against_the_declared_return_type() {
13067        let error = rejects(
13068            "\
13069fn label(n: Int) -> String {
13070  if n == 0 {
13071    return 0
13072  }
13073  \"other\"
13074}
13075",
13076        );
13077        assert_eq!(error.code, MISMATCH);
13078        assert_eq!(error.message, "expected `String`, found `Int`");
13079        assert_eq!(
13080            error.labels[0].message,
13081            "the declared return type is `String`"
13082        );
13083    }
13084
13085    #[test]
13086    fn a_block_s_value_is_its_tail() {
13087        accepts_body("  let n = {\n    let base = 1\n    base + 1\n  }\n  println(\"{n}\")?");
13088        accepts_body("  let nothing = { }\n  println(\"{nothing}\")?");
13089    }
13090
13091    #[test]
13092    fn a_function_with_no_return_type_returns_unit() {
13093        accepts(
13094            "\
13095fn record(var log: Vector<String>, entry: String) {
13096  log.push(entry)
13097}
13098",
13099        );
13100        let error = rejects("fn total() {\n  1\n}\n");
13101        assert_eq!(error.code, MISMATCH);
13102        assert_eq!(error.message, "expected `()`, found `Int`");
13103        assert_eq!(
13104            error.labels[0].message,
13105            "this function declares no return type, so it returns `()`"
13106        );
13107    }
13108
13109    #[test]
13110    fn checks_a_for_loop_s_iterable_and_binding() {
13111        accepts(
13112            "\
13113fn total(items: Array<Int>) -> Int {
13114  var sum = 0
13115  for item in items {
13116    sum += item
13117  }
13118  sum
13119}
13120",
13121        );
13122        let error = rejects(
13123            "\
13124fn total(items: Array<String>) -> Int {
13125  var sum = 0
13126  for item in items {
13127    sum += item
13128  }
13129  sum
13130}
13131",
13132        );
13133        assert_eq!(error.code, OPERATOR);
13134        assert_eq!(error.message, "`+` is not defined for `Int` and `String`");
13135    }
13136
13137    #[test]
13138    fn rejects_iterating_something_that_is_not_a_sequence() {
13139        let error = rejects_body("  for n in 1 {\n    println(\"{n}\")?\n  }");
13140        assert_eq!(error.code, ITERABLE);
13141        assert_eq!(
13142            error.message,
13143            "`for` iterates an `Array`, a `Vector`, a `Range`, a `Set`, or a `Map`, but found `Int`"
13144        );
13145        assert_eq!(
13146            error.rule.unwrap(),
13147            "`for` iterates a sequence; iteration order is defined by each collection type."
13148        );
13149        assert_eq!(error.help.unwrap(), "write a range, as in `0..<n`");
13150    }
13151
13152    #[test]
13153    fn checks_an_assignment_against_the_place_s_type() {
13154        let error = rejects_body("  var n = 1\n  n = \"one\"");
13155        assert_eq!(error.code, MISMATCH);
13156        assert_eq!(error.message, "expected `Int`, found `String`");
13157    }
13158
13159    #[test]
13160    fn checks_a_compound_assignment_with_the_operator_s_rule() {
13161        accepts_body("  var n = 1\n  n += 2\n  println(\"{n}\")?");
13162        let error = rejects_body("  var n = 1\n  n += 1.0");
13163        assert_eq!(error.code, OPERATOR);
13164        assert_eq!(error.message, "`+` is not defined for `Int` and `Float`");
13165    }
13166
13167    #[test]
13168    fn a_range_takes_two_ints() {
13169        accepts_body("  let range = 0..<3\n  println(\"{range.length()}\")?");
13170        let error = rejects_body("  let range = 0..<\"three\"");
13171        assert_eq!(error.code, MISMATCH);
13172        assert_eq!(error.message, "expected `Int`, found `String`");
13173    }
13174
13175    // ------------------------------------------------- ? and await
13176
13177    #[test]
13178    fn checks_the_question_mark_against_the_enclosing_return_type() {
13179        accepts(
13180            "\
13181fn double(text: String) -> Result<Int, Error> {
13182  let value = Int.parse(text)?
13183  Ok(value * 2)
13184}
13185",
13186        );
13187    }
13188
13189    #[test]
13190    fn rejects_the_question_mark_on_a_value_that_cannot_fail() {
13191        let error = rejects(
13192            "\
13193fn length(text: String) -> Result<Int, Error> {
13194  let n = text.length()?
13195  Ok(n)
13196}
13197",
13198        );
13199        assert_eq!(error.code, TRY_OPERAND);
13200        assert_eq!(
13201            error.message,
13202            "`?` needs a `Result` or an `Option`, but found `Int`"
13203        );
13204        assert_eq!(
13205            error.rule.unwrap(),
13206            "`expr?` returns the error from the current function."
13207        );
13208        assert_eq!(error.help.unwrap(), "`Int` cannot fail, so drop the `?`");
13209    }
13210
13211    #[test]
13212    fn rejects_the_question_mark_when_the_failure_types_differ() {
13213        let error = rejects(
13214            "\
13215enum ParseError {
13216  NotANumber
13217}
13218
13219fn double(text: String) -> Result<Int, ParseError> {
13220  let value = Int.parse(text)?
13221  Ok(value * 2)
13222}
13223",
13224        );
13225        assert_eq!(error.code, TRY_RETURN);
13226        assert_eq!(
13227            error.message,
13228            "`?` propagates `Error`, but this function returns `ParseError` as its failure"
13229        );
13230        assert_eq!(
13231            error.rule.unwrap(),
13232            "`expr?` returns the error from the current function, so the two failure types must be the same."
13233        );
13234        assert_eq!(
13235            error.help.unwrap(),
13236            "map the failure first, as in `expr.mapError(fn(error) { ... })?`, or declare this function `-> Result<_, Error>`"
13237        );
13238    }
13239
13240    #[test]
13241    fn rejects_the_question_mark_in_a_function_that_cannot_fail() {
13242        let error = rejects(
13243            "\
13244fn double(text: String) -> Int {
13245  Int.parse(text)? * 2
13246}
13247",
13248        );
13249        assert_eq!(error.code, TRY_RETURN);
13250        assert_eq!(
13251            error.message,
13252            "`?` needs a function that returns a `Result`, but this one returns `Int`"
13253        );
13254        assert_eq!(
13255            error.help.unwrap(),
13256            "declare this function `-> Result<Int, Error>`, or handle the `Err` with `unwrapOr`"
13257        );
13258    }
13259
13260    // ---- `?` inside a function value
13261
13262    /// The case the rule was written for, from `examples/tasks/load.cove`: a
13263    /// `?` in a `clock.timeout` body. The schema declares that body `Any`, so
13264    /// nothing outside it says what it produces and the body's own value
13265    /// does — and a `Dashboard` has nowhere to put an `Err`.
13266    #[test]
13267    fn rejects_the_question_mark_in_a_body_a_schema_declared_any() {
13268        let error = rejects(
13269            "\
13270use clock
13271
13272struct Dashboard {
13273  panel: String
13274}
13275
13276fn panelOf(name: String) -> Result<String, Error> {
13277  Ok(name)
13278}
13279
13280export fn load() -> Result<Dashboard, Error> {
13281  let result = clock.timeout(1s) {
13282    Dashboard(panel: panelOf(\"bookings\")?)
13283  }?
13284  Ok(result)
13285}
13286",
13287        );
13288        assert_eq!(error.code, TRY_RETURN);
13289        assert_eq!(
13290            error.message,
13291            "`?` propagates `Error`, but this function value produces `Dashboard`"
13292        );
13293        assert_eq!(error.rule.unwrap(), TRY_LAMBDA_RULE);
13294        assert_eq!(
13295            error.help.unwrap(),
13296            "end the body with a `Result`, as in `Ok(...)`, so this function value produces `Result<Dashboard, Error>` and the `?` has an `Err` to return; then answer that failure where the value arrives"
13297        );
13298    }
13299
13300    /// The same body written so that it carries its own failure. The `Ok`
13301    /// leaves its error type open, and the `?` is what states it: `Result`
13302    /// and `Error` come from the two halves of the body together.
13303    #[test]
13304    fn a_body_that_ends_with_a_result_carries_its_own_failure() {
13305        accepts(
13306            "\
13307use clock
13308
13309fn panelOf(name: String) -> Result<String, Error> {
13310  Ok(name)
13311}
13312
13313export fn load() -> Result<String, Error> {
13314  let result = clock.timeout(1s) {
13315    Ok(panelOf(\"bookings\")?)
13316  }?
13317  result
13318}
13319",
13320        );
13321    }
13322
13323    /// A lambda no place types at all is the same question with nothing in
13324    /// the way of it: its result is its body's value, and an `Int` cannot
13325    /// carry an `Error`.
13326    #[test]
13327    fn rejects_the_question_mark_in_a_lambda_nothing_types() {
13328        let error = rejects(
13329            "\
13330fn run() -> Int {
13331  let parse = fn(text: String) {
13332    Int.parse(text)?
13333  }
13334  1
13335}
13336",
13337        );
13338        assert_eq!(error.code, TRY_RETURN);
13339        assert_eq!(
13340            error.message,
13341            "`?` propagates `Error`, but this function value produces `Int`"
13342        );
13343    }
13344
13345    /// A `?` in a spawned task's body returns from the *task*, so the value
13346    /// the handle settles on would be an `Err` in a slot typed `Int`. The
13347    /// program the scope rule is written for spawns `work()` and lets the
13348    /// `Task<Result<Int, Error>>` say so.
13349    #[test]
13350    fn rejects_the_question_mark_in_a_spawned_body() {
13351        let error = rejects(
13352            "\
13353fn work() -> Result<Int, Error> {
13354  Ok(1)
13355}
13356
13357export async fn run() -> Result<Int, Error> {
13358  scope tasks {
13359    let job = tasks.spawn { work()? }
13360    let value = await job
13361    Ok(value)
13362  }
13363}
13364",
13365        );
13366        assert_eq!(error.code, TRY_RETURN);
13367        assert_eq!(
13368            error.message,
13369            "`?` propagates `Error`, but this function value produces `Int`"
13370        );
13371    }
13372
13373    /// `?` on an `Option` asks the same question and gets the same answer in
13374    /// the `Option`'s words.
13375    #[test]
13376    fn rejects_the_option_question_mark_in_a_lambda_nothing_types() {
13377        let error = rejects(
13378            "\
13379fn run() -> Int {
13380  let first = fn(text: String) {
13381    text.words().get(0)?
13382  }
13383  1
13384}
13385",
13386        );
13387        assert_eq!(error.code, TRY_RETURN);
13388        assert_eq!(
13389            error.message,
13390            "`?` on an `Option` returns `None`, but this function value produces `String`"
13391        );
13392        assert_eq!(
13393            error.help.unwrap(),
13394            "end the body with an `Option`, as in `Some(...)`, so this function value produces `Option<String>` and the `?` has a `None` to return; then answer the missing value where it arrives"
13395        );
13396    }
13397
13398    /// A place that *does* declare the result is the check
13399    /// `Checker::try_expr` already made, and it is still the one that
13400    /// reports: nothing is held, so nothing is said twice.
13401    #[test]
13402    fn a_written_function_type_is_checked_where_the_question_mark_is() {
13403        accepts(
13404            "\
13405fn run() -> Int {
13406  let parse: fn(String) -> Result<Int, Error> = fn(text) {
13407    Ok(Int.parse(text)?)
13408  }
13409  1
13410}
13411",
13412        );
13413        let error = rejects(
13414            "\
13415fn run() -> Int {
13416  let parse: fn(String) -> Int = fn(text) {
13417    Int.parse(text)?
13418  }
13419  1
13420}
13421",
13422        );
13423        assert_eq!(error.code, TRY_RETURN);
13424        assert_eq!(
13425            error.message,
13426            "`?` needs a function that returns a `Result`, but this one returns `Int`"
13427        );
13428    }
13429
13430    /// A `?` in a body the enclosing declaration answers for is not a
13431    /// function value's problem. `Result.mapError`'s callback is the place
13432    /// this could have gone wrong: the expectation states its parameters and
13433    /// leaves its result open, which is one of the shapes that waits.
13434    #[test]
13435    fn a_callback_whose_result_the_expectation_leaves_open_is_left_alone() {
13436        accepts(
13437            "\
13438enum ParseError {
13439  NotANumber
13440}
13441
13442fn parse(text: String) -> Result<Int, ParseError> {
13443  Int.parse(text).mapError(fn(cause) {
13444    ParseError.NotANumber
13445  })
13446}
13447",
13448        );
13449    }
13450
13451    #[test]
13452    fn the_question_mark_unwraps_an_option_inside_an_option() {
13453        accepts(
13454            "\
13455fn shout(text: String) -> Option<String> {
13456  let word = text.words().get(0)?
13457  Some(\"{word}!\")
13458}
13459",
13460        );
13461        let error = rejects(
13462            "\
13463fn shout(text: String) -> String {
13464  let word = text.words().get(0)?
13465  \"{word}!\"
13466}
13467",
13468        );
13469        assert_eq!(error.code, TRY_RETURN);
13470        assert_eq!(
13471            error.message,
13472            "`?` on an `Option` needs a function that returns an `Option`, but this one returns `String`"
13473        );
13474    }
13475
13476    #[test]
13477    fn map_error_replaces_the_failure_type() {
13478        accepts(
13479            "\
13480enum ParseError {
13481  NotANumber(String)
13482}
13483
13484fn parseOrFail(text: String) -> Result<Int, ParseError> {
13485  Int.parse(text).mapError(fn(error) { ParseError.NotANumber(text) })
13486}
13487",
13488        );
13489        let error = rejects(
13490            "\
13491enum ParseError {
13492  NotANumber(String)
13493}
13494
13495fn parseOrFail(text: String) -> Result<Int, ParseError> {
13496  Int.parse(text).mapError(fn(error) { text })
13497}
13498",
13499        );
13500        assert_eq!(error.code, MISMATCH);
13501        assert_eq!(
13502            error.message,
13503            "expected `Result<Int, ParseError>`, found `Result<Int, String>`"
13504        );
13505    }
13506
13507    #[test]
13508    fn map_error_also_takes_a_callback_of_the_error() {
13509        accepts(
13510            "\
13511fn keep(text: String) -> Result<Int, Error> {
13512  Int.parse(text).mapError(fn(error) { error })
13513}
13514",
13515        );
13516    }
13517
13518    #[test]
13519    fn calling_an_async_function_produces_a_task_that_await_settles() {
13520        accepts(
13521            "\
13522async fn load() -> Int {
13523  1
13524}
13525
13526async fn run() -> Int {
13527  await load()
13528}
13529",
13530        );
13531        let error = rejects(
13532            "\
13533async fn load() -> Int {
13534  1
13535}
13536
13537async fn run() -> Int {
13538  load()
13539}
13540",
13541        );
13542        assert_eq!(error.code, MISMATCH);
13543        assert_eq!(error.message, "expected `Int`, found `Task<Int>`");
13544    }
13545
13546    #[test]
13547    fn rejects_awaiting_something_that_is_not_a_task() {
13548        let error = rejects_body("  let n = await 1");
13549        assert_eq!(error.code, AWAIT_OPERAND);
13550        assert_eq!(error.message, "`await` needs a task, but found `Int`");
13551        assert_eq!(
13552            error.help.unwrap(),
13553            "call an `async fn`, or spawn the work into a task scope, and await that handle"
13554        );
13555    }
13556
13557    #[test]
13558    fn rejects_the_question_mark_on_a_task() {
13559        let error = rejects(
13560            "\
13561async fn load() -> Result<Int, Error> {
13562  Ok(1)
13563}
13564
13565async fn run() -> Result<Int, Error> {
13566  let value = load()?
13567  Ok(value)
13568}
13569",
13570        );
13571        assert_eq!(error.code, TRY_OPERAND);
13572        assert_eq!(
13573            error.message,
13574            "`?` needs a `Result` or an `Option`, but found `Task<Result<Int, Error>>`"
13575        );
13576        assert_eq!(
13577            error.help.unwrap(),
13578            "settle the task first, as in `task.await()?`"
13579        );
13580    }
13581
13582    #[test]
13583    fn a_scope_spawns_tasks_that_carry_the_block_s_value() {
13584        accepts(
13585            "\
13586async fn run() -> Result<Int, Error> {
13587  scope tasks {
13588    let first = tasks.spawn { 1 }
13589    let value = await first
13590    Ok(value)
13591  }
13592}
13593",
13594        );
13595    }
13596
13597    /// The case the rule must not break, taken from
13598    /// `examples/covecheck/runner_test.cove`'s `counting`: a `scope` whose
13599    /// children answer `Unit` has nothing for scope exit to return, so it is
13600    /// at home in a function that answers nothing.
13601    #[test]
13602    fn a_scope_of_unit_children_is_at_home_in_a_unit_function() {
13603        accepts(
13604            "\
13605fn counting(turns: Shared<Int>, stop: Bool) {
13606  scope work {
13607    let task = work.spawn {
13608      var at = 0
13609      while at < 10 {
13610        turns.lock(fn(var it) {
13611          it += 1
13612        })
13613        at += 1
13614      }
13615    }
13616    if stop {
13617      task.cancel()
13618    } else {
13619      task.await()
13620    }
13621  }
13622}
13623",
13624        );
13625    }
13626
13627    #[test]
13628    fn an_unawaited_failing_child_needs_a_function_that_can_return_its_failure() {
13629        let error = rejects(
13630            "\
13631fn work() -> Result<Int, Error> {
13632  Ok(1)
13633}
13634
13635fn run() {
13636  scope tasks {
13637    let job = tasks.spawn { work() }
13638  }
13639}
13640",
13641        );
13642        assert_eq!(error.code, SCOPE_CHILD_FAILURE);
13643        assert_eq!(
13644            error.message,
13645            "nothing awaits `job`, so leaving `tasks` propagates its `Error`, but this function returns `()`"
13646        );
13647        assert_eq!(
13648            error.help.unwrap(),
13649            "declare this function `-> Result<(), Error>`, or await `job` and answer its `Err` here"
13650        );
13651    }
13652
13653    /// The same program, awaited. An awaited task is joined where the
13654    /// `await` is written, so scope exit passes over it and the failure is
13655    /// the awaiting expression's.
13656    #[test]
13657    fn awaiting_a_failing_child_leaves_the_enclosing_function_alone() {
13658        accepts(
13659            "\
13660fn work() -> Result<Int, Error> {
13661  Ok(1)
13662}
13663
13664fn run() -> Int {
13665  scope tasks {
13666    let job = tasks.spawn { work() }
13667    job.await().unwrapOr(0)
13668  }
13669}
13670",
13671        );
13672        accepts(
13673            "\
13674fn work() -> Result<Int, Error> {
13675  Ok(1)
13676}
13677
13678fn run() -> Int {
13679  scope tasks {
13680    (await tasks.spawn { work() }).unwrapOr(0)
13681  }
13682}
13683",
13684        );
13685    }
13686
13687    /// A `cancel()` is not a settling. Cancellation stops work that has not
13688    /// happened and does not undo work that has, so a child that finished
13689    /// with an `Err` before the request reached it is still waited for at
13690    /// scope exit and still returns.
13691    #[test]
13692    fn cancelling_a_failing_child_does_not_settle_it() {
13693        let error = rejects(
13694            "\
13695fn work() -> Result<Int, Error> {
13696  Ok(1)
13697}
13698
13699fn run() -> Int {
13700  scope tasks {
13701    let job = tasks.spawn { work() }
13702    job.cancel()
13703    0
13704  }
13705}
13706",
13707        );
13708        assert_eq!(error.code, SCOPE_CHILD_FAILURE);
13709        assert_eq!(
13710            error.message,
13711            "nothing awaits `job`, so leaving `tasks` propagates its `Error`, but this function returns `Int`"
13712        );
13713    }
13714
13715    /// A function that already answers a `Result` answers this one too, so
13716    /// nothing is asked of it — which is what `examples/callbacks/main.cove`
13717    /// relies on, where a timer that answers `Result<Unit, Error>` is
13718    /// cancelled and never awaited.
13719    #[test]
13720    fn a_result_returning_function_carries_its_children_s_failures() {
13721        accepts(
13722            "\
13723fn work() -> Result<Int, Error> {
13724  Ok(1)
13725}
13726
13727fn run() -> Result<Unit, Error> {
13728  scope tasks {
13729    let job = tasks.spawn { work() }
13730    job.cancel()
13731  }
13732  Ok(())
13733}
13734",
13735        );
13736    }
13737
13738    /// Two unhandled children whose failures differ cannot both be the
13739    /// function's, so the one that does not fit is named. Each child is
13740    /// measured against the declared failure type, which is the unification
13741    /// the language already has.
13742    #[test]
13743    fn failures_of_several_children_must_fit_one_declared_failure() {
13744        let error = rejects(
13745            "\
13746struct Wrong {
13747  why: String
13748}
13749
13750fn fails() -> Result<Int, Wrong> {
13751  Err(Wrong(why: \"no\"))
13752}
13753
13754fn run() -> Result<Unit, Error> {
13755  scope tasks {
13756    let job = tasks.spawn { fails() }
13757  }
13758  Ok(())
13759}
13760",
13761        );
13762        assert_eq!(error.code, SCOPE_CHILD_FAILURE);
13763        assert_eq!(
13764            error.message,
13765            "nothing awaits `job`, so leaving `tasks` propagates its `Wrong`, but this function returns `Error` as its failure"
13766        );
13767        assert_eq!(
13768            error.help.unwrap(),
13769            "map the failure inside the task, as in `tasks.spawn { ... .mapError(fn(error) { ... }) }`, or declare this function `-> Result<(), Wrong>`"
13770        );
13771    }
13772
13773    /// A handle spawned into an outer scope and awaited inside an inner one
13774    /// is awaited, so every open frame is searched rather than the innermost.
13775    #[test]
13776    fn a_child_awaited_inside_a_nested_scope_is_awaited() {
13777        accepts(
13778            "\
13779fn work() -> Result<Int, Error> {
13780  Ok(1)
13781}
13782
13783fn run() -> Int {
13784  scope outer {
13785    let job = outer.spawn { work() }
13786    scope inner {
13787      job.await().unwrapOr(0)
13788    }
13789  }
13790}
13791",
13792        );
13793    }
13794
13795    // ------------------------------------------------- `Shared`
13796
13797    /// The Language Card's own example: mutable state wrapped in a `Shared`,
13798    /// reached through a scoped `lock`.
13799    const METRICS: &str = "\
13800struct Metrics {
13801  requests: Int
13802  failures: Int
13803}
13804
13805impl Metrics {
13806  fn record(var self, failed: Bool) {
13807    self.requests += 1
13808    if failed {
13809      self.failures += 1
13810    }
13811  }
13812}
13813";
13814
13815    #[test]
13816    fn a_lock_gives_its_closure_the_wrapped_type_and_carries_its_result() {
13817        accepts(&format!(
13818            "{METRICS}
13819fn run() -> Int {{
13820  let metrics = Shared(Metrics(requests: 0, failures: 0))
13821  metrics.lock(fn(var value) {{
13822    value.record(true)
13823  }})
13824  metrics.lock(fn(value) {{
13825    value.requests
13826  }})
13827}}
13828"
13829        ));
13830    }
13831
13832    #[test]
13833    fn a_lock_result_has_the_closure_s_type() {
13834        let error = rejects(&format!(
13835            "{METRICS}
13836fn run() -> String {{
13837  let metrics = Shared(Metrics(requests: 0, failures: 0))
13838  metrics.lock(fn(value) {{
13839    value.requests
13840  }})
13841}}
13842"
13843        ));
13844        assert_eq!(error.message, "expected `String`, found `Int`");
13845    }
13846
13847    /// The closure's parameter type is derived from what the `Shared` wraps,
13848    /// so the closure sees that type and nothing else.
13849    #[test]
13850    fn a_lock_closure_takes_the_wrapped_type() {
13851        let error = rejects(&format!(
13852            "{METRICS}
13853fn run() -> Int {{
13854  let metrics = Shared(Metrics(requests: 0, failures: 0))
13855  metrics.lock(fn(value) {{
13856    value.attempts
13857  }})
13858}}
13859"
13860        ));
13861        assert_eq!(error.code, UNKNOWN_FIELD);
13862        assert_eq!(error.message, "`Metrics` has no field `attempts`");
13863    }
13864
13865    /// A `Shared<Vector<T>>` would let a vector be reached from two tasks,
13866    /// which is what the sentence naming `Shared` forbids.
13867    #[test]
13868    fn a_shared_vector_is_refused_where_the_type_is_written() {
13869        let error = rejects_body("  let counts: Shared<Vector<Int>> = Shared(Vector.of(1))");
13870        assert_eq!(error.code, TASK_SAFETY);
13871        assert_eq!(
13872            error.message,
13873            "`Shared` cannot wrap a `Vector<Int>`, which cannot cross a task boundary"
13874        );
13875        assert!(error.rule.unwrap().contains("A vector cannot cross"));
13876    }
13877
13878    #[test]
13879    fn a_shared_vector_is_refused_where_it_is_constructed() {
13880        let error = rejects_body("  let counts = Shared(Vector.of(1))");
13881        assert_eq!(error.code, TASK_SAFETY);
13882    }
13883
13884    #[test]
13885    fn a_shared_of_an_array_of_vectors_names_the_vector() {
13886        let error = rejects_body("  let counts: Shared<Array<Vector<Int>>> = Shared([])");
13887        assert_eq!(
13888            error.message,
13889            "`Shared` cannot wrap `Array<Vector<Int>>`: the `Vector<Int>` in it cannot cross a task boundary"
13890        );
13891    }
13892
13893    #[test]
13894    fn a_shared_does_not_conform_to_snapshot() {
13895        let error = rejects_body("  let counts = Shared(1)\n  let copy = counts.snapshot()");
13896        assert_eq!(error.message, "`Shared<Int>` does not implement `Snapshot`");
13897        assert!(error.rule.unwrap().contains("synchronized values"));
13898    }
13899
13900    #[test]
13901    fn a_shared_has_no_operation_but_lock() {
13902        let error = rejects_body("  let counts = Shared(1)\n  let value = counts.get()");
13903        assert_eq!(error.code, UNKNOWN_METHOD);
13904        assert_eq!(error.message, "`Shared` has no method `get`");
13905    }
13906
13907    // ------------------------------------------------- aliases
13908
13909    #[test]
13910    fn expands_a_type_alias() {
13911        accepts(
13912            "\
13913type Transform = fn(Int) -> Int
13914
13915fn apply(value: Int, transform: Transform) -> Int {
13916  transform(value)
13917}
13918
13919fn run() -> Int {
13920  apply(1, fn(n) { n + 1 })
13921}
13922",
13923        );
13924        let error = rejects(
13925            "\
13926type Transform = fn(Int) -> Int
13927
13928fn apply(value: Int, transform: Transform) -> Int {
13929  transform(value)
13930}
13931
13932fn run() -> Int {
13933  apply(1, fn(n) { \"{n}\" })
13934}
13935",
13936        );
13937        assert_eq!(error.code, MISMATCH);
13938        assert_eq!(error.message, "expected `Int`, found `String`");
13939    }
13940
13941    #[test]
13942    fn rejects_a_type_alias_that_expands_to_itself() {
13943        let error = rejects("type Loop = Loop\n\nfn run(value: Loop) {\n}\n");
13944        assert_eq!(error.code, ALIAS_CYCLE);
13945        assert_eq!(error.message, "`Loop` expands to itself");
13946        assert_eq!(
13947            error.rule.unwrap(),
13948            "A type alias names an existing type; it cannot be defined in terms of itself."
13949        );
13950    }
13951
13952    // ------------------------------------------- recursive value layouts
13953    //
13954    // ADR 0035: a value type may not contain itself, because a value is a
13955    // run of words laid out where the value is and a declaration that
13956    // contains itself has no finite width. The escape is a type whose value
13957    // is a reference, and every recursive declaration in the corpus already
13958    // takes one.
13959
13960    #[test]
13961    fn rejects_a_struct_that_contains_itself() {
13962        let error = rejects("struct Node {\n  value: Int,\n  next: Node,\n}\n");
13963        assert_eq!(error.code, LAYOUT_CYCLE);
13964        assert_eq!(
13965            error.message,
13966            "`Node` contains itself by value, through field `next`"
13967        );
13968        assert_eq!(error.rule.unwrap(), LAYOUT_CYCLE_RULE);
13969        assert_eq!(
13970            error.help.unwrap(),
13971            "break the cycle by holding one of its steps behind a reference: `Array<Node>`, `Vector<Node>` and `Shared<Node>` are each one word, so a cycle that passes through one has a finite width"
13972        );
13973    }
13974
13975    #[test]
13976    fn rejects_a_struct_that_contains_itself_through_an_option() {
13977        let error = rejects("struct Node {\n  value: Int,\n  next: Option<Node>,\n}\n");
13978        assert_eq!(error.code, LAYOUT_CYCLE);
13979        assert_eq!(
13980            error.message,
13981            "`Node` contains itself by value, through field `next`"
13982        );
13983    }
13984
13985    #[test]
13986    fn rejects_an_enum_whose_case_carries_itself() {
13987        let error = rejects("enum List {\n  Empty,\n  Cons(Int, List),\n}\n");
13988        assert_eq!(error.code, LAYOUT_CYCLE);
13989        assert_eq!(
13990            error.message,
13991            "`List` contains itself by value, through case `Cons`"
13992        );
13993    }
13994
13995    #[test]
13996    fn rejects_two_structs_that_contain_each_other() {
13997        let error = rejects("struct A {\n  b: B,\n}\n\nstruct B {\n  a: A,\n}\n");
13998        assert_eq!(error.code, LAYOUT_CYCLE);
13999        assert_eq!(
14000            error.message,
14001            "`A` contains itself by value: `A` -> `B` -> `A`"
14002        );
14003        let labels: Vec<&str> = error
14004            .labels
14005            .iter()
14006            .map(|label| label.message.as_str())
14007            .collect();
14008        assert_eq!(
14009            labels,
14010            vec![
14011                "field `b` puts `B` inside `A`",
14012                "field `a` puts `A` inside `B`"
14013            ]
14014        );
14015    }
14016
14017    #[test]
14018    fn rejects_a_three_step_cycle() {
14019        let error = rejects(
14020            "struct A {\n  b: B,\n}\n\nstruct B {\n  c: C,\n}\n\nstruct C {\n  a: Option<A>,\n}\n",
14021        );
14022        assert_eq!(error.code, LAYOUT_CYCLE);
14023        assert_eq!(
14024            error.message,
14025            "`A` contains itself by value: `A` -> `B` -> `C` -> `A`"
14026        );
14027    }
14028
14029    #[test]
14030    fn a_cycle_is_reported_once_however_many_declarations_it_runs_through() {
14031        let errors = errors_of("struct A {\n  b: B,\n}\n\nstruct B {\n  a: A,\n}\n");
14032        assert_eq!(errors.len(), 1);
14033    }
14034
14035    #[test]
14036    fn a_struct_holds_itself_through_a_vector() {
14037        accepts("struct Node {\n  label: String,\n  peers: Vector<Node>,\n}\n");
14038    }
14039
14040    #[test]
14041    fn an_enum_holds_itself_through_an_array_and_a_map() {
14042        accepts("enum Json {\n  Null,\n  Items(Array<Json>),\n  Fields(Map<String, Json>),\n}\n");
14043    }
14044
14045    #[test]
14046    fn a_cycle_through_a_closure_or_a_trait_object_is_a_reference() {
14047        accepts("trait Render {\n  fn render(self) -> String\n}\n\nstruct Node {\n  child: dyn Render,\n  make: fn() -> Node,\n}\n");
14048    }
14049
14050    #[test]
14051    fn a_generic_declaration_that_holds_its_parameter_carries_the_cycle() {
14052        let error =
14053            rejects("struct Cell<T> {\n  it: T,\n}\n\nstruct Loop {\n  cell: Cell<Loop>,\n}\n");
14054        assert_eq!(error.code, LAYOUT_CYCLE);
14055        assert_eq!(
14056            error.message,
14057            "`Loop` contains itself by value, through field `cell`"
14058        );
14059    }
14060
14061    #[test]
14062    fn a_generic_declaration_that_holds_its_parameter_behind_a_reference_does_not() {
14063        accepts(
14064            "struct Holder<T> {\n  it: Vector<T>,\n}\n\nstruct Node {\n  held: Holder<Node>,\n}\n",
14065        );
14066    }
14067
14068    #[test]
14069    fn a_cycle_through_an_imported_generic_is_still_a_cycle() {
14070        // A cycle cannot leave a module and come back — resolution refuses a
14071        // package whose modules import in a cycle — but an imported
14072        // declaration can still carry one, because what it holds by value is
14073        // read from the module that declares it.
14074        let error = rejects_modules(&[
14075            ("cell", "/// A box.\nexport struct Cell<T> {\n  it: T,\n}\n"),
14076            (
14077                "app",
14078                "use cell.Cell\n\nstruct Loop {\n  cell: Cell<Loop>,\n}\n",
14079            ),
14080        ]);
14081        assert_eq!(error.code, LAYOUT_CYCLE);
14082        assert_eq!(
14083            error.message,
14084            "`Loop` contains itself by value, through field `cell`"
14085        );
14086    }
14087
14088    #[test]
14089    fn nesting_one_generic_inside_itself_is_finite() {
14090        accepts("struct Cell<T> {\n  it: T,\n}\n\nstruct Twice {\n  it: Cell<Cell<Int>>,\n}\n");
14091    }
14092
14093    // ------------------------------------------------- the Host API schema
14094    //
14095    // ADR 0001's schema is one description shared by the compiler, runtime,
14096    // and CLI, and these are the compiler's half of reading it. The runtime's
14097    // half is in `cove_runtime::host`; the two check the same table against
14098    // the same call, and a program that gets past both has been checked
14099    // twice.
14100
14101    #[test]
14102    fn a_host_call_produces_the_type_its_schema_declares() {
14103        // `env.get` declares `Option<String>` and `documents.read` declares
14104        // `Result<String, Error>`, so both are ordinary typed values here.
14105        accepts(
14106            "\
14107use console.println
14108use env.get
14109use documents
14110
14111export fn main() -> Result<Unit, Error> {
14112  let port: String = env.get(\"PORT\").unwrapOr(\"8080\")
14113  let note: String = documents.read(\"input\")?
14114  println(\"{port} {note}\")?
14115  Ok(())
14116}
14117",
14118        );
14119    }
14120
14121    #[test]
14122    fn a_host_call_s_result_is_checked_where_it_is_used() {
14123        let error = rejects(
14124            "\
14125use env.get
14126
14127export fn main() -> Int {
14128  get(\"PORT\").unwrapOr(\"8080\") + 1
14129}
14130",
14131        );
14132        assert_eq!(error.code, OPERATOR);
14133        assert_eq!(error.message, "`+` is not defined for `String` and `Int`");
14134    }
14135
14136    #[test]
14137    fn an_argument_a_host_operation_does_not_declare_is_rejected_at_the_call() {
14138        let error = rejects(
14139            "\
14140use documents
14141
14142export fn main() -> Result<Unit, Error> {
14143  documents.read(1)?
14144  Ok(())
14145}
14146",
14147        );
14148        assert_eq!(error.code, MISMATCH);
14149        assert_eq!(error.message, "expected `String`, found `Int`");
14150        assert_eq!(
14151            error.rule.unwrap(),
14152            "Types are nominal and the only implicit conversion is to `dyn Trait`: a value must otherwise already have the type its place asks for."
14153        );
14154    }
14155
14156    /// The same mistake the boundary refuses, caught where it has a span.
14157    #[test]
14158    fn a_host_call_with_the_wrong_number_of_arguments_is_rejected_at_the_call() {
14159        let error = rejects(
14160            "\
14161use documents
14162
14163export fn main() -> Result<Unit, Error> {
14164  documents.read(\"input\", \"extra\")?
14165  Ok(())
14166}
14167",
14168        );
14169        assert_eq!(error.code, ARITY);
14170        assert_eq!(
14171            error.message,
14172            "`documents.read` takes 1 argument, but 2 were given"
14173        );
14174        assert_eq!(
14175            error.help.unwrap(),
14176            "the Host API schema declares `documents.read(String) -> Result<String, Error>`",
14177            "the boundary's diagnostic for the same mistake quotes it word for word"
14178        );
14179    }
14180
14181    /// `console.println("a", "b")` is one line of two parts, so a variadic
14182    /// operation accepts any number of arguments and checks every one of them
14183    /// against its one declared type.
14184    #[test]
14185    fn a_variadic_host_operation_checks_every_argument() {
14186        accepts(
14187            "\
14188use console
14189
14190export fn main() -> Result<Unit, Error> {
14191  console.println()?
14192  console.println(\"one\", \"two\", \"three\")?
14193  Ok(())
14194}
14195",
14196        );
14197
14198        let error = rejects(
14199            "\
14200use console
14201
14202export fn main() -> Result<Unit, Error> {
14203  console.println(\"one\", 2)?
14204  Ok(())
14205}
14206",
14207        );
14208        assert_eq!(error.code, MISMATCH);
14209        assert_eq!(error.message, "expected `String`, found `Int`");
14210    }
14211
14212    /// `clock.timeout` declares `Any` for the work it bounds, which is not a
14213    /// gap in the schema but a claim: the operation's meaning does not depend
14214    /// on which value it was given. `Unknown` is what that claim is here.
14215    #[test]
14216    fn a_parameter_declared_any_accepts_whatever_it_is_given() {
14217        accepts(
14218            "\
14219use clock
14220
14221export fn main() -> Result<Unit, Error> {
14222  clock.timeout(500ms) {
14223    1
14224  }?
14225  clock.every(60s, fn() {
14226    Ok(())
14227  })?
14228  Ok(())
14229}
14230",
14231        );
14232    }
14233
14234    #[test]
14235    fn an_operation_the_schema_does_not_declare_is_rejected() {
14236        let error = rejects(
14237            "\
14238use documents
14239
14240export fn main() -> Result<Unit, Error> {
14241  documents.write(\"input\", \"text\")?
14242  Ok(())
14243}
14244",
14245        );
14246        assert_eq!(error.code, UNKNOWN_HOST_OPERATION);
14247        assert_eq!(
14248            error.message,
14249            "host module `documents` has no operation `write`"
14250        );
14251        assert_eq!(error.help.unwrap(), "`documents` exposes `read`");
14252    }
14253
14254    /// A host type is nominal and named the way source writes it, so a
14255    /// signature written in terms of one is checked like any other.
14256    #[test]
14257    fn a_host_type_is_a_type() {
14258        accepts(
14259            "\
14260use http
14261
14262/// Answers one request.
14263export fn health(request: http.Request) -> http.Response {
14264  http.json(200, request.path)
14265}
14266",
14267        );
14268
14269        let error = rejects(
14270            "\
14271use http
14272
14273export fn health(request: http.Request) -> Int {
14274  http.json(200, \"ok\")
14275}
14276",
14277        );
14278        assert_eq!(error.code, MISMATCH);
14279        assert_eq!(error.message, "expected `Int`, found `http.Response`");
14280    }
14281
14282    /// A host type's fields come from the schema, which is the one place they
14283    /// are read: the boundary checks a declared type by name only.
14284    #[test]
14285    fn a_host_type_s_fields_are_typed_by_the_schema() {
14286        let error = rejects(
14287            "\
14288use http
14289
14290export fn path(request: http.Request) -> Int {
14291  request.path
14292}
14293",
14294        );
14295        assert_eq!(error.code, MISMATCH);
14296        assert_eq!(error.message, "expected `Int`, found `String`");
14297
14298        let missing = rejects(
14299            "\
14300use http
14301
14302export fn path(request: http.Request) -> String {
14303  request.query
14304}
14305",
14306        );
14307        assert_eq!(missing.code, UNKNOWN_FIELD);
14308        assert_eq!(missing.message, "`http.Request` has no field `query`");
14309        assert_eq!(
14310            missing.help.unwrap(),
14311            "`http.Request` declares `method`, `path`, `body`"
14312        );
14313    }
14314
14315    /// A host type that is plain data is initialized from Cove source exactly
14316    /// as a struct is, labels and all.
14317    #[test]
14318    fn a_host_type_is_initialized_with_the_fields_the_schema_declares() {
14319        accepts(
14320            "\
14321use http
14322
14323/// Answers one request.
14324fn health(request: http.Request) -> http.Response {
14325  http.json(200, \"ok\")
14326}
14327
14328/// The one route this program serves.
14329export fn routes() -> Array<http.Route> {
14330  [http.Route(method: http.Method.Get, path: \"/health\", handler: health)]
14331}
14332",
14333        );
14334
14335        let error = rejects(
14336            "\
14337use http
14338
14339export fn routes() -> Array<http.Route> {
14340  [http.Route(method: http.Method.Get, path: 8080, handler: 1)]
14341}
14342",
14343        );
14344        assert_eq!(error.code, MISMATCH);
14345        assert_eq!(error.message, "expected `String`, found `Int`");
14346    }
14347
14348    #[test]
14349    fn a_case_the_host_enum_does_not_declare_is_rejected() {
14350        let error = rejects(
14351            "\
14352use http
14353
14354export fn method() -> http.Method {
14355  http.Method.Delete
14356}
14357",
14358        );
14359        assert_eq!(error.code, UNKNOWN_CASE);
14360        assert_eq!(error.message, "`http.Method` has no case `Delete`");
14361        assert_eq!(error.help.unwrap(), "`http.Method` declares `Get`, `Post`");
14362    }
14363
14364    /// A resource handle answers the operations its kind declares, checked
14365    /// through the same entry the boundary dispatches them through.
14366    #[test]
14367    fn an_operation_on_a_host_resource_is_checked_against_its_kind() {
14368        accepts(
14369            "\
14370use http
14371use console.println
14372
14373export fn main() -> Result<Unit, Error> {
14374  let server = http.listen(8080)?
14375  println(\"listening on :{server.port()}\")?
14376  server.close()?
14377  Ok(())
14378}
14379",
14380        );
14381
14382        let error = rejects(
14383            "\
14384use http
14385
14386export fn main() -> Result<Unit, Error> {
14387  let server = http.listen(8080)?
14388  server.handle(\"routes\")?
14389  Ok(())
14390}
14391",
14392        );
14393        assert_eq!(error.code, MISMATCH);
14394        assert_eq!(
14395            error.message,
14396            "expected `Array<http.Route>`, found `String`"
14397        );
14398    }
14399
14400    #[test]
14401    fn an_operation_a_host_resource_does_not_declare_is_rejected() {
14402        let error = rejects(
14403            "\
14404use http
14405
14406export fn main() -> Result<Unit, Error> {
14407  let server = http.listen(8080)?
14408  server.stop()?
14409  Ok(())
14410}
14411",
14412        );
14413        assert_eq!(error.code, UNKNOWN_HOST_OPERATION);
14414        assert_eq!(error.message, "`http.Server` has no operation `stop`");
14415        assert_eq!(
14416            error.help.unwrap(),
14417            "`http.Server` answers `port`, `handle`, `close`"
14418        );
14419    }
14420
14421    #[test]
14422    fn a_type_a_host_module_does_not_declare_is_rejected() {
14423        let error = rejects(
14424            "\
14425use http
14426
14427export fn handle(request: http.Payload) -> Int {
14428  1
14429}
14430",
14431        );
14432        assert_eq!(error.code, UNKNOWN_HOST_TYPE);
14433        assert_eq!(
14434            error.message,
14435            "host module `http` declares no type `Payload`"
14436        );
14437        assert_eq!(
14438            error.help.unwrap(),
14439            "`http` declares `Method`, `Request`, `Response`, `Route`, `Server`"
14440        );
14441    }
14442
14443    // --------------------------------------- the four kinds of unknown
14444
14445    // Each of these pins one classification by its *effect*: a recovery
14446    // unknown says nothing more, a dynamic boundary warns, an unconstrained
14447    // result is noted, and a language gap is reported. The module
14448    // documentation lists which construction site is which; these say what
14449    // the difference is worth to someone reading `cove check`.
14450
14451    // ---- dynamic boundary: a host no schema describes
14452
14453    /// A host module no schema describes is the one host call the checker
14454    /// still abstains from: an embedder that hands its module's schema over
14455    /// gets it checked like any other, and one that does not leaves the
14456    /// boundary to hold the host to its word.
14457    ///
14458    /// This pass says nothing about it. The fact belongs to the `use` that
14459    /// named the module — no edit to `sensors.read` can fix it, and the
14460    /// remedy is one thing to say however many calls a program makes — and
14461    /// `cove::resolve::unchecked_host` puts the warning there. What this
14462    /// pass owes is silence per call and a `Ty::dynamic_boundary` that says
14463    /// why.
14464    #[test]
14465    fn a_call_into_a_host_module_with_no_schema_is_not_reported_at_the_call() {
14466        let source = "\
14467use console.println
14468use sensors
14469
14470export fn main() -> Result<Unit, Error> {
14471  let value = sensors.read(\"pressure\")
14472  println(\"{value + 1}\")?
14473  Ok(())
14474}
14475";
14476        accepts(source);
14477        assert!(warnings_of(source).is_empty());
14478        assert!(notes_of(source).is_empty());
14479    }
14480
14481    /// The shape an embedding is written in: a callback a host stores and
14482    /// calls later, registered with a module no schema describes.
14483    ///
14484    /// Nothing on this side states what the callback takes or produces, and
14485    /// nothing can: that is the abstention, not a gap in the program. So the
14486    /// unannotated parameter is not reported and the early `return` is not
14487    /// an error, either of which would have refused a program that runs.
14488    #[test]
14489    fn a_callback_into_a_host_module_with_no_schema_is_not_reported() {
14490        let source = "\
14491use sensors
14492
14493fn run() -> Int {
14494  sensors.watch(fn(reading) { return 1 })
14495  1
14496}
14497";
14498        accepts(source);
14499        assert!(
14500            warnings_of(source).is_empty(),
14501            "{:?}",
14502            warnings_of(source)
14503                .iter()
14504                .map(|d| d.code.clone())
14505                .collect::<Vec<_>>()
14506        );
14507    }
14508
14509    #[test]
14510    fn a_member_of_a_host_module_with_no_schema_read_as_a_value_is_not_reported() {
14511        let source = "\
14512use sensors
14513
14514fn run() -> Int {
14515  let reading = sensors.latest
14516  1
14517}
14518";
14519        accepts(source);
14520        assert!(warnings_of(source).is_empty());
14521    }
14522
14523    #[test]
14524    fn a_type_from_a_host_module_with_no_schema_warns_rather_than_failing() {
14525        let warning = warns(
14526            "\
14527use sensors
14528
14529fn handle(reading: sensors.Reading) -> Int {
14530  1
14531}
14532",
14533        );
14534        assert_eq!(warning.code, HOST_TYPE);
14535        assert_eq!(
14536            warning.message,
14537            "`sensors.Reading` comes from a host module no Host API schema describes, so values of it are unchecked"
14538        );
14539        assert_eq!(
14540            warning.rule.as_deref().unwrap(),
14541            "A Host API's types come from its schema; the checker reads the shipped schemas and any an embedder supplies."
14542        );
14543    }
14544
14545    /// A host *operation* is a value, and the schema says which one.
14546    ///
14547    /// The interpreter has always bound one and called it later, so refusing
14548    /// the form would remove a capability the language has. Reading the
14549    /// schema instead turns what used to be an unknown into the operation's
14550    /// own function type, so a call made through the value is checked exactly
14551    /// as a direct call is.
14552    #[test]
14553    fn a_host_operation_read_as_a_value_has_the_type_its_schema_declares() {
14554        let source = "\
14555use console.println
14556use http
14557
14558export fn main() -> Result<Unit, Error> {
14559  let get = http.fetch
14560  let body = get(\"https://example.com\")?
14561  println(\"{body}\")?
14562  Ok(())
14563}
14564";
14565        accepts(source);
14566        assert!(warnings_of(source).is_empty());
14567        assert!(notes_of(source).is_empty());
14568    }
14569
14570    /// The value is a real function type, so a call through it is checked.
14571    #[test]
14572    fn a_call_through_a_host_operation_value_is_checked() {
14573        let error = rejects(
14574            "\
14575use http
14576
14577fn run() -> Int {
14578  let get = http.fetch
14579  get(1)
14580  1
14581}
14582",
14583        );
14584        assert_eq!(error.code, MISMATCH);
14585    }
14586
14587    /// A *variadic* operation is the one this language has no function type
14588    /// for, so the value keeps working and the gap is a note rather than a
14589    /// refusal or a silence.
14590    #[test]
14591    fn a_variadic_host_operation_used_as_a_value_is_noted() {
14592        let source = "\
14593use console
14594
14595fn run() -> Int {
14596  let write = console.println
14597  1
14598}
14599";
14600        accepts(source);
14601        assert!(warnings_of(source).is_empty());
14602        let notes = notes_of(source);
14603        assert_eq!(notes.len(), 1);
14604        assert_eq!(notes[0].code, VARIADIC_AS_VALUE);
14605        assert_eq!(
14606            notes[0].message,
14607            "`console.println` is variadic, so this value has no function type here"
14608        );
14609    }
14610
14611    /// A host *type* is not a value, exactly as a bare `Vector` is not, and
14612    /// the correction names a form the language has.
14613    #[test]
14614    fn a_host_type_read_as_a_value_is_an_error() {
14615        let error = rejects(
14616            "\
14617use http
14618
14619fn run() -> Int {
14620  let route = http.Route
14621  1
14622}
14623",
14624        );
14625        assert_eq!(error.code, NOT_A_VALUE);
14626        assert_eq!(error.message, "`http.Route` is a host type, not a value");
14627        assert_eq!(
14628            error.help.unwrap(),
14629            "construct one, as in `http.Route(field: value)`, or call the operation that answers one"
14630        );
14631    }
14632
14633    // ---- unconstrained API: a schema's `Any`
14634
14635    /// `Any` in a result is the checker saying what it will not prove, so it
14636    /// is a note: nothing is wrong, and `--deny-warnings` has nothing to act
14637    /// on. What the note has to carry is the schema's own promise.
14638    #[test]
14639    fn a_host_result_declared_any_is_noted_at_the_call() {
14640        let source = "\
14641use clock
14642
14643export fn main() -> Result<Unit, Error> {
14644  let value = clock.timeout(1s) {
14645    1
14646  }?
14647  Ok(())
14648}
14649";
14650        accepts(source);
14651        assert!(warnings_of(source).is_empty());
14652        let notes = notes_of(source);
14653        assert_eq!(notes.len(), 1);
14654        assert_eq!(notes[0].code, UNCONSTRAINED_RESULT);
14655        assert_eq!(
14656            notes[0].message,
14657            "`clock.timeout` declares its result `Result<Any, Error>`, so nothing here says what this call produced"
14658        );
14659        assert_eq!(
14660            notes[0].help.as_deref().unwrap(),
14661            "whatever the program does with the result of `clock.timeout` is checked at run time and by nothing here; the Host API schema declares `clock.timeout(Duration, Any) -> Result<Any, Error>`"
14662        );
14663    }
14664
14665    /// `Any` in a parameter promises to accept every value, so there is no
14666    /// check to skip and nothing to say. `clock.every` declares one and
14667    /// answers `Result<Unit, Error>`.
14668    #[test]
14669    fn a_parameter_declared_any_is_not_noted() {
14670        let source = "\
14671use clock
14672
14673export fn main() -> Result<Unit, Error> {
14674  clock.every(1s) {
14675    1
14676  }?
14677  Ok(())
14678}
14679";
14680        accepts(source);
14681        assert!(notes_of(source).is_empty());
14682        assert!(warnings_of(source).is_empty());
14683    }
14684
14685    /// The type an `Any` result carries is unknown, so what the program does
14686    /// with it afterwards is unchecked — which is exactly what the note
14687    /// warns a reader to expect.
14688    #[test]
14689    fn what_an_any_result_is_used_for_is_not_checked() {
14690        accepts(
14691            "\
14692use clock
14693
14694export fn main() -> Result<Unit, Error> {
14695  let value = clock.timeout(1s) {
14696    1
14697  }?
14698  let text: String = value
14699  Ok(())
14700}
14701",
14702        );
14703    }
14704
14705    /// The other end of the `Any` promise: a schema may declare a *field*
14706    /// `Any`, and reading one leaves the program holding a value no schema
14707    /// described, exactly as calling an `Any`-result operation does.
14708    /// `http.Route.handler` is the one the shipped schema declares.
14709    #[test]
14710    fn a_host_field_declared_any_is_noted_where_it_is_read() {
14711        let source = "\
14712use http
14713
14714fn readHandler(route: http.Route) -> Int {
14715  let handler = route.handler
14716  1
14717}
14718";
14719        accepts(source);
14720        assert!(warnings_of(source).is_empty());
14721        let notes = notes_of(source);
14722        assert_eq!(notes.len(), 1);
14723        assert_eq!(notes[0].code, UNCONSTRAINED_FIELD);
14724        assert_eq!(
14725            notes[0].message,
14726            "`http.Route` declares `handler` as `Any`, so nothing here says what this field holds"
14727        );
14728    }
14729
14730    /// A rejected call produces nothing to say anything about, so the note
14731    /// about its result is not also printed: one mistake, one diagnostic.
14732    #[test]
14733    fn an_arity_error_on_an_any_result_operation_is_not_also_noted() {
14734        let source = "\
14735use clock
14736
14737export fn main() -> Result<Unit, Error> {
14738  clock.timeout(1s, 2, 3)?
14739  Ok(())
14740}
14741";
14742        let error = rejects(source);
14743        assert_eq!(error.code, ARITY);
14744        assert!(notes_of(source).is_empty());
14745    }
14746
14747    // ---- language gap: reported, never silent
14748
14749    #[test]
14750    fn a_capitalized_name_no_module_declares_is_an_error() {
14751        let error = rejects("fn run() -> Int {\n  Sensor(1)\n  1\n}\n");
14752        assert_eq!(error.code, UNRESOLVED_NAME);
14753        assert_eq!(error.message, "cannot find `Sensor` in this scope");
14754        assert_eq!(
14755            error.help.unwrap(),
14756            "declare `struct Sensor` or `enum Sensor` in this module, `use <module>.Sensor` to import it, or `use <host>` and write `<host>.Sensor`"
14757        );
14758    }
14759
14760    #[test]
14761    fn a_lowercase_name_nothing_declares_is_an_error() {
14762        let error = rejects("fn run() -> Int {\n  total\n}\n");
14763        assert_eq!(error.code, UNKNOWN_NAME);
14764        assert_eq!(error.message, "cannot find `total` in this scope");
14765        assert_eq!(
14766            error.rule.unwrap(),
14767            "A name must be a local binding, a parameter, a declaration of this module, or something `use` imports."
14768        );
14769        assert_eq!(
14770            error.help.unwrap(),
14771            "declare `let total = ...` before this expression, or `use <host>.total`"
14772        );
14773    }
14774
14775    #[test]
14776    fn an_unknown_type_name_is_an_error() {
14777        let error = rejects("fn run(value: Missing) -> Int {\n  1\n}\n");
14778        assert_eq!(error.code, UNKNOWN_TYPE);
14779        assert_eq!(error.message, "`Missing` names no type this module can see");
14780    }
14781
14782    #[test]
14783    fn a_type_used_as_a_value_is_an_error() {
14784        let error = rejects(
14785            "\
14786struct Counter { hits: Int }
14787
14788fn run() -> Int {
14789  Counter
14790  1
14791}
14792",
14793        );
14794        assert_eq!(error.code, NOT_A_VALUE);
14795        assert_eq!(error.message, "`Counter` is a struct, not a value");
14796        assert_eq!(
14797            error.help.unwrap(),
14798            "construct one, as in `Counter(field: value)`, or name a value instead"
14799        );
14800    }
14801
14802    #[test]
14803    fn a_host_module_used_as_a_value_is_an_error() {
14804        let error = rejects(
14805            "\
14806use console
14807
14808fn run() -> Int {
14809  console
14810  1
14811}
14812",
14813        );
14814        assert_eq!(error.code, NOT_A_VALUE);
14815        assert_eq!(error.message, "`console` is a host module, not a value");
14816    }
14817
14818    /// The follow-up ADR 0004 left open: a lambda's result comes from its
14819    /// body's value, so an early `return` produces one where the body's
14820    /// value is not, and nothing written says what the two must agree on.
14821    #[test]
14822    fn a_return_in_a_function_value_nothing_expects_is_an_error() {
14823        let error = rejects_body("  let double = fn(n: Int) { return n * 2 }\n  double(4)");
14824        assert_eq!(error.code, LAMBDA_RETURN);
14825        assert_eq!(
14826            error.message,
14827            "this function value uses `return`, but nothing says what it produces"
14828        );
14829        assert_eq!(
14830            error.rule.unwrap(),
14831            "A `return` is checked against a stated result type: a declaration writes one, and a function value takes one from the place that holds it."
14832        );
14833    }
14834
14835    #[test]
14836    fn a_return_in_a_function_value_the_place_types_is_checked() {
14837        accepts_body("  let double: fn(Int) -> Int = fn(n) { return n * 2 }\n  double(4)");
14838        let error =
14839            rejects_body("  let double: fn(Int) -> Int = fn(n) { return \"two\" }\n  double(4)");
14840        assert_eq!(error.code, MISMATCH);
14841        assert_eq!(error.message, "expected `Int`, found `String`");
14842    }
14843
14844    /// An argument the checker has already abstained about is not a second
14845    /// place to complain: the abstention was reported where it was made.
14846    #[test]
14847    fn a_return_inside_a_body_a_schema_declared_any_is_not_reported() {
14848        accepts(
14849            "\
14850use clock
14851
14852export fn main() -> Result<Unit, Error> {
14853  clock.every(1s) {
14854    return 1
14855  }?
14856  Ok(())
14857}
14858",
14859        );
14860    }
14861
14862    #[test]
14863    fn a_lambda_parameter_with_no_expected_type_is_refused() {
14864        let error = rejects(&in_main(
14865            "  let double = fn(n) { n * 2 }\n  println(\"{double(4)}\")?",
14866        ));
14867        assert_eq!(error.code, UNCONSTRAINED);
14868        assert_eq!(error.message, "nothing says what `n` is");
14869        assert_eq!(
14870            error.help.unwrap(),
14871            "write the type, as in `n: <type>`, or give this function value to a place that declares one"
14872        );
14873    }
14874
14875    #[test]
14876    fn an_empty_array_literal_with_no_expected_type_is_refused() {
14877        let error = rejects(&in_main(
14878            "  let empty = []\n  println(\"{empty.length()} {empty.isEmpty()}\")?",
14879        ));
14880        assert_eq!(error.code, UNCONSTRAINED);
14881        assert_eq!(error.message, "nothing says what this empty array holds");
14882        assert_eq!(
14883            error.help.unwrap(),
14884            "write the type on the place that holds it, as in `let items: Array<Int> = []`"
14885        );
14886    }
14887
14888    #[test]
14889    fn an_empty_array_literal_the_place_types_does_not_warn() {
14890        accepts_body("  let empty: Array<Int> = []\n  println(\"{empty.length()}\")?");
14891        assert!(warnings_of(&in_main(
14892            "  let empty: Array<Int> = []\n  println(\"{empty.length()}\")?"
14893        ))
14894        .is_empty());
14895    }
14896
14897    #[test]
14898    fn a_bare_none_with_no_expected_type_is_refused() {
14899        let error = rejects(&in_main(
14900            "  let missing = None\n  println(\"{missing.isNone()}\")?",
14901        ));
14902        assert_eq!(error.code, UNCONSTRAINED);
14903        assert_eq!(
14904            error.message,
14905            "nothing says what this `None` is an `Option` of"
14906        );
14907    }
14908
14909    #[test]
14910    fn a_none_the_place_types_does_not_warn() {
14911        assert!(warnings_of(&in_main(
14912            "  let missing: Option<Int> = None\n  println(\"{missing.isNone()}\")?"
14913        ))
14914        .is_empty());
14915    }
14916
14917    // ---- the empty collection literals
14918
14919    // `Vector.of()`, `Set.of()` and `Map.of()` are the empty collection
14920    // literals, and they read their element types the same way the empty
14921    // array literal above reads its own: off the place the value is given
14922    // to. What differs is only that they arrive as calls, so what states
14923    // the type is the result of a signature rather than a literal's own
14924    // shape.
14925
14926    #[test]
14927    fn an_empty_collection_literal_settles_from_a_declared_return_type() {
14928        for source in [
14929            "fn f() -> Vector<Int> {\n  Vector.of()\n}\n",
14930            "fn f() -> Set<Int> {\n  Set.of()\n}\n",
14931            "fn f() -> Map<String, Int> {\n  Map.of()\n}\n",
14932        ] {
14933            accepts(source);
14934            assert!(
14935                warnings_of(source).is_empty(),
14936                "the return type says what it holds: {source}"
14937            );
14938        }
14939    }
14940
14941    #[test]
14942    fn an_empty_collection_literal_settles_from_a_let_annotation() {
14943        accepts_body("  let empty: Vector<Int> = Vector.of()\n  println(\"{empty.length()}\")?");
14944        assert!(warnings_of(&in_main(
14945            "  let empty: Vector<Int> = Vector.of()\n  println(\"{empty.length()}\")?"
14946        ))
14947        .is_empty());
14948        // And the element type it settled on is the one the annotation
14949        // wrote, not an unknown that would have accepted anything.
14950        let error = rejects_body("  var empty: Vector<Int> = Vector.of()\n  empty.push(\"one\")");
14951        assert_eq!(error.message, "expected `Int`, found `String`");
14952    }
14953
14954    #[test]
14955    fn an_empty_collection_literal_settles_from_a_parameter_s_default() {
14956        let source = "\
14957fn count(items: Vector<Int> = Vector.of()) -> Int {
14958  items.length()
14959}
14960
14961fn run() -> Int {
14962  count()
14963}
14964";
14965        accepts(source);
14966        assert!(warnings_of(source).is_empty());
14967    }
14968
14969    #[test]
14970    fn an_empty_collection_literal_settles_from_the_argument_position() {
14971        let source = "\
14972fn count(items: Set<Int>) -> Int {
14973  items.length()
14974}
14975
14976fn run() -> Int {
14977  count(Set.of())
14978}
14979";
14980        accepts(source);
14981        assert!(warnings_of(source).is_empty());
14982    }
14983
14984    #[test]
14985    fn an_empty_collection_literal_settles_from_a_struct_field() {
14986        let source = "\
14987struct Basket {
14988  items: Vector<Int>
14989}
14990
14991fn empty() -> Basket {
14992  Basket(items: Vector.of())
14993}
14994";
14995        accepts(source);
14996        assert!(warnings_of(source).is_empty());
14997    }
14998
14999    /// A literal with items has always read its type off them, and the
15000    /// expectation is still only consulted for what they left unsettled: a
15001    /// disagreement between the two is the same mismatch on the whole
15002    /// value it always was, reported once.
15003    #[test]
15004    fn a_collection_literal_with_items_still_reads_them_and_not_the_place() {
15005        accepts_body("  let items = Vector.of(1, 2)\n  println(\"{items.length()}\")?");
15006        assert!(warnings_of(&in_main(
15007            "  let items = Vector.of(1, 2)\n  println(\"{items.length()}\")?"
15008        ))
15009        .is_empty());
15010        let error = rejects("fn f() -> Vector<String> {\n  Vector.of(1, 2)\n}\n");
15011        assert_eq!(
15012            error.message,
15013            "expected `Vector<String>`, found `Vector<Int>`"
15014        );
15015    }
15016
15017    // ---- recovery: everything has already been said
15018
15019    #[test]
15020    fn an_error_inside_an_unchecked_call_is_still_reported() {
15021        // Abstaining about the callee never means abstaining about the
15022        // arguments.
15023        let error = rejects(
15024            "\
15025use console.println
15026
15027export fn main() -> Result<Unit, Error> {
15028  println(1 + 1.0)?
15029  Ok(())
15030}
15031",
15032        );
15033        assert_eq!(error.code, OPERATOR);
15034    }
15035
15036    /// One mistake is one diagnostic, however far the unknown it produced
15037    /// travels: `rejects` insists on exactly one error, and every operation
15038    /// on the recovered value below would have had something to say.
15039    #[test]
15040    fn a_recovery_unknown_is_reported_once_however_far_it_spreads() {
15041        let error = rejects(
15042            "\
15043fn run(value: Missing) -> Int {
15044  value.field.other().length() + 1
15045}
15046",
15047        );
15048        assert_eq!(error.code, UNKNOWN_TYPE);
15049    }
15050
15051    /// An argument of a call that was just rejected is given to a place this
15052    /// pass has nothing to say about, so the gaps inside it are not reported
15053    /// as if they were the program's second mistake.
15054    #[test]
15055    fn the_arguments_of_a_rejected_call_are_not_reported_again() {
15056        let source = "\
15057fn run() -> Int {
15058  missing([], None, fn(n) { n })
15059  1
15060}
15061";
15062        let error = rejects(source);
15063        assert_eq!(error.code, UNKNOWN_NAME);
15064        assert!(warnings_of(source).is_empty());
15065    }
15066
15067    /// A body given to a place a schema declared `Any` is a body with an
15068    /// answer of its own, made at the call: the note says exactly that
15069    /// nothing about this value was proved. Its own value is not asked a
15070    /// second time to state a type nothing outside it stated either.
15071    #[test]
15072    fn a_gap_in_the_value_of_a_body_a_schema_declared_any_is_not_reported() {
15073        let source = "\
15074use clock
15075
15076export fn main() -> Result<Unit, Error> {
15077  clock.timeout(1s) {
15078    []
15079  }?
15080  Ok(())
15081}
15082";
15083        accepts(source);
15084        assert!(warnings_of(source).is_empty());
15085    }
15086
15087    // -------------------------------- unknowns that must not escape
15088    //
15089    // `Unknown::Placeholder` claims to reach no type a program observes, and
15090    // `Checker::expr` and `Checker::declare` assert it in debug builds. These
15091    // pin the two places that used to break the claim, each of which used to
15092    // check clean and then be wrong at run time.
15093
15094    /// A struct's type parameter that no field mentions used to become a
15095    /// placeholder, which compares equal to everything: `needsString` below
15096    /// wants a `Tagged<String>` and used to accept a `Tagged<_>`.
15097    #[test]
15098    fn a_struct_type_parameter_nothing_settles_is_reported() {
15099        let source = "\
15100struct Tagged<T> { n: Int }
15101
15102fn needsString(t: Tagged<String>) -> Int { t.n }
15103
15104fn run() -> Int {
15105  let p = Tagged(n: 1)
15106  needsString(p)
15107}
15108";
15109        let error = rejects(source);
15110        assert_eq!(error.code, UNCONSTRAINED);
15111        assert_eq!(error.message, "nothing says what `T` is in `Tagged<T>`");
15112    }
15113
15114    /// The place holding the value settles it, whether it is an annotation
15115    /// or the parameter of the call it is given to.
15116    #[test]
15117    fn a_struct_type_parameter_the_place_states_is_settled() {
15118        for body in [
15119            "  let p: Tagged<String> = Tagged(n: 1)\n  needsString(p)",
15120            "  needsString(Tagged(n: 1))",
15121        ] {
15122            let source = format!(
15123                "\
15124struct Tagged<T> {{ n: Int }}
15125
15126fn needsString(t: Tagged<String>) -> Int {{ t.n }}
15127
15128fn run() -> Int {{
15129{body}
15130}}
15131"
15132            );
15133            accepts(&source);
15134            assert!(warnings_of(&source).is_empty(), "{source}");
15135        }
15136    }
15137
15138    /// `Result.mapError`'s callback produces whatever its body produces, so
15139    /// the expectation states its parameters and leaves its result open. An
15140    /// early `return` in it therefore has nothing to agree with — which used
15141    /// to check clean and then fail at run time, because the placeholder
15142    /// result propagated into the `Err` binding's type.
15143    #[test]
15144    fn a_return_in_a_map_error_callback_is_reported() {
15145        let error = rejects(
15146            "\
15147fn attempt() -> Result<Int, Error> { Ok(1) }
15148
15149fn run() -> Int {
15150  let r = attempt().mapError(fn(error) { return 42 })
15151  match r {
15152    Ok(v) => v
15153    Err(e) => e.length()
15154  }
15155}
15156",
15157        );
15158        assert_eq!(error.code, LAMBDA_RETURN);
15159    }
15160
15161    /// Without the `return` the checker gets the type right, and says so
15162    /// about what is done with it.
15163    #[test]
15164    fn a_map_error_callback_that_ends_with_its_value_types_the_failure() {
15165        let error = rejects(
15166            "\
15167fn attempt() -> Result<Int, Error> { Ok(1) }
15168
15169fn run() -> Int {
15170  let r = attempt().mapError(fn(error) { 42 })
15171  match r {
15172    Ok(v) => v
15173    Err(e) => e.length()
15174  }
15175}
15176",
15177        );
15178        assert_eq!(error.code, UNKNOWN_METHOD);
15179    }
15180
15181    /// A function value given to a place that is not a function type is a
15182    /// mismatch like any other. `Checker::expr` hands the expectation to
15183    /// `Checker::lambda` rather than checking the result against it, because
15184    /// a lambda reads the expectation to type its parameters — and the check
15185    /// that skipped used to be skipped for good, so the value was silently
15186    /// accepted.
15187    #[test]
15188    fn a_function_value_given_to_a_place_that_is_not_one_is_a_mismatch() {
15189        for source in [
15190            "fn run() -> Int {\n  let x: Int = fn(n: Int) { n }\n  x\n}\n",
15191            "fn run() -> Int {\n  let x: Int = fn(n: Int) { return n }\n  x\n}\n",
15192        ] {
15193            let error = rejects(source);
15194            assert_eq!(error.code, MISMATCH, "{source}");
15195        }
15196    }
15197
15198    /// A placeholder is the one unknown that must never be observable, and
15199    /// it is now a value rather than a convention, so the difference can be
15200    /// asked about.
15201    #[test]
15202    fn only_a_placeholder_answers_that_it_must_not_escape() {
15203        assert!(Ty::placeholder().holds_placeholder());
15204        assert!(!Ty::recovery().holds_placeholder());
15205        assert!(!Ty::dynamic_boundary().holds_placeholder());
15206        assert!(!Ty::unconstrained().holds_placeholder());
15207        // And it is found however deeply it is buried, which is what makes
15208        // the assertions in `expr` and `declare` worth having.
15209        assert!(Ty::Array(Box::new(Ty::Option(Box::new(Ty::placeholder())))).holds_placeholder());
15210        assert!(Ty::func(false, vec![Ty::Int], Ty::placeholder()).holds_placeholder());
15211        // Every other kind is one the checker has already accounted for, so
15212        // a form given to a place typed by one adds nothing by complaining.
15213        assert!(Ty::recovery().is_accounted_for());
15214        assert!(Ty::dynamic_boundary().is_accounted_for());
15215        assert!(Ty::unconstrained().is_accounted_for());
15216        assert!(!Ty::placeholder().is_accounted_for());
15217    }
15218
15219    // ------------------- a gap a sibling or a branch settles is no gap
15220
15221    /// `[[], [1]]` is an `Array<Array<Int>>`: the sibling says what the
15222    /// empty literal holds, so nothing was left unproved and nothing is
15223    /// reported. The element type is the joined one, not `Array<_>`.
15224    #[test]
15225    fn an_empty_array_a_sibling_settles_is_not_reported() {
15226        let source = "\
15227fn run() -> Int {
15228  let rows = [[], [1]]
15229  rows.length()
15230}
15231";
15232        accepts(source);
15233        assert!(warnings_of(source).is_empty());
15234        // The join reached inside the shared shape, so the elements are
15235        // still checked from here on.
15236        let error = rejects(
15237            "\
15238fn run() -> Int {
15239  let rows = [[], [1]]
15240  let first: Array<String> = rows[0]
15241  1
15242}
15243",
15244        );
15245        assert_eq!(error.code, MISMATCH);
15246    }
15247
15248    #[test]
15249    fn a_none_a_sibling_settles_is_not_reported() {
15250        let source = "\
15251fn run() -> Int {
15252  let values = [None, Some(1)]
15253  values.length()
15254}
15255";
15256        accepts(source);
15257        assert!(warnings_of(source).is_empty());
15258    }
15259
15260    #[test]
15261    fn a_none_the_other_branch_settles_is_not_reported() {
15262        let source = "\
15263fn run() -> Int {
15264  let value = if true { None } else { Some(1) }
15265  value.unwrapOr(0)
15266}
15267";
15268        accepts(source);
15269        assert!(warnings_of(source).is_empty());
15270    }
15271
15272    /// Branches that genuinely disagree are still one diagnostic, not one
15273    /// per branch: the probe only supplies an expectation when the two
15274    /// already agree.
15275    #[test]
15276    fn branches_that_disagree_are_still_reported_once() {
15277        let error = rejects(
15278            "\
15279fn run() -> Int {
15280  let value = if true { 1 } else { \"two\" }
15281  1
15282}
15283",
15284        );
15285        assert_eq!(error.code, BRANCHES);
15286    }
15287
15288    // ------------------------------------------------- entry shape
15289
15290    fn config_with_entry(entry: &str) -> Config {
15291        let mut runs = BTreeMap::new();
15292        runs.insert(
15293            "run".to_string(),
15294            crate::config::RunConfig {
15295                entry: entry.to_string(),
15296                allow: Vec::new(),
15297                fuel: None,
15298                deadline: None,
15299                max_host_calls: None,
15300                max_tasks: None,
15301                trace: None,
15302                generates: None,
15303            },
15304        );
15305        Config {
15306            runs,
15307            ..Config::default()
15308        }
15309    }
15310
15311    #[track_caller]
15312    fn entry_errors(source: &str) -> Vec<Diagnostic> {
15313        diagnostics_with(source, config_with_entry("main.main"))
15314            .into_iter()
15315            .filter(|d| d.severity == Severity::Error)
15316            .collect()
15317    }
15318
15319    #[test]
15320    fn accepts_both_entry_shapes() {
15321        assert!(
15322            entry_errors("export fn main() -> Result<Unit, Error> {\n  Ok(())\n}\n").is_empty()
15323        );
15324        assert!(entry_errors(
15325            "export fn main(args: Array<String>) -> Result<Unit, Error> {\n  Ok(())\n}\n"
15326        )
15327        .is_empty());
15328        assert!(entry_errors("export fn main() {\n}\n").is_empty());
15329    }
15330
15331    #[test]
15332    fn rejects_an_entry_with_two_parameters() {
15333        let errors = entry_errors(
15334            "export fn main(args: Array<String>, extra: Int) -> Result<Unit, Error> {\n  Ok(())\n}\n",
15335        );
15336        assert_eq!(errors.len(), 1);
15337        assert_eq!(errors[0].code, ENTRY);
15338        assert_eq!(errors[0].message, "entry `main.main` declares 2 parameters");
15339        assert_eq!(
15340            errors[0].rule.as_deref().unwrap(),
15341            "An entry function takes either no parameters or one `Array<String>` of process arguments."
15342        );
15343        assert_eq!(
15344            errors[0].help.as_deref().unwrap(),
15345            "write `fn main()` or `fn main(args: Array<String>)`"
15346        );
15347    }
15348
15349    #[test]
15350    fn rejects_an_entry_whose_parameter_is_not_the_process_arguments() {
15351        let errors =
15352            entry_errors("export fn main(count: Int) -> Result<Unit, Error> {\n  Ok(())\n}\n");
15353        assert_eq!(errors.len(), 1);
15354        assert_eq!(errors[0].code, ENTRY);
15355        assert_eq!(
15356            errors[0].message,
15357            "entry `main.main` takes `Int`, but the host passes `Array<String>`"
15358        );
15359        assert_eq!(
15360            errors[0].help.as_deref().unwrap(),
15361            "write `fn main(args: Array<String>)`"
15362        );
15363    }
15364
15365    #[test]
15366    fn rejects_an_entry_whose_result_the_host_cannot_report() {
15367        let errors = entry_errors("export fn main() -> Int {\n  1\n}\n");
15368        assert_eq!(errors.len(), 1);
15369        assert_eq!(errors[0].code, ENTRY);
15370        assert_eq!(
15371            errors[0].message,
15372            "entry `main.main` returns `Int`, which the host cannot report"
15373        );
15374        assert_eq!(
15375            errors[0].rule.as_deref().unwrap(),
15376            "The host reports an entry's failure through its `Err`, so an entry returns `()` or a `Result`."
15377        );
15378    }
15379
15380    // --------------------------------------------- the whole repository
15381
15382    /// Every program in the repository, checked the way the CLI checks one.
15383    ///
15384    /// A package that exists to pin a check-time failure must fail; every
15385    /// other package must check with no errors at all. That is the
15386    /// acceptance bar for this pass, and it keeps itself honest: a new
15387    /// example or end-to-end case joins it by existing.
15388    ///
15389    /// Most such packages are named `fail_...`. Two are not, and are named
15390    /// here rather than renamed: `fn_labels` and `type_struct` were cases
15391    /// that ran, printed, and then failed at run time until ADR 0021 made
15392    /// their last line a check-time error, and their names say what they are
15393    /// about — every accepted call form, and every accepted struct form —
15394    /// rather than what the last line of each does.
15395    #[test]
15396    fn every_program_in_the_repository_checks() {
15397        let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
15398        let mut packages = vec![root.join("examples"), root.join("tests/e2e")];
15399        let mut nested: Vec<PathBuf> = std::fs::read_dir(root.join("tests/e2e"))
15400            .expect("the end-to-end suite exists")
15401            .filter_map(|entry| entry.ok().map(|entry| entry.path()))
15402            .filter(|path| path.join("cove.toml").is_file())
15403            .collect();
15404        nested.sort();
15405        packages.append(&mut nested);
15406        assert!(
15407            packages.len() > 8,
15408            "expected to find every package, found {packages:?}"
15409        );
15410
15411        let mut failures = Vec::new();
15412        for directory in &packages {
15413            let name = directory
15414                .file_name()
15415                .expect("a package directory has a name")
15416                .to_string_lossy()
15417                .into_owned();
15418            let must_fail =
15419                name.starts_with("fail_") || matches!(name.as_str(), "fn_labels" | "type_struct");
15420
15421            let mut sources = SourceMap::new();
15422            let package = match crate::package::load(directory, &mut sources) {
15423                Ok(package) => package,
15424                Err(diagnostics) => {
15425                    if !must_fail {
15426                        failures.push(format!(
15427                            "{name}: does not load: {}",
15428                            render_all(&sources, &diagnostics)
15429                        ));
15430                    }
15431                    continue;
15432                }
15433            };
15434            let program = match resolve(&package) {
15435                Ok(program) => program,
15436                Err(diagnostics) => {
15437                    if !must_fail {
15438                        failures.push(format!(
15439                            "{name}: does not resolve: {}",
15440                            render_all(&sources, &diagnostics)
15441                        ));
15442                    }
15443                    continue;
15444                }
15445            };
15446            let errors: Vec<Diagnostic> = check(&package, &program)
15447                .into_iter()
15448                .filter(|d| d.severity == Severity::Error)
15449                .collect();
15450            match (must_fail, errors.is_empty()) {
15451                (false, false) => failures.push(format!(
15452                    "{name}: does not type-check: {}",
15453                    render_all(&sources, &errors)
15454                )),
15455                (true, true) => {
15456                    failures.push(format!("{name}: was expected to fail, but it checks"))
15457                }
15458                _ => {}
15459            }
15460        }
15461        assert!(failures.is_empty(), "{}", failures.join("\n"));
15462    }
15463
15464    // ---------------------------------------------------- import environment
15465
15466    const LEVELS: &str = "\
15467/// Supported logging levels.
15468export enum LogLevel {
15469  Debug
15470  Info
15471}
15472
15473/// Validated configuration.
15474export struct Config {
15475  port: Int
15476  level: LogLevel
15477}
15478
15479/// A pair of ports.
15480export struct Pair<T> {
15481  first: T
15482  second: T
15483}
15484
15485/// The shape a handler has.
15486export type Handler = fn(Int) -> String
15487
15488impl Config {
15489  /// The port, as text.
15490  export fn describe(self) -> String {
15491    \"{self.port}\"
15492  }
15493}
15494
15495/// Loads configuration.
15496export fn load() -> Config {
15497  Config(port: 8080, level: LogLevel.Debug)
15498}
15499
15500fn secret() -> Int {
15501  1
15502}
15503";
15504
15505    #[test]
15506    fn the_checker_sees_an_imported_struct_s_fields() {
15507        accepts_modules(&[
15508            ("levels", LEVELS),
15509            (
15510                "app",
15511                "use levels.load\n\n/// Entry point.\nexport fn main() -> Int {\n  load().port\n}\n",
15512            ),
15513        ]);
15514    }
15515
15516    #[test]
15517    fn a_field_an_imported_struct_does_not_declare_is_rejected() {
15518        let error = rejects_modules(&[
15519            ("levels", LEVELS),
15520            (
15521                "app",
15522                "use levels.load\n\n/// Entry point.\nexport fn main() -> Int {\n  load().host\n}\n",
15523            ),
15524        ]);
15525        assert_eq!(error.code, UNKNOWN_FIELD);
15526        // The type is named by the module that declares it.
15527        assert!(error.message.contains("levels.Config"));
15528    }
15529
15530    #[test]
15531    fn an_imported_struct_s_field_keeps_its_type() {
15532        let error = rejects_modules(&[
15533            ("levels", LEVELS),
15534            (
15535                "app",
15536                "use levels.load\n\n/// Entry point.\nexport fn main() -> String {\n  load().port\n}\n",
15537            ),
15538        ]);
15539        assert_eq!(error.code, MISMATCH);
15540        assert!(error.message.contains("Int"));
15541    }
15542
15543    #[test]
15544    fn an_imported_struct_is_initialized_and_checked_like_a_declared_one() {
15545        accepts_modules(&[
15546            ("levels", LEVELS),
15547            (
15548                "app",
15549                "use levels.Config\nuse levels.LogLevel\n\n/// Entry point.\nexport fn main() -> Config {\n  Config(port: 1, level: LogLevel.Info)\n}\n",
15550            ),
15551        ]);
15552        let error = rejects_modules(&[
15553            ("levels", LEVELS),
15554            (
15555                "app",
15556                "use levels.Config\nuse levels.LogLevel\n\n/// Entry point.\nexport fn main() -> Config {\n  Config(port: \"1\", level: LogLevel.Info)\n}\n",
15557            ),
15558        ]);
15559        assert_eq!(error.code, MISMATCH);
15560    }
15561
15562    #[test]
15563    fn an_imported_function_s_arguments_are_checked() {
15564        let error = rejects_modules(&[
15565            (
15566                "greet",
15567                "/// Greets by name.\nexport fn greeting(name: String) -> String {\n  name\n}\n",
15568            ),
15569            (
15570                "app",
15571                "use greet.greeting\n\n/// Entry point.\nexport fn main() -> String {\n  greeting(1)\n}\n",
15572            ),
15573        ]);
15574        assert_eq!(error.code, MISMATCH);
15575    }
15576
15577    #[test]
15578    fn an_imported_method_is_reached_through_the_value_s_type() {
15579        accepts_modules(&[
15580            ("levels", LEVELS),
15581            (
15582                "app",
15583                "use levels.load\n\n/// Entry point.\nexport fn main() -> String {\n  load().describe()\n}\n",
15584            ),
15585        ]);
15586    }
15587
15588    #[test]
15589    fn an_imported_enum_s_cases_are_checked() {
15590        accepts_modules(&[
15591            ("levels", LEVELS),
15592            (
15593                "app",
15594                "use levels.LogLevel\n\n/// Entry point.\nexport fn main(level: LogLevel) -> String {\n  match level {\n    LogLevel.Debug => \"d\"\n    LogLevel.Info => \"i\"\n  }\n}\n",
15595            ),
15596        ]);
15597        let error = rejects_modules(&[
15598            ("levels", LEVELS),
15599            (
15600                "app",
15601                "use levels.LogLevel\n\n/// Entry point.\nexport fn main() -> LogLevel {\n  LogLevel.Bogus\n}\n",
15602            ),
15603        ]);
15604        assert_eq!(error.code, UNKNOWN_CASE);
15605    }
15606
15607    #[test]
15608    fn an_imported_generic_type_keeps_its_arity_and_arguments() {
15609        accepts_modules(&[
15610            ("levels", LEVELS),
15611            (
15612                "app",
15613                "use levels.Pair\n\n/// Entry point.\nexport fn main() -> Int {\n  Pair(first: 1, second: 2).first\n}\n",
15614            ),
15615        ]);
15616        let error = rejects_modules(&[
15617            ("levels", LEVELS),
15618            (
15619                "app",
15620                "use levels.Pair\n\n/// Entry point.\nexport fn main() -> Pair<Int> {\n  Pair(first: 1, second: \"2\")\n}\n",
15621            ),
15622        ]);
15623        assert_eq!(error.code, MISMATCH);
15624    }
15625
15626    /// A module that exports a nominal type and not its representation:
15627    /// `Token.of` and `text` are the only ways in from outside.
15628    const OPAQUE: &str = "\
15629/// A token, whose representation is this module's own business.
15630export opaque struct Token {
15631  raw: String
15632}
15633
15634/// Reads the representation from the module that declares it.
15635fn rawOf(token: Token) -> String {
15636  token.raw
15637}
15638
15639impl Token {
15640  /// Builds a token.
15641  export fn of(raw: String) -> Token {
15642    Token(raw: raw)
15643  }
15644
15645  /// The token as text.
15646  export fn text(self) -> String {
15647    rawOf(self)
15648  }
15649}
15650";
15651
15652    /// The same interface over a different representation. A caller written
15653    /// against [`OPAQUE`] must not be able to tell the two apart.
15654    const OPAQUE_REPRESENTATION_CHANGED: &str = "\
15655/// A token, whose representation is this module's own business.
15656export opaque struct Token {
15657  scheme: String
15658  body: String
15659}
15660
15661impl Token {
15662  /// Builds a token.
15663  export fn of(raw: String) -> Token {
15664    Token(scheme: \"bearer\", body: raw)
15665  }
15666
15667  /// The token as text.
15668  export fn text(self) -> String {
15669    self.body
15670  }
15671}
15672";
15673
15674    /// The module that declares an opaque type is unaffected by it: it
15675    /// writes the synthesized constructor and reads the fields as it would
15676    /// for any struct.
15677    #[test]
15678    fn the_declaring_module_builds_and_inspects_an_opaque_type() {
15679        accepts_modules(&[("auth", OPAQUE)]);
15680    }
15681
15682    #[test]
15683    fn another_module_may_not_build_an_opaque_type_field_by_field() {
15684        for caller in [
15685            "use auth.Token\n\n/// Entry point.\nexport fn main() -> Token {\n  Token(raw: \"t\")\n}\n",
15686            "use auth\n\n/// Entry point.\nexport fn main() -> auth.Token {\n  auth.Token(raw: \"t\")\n}\n",
15687        ] {
15688            let error = rejects_modules(&[("auth", OPAQUE), ("app", caller)]);
15689            assert_eq!(error.code, OPAQUE_CONSTRUCTION, "{caller}");
15690            // The help names what the module did export instead.
15691            assert!(error
15692                .help
15693                .as_ref()
15694                .expect("the diagnostic offers a correction")
15695                .contains("Token.of()"));
15696        }
15697    }
15698
15699    #[test]
15700    fn another_module_may_not_read_an_opaque_type_s_field() {
15701        let error = rejects_modules(&[
15702            ("auth", OPAQUE),
15703            (
15704                "app",
15705                "use auth.Token\n\n/// Entry point.\nexport fn main(token: Token) -> String {\n  token.raw\n}\n",
15706            ),
15707        ]);
15708        assert_eq!(error.code, OPAQUE_FIELD);
15709        assert!(error
15710            .help
15711            .as_ref()
15712            .expect("the diagnostic offers a correction")
15713            .contains("text()"));
15714    }
15715
15716    /// Assignment reaches the field through the same check, so a caller
15717    /// cannot write what it may not read.
15718    #[test]
15719    fn another_module_may_not_assign_an_opaque_type_s_field() {
15720        let error = rejects_modules(&[
15721            ("auth", OPAQUE),
15722            (
15723                "app",
15724                "use auth.Token\n\n/// Entry point.\nexport fn main(var token: Token) {\n  token.raw = \"other\"\n}\n",
15725            ),
15726        ]);
15727        assert_eq!(error.code, OPAQUE_FIELD);
15728        // A write is refused in the words of a write, and corrected in
15729        // them: "read the value through a method" is no answer here.
15730        assert!(
15731            error.message.contains("cannot be assigned"),
15732            "{}",
15733            error.message
15734        );
15735        let help = error.help.expect("the diagnostic offers a correction");
15736        assert!(help.starts_with("change the value"), "{help}");
15737    }
15738
15739    /// The refusal is the whole diagnosis: a caller that guesses at the
15740    /// representation is not told how close it came.
15741    #[test]
15742    fn a_refused_construction_does_not_disclose_the_fields() {
15743        for call in ["Token(bogus: 1)", "Token()", "Token(scheme: \"bearer\")"] {
15744            let caller = format!(
15745                "use auth.Token\n\n/// Entry point.\nexport fn main() -> Token {{\n  {call}\n}}\n"
15746            );
15747            // `rejects_modules` insists on exactly one error, which is the
15748            // point: no `unknown_label` naming the fields, and no
15749            // `missing_argument` rendering the declaring module's source.
15750            let error = rejects_modules(&[
15751                ("auth", OPAQUE_REPRESENTATION_CHANGED),
15752                ("app", caller.as_str()),
15753            ]);
15754            assert_eq!(error.code, OPAQUE_CONSTRUCTION, "{call}");
15755            for hidden in ["scheme", "body"] {
15756                let rendered = format!(
15757                    "{}{}",
15758                    error.message,
15759                    error.help.clone().unwrap_or_default()
15760                );
15761                assert!(!rendered.contains(hidden), "{call} disclosed `{hidden}`");
15762            }
15763        }
15764    }
15765
15766    /// The help names what the declaring module published, not what the
15767    /// module being checked is in the middle of writing: a caller may
15768    /// conform a foreign opaque type to a trait of its own, and being told
15769    /// to call the method whose body is the error is no correction.
15770    #[test]
15771    fn the_help_names_only_the_declaring_module_s_methods() {
15772        let error = rejects_modules(&[
15773            ("auth", OPAQUE),
15774            (
15775                "app",
15776                "use auth.Token\n\n/// A thing with a text form.\ntrait Show {\n  /// Shows it.\n  fn show(self) -> String\n}\n\nimpl Show for Token {\n  fn show(self) -> String { self.raw }\n}\n",
15777            ),
15778        ]);
15779        assert_eq!(error.code, OPAQUE_FIELD);
15780        let help = error.help.expect("the diagnostic offers a correction");
15781        assert!(help.contains("text()"), "{help}");
15782        assert!(!help.contains("show()"), "{help}");
15783    }
15784
15785    /// The type's name and its exported operations are what an opaque
15786    /// export is for, so all of them still work across the boundary.
15787    #[test]
15788    fn another_module_uses_an_opaque_type_through_its_exported_operations() {
15789        accepts_modules(&[
15790            ("auth", OPAQUE),
15791            (
15792                "app",
15793                "use auth.Token\n\n/// Entry point.\nexport fn main() -> String {\n  Token.of(\"t\").text()\n}\n",
15794            ),
15795        ]);
15796    }
15797
15798    /// The point of the modifier: the representation is free to change
15799    /// underneath a caller that only names the type and its operations.
15800    #[test]
15801    fn an_opaque_type_s_representation_may_change_without_touching_its_callers() {
15802        let caller = "use auth.Token\n\n/// Entry point.\nexport fn main() -> String {\n  Token.of(\"t\").text()\n}\n";
15803        accepts_modules(&[("auth", OPAQUE), ("app", caller)]);
15804        accepts_modules(&[("auth", OPAQUE_REPRESENTATION_CHANGED), ("app", caller)]);
15805    }
15806
15807    /// A plain `export struct` is unchanged: its representation is public,
15808    /// which is what every module written before `opaque` depends on.
15809    #[test]
15810    fn a_plain_exported_struct_still_exposes_its_representation() {
15811        accepts_modules(&[
15812            ("levels", LEVELS),
15813            (
15814                "app",
15815                "use levels.Config\nuse levels.LogLevel\n\n/// Entry point.\nexport fn main() -> Int {\n  Config(port: 1, level: LogLevel.Info).port\n}\n",
15816            ),
15817        ]);
15818    }
15819
15820    #[test]
15821    fn an_imported_type_alias_expands() {
15822        accepts_modules(&[
15823            ("levels", LEVELS),
15824            (
15825                "app",
15826                "use levels.Handler\n\n/// Entry point.\nexport fn main(handler: Handler) -> String {\n  handler(1)\n}\n",
15827            ),
15828        ]);
15829    }
15830
15831    /// A module imported whole makes its exports writable qualified, with
15832    /// the same checking a `use` of each would give.
15833    #[test]
15834    fn a_module_imported_whole_is_named_qualified() {
15835        accepts_modules(&[
15836            ("levels", LEVELS),
15837            (
15838                "app",
15839                "use levels\n\n/// Entry point.\nexport fn main() -> levels.Config {\n  levels.load()\n}\n",
15840            ),
15841        ]);
15842        let error = rejects_modules(&[
15843            ("levels", LEVELS),
15844            (
15845                "app",
15846                "use levels\n\n/// Entry point.\nexport fn main() -> Int {\n  levels.load()\n}\n",
15847            ),
15848        ]);
15849        assert_eq!(error.code, MISMATCH);
15850    }
15851
15852    #[test]
15853    fn a_qualified_name_a_module_does_not_export_is_rejected() {
15854        let error = rejects_modules(&[
15855            ("levels", LEVELS),
15856            (
15857                "app",
15858                "use levels\n\n/// Entry point.\nexport fn main() -> Int {\n  levels.secret()\n}\n",
15859            ),
15860        ]);
15861        assert_eq!(error.code, UNKNOWN_MEMBER);
15862        assert!(error.message.contains("not exported"));
15863    }
15864
15865    #[test]
15866    fn a_qualified_name_a_module_does_not_declare_is_rejected() {
15867        let error = rejects_modules(&[
15868            ("levels", LEVELS),
15869            (
15870                "app",
15871                "use levels\n\n/// Entry point.\nexport fn main() -> Int {\n  levels.missing()\n}\n",
15872            ),
15873        ]);
15874        assert_eq!(error.code, UNKNOWN_MEMBER);
15875        assert!(error.message.contains("declares no `missing`"));
15876    }
15877
15878    /// Two modules may each declare a `Config`, and the checker must not
15879    /// confuse them: a declaration is known by the module that declares it.
15880    #[test]
15881    fn two_modules_declaring_one_name_are_different_types() {
15882        let error = rejects_modules(&[
15883            ("levels", LEVELS),
15884            (
15885                "app",
15886                "use levels.load\n\n/// This module's own `Config`.\nexport struct Config {\n  port: Int\n}\n\n\
15887                 /// Entry point.\nexport fn main() -> Config {\n  load()\n}\n",
15888            ),
15889        ]);
15890        assert_eq!(error.code, MISMATCH);
15891        assert!(error.message.contains("levels.Config"));
15892    }
15893
15894    /// A type reached only as an imported function's result still has its
15895    /// fields, even though this module could not write its name.
15896    #[test]
15897    fn a_type_reached_without_importing_it_still_has_its_fields() {
15898        accepts_modules(&[
15899            ("levels", LEVELS),
15900            (
15901                "app",
15902                "use levels.load\n\n/// Entry point.\nexport fn main() -> String {\n  load().describe()\n}\n",
15903            ),
15904        ]);
15905        let error = rejects_modules(&[
15906            ("levels", LEVELS),
15907            (
15908                "app",
15909                "use levels.load\n\n/// Entry point.\nexport fn main() -> String {\n  load().level\n}\n",
15910            ),
15911        ]);
15912        assert_eq!(error.code, MISMATCH);
15913        assert!(error.message.contains("levels.LogLevel"));
15914    }
15915
15916    /// The transitive case: a module that imports a module that imports a
15917    /// third still sees one identity for the third's type.
15918    #[test]
15919    fn a_type_keeps_one_identity_through_two_imports() {
15920        accepts_modules(&[
15921            ("levels", LEVELS),
15922            (
15923                "middle",
15924                "use levels.load\nuse levels.Config\n\n/// Reloads.\nexport fn reload() -> Config {\n  load()\n}\n",
15925            ),
15926            (
15927                "app",
15928                "use middle.reload\nuse levels.Config\n\n/// Entry point.\nexport fn main() -> Config {\n  reload()\n}\n",
15929            ),
15930        ]);
15931    }
15932
15933    /// A diamond needs no special treatment: importing a module runs none
15934    /// of its code, and both sides of the diamond name the same declaration.
15935    #[test]
15936    fn a_type_keeps_one_identity_through_a_diamond() {
15937        accepts_modules(&[
15938            ("levels", LEVELS),
15939            (
15940                "left",
15941                "use levels.load\nuse levels.Config\n\n/// Loads.\nexport fn fromLeft() -> Config {\n  load()\n}\n",
15942            ),
15943            (
15944                "right",
15945                "use levels.load\nuse levels.Config\n\n/// Loads.\nexport fn fromRight() -> Config {\n  load()\n}\n",
15946            ),
15947            (
15948                "app",
15949                "use left.fromLeft\nuse right.fromRight\n\n/// Entry point.\nexport fn main() -> Int {\n  fromLeft().port + fromRight().port\n}\n",
15950            ),
15951        ]);
15952    }
15953
15954    // ------------------------------------------ conformances across modules
15955
15956    const DISPLAY: &str = "\
15957/// Renders itself.
15958export trait Display {
15959  /// The full form.
15960  fn describe(self) -> String
15961
15962  /// A short form, defaulting to the full one.
15963  fn label(self) -> String { self.describe() }
15964}
15965
15966/// Renders anything that conforms.
15967export fn render<T: Display>(value: T) -> String {
15968  value.label()
15969}
15970";
15971
15972    const BOOKING: &str = "\
15973/// A booking.
15974export struct Booking {
15975  id: Int
15976}
15977";
15978
15979    /// A conformance declared where the type is, for an imported trait: the
15980    /// bound it satisfies is checked in a third module that imports both.
15981    #[test]
15982    fn a_bound_is_satisfied_by_a_conformance_to_an_imported_trait() {
15983        let booking = format!(
15984            "use display.Display\n\n{BOOKING}\nimpl Display for Booking {{\n  \
15985             /// The full form.\n  fn describe(self) -> String {{\n    \"b\"\n  }}\n}}\n"
15986        );
15987        accepts_modules(&[
15988            ("display", DISPLAY),
15989            ("booking", &booking),
15990            (
15991                "app",
15992                "use display.render\nuse booking.Booking\n\n\
15993                 /// Entry point.\nexport fn main() -> String {\n  render(Booking(id: 1))\n}\n",
15994            ),
15995        ]);
15996    }
15997
15998    /// And the reverse: the conformance is declared where the trait is, for
15999    /// an imported type.
16000    #[test]
16001    fn a_bound_is_satisfied_by_a_conformance_to_an_imported_type() {
16002        let display = format!(
16003            "use booking.Booking\n\n{DISPLAY}\nimpl Display for Booking {{\n  \
16004             /// The full form.\n  fn describe(self) -> String {{\n    \"b\"\n  }}\n}}\n"
16005        );
16006        accepts_modules(&[
16007            ("booking", BOOKING),
16008            ("display", &display),
16009            (
16010                "app",
16011                "use display.render\nuse booking.Booking\n\n\
16012                 /// Entry point.\nexport fn main() -> String {\n  render(Booking(id: 1))\n}\n",
16013            ),
16014        ]);
16015    }
16016
16017    /// A trait method supplied by a conformance in another module is a
16018    /// method of the type, reachable wherever that conformance is visible.
16019    #[test]
16020    fn a_conformance_method_declared_elsewhere_is_a_method_of_the_type() {
16021        let display = format!(
16022            "use booking.Booking\n\n{DISPLAY}\nimpl Display for Booking {{\n  \
16023             /// The full form.\n  fn describe(self) -> String {{\n    \"b\"\n  }}\n}}\n"
16024        );
16025        accepts_modules(&[
16026            ("booking", BOOKING),
16027            ("display", &display),
16028            (
16029                "app",
16030                "use display.Display\nuse booking.Booking\n\n\
16031                 /// Entry point.\nexport fn main(value: Booking) -> String {\n  value.describe()\n}\n",
16032            ),
16033        ]);
16034    }
16035
16036    #[test]
16037    fn a_type_that_conforms_nowhere_does_not_satisfy_an_imported_bound() {
16038        let error = rejects_modules(&[
16039            ("display", DISPLAY),
16040            ("booking", BOOKING),
16041            (
16042                "app",
16043                "use display.render\nuse booking.Booking\n\n\
16044                 /// Entry point.\nexport fn main() -> String {\n  render(Booking(id: 1))\n}\n",
16045            ),
16046        ]);
16047        assert_eq!(error.code, UNSATISFIED_BOUND);
16048        assert!(error.message.contains("booking.Booking"));
16049        assert!(error.message.contains("display.Display"));
16050    }
16051
16052    /// `dyn` names an imported trait through a `use` of the trait itself,
16053    /// and the conversion consults the same conformances a bound does.
16054    #[test]
16055    fn dyn_names_an_imported_trait() {
16056        let booking = format!(
16057            "use display.Display\n\n{BOOKING}\nimpl Display for Booking {{\n  \
16058             /// The full form.\n  fn describe(self) -> String {{\n    \"b\"\n  }}\n}}\n"
16059        );
16060        accepts_modules(&[
16061            ("display", DISPLAY),
16062            ("booking", &booking),
16063            (
16064                "app",
16065                "use display.Display\nuse booking.Booking\n\n\
16066                 /// Entry point.\nexport fn main() -> String {\n  \
16067                 let shown: dyn Display = Booking(id: 1)\n  shown.label()\n}\n",
16068            ),
16069        ]);
16070    }
16071
16072    #[test]
16073    fn a_trait_neither_declared_nor_imported_is_not_a_trait() {
16074        let error = rejects_modules(&[
16075            ("display", DISPLAY),
16076            (
16077                "app",
16078                "/// Entry point.\nexport fn main() -> Int {\n  1\n}\n\n\
16079                 /// Renders.\nfn show<T: Display>(value: T) -> String {\n  \"x\"\n}\n",
16080            ),
16081        ]);
16082        assert_eq!(error.code, UNKNOWN_TRAIT);
16083    }
16084
16085    /// Two modules may each declare a `Display`, and a `dyn` of one is not a
16086    /// `dyn` of the other.
16087    #[test]
16088    fn two_modules_declaring_one_trait_name_are_different_traits() {
16089        let booking = format!(
16090            "use display.Display\n\n{BOOKING}\nimpl Display for Booking {{\n  \
16091             /// The full form.\n  fn describe(self) -> String {{\n    \"b\"\n  }}\n}}\n"
16092        );
16093        let error = rejects_modules(&[
16094            ("display", DISPLAY),
16095            ("booking", &booking),
16096            (
16097                "app",
16098                "use booking.Booking\n\n\
16099                 /// This module's own `Display`, unrelated to `display`'s.\n\
16100                 trait Display {\n  /// The full form.\n  fn describe(self) -> String\n}\n\n\
16101                 /// Entry point.\nexport fn main() -> Int {\n  \
16102                 let shown: dyn Display = Booking(id: 1)\n  1\n}\n",
16103            ),
16104        ]);
16105        assert_eq!(error.code, MISMATCH);
16106        assert!(error.message.contains("dyn Display"));
16107    }
16108
16109    /// A conformance's signature is checked in the module that declares the
16110    /// conformance, against the trait it imported.
16111    #[test]
16112    fn a_conformance_to_an_imported_trait_must_match_its_signature() {
16113        let booking = format!(
16114            "use display.Display\n\n{BOOKING}\nimpl Display for Booking {{\n  \
16115             /// The full form.\n  fn describe(self) -> Int {{\n    1\n  }}\n}}\n"
16116        );
16117        let error = rejects_modules(&[("display", DISPLAY), ("booking", &booking)]);
16118        assert_eq!(error.code, CONFORMANCE_SIGNATURE);
16119    }
16120
16121    #[test]
16122    fn a_name_neither_declared_nor_imported_is_still_unresolved() {
16123        let error = rejects_modules(&[
16124            (
16125                "greet",
16126                "/// Greets.\nexport fn greeting() -> String {\n  \"hi\"\n}\n",
16127            ),
16128            (
16129                "app",
16130                "/// Entry point.\nexport fn main() -> String {\n  greeting()\n}\n",
16131            ),
16132        ]);
16133        assert_eq!(error.code, UNKNOWN_NAME);
16134    }
16135
16136    fn render_all(sources: &SourceMap, diagnostics: &[Diagnostic]) -> String {
16137        diagnostics
16138            .iter()
16139            .map(|d| cove_diag::render(sources, d))
16140            .collect::<Vec<_>>()
16141            .join("")
16142    }
16143}