beck_core/check/
traits.rs

1//! `trait` and `impl`, checked.
2//!
3//! `docs/03-type-and-effect-system.md` §3.1 asks for "traits/typeclasses with coherence (orphan
4//! rule)", and `docs/11-language-tour.md` §11.3 writes what they look like. Until now the parser
5//! read both forms and the checker warned that it did nothing with them — the oldest unpaid debt in
6//! the project, named by four reports and by the one refusal file left in `sicp/refusals/`.
7//!
8//! # The shape of it
9//!
10//! A **trait** is a set of signatures over an abstract `Self`:
11//!
12//! ```text
13//! trait Show:
14//!     def show(self) -> Str
15//!     def tagged(self, prefix: Str) -> Str uses log
16//! ```
17//!
18//! An **impl** supplies the bodies, and writes no types at all:
19//!
20//! ```text
21//! impl[T] Show for Tree[T]:
22//!     def show(self):
23//!         return "a tree"
24//! ```
25//!
26//! The impl's method writes *names*; the trait already wrote the types, the return type and the
27//! effect row, and repeating them would be a second place for them to disagree. So an annotation in
28//! an impl is refused rather than checked (`B0362`), and the note says where the signature lives.
29//!
30//! # How it is compiled
31//!
32//! An impl is **desugared into ordinary top-level definitions** before anything is checked. Each
33//! method becomes a `def` whose name is [`mangle`]d — `Show::show@Tree`, which no source identifier
34//! can collide with — whose parameter types come from the trait with `Self` replaced by the impl's
35//! target, and whose type parameters are the impl's. From there it is a definition like any other:
36//! `collect_signatures` gives it a scheme, `check_items` checks its body, placement places it, the
37//! effect row is inferred and bounded by the trait's declared one, and the evaluator calls it
38//! through `CoreKind::Global`.
39//!
40//! That is why this pass adds **no IR node and no evaluator case**. Dispatch is static: a call
41//! `p.show()` resolves at check time from the type of `p` to exactly one mangled global.
42//!
43//! # Bounds, and the dictionary that is not a data structure
44//!
45//! `def largest[T: Ord](xs: list[T]) -> Option[T]` carries a **bound**, and it is lowered by the
46//! same trick: the definition gains one ordinary parameter per method of each bound, named exactly
47//! as an impl method is named but with the *type parameter* as the target — `Ord::before@T`. Inside
48//! the body, `a.before(b)` resolves `Ord::before@T` and finds a **local**; at a call site with
49//! `T := Int` the caller passes `Ord::before@Int`, which is a **global**. One name scheme, two kinds
50//! of binding, and one resolution rule that reads both:
51//!
52//! ```text
53//! def largest[T: Ord](xs: list[T]) -> Option[T]
54//!   ⇒ def largest[T](xs: list[T], Ord::before@T: (T, T) -> Bool) -> Option[T]
55//!
56//! largest([3, 1])   ⇒   largest([3, 1], Ord::before@Int)
57//! ```
58//!
59//! A dictionary is therefore not a record and not a runtime value of its own — it is a function
60//! argument — so bounds add no IR node either. A bounded definition calling another passes its own
61//! parameter straight through, which is what makes the recursion terminate.
62//!
63//! # What it is not
64//!
65//! **A trait crosses a module boundary as a name, not as a scope.** A `.becki` publishes the
66//! module's traits, its impls, and the *bound* on a bounded definition — what it drops is the
67//! mangled method definitions and the lowered dictionary parameters, whose names no source could
68//! write; [`Checker::import_bounded`] rebuilds those from the bound. So an imported impl is usable
69//! exactly where the trait's own module is imported **directly**, which is the rule a `def`
70//! already follows, and an impl for a trait the importer never names is dropped with `B0388`
71//! rather than in silence.
72//!
73//! **A bounded definition cannot be passed as a value.** Its dictionaries are supplied at the call
74//! site, and a reference that is never called has no call site to supply them.
75
76use std::collections::BTreeSet;
77use std::sync::Arc;
78
79use beck_diag::{Diagnostic, Span};
80use beck_syntax::{sym, Node, ScopeSet, Symbol};
81
82use super::{BindKind, Binding, Checker};
83use crate::core::{Const, Core, CoreKind};
84use crate::ty::{ImplSig, MethodSig, Row, Scheme, TraitSig, Ty, TyDecl};
85
86/// The separator that makes a desugared impl method unnameable from source.
87///
88/// `::` and `@` are not identifier characters in either surface, so `Show::show@Tree` cannot
89/// collide with anything a program declares, and a stray one in a diagnostic is recognisable as
90/// compiler-generated rather than as something the author wrote.
91pub(crate) fn mangle(trait_name: &str, method: &str, target: &str) -> Arc<str> {
92    Arc::from(format!("{trait_name}::{method}@{target}"))
93}
94
95/// Is this the name of a desugared impl method rather than something a program wrote?
96pub fn is_impl_method(name: &str) -> bool {
97    name.contains("::") && name.contains('@')
98}
99
100/// A `trait` declaration: the signatures it requires, as written.
101///
102/// The signature is kept as **syntax** rather than as a `Ty` because that is what an impl needs:
103/// desugaring splices the trait's `(params …)`, `(returns …)` and `(uses …)` into the impl's `def`
104/// with `Self` rewritten, and a `Ty` would have to be rendered back to a node to do it.
105#[derive(Clone, Debug)]
106pub(super) struct TraitDecl {
107    pub methods: Vec<TraitMethod>,
108    /// The same declaration as types — what a `.becki` publishes and what `--wire-compat`
109    /// compares. Built once, here, so that a locally-declared trait and an imported one are the
110    /// same thing to everything downstream.
111    pub sig: TraitSig,
112    pub span: Span,
113}
114
115#[derive(Clone, Debug)]
116pub(super) struct TraitMethod {
117    pub name: Arc<str>,
118    pub params: Node,
119    pub returns: Node,
120    pub uses: Node,
121    pub span: Span,
122}
123
124/// One `impl Trait for Type`, keyed elsewhere by the pair.
125#[derive(Clone, Debug)]
126pub(super) struct ImplDecl {
127    /// The head constructor of the target: `Tree` for `Tree[T]`. Dispatch keys on this, so
128    /// `Tree[Int]` and `Tree[Str]` share one impl and coherence has one entry to check.
129    pub target: Arc<str>,
130    /// The published form — the header an importing module reads.
131    pub sig: ImplSig,
132    pub span: Span,
133}
134
135/// `Self`, the name a trait's signatures are written in terms of.
136const SELF: &str = "Self";
137
138/// The head of a written function type, as the parser produces it.
139const FN_TYPE: &str = "fn-type";
140
141/// One dictionary parameter of a bounded definition, in the order it was appended.
142#[derive(Clone, Debug)]
143pub(super) struct DictParam {
144    /// The type parameter the bound is on: `T` in `[T: Ord]`.
145    pub param: Arc<str>,
146    pub trait_name: Arc<str>,
147    pub method: Arc<str>,
148}
149
150/// The name of one entry in a `(typarams …)` list, bounded or not.
151pub(super) fn typaram_name(p: &Node) -> Option<Arc<str>> {
152    if p.is_form(sym::ANNOT) {
153        return p
154            .args
155            .first()
156            .and_then(|n| n.as_var())
157            .map(|s| s.name.clone());
158    }
159    p.as_var().map(|s| s.name.clone())
160}
161
162/// Every **bounded** parameter of a `(typarams …)` node, with its traits, in written order.
163pub(super) fn bounds_of(typarams: &Node) -> Vec<(Arc<str>, Vec<Arc<str>>)> {
164    if !typarams.is_form(sym::TYPARAMS) {
165        return Vec::new();
166    }
167    typarams
168        .args
169        .iter()
170        .filter(|p| p.is_form(sym::ANNOT) && p.args.len() >= 2)
171        .filter_map(|p| {
172            let name = typaram_name(p)?;
173            let traits: Vec<Arc<str>> = p.args[1..]
174                .iter()
175                .filter_map(|b| b.as_var().map(|s| s.name.clone()))
176                .collect();
177            Some((name, traits))
178        })
179        .collect()
180}
181
182impl Checker<'_> {
183    /// Collect every `trait` declaration, before any impl is expanded and before any signature is
184    /// read.
185    pub(super) fn collect_traits(&mut self, items: &[&Node]) {
186        for item in items {
187            let (item, _) = self.undecorate(item);
188            if !item.is_form(sym::TRAIT) || item.args.is_empty() {
189                continue;
190            }
191            let Some(name) = item.args[0].as_var().map(|s| s.name.clone()) else {
192                continue;
193            };
194            if self.types.contains_key(&name) {
195                self.error(
196                    "B0380",
197                    format!("`{name}` is already a type, so it cannot also be a trait"),
198                    item.span(),
199                );
200                continue;
201            }
202            let mut methods: Vec<TraitMethod> = Vec::new();
203            for m in &item.args[1..] {
204                let Some(method) = self.trait_method(m, &name) else {
205                    continue;
206                };
207                if methods.iter().any(|x| x.name == method.name) {
208                    self.error(
209                        "B0381",
210                        format!("`{name}` declares `{}` twice", method.name),
211                        method.span,
212                    );
213                    continue;
214                }
215                methods.push(method);
216            }
217            if methods.is_empty() {
218                self.diags.push(
219                    Diagnostic::error(
220                        "B0381",
221                        format!("`{name}` declares no methods"),
222                        item.span(),
223                    )
224                    .with_note(
225                        "a trait with nothing in it can be implemented and never used, which is a \
226                         marker rather than an abstraction; Beck has no marker traits because \
227                         placement and effects are already properties of the signature",
228                    ),
229                );
230                continue;
231            }
232            let sig = self.trait_sig(&name, &methods);
233            let decl = TraitDecl {
234                methods,
235                sig,
236                span: item.span(),
237            };
238            for m in &decl.methods {
239                // One method name to one trait. Two traits declaring `show` would make `x.show()`
240                // ambiguous at every call site, and resolving it by which impls exist would make
241                // adding an impl change what an unrelated call means.
242                if let Some(other) = self.trait_methods.get(&m.name) {
243                    self.error(
244                        "B0381",
245                        format!("`{}` is already a method of trait `{other}`", m.name),
246                        m.span,
247                    );
248                    continue;
249                }
250                if self.schemes.contains_key(&m.name) || self.prims.contains_key(&m.name) {
251                    self.error(
252                        "B0381",
253                        format!(
254                            "`{}` is already a definition, so `{name}` cannot declare it",
255                            m.name
256                        ),
257                        m.span,
258                    );
259                    continue;
260                }
261                self.trait_methods.insert(m.name.clone(), name.clone());
262                self.globals.push(Binding {
263                    name: m.name.clone(),
264                    scopes: ScopeSet::empty(),
265                    kind: BindKind::TraitMethod(m.name.clone()),
266                });
267            }
268            self.own_traits.push(name.clone());
269            if self.traits.insert(name.clone(), decl).is_some() {
270                self.error(
271                    "B0380",
272                    format!("trait `{name}` is declared twice"),
273                    item.span(),
274                );
275            }
276        }
277    }
278
279    /// A trait's methods as *types*, for publication and comparison.
280    ///
281    /// `Self` is resolved to `Ty::con("Self")` by registering it as a type for exactly the length of
282    /// this call. It is not a name any other pass looks up, and leaving it registered would let a
283    /// declaration elsewhere mention a type that does not exist.
284    fn trait_sig(&mut self, name: &Arc<str>, methods: &[TraitMethod]) -> TraitSig {
285        let placeholder = TyDecl::Newtype {
286            name: Arc::from(SELF),
287            params: Vec::new(),
288            inner: Ty::unit(),
289        };
290        self.types.insert(Arc::from(SELF), placeholder);
291        let out = TraitSig {
292            name: name.clone(),
293            methods: methods
294                .iter()
295                .map(|m| MethodSig {
296                    name: m.name.clone(),
297                    params: m
298                        .params
299                        .args
300                        .iter()
301                        .map(|p| {
302                            (
303                                p.args[0]
304                                    .as_var()
305                                    .map(|s| s.name.clone())
306                                    .unwrap_or_else(|| Arc::from("?")),
307                                self.ty_from_node(&p.args[1]),
308                            )
309                        })
310                        .collect(),
311                    ret: self.ty_from_node(&m.returns.args[0]),
312                    effects: self.declared_row(Some(&m.uses)).atoms.into_iter().collect(),
313                })
314                .collect(),
315        };
316        self.types.remove(SELF);
317        out
318    }
319
320    /// One signature inside a `trait` body.
321    fn trait_method(&mut self, m: &Node, trait_name: &str) -> Option<TraitMethod> {
322        let (m, _) = self.undecorate(m);
323        if !m.is_form(sym::DEF) || m.args.len() < 5 {
324            self.error(
325                "B0381",
326                format!("`{trait_name}` may only contain `def` signatures"),
327                m.span(),
328            );
329            return None;
330        }
331        let name = m.args[0].as_var()?.name.clone();
332        if !m.args[1].args.is_empty() {
333            self.error(
334                "B0381",
335                format!("`{name}` may not take type parameters of its own"),
336                m.args[1].span(),
337            );
338            return None;
339        }
340        // A body in a trait would be a *default* method, which is a separate feature: it needs the
341        // body checked once against an abstract `Self` rather than once per impl.
342        if m.args.len() > 5 {
343            self.diags.push(
344                Diagnostic::error(
345                    "B0381",
346                    format!("`{name}` has a body, and a trait declares signatures"),
347                    m.span(),
348                )
349                .with_note(
350                    "a default method would have to be checked against an abstract `Self` rather \
351                     than against each implementing type, which is not built",
352                ),
353            );
354            return None;
355        }
356        let params = self.trait_params(&m.args[2], &name)?;
357        if m.args[3].args.is_empty() {
358            self.error(
359                "B0381",
360                format!("`{name}` needs a return type"),
361                m.args[0].span(),
362            );
363            return None;
364        }
365        Some(TraitMethod {
366            name,
367            params,
368            returns: m.args[3].clone(),
369            uses: m.args[4].clone(),
370            span: m.span(),
371        })
372    }
373
374    /// The parameter list of a trait method, with a bare `self` given its implicit type.
375    ///
376    /// At least one parameter has to mention `Self`, because dispatch is by the receiver: a method
377    /// nothing dispatches on could never be resolved from a call.
378    fn trait_params(&mut self, params: &Node, method: &str) -> Option<Node> {
379        let mut out = Vec::new();
380        let mut mentions_self = false;
381        for p in &params.args {
382            let (name, ty) = if p.is_form(sym::ANNOT) && p.args.len() == 2 {
383                (p.args[0].clone(), p.args[1].clone())
384            } else if p.as_var().map(|s| s.name.as_ref() == "self") == Some(true) {
385                // `def show(self) -> Str` — `self` alone means `self: Self`, which is the notation
386                // `docs/11` §11.3 writes.
387                (p.clone(), Node::sym(SELF, p.span()))
388            } else {
389                self.error(
390                    "B0381",
391                    format!("`{method}`'s parameters need types, and only `self` is implicit"),
392                    p.span(),
393                );
394                return None;
395            };
396            if mentions(&ty, SELF) {
397                mentions_self = true;
398            }
399            let span = name.span().to(ty.span());
400            out.push(Node::form(sym::ANNOT, vec![name, ty], span));
401        }
402        if !mentions_self {
403            self.diags.push(
404                Diagnostic::error(
405                    "B0381",
406                    format!("`{method}` never mentions `Self`, so nothing dispatches on it"),
407                    params.span(),
408                )
409                .with_note(
410                    "a trait method is resolved from the type of an argument; one that mentions \
411                     `Self` only in its return type would need the call site to say which impl it \
412                     meant, and there is no notation for that",
413                ),
414            );
415            return None;
416        }
417        Some(Node::form(sym::PARAMS, out, params.span()))
418    }
419
420    /// Turn every `impl` into ordinary `def` items, and register what each one implements.
421    ///
422    /// Returns the synthesised nodes; the caller keeps them alive and appends them to the item
423    /// list, so that every later pass sees definitions rather than a form it has to know about.
424    pub(super) fn expand_impls(&mut self, items: &[&Node]) -> Vec<Node> {
425        let mut out = Vec::new();
426        for item in items {
427            let (item, _) = self.undecorate(item);
428            if !item.is_form(sym::IMPL) || item.args.len() < 3 {
429                continue;
430            }
431            self.expand_impl(item, &mut out);
432        }
433        out
434    }
435
436    fn expand_impl(&mut self, item: &Node, out: &mut Vec<Node>) {
437        let span = item.span();
438        let Some(trait_name) = item.args[0].as_var().map(|s| s.name.clone()) else {
439            return;
440        };
441        let Some(decl) = self.traits.get(&trait_name).cloned() else {
442            self.error("B0383", format!("cannot find trait `{trait_name}`"), span);
443            return;
444        };
445        let target_node = &item.args[2];
446        let Some(target) = target_node.head_name().map(Arc::<str>::from) else {
447            self.error("B0383", "expected a type to implement the trait for", span);
448            return;
449        };
450
451        // The impl's own type parameters, bound rigidly for the duration: `impl[T] Show for
452        // Tree[T]` is one impl covering every `T`, and each method it produces is a generic `def`
453        // exactly as if it had been written by hand.
454        let typarams = item.args[1].clone();
455        let param_names = Self::typaram_names(item);
456
457        if !self.types.contains_key(&target)
458            && crate::prelude::builtin_arity(&target).is_none()
459            && !param_names.contains(&target)
460        {
461            self.error(
462                "B0383",
463                format!("cannot find type `{target}`"),
464                target_node.span(),
465            );
466            return;
467        }
468        if param_names.contains(&target) {
469            self.diags.push(
470                Diagnostic::error(
471                    "B0384",
472                    format!("`{target}` is a type parameter, so this impl covers every type"),
473                    target_node.span(),
474                )
475                .with_note(
476                    "a blanket impl makes coherence a search rather than a lookup, and Beck's \
477                     orphan rule is written for one impl per trait per type constructor",
478                ),
479            );
480            return;
481        }
482        // Coherence, half one: one impl per trait per type constructor. Keyed on the *head*, so
483        // `Tree[Int]` and `Tree[Str]` cannot be given different behaviour and a call never has to
484        // pick between two.
485        let key = (trait_name.clone(), target.clone());
486        if let Some(prev) = self.impls.get(&key) {
487            self.diags.push(
488                Diagnostic::error(
489                    "B0384",
490                    format!("`{trait_name}` is already implemented for `{target}`"),
491                    span,
492                )
493                .with_label(prev.span, "the first implementation")
494                .with_note(
495                    "coherence: one impl per trait per type, so that what a call means never \
496                     depends on which impls happen to be in scope",
497                ),
498            );
499            return;
500        }
501        // Coherence, half two: the orphan rule. Implementing somebody else's trait for somebody
502        // else's type is what makes two libraries able to conflict.
503        // *Declared here*, not merely in scope. A trait that arrived from the prelude or from an
504        // import is somebody else's, and implementing somebody else's trait for somebody else's
505        // type is exactly what the rule refuses.
506        let owns_trait = self.own_traits.contains(&trait_name);
507        let owns_type = self.own_types.contains(&target);
508        if !owns_trait && !owns_type {
509            self.diags.push(
510                Diagnostic::error(
511                    "B0385",
512                    format!("neither `{trait_name}` nor `{target}` is declared in this module"),
513                    span,
514                )
515                .with_note(
516                    "the orphan rule: an impl belongs with the trait or with the type, so that two \
517                     modules cannot both supply one and disagree",
518                ),
519            );
520            return;
521        }
522
523        // The published header: the target with the impl's own parameters rigid, so `Bundle[T]`
524        // reads back as a type rather than as a name plus a promise.
525        let sig = {
526            let before = std::mem::take(&mut self.typarams);
527            self.typarams = param_names.iter().cloned().collect();
528            let target_ty = self.ty_from_node(target_node);
529            self.typarams = before;
530            ImplSig {
531                trait_name: trait_name.clone(),
532                params: param_names.clone(),
533                target: target_ty,
534                // Filled in after the bodies are checked — this is the header, and what its
535                // methods perform is not known until they have been read.
536                effects: Vec::new(),
537            }
538        };
539
540        // An interface publishes the header and not the bodies, exactly as it publishes a `def`'s
541        // signature and not its body. What it *does* publish about a method is its **row**, since
542        // `docs/27` made that a property of the impl rather than of the trait: a caller in another
543        // module has nowhere else to learn it.
544        if self.mode == super::Mode::Interface {
545            let mut sig = sig;
546            for m in &item.args[3..] {
547                let (m, _) = self.undecorate(m);
548                // `def add uses raises(MoneyError)` — a bodyless `def` carrying only a row, which
549                // is what `render_impl` writes.
550                if !m.is_form(sym::DEF) || m.args.len() > 5 {
551                    self.diags.push(
552                        Diagnostic::error(
553                            "B0382",
554                            "an impl in a `.becki` publishes its methods' effects, not their bodies",
555                            m.span(),
556                        )
557                        .with_note(
558                            "the implementation stays in the module that wrote it; what crosses is \
559                             that it exists and what it performs, which is what a call in another \
560                             module needs to resolve",
561                        ),
562                    );
563                    continue;
564                }
565                let Some(name) = m.args[0].as_var().map(|s| s.name.clone()) else {
566                    continue;
567                };
568                let row = self.declared_row(m.args.get(4));
569                if !row.atoms.is_empty() {
570                    sig.effects.push((name, row.atoms.into_iter().collect()));
571                }
572            }
573            self.register_impl(key, target.clone(), sig, span);
574            return;
575        }
576        if item.args.len() == 3 {
577            self.diags.push(
578                Diagnostic::error("B0382", "this impl has no methods", span).with_note(
579                    "a header with nothing behind it is a declaration, which is what a `.becki` \
580                     interface is made of; an ordinary module has to implement what it claims",
581                ),
582            );
583            return;
584        }
585
586        let mut seen: BTreeSet<Arc<str>> = BTreeSet::new();
587        for m in &item.args[3..] {
588            let (m, _) = self.undecorate(m);
589            if !m.is_form(sym::DEF) || m.args.len() < 6 {
590                self.error(
591                    "B0382",
592                    "an impl may only contain `def`s with bodies",
593                    m.span(),
594                );
595                continue;
596            }
597            let Some(name) = m.args[0].as_var().map(|s| s.name.clone()) else {
598                continue;
599            };
600            let Some(sig) = decl.methods.iter().find(|x| x.name == name) else {
601                self.diags.push(
602                    Diagnostic::error(
603                        "B0382",
604                        format!("`{trait_name}` has no method `{name}`"),
605                        m.args[0].span(),
606                    )
607                    .with_label(decl.span, "the trait is declared here"),
608                );
609                continue;
610            };
611            if !seen.insert(name.clone()) {
612                self.error(
613                    "B0382",
614                    format!("`{name}` is implemented twice for `{target}`"),
615                    m.span(),
616                );
617                continue;
618            }
619            if let Some(def) =
620                self.impl_method(m, sig, &trait_name, &target, target_node, &typarams)
621            {
622                if let Some(s) = def.args[0].as_var() {
623                    self.impl_methods.insert(s.name.clone());
624                }
625                // A bound on the *impl* is spent here rather than by the sweep over the written
626                // items, because this method does not exist until the line above synthesised it:
627                // `expand_bounds` runs over the module as the person wrote it, and an impl's
628                // methods are not in it. Without this a bounded impl's method has its parameter in
629                // scope and no dictionary to call anything through.
630                let def = self.expand_bounds(&def).unwrap_or(def);
631                out.push(def);
632            }
633        }
634
635        let missing: Vec<String> = decl
636            .methods
637            .iter()
638            .filter(|m| !seen.contains(&m.name))
639            .map(|m| m.name.to_string())
640            .collect();
641        if !missing.is_empty() {
642            self.diags.push(
643                Diagnostic::error(
644                    "B0382",
645                    format!("`{target}` does not implement all of `{trait_name}`"),
646                    span,
647                )
648                .with_primary_label(format!("missing: {}", missing.join(", ")))
649                .with_label(decl.span, "declared here"),
650            );
651        }
652        self.register_impl(key, target, sig, span);
653    }
654
655    fn register_impl(
656        &mut self,
657        key: (Arc<str>, Arc<str>),
658        target: Arc<str>,
659        sig: ImplSig,
660        span: Span,
661    ) {
662        self.own_impls.push(key.clone());
663        self.impls.insert(key, ImplDecl { target, sig, span });
664    }
665
666    /// One impl method, rewritten into a top-level `def` with a mangled name.
667    fn impl_method(
668        &mut self,
669        m: &Node,
670        sig: &TraitMethod,
671        trait_name: &str,
672        target: &str,
673        target_node: &Node,
674        typarams: &Node,
675    ) -> Option<Node> {
676        if !m.args[1].args.is_empty() {
677            self.error(
678                "B0382",
679                format!("`{}` takes its type parameters from the impl", sig.name),
680                m.args[1].span(),
681            );
682            return None;
683        }
684        if !m.args[3].args.is_empty() || !m.args[4].args.is_empty() {
685            self.diags.push(
686                Diagnostic::error(
687                    "B0382",
688                    format!(
689                        "`{}` may not restate its return type or its effects",
690                        sig.name
691                    ),
692                    m.args[0].span(),
693                )
694                .with_label(sig.span, "the trait already said both")
695                .with_note(
696                    "an impl writes the body; the signature is the trait's, and a second copy of \
697                     it is a second place for it to be wrong",
698                ),
699            );
700            return None;
701        }
702        let written = &m.args[2].args;
703        if written.len() != sig.params.args.len() {
704            self.error(
705                "B0382",
706                format!(
707                    "`{}` takes {} parameter(s), got {}",
708                    sig.name,
709                    sig.params.args.len(),
710                    written.len()
711                ),
712                m.args[2].span(),
713            );
714            return None;
715        }
716        // The impl supplies names, the trait supplies types, and `Self` becomes the target.
717        let mut params = Vec::new();
718        for (w, s) in written.iter().zip(&sig.params.args) {
719            if w.is_form(sym::ANNOT) {
720                self.diags.push(
721                    Diagnostic::error(
722                        "B0382",
723                        format!("`{}`'s parameter types come from the trait", sig.name),
724                        w.span(),
725                    )
726                    .with_label(sig.span, "declared here"),
727                );
728                return None;
729            }
730            let Some(name) = w.as_var() else {
731                self.error("B0382", "expected a parameter name", w.span());
732                return None;
733            };
734            let ty = substitute_self(&s.args[1], target_node);
735            let span = w.span().to(ty.span());
736            params.push(Node::form(
737                sym::ANNOT,
738                vec![Node::sym(&name.name, w.span()), ty],
739                span,
740            ));
741        }
742        let name = mangle(trait_name, &sig.name, target);
743        Some(Node::form(
744            sym::DEF,
745            vec![
746                Node::sym(&name, m.args[0].span()),
747                typarams.clone(),
748                Node::form(sym::PARAMS, params, m.args[2].span()),
749                substitute_self(&sig.returns, target_node),
750                sig.uses.clone(),
751                m.args[5].clone(),
752            ],
753            m.span(),
754        ))
755    }
756
757    // ------------------------------------------------------------------------------- bounds
758
759    /// Rewrite every bounded `def` so that its dictionaries are ordinary parameters.
760    ///
761    /// Returns the replacement for `item`, or `None` when it has no bounds and needs none. Run
762    /// before `collect_signatures`, so every later pass sees a definition with one more argument
763    /// and nothing else to know about.
764    pub(super) fn expand_bounds(&mut self, item: &Node) -> Option<Node> {
765        if item.is_form(sym::DECORATE) && item.args.len() == 2 {
766            let inner = self.expand_bounds(&item.args[1])?;
767            let mut out = item.clone();
768            out.args[1] = inner;
769            return Some(out);
770        }
771        if !item.is_form(sym::DEF) || item.args.len() < 5 {
772            return None;
773        }
774        let bounds = bounds_of(&item.args[1]);
775        if bounds.is_empty() {
776            return None;
777        }
778        let name = item.args[0].as_var().map(|s| s.name.clone())?;
779        let mut extra = Vec::new();
780        let mut specs = Vec::new();
781        for (param, traits) in &bounds {
782            let param_node = Node::sym(param, item.args[1].span());
783            for t in traits {
784                let Some(decl) = self.traits.get(t).cloned() else {
785                    self.error(
786                        "B0383",
787                        format!("cannot find trait `{t}`"),
788                        item.args[1].span(),
789                    );
790                    continue;
791                };
792                for m in &decl.methods {
793                    let dict = mangle(t, &m.name, param);
794                    let span = item.args[1].span();
795                    // The method's own signature with `Self` := the type parameter. Its row is left
796                    // to `ty_from_node`, which mints a variable for a written function type — so a
797                    // caller that supplies a pure impl stays pure (`docs/27` §27.3).
798                    let mut fn_ty: Vec<Node> = m
799                        .params
800                        .args
801                        .iter()
802                        .map(|p| substitute_self(&p.args[1], &param_node))
803                        .collect();
804                    fn_ty.push(substitute_self(&m.returns.args[0], &param_node));
805                    extra.push(Node::form(
806                        sym::ANNOT,
807                        vec![Node::sym(&dict, span), Node::form(FN_TYPE, fn_ty, span)],
808                        span,
809                    ));
810                    specs.push(DictParam {
811                        param: param.clone(),
812                        trait_name: t.clone(),
813                        method: m.name.clone(),
814                    });
815                }
816            }
817        }
818        if specs.is_empty() {
819            return None;
820        }
821        self.dicts.insert(name, specs);
822        let mut out = item.clone();
823        // The type-parameter list keeps only the names from here on: the bound has been spent, and
824        // leaving it would make `bind_typarams` read a form it does not need to know about.
825        out.args[1] = Node::form(
826            sym::TYPARAMS,
827            bounds_of(&item.args[1])
828                .iter()
829                .map(|(p, _)| Node::sym(p, item.args[1].span()))
830                .chain(
831                    item.args[1]
832                        .args
833                        .iter()
834                        .filter(|p| !p.is_form(sym::ANNOT))
835                        .cloned(),
836                )
837                .collect(),
838            item.args[1].span(),
839        );
840        out.args[2].args.extend(extra);
841        Some(out)
842    }
843
844    /// The bounds on a definition's type parameters, recovered from the dictionaries it was given.
845    ///
846    /// One entry per bounded parameter, in the order the parameters were written, with each
847    /// parameter's traits in the order they were written — which is the order the dictionaries were
848    /// appended in, so reading them back off the dictionaries cannot disagree with the signature.
849    pub(super) fn bounds_of_def(&self, name: &Arc<str>) -> Vec<(Arc<str>, Vec<Arc<str>>)> {
850        let Some(specs) = self.dicts.get(name) else {
851            return Vec::new();
852        };
853        let mut out: Vec<(Arc<str>, Vec<Arc<str>>)> = Vec::new();
854        for s in specs {
855            match out.iter_mut().find(|(p, _)| *p == s.param) {
856                Some((_, traits)) => {
857                    if !traits.contains(&s.trait_name) {
858                        traits.push(s.trait_name.clone());
859                    }
860                }
861                None => out.push((s.param.clone(), vec![s.trait_name.clone()])),
862            }
863        }
864        out
865    }
866
867    /// Apply a **bounded** definition, supplying one dictionary per method of each bound.
868    ///
869    /// The ordinary arguments are checked *and* the result is unified with what the context wants,
870    /// both before any dictionary is resolved — because until then the call's `T` is a variable and
871    /// there is nothing to look an impl up by. Consulting the expectation is what makes
872    /// `def none_yet() -> Option[Int]: return largest([])` work: the element type is not in the
873    /// argument, and it is in the return type.
874    pub(super) fn apply_bounded(
875        &mut self,
876        name: &Arc<str>,
877        specs: &[DictParam],
878        args: &[Node],
879        expected: Option<&Ty>,
880        span: Span,
881    ) -> Core {
882        let Some(scheme) = self.schemes.get(name).cloned() else {
883            return Core::new(CoreKind::Const(Const::Unit), self.subst.fresh(), span);
884        };
885        let (ty, named) = self.subst.instantiate_named(&scheme);
886        let func = Core::new(CoreKind::Global(name.clone()), ty.clone(), span);
887        let Ty::Fun(param_tys, ret, latent) = ty else {
888            return self.apply_fn(func, args, span);
889        };
890        self.perform(&latent);
891        let ordinary = param_tys.len().saturating_sub(specs.len());
892        if args.len() != ordinary {
893            self.error(
894                "B0351",
895                format!("expected {ordinary} argument(s), got {}", args.len()),
896                span,
897            );
898        }
899        let mut checked = self.check_args(args, &param_tys[..ordinary]);
900        if let Some(want) = expected {
901            // Deliberately not reported as a mismatch here: the caller unifies the result again
902            // when it has a label for what went wrong, and a second message would be noise.
903            let _ = self.subst.unify(&ret, want);
904        }
905        for (i, spec) in specs.iter().enumerate() {
906            let at = named
907                .get(&spec.param)
908                .map(|t| self.subst.resolve(t))
909                .unwrap_or_else(|| self.subst.fresh());
910            let Some(dict) = self.dictionary_at(&spec.trait_name, &spec.method, &at, span, 0)
911            else {
912                continue;
913            };
914            if let Some(want) = param_tys.get(ordinary + i) {
915                self.unify(&dict.ty, want, span, "implementation");
916            }
917            checked.push(dict);
918        }
919        Core::new(
920            CoreKind::App {
921                func: Box::new(func),
922                args: checked,
923            },
924            *ret,
925            span,
926        )
927    }
928
929    /// The implementation of one trait method at one type, as something callable.
930    ///
931    /// Two kinds of answer, and the whole design is that they are found the same way. If the type
932    /// is a **type parameter** of the definition being checked, the implementation arrived as a
933    /// dictionary parameter and this is a local. Otherwise it is a concrete type and this is the
934    /// impl's own global. Both are named `Trait::method@Target`.
935    pub(super) fn dictionary(
936        &mut self,
937        trait_name: &Arc<str>,
938        method: &Arc<str>,
939        ty: &Ty,
940        span: Span,
941    ) -> Option<Core> {
942        let head = ty.con_name().map(Arc::<str>::from);
943        if let Some(head) = &head {
944            if self.typarams.contains(head) {
945                let want = mangle(trait_name, method, head);
946                if let Some(BindKind::Local(id, t)) =
947                    self.resolve(&Symbol::new(&want)).map(|b| b.kind.clone())
948                {
949                    return Some(Core::new(CoreKind::Var(id), t, span));
950                }
951                self.diags.push(
952                    Diagnostic::error(
953                        "B0386",
954                        format!("`{head}` is not known to implement `{trait_name}`"),
955                        span,
956                    )
957                    .with_primary_label(format!("`{method}` needs it"))
958                    .with_fix(format!("bound it: `[{head}: {trait_name}]`")),
959                );
960                return None;
961            }
962        }
963        let Some(head) = head else {
964            self.diags.push(
965                Diagnostic::error(
966                    "B0386",
967                    format!("cannot tell which type `{method}` dispatches on here"),
968                    span,
969                )
970                .with_primary_label("the type is not determined at this call")
971                .with_fix("annotate it, or pass an argument that fixes it")
972                .with_note(
973                    "an implementation is chosen from a concrete type or from a bound on a type \
974                     parameter; this is neither yet, and the choice is made where the call is \
975                     written rather than after the whole body has been read",
976                ),
977            );
978            return None;
979        };
980        let Some(found) = self.impls.get(&(trait_name.clone(), head.clone())) else {
981            let decl = self.traits.get(trait_name).map(|d| d.span);
982            let mut d = Diagnostic::error(
983                "B0387",
984                format!("`{head}` does not implement `{trait_name}`"),
985                span,
986            )
987            .with_primary_label(format!(
988                "`{method}` needs an `impl {trait_name} for {head}`"
989            ));
990            if let Some(at) = decl {
991                d = d.with_label(at, "the trait is declared here");
992            }
993            self.diags.push(d);
994            return None;
995        };
996        let name = mangle(trait_name, method, &found.target);
997        let ty = self
998            .schemes
999            .get(&name)
1000            .map(|sc| self.subst.instantiate(sc))?;
1001        Some(Core::new(CoreKind::Global(name), ty, span))
1002    }
1003
1004    /// Register an imported module's **trait declarations**.
1005    ///
1006    /// An imported trait is turned back into the syntax a local one is kept as, so that everything
1007    /// downstream — dispatch, an impl for a local type, a bound on a local definition — cannot tell
1008    /// the difference.
1009    ///
1010    /// Separate from [`Checker::import_impls`] because the two run in different passes over the
1011    /// *whole* import list, and that separation is load-bearing rather than tidy: an `impl` and a
1012    /// bounded `def` both resolve a trait **by name**, so registering each module's traits and
1013    /// impls together made whether an imported `impl` survived depend on the order the `import`
1014    /// lines were written in — the trait's module had to be named first. Nothing gives `import` an
1015    /// order (D23 fixes where a name resolves *from*, not a sequence), and the impl was dropped
1016    /// silently, so the failure surfaced one module later as `B0387`.
1017    pub(super) fn import_trait_decls(&mut self, traits: &[TraitSig]) {
1018        for t in traits {
1019            let methods: Vec<TraitMethod> = t
1020                .methods
1021                .iter()
1022                .map(|m| TraitMethod {
1023                    name: m.name.clone(),
1024                    params: Node::form(
1025                        sym::PARAMS,
1026                        m.params
1027                            .iter()
1028                            .map(|(n, ty)| {
1029                                Node::form(
1030                                    sym::ANNOT,
1031                                    vec![Node::sym(n, Span::NONE), ty_to_node(ty)],
1032                                    Span::NONE,
1033                                )
1034                            })
1035                            .collect(),
1036                        Span::NONE,
1037                    ),
1038                    returns: Node::form(sym::RETURNS, vec![ty_to_node(&m.ret)], Span::NONE),
1039                    uses: Node::form(
1040                        "uses",
1041                        m.effects
1042                            .iter()
1043                            .map(|e| Node::sym(e.name(), Span::NONE))
1044                            .collect(),
1045                        Span::NONE,
1046                    ),
1047                    span: Span::NONE,
1048                })
1049                .collect();
1050            for m in &methods {
1051                self.trait_methods.insert(m.name.clone(), t.name.clone());
1052                self.globals.push(Binding {
1053                    name: m.name.clone(),
1054                    scopes: ScopeSet::empty(),
1055                    kind: BindKind::TraitMethod(m.name.clone()),
1056                });
1057            }
1058            self.traits.insert(
1059                t.name.clone(),
1060                TraitDecl {
1061                    methods,
1062                    sig: t.clone(),
1063                    span: Span::NONE,
1064                },
1065            );
1066        }
1067    }
1068
1069    /// Register an imported module's `impl`s, once **every** import's traits are known.
1070    ///
1071    /// The methods an impl names are registered as *signatures*: the bodies stayed in the module
1072    /// that wrote them, and what crosses is that they exist and what they promise.
1073    ///
1074    /// The `module` name is for the diagnostic below, which is the other half of the fix. A
1075    /// missing trait here used to mean two different things — "declared by an import this loop has
1076    /// not reached yet" and "not imported at all" — and `continue` served both. The first was the
1077    /// bug and the pass split above removes it; what is left is the second, and it is **not an
1078    /// error**: an import is visible where it is written and not through somebody else's, so a
1079    /// module may perfectly well publish an `impl` for a trait the importer never names. It is
1080    /// also not nothing, because the impl is *dropped* and any later attempt to use it fails
1081    /// somewhere else — which is what `B0388` exists to have said first.
1082    pub(super) fn import_impls(&mut self, module: &str, impls: &[ImplSig]) {
1083        for i in impls {
1084            let head = i.head();
1085            let Some(decl) = self.traits.get(&i.trait_name).cloned() else {
1086                self.diags.push(
1087                    Diagnostic::warning(
1088                        "B0388",
1089                        format!(
1090                            "`{module}` implements `{}`, which this program does not import",
1091                            i.trait_name
1092                        ),
1093                        Span::NONE,
1094                    )
1095                    // A label needs a span and an interface has none — the impl was read out of a
1096                    // `.becki`, not out of this file — so what a label would have said is a note.
1097                    .with_note(format!(
1098                        "`impl {} for {}` is dropped, so its methods cannot be called here",
1099                        i.trait_name,
1100                        i.head()
1101                    ))
1102                    .with_note(
1103                        "a trait is a name, and a name is visible where its module is imported \
1104                         directly rather than through somebody else's import",
1105                    )
1106                    .with_fix(format!(
1107                        "import the module that declares `{}`",
1108                        i.trait_name
1109                    )),
1110                );
1111                continue;
1112            };
1113            for m in &decl.sig.methods {
1114                // The signature the importing module will call through: the trait's shape, with
1115                // `Self` replaced by this impl's target, and **this impl's** row rather than the
1116                // trait's. `docs/27` inverted that: a trait's row is a floor and an impl may be
1117                // more effectful, so taking the row off the trait here would let a fallible method
1118                // arrive in another module looking pure.
1119                let name = mangle(&i.trait_name, &m.name, &head);
1120                let row = i
1121                    .effects
1122                    .iter()
1123                    .find(|(n, _)| *n == m.name)
1124                    .map(|(_, r)| Row::of(r.iter().cloned()))
1125                    .unwrap_or_else(|| Row::of(m.effects.iter().cloned()));
1126                let params: Vec<Ty> = m
1127                    .params
1128                    .iter()
1129                    .map(|(_, t)| substitute_self_ty(t, &i.target))
1130                    .collect();
1131                let ret = substitute_self_ty(&m.ret, &i.target);
1132                let ty = Ty::fun_eff(params, ret, row);
1133                self.schemes
1134                    .insert(name.clone(), Scheme::generic(i.params.clone(), ty));
1135            }
1136            self.impls.insert(
1137                (i.trait_name.clone(), head.clone()),
1138                ImplDecl {
1139                    target: head,
1140                    sig: i.clone(),
1141                    span: Span::NONE,
1142                },
1143            );
1144        }
1145    }
1146
1147    /// Rebuild an imported definition's dictionary parameters from its published bound.
1148    ///
1149    /// The mirror of [`Checker::expand_bounds`], and it has to produce exactly the same parameters
1150    /// in exactly the same order — a `.becki` publishes `def total[T: Priced](xs: list[T]) -> Int`
1151    /// and the module that wrote it lowered that to a two-parameter function. Working from types
1152    /// rather than from syntax, because an imported name arrives as a scheme.
1153    pub(super) fn import_bounded(
1154        &mut self,
1155        name: &Arc<str>,
1156        bounds: &[(Arc<str>, Vec<Arc<str>>)],
1157        scheme: Scheme,
1158    ) -> Scheme {
1159        let Ty::Fun(mut params, ret, row) = scheme.ty.clone() else {
1160            return scheme;
1161        };
1162        let mut specs = Vec::new();
1163        for (param, traits) in bounds {
1164            let at = Ty::con(param);
1165            for t in traits {
1166                let Some(decl) = self.traits.get(t).cloned() else {
1167                    continue;
1168                };
1169                for m in &decl.sig.methods {
1170                    // A **fresh row variable**, matching what `expand_bounds` mints locally: a
1171                    // bounded definition is effect-polymorphic in its bounds, so a caller that
1172                    // supplies a pure impl stays pure and one that supplies a fallible impl
1173                    // inherits exactly its failure (`docs/27` §27.3, `docs/27` §27.7).
1174                    let row = self.subst.fresh_row();
1175                    params.push(Ty::fun_eff(
1176                        m.params
1177                            .iter()
1178                            .map(|(_, ty)| substitute_self_ty(ty, &at))
1179                            .collect(),
1180                        substitute_self_ty(&m.ret, &at),
1181                        row,
1182                    ));
1183                    specs.push(DictParam {
1184                        param: param.clone(),
1185                        trait_name: t.clone(),
1186                        method: m.name.clone(),
1187                    });
1188                }
1189            }
1190        }
1191        if specs.is_empty() {
1192            return scheme;
1193        }
1194        self.dicts.insert(name.clone(), specs);
1195        Scheme::generic(scheme.params.clone(), Ty::Fun(params, ret, row))
1196    }
1197
1198    /// A call to a trait method, resolved from the type of the argument that carries `Self`.
1199    pub(super) fn trait_call(&mut self, method: &Arc<str>, args: &[Node], span: Span) -> Core {
1200        let unit = || Core::new(CoreKind::Const(Const::Unit), Ty::unit(), span);
1201        let Some(trait_name) = self.trait_methods.get(method).cloned() else {
1202            return unit();
1203        };
1204        let Some(decl) = self.traits.get(&trait_name).cloned() else {
1205            return unit();
1206        };
1207        let Some(sig) = decl.methods.iter().find(|m| &m.name == method) else {
1208            return unit();
1209        };
1210        // Which parameter carries `Self` — the first one that mentions it. `trait_params` refused
1211        // the method if none did, so this is a position and not a search that can fail.
1212        let at = sig
1213            .params
1214            .args
1215            .iter()
1216            .position(|p| mentions(&p.args[1], SELF))
1217            .unwrap_or(0);
1218        if args.len() <= at {
1219            self.error(
1220                "B0351",
1221                format!(
1222                    "`{method}` takes {} argument(s), got {}",
1223                    sig.params.args.len(),
1224                    args.len()
1225                ),
1226                span,
1227            );
1228            return unit();
1229        }
1230        let receiver = self.expr(&args[at], None);
1231        let ty = self.subst.resolve(&receiver.ty);
1232        // The implementation may have bounds of its own — `impl[T: Ord] Ranked for list[T]` — and
1233        // then it takes a dictionary the call site has to supply, which is a question about the
1234        // receiver's type rather than about this call's arguments (`super::dispatch`).
1235        if let Some(call) = self.apply_bounded_impl(&trait_name, method, &receiver, at, args, span)
1236        {
1237            return call;
1238        }
1239        // One rule for both kinds of answer: a concrete receiver finds the impl's own global, and a
1240        // bounded type parameter finds the dictionary its definition was handed.
1241        let Some(func) = self.dictionary(&trait_name, method, &ty, args[at].span()) else {
1242            return unit();
1243        };
1244        self.apply_fn_with(func, receiver, at, args, span)
1245    }
1246}
1247
1248/// A type as a type *expression*, so a published signature can be spliced like a written one.
1249///
1250/// The inverse of `ty_from_node`, and the reason an imported trait behaves exactly like a local
1251/// one: desugaring an impl or a bound is a syntax rewrite, so an imported trait has to arrive as
1252/// syntax. Every span is [`Span::NONE`] — "macro-generated code that chose not to borrow one" —
1253/// because the nodes describe a declaration in a file this module does not own.
1254fn ty_to_node(t: &Ty) -> Node {
1255    let span = Span::NONE;
1256    match t {
1257        Ty::Con(n, args) if args.is_empty() => Node::sym(n, span),
1258        Ty::Con(n, args) => Node::form_sym(
1259            beck_syntax::Symbol::new(n),
1260            args.iter().map(ty_to_node).collect(),
1261            span,
1262        ),
1263        Ty::Fun(ps, r, _) => {
1264            let mut parts: Vec<Node> = ps.iter().map(ty_to_node).collect();
1265            parts.push(ty_to_node(r));
1266            Node::form(FN_TYPE, parts, span)
1267        }
1268        // A published row is closed and a published signature has no free variables, so this is
1269        // unreachable for anything `Interface` carries. `Unit` rather than a panic: a malformed
1270        // `.becki` should be a diagnostic somewhere, never a crash here.
1271        Ty::Var(_) => Node::sym(Ty::UNIT, span),
1272    }
1273}
1274
1275/// Does this type expression mention `name` anywhere?
1276fn mentions(n: &Node, name: &str) -> bool {
1277    n.head_name() == Some(name) || n.args.iter().any(|a| mentions(a, name))
1278}
1279
1280/// Replace `Self` with the impl's target throughout a *type*.
1281fn substitute_self_ty(t: &Ty, target: &Ty) -> Ty {
1282    match t {
1283        Ty::Con(n, args) if n.as_ref() == SELF && args.is_empty() => target.clone(),
1284        Ty::Con(n, args) => Ty::Con(
1285            n.clone(),
1286            args.iter().map(|a| substitute_self_ty(a, target)).collect(),
1287        ),
1288        Ty::Fun(ps, r, row) => Ty::Fun(
1289            ps.iter().map(|p| substitute_self_ty(p, target)).collect(),
1290            Box::new(substitute_self_ty(r, target)),
1291            row.clone(),
1292        ),
1293        Ty::Var(_) => t.clone(),
1294    }
1295}
1296
1297/// Replace `Self` with the impl's target throughout a type expression.
1298fn substitute_self(n: &Node, target: &Node) -> Node {
1299    if n.head_name() == Some(SELF) && n.args.is_empty() {
1300        let mut t = target.clone();
1301        t.meta = n.meta.clone();
1302        return t;
1303    }
1304    let mut out = n.clone();
1305    out.args = n.args.iter().map(|a| substitute_self(a, target)).collect();
1306    out
1307}
1308
1309#[cfg(test)]
1310mod tests {
1311    use std::sync::Arc;
1312
1313    use crate::check_str;
1314
1315    fn codes(src: &str) -> Vec<&'static str> {
1316        let (_, d, _) = check_str("t.beck", src);
1317        d.iter().map(|x| x.code).collect()
1318    }
1319
1320    fn errors(src: &str) -> String {
1321        let (_, d, map) = check_str("t.beck", src);
1322        d.render(&map)
1323    }
1324
1325    const SHOW: &str = "\
1326trait Show:
1327    def show(self) -> Str
1328
1329model Point:
1330    x: Int
1331
1332impl Show for Point:
1333    def show(self):
1334        return str(self.x)
1335";
1336
1337    #[test]
1338    fn a_trait_and_an_impl_check() {
1339        assert_eq!(codes(SHOW), Vec::<&str>::new());
1340    }
1341
1342    #[test]
1343    fn a_call_resolves_to_the_impl_for_the_receivers_type() {
1344        let src = format!(
1345            "{SHOW}
1346def label(p: Point) -> Str:
1347    return p.show()
1348
1349def same(p: Point) -> Str:
1350    return show(p)
1351"
1352        );
1353        assert_eq!(codes(&src), Vec::<&str>::new());
1354
1355        // …and the desugared definition is what the call names, so nothing downstream of the
1356        // checker has to know a trait was involved.
1357        let (program, _, _) = check_str("t.beck", &src);
1358        assert!(
1359            program.defs.contains_key("Show::show@Point"),
1360            "{:?}",
1361            program.defs.keys().collect::<Vec<_>>()
1362        );
1363        assert!(super::is_impl_method("Show::show@Point"));
1364        assert!(!super::is_impl_method("label"));
1365    }
1366
1367    #[test]
1368    fn one_impl_covers_every_argument_of_a_parameterised_type() {
1369        // The feature docs/27 built, meeting the feature this one does: `impl[T] Show for Tree[T]`
1370        // is one impl, and a call at `Tree[Int]` and a call at `Tree[Str]` both find it.
1371        let src = "\
1372trait Show:
1373    def show(self) -> Str
1374
1375union Tree[T]:
1376    Leaf(value: T)
1377
1378impl[T] Show for Tree[T]:
1379    def show(self):
1380        return \"leaf\"
1381
1382def a() -> Str:
1383    return Leaf(value=1).show()
1384
1385def b() -> Str:
1386    return Leaf(value=\"x\").show()
1387";
1388        assert_eq!(codes(src), Vec::<&str>::new());
1389    }
1390
1391    #[test]
1392    fn a_type_with_no_impl_is_refused_by_name() {
1393        let src = format!(
1394            "{SHOW}
1395model Other:
1396    y: Int
1397
1398def f(o: Other) -> Str:
1399    return o.show()
1400"
1401        );
1402        let text = errors(&src);
1403        assert!(text.contains("B0387"), "{text}");
1404        assert!(text.contains("impl Show for Other"), "{text}");
1405    }
1406
1407    #[test]
1408    fn coherence_is_one_impl_per_trait_per_type() {
1409        let dup =
1410            format!("{SHOW}\nimpl Show for Point:\n    def show(self):\n        return \"\"\n");
1411        assert!(codes(&dup).contains(&"B0384"), "{:?}", codes(&dup));
1412
1413        // …and no blanket impl, because that would make coherence a search.
1414        let blanket = "\
1415trait Show:
1416    def show(self) -> Str
1417
1418impl[T] Show for T:
1419    def show(self):
1420        return \"\"
1421";
1422        assert!(codes(blanket).contains(&"B0384"), "{:?}", codes(blanket));
1423    }
1424
1425    #[test]
1426    fn the_orphan_rule_needs_the_trait_or_the_type() {
1427        // Neither is declared here, so this impl belongs in whichever module owns one of them.
1428        let src = "\
1429impl Show for Int:
1430    def show(self):
1431        return \"\"
1432";
1433        // The trait is not declared either, so the first thing reported is that.
1434        assert!(codes(src).contains(&"B0383"), "{:?}", codes(src));
1435
1436        // With the trait local and the type foreign, it is allowed — that is the rule, not a
1437        // blanket ban on implementing for a builtin.
1438        let owns_trait = "\
1439trait Show:
1440    def show(self) -> Str
1441
1442impl Show for Int:
1443    def show(self):
1444        return str(self)
1445";
1446        assert_eq!(codes(owns_trait), Vec::<&str>::new());
1447    }
1448
1449    #[test]
1450    fn an_impl_must_be_complete_and_no_more() {
1451        let two = "\
1452trait Show:
1453    def show(self) -> Str
1454    def tag(self) -> Str
1455
1456model Point:
1457    x: Int
1458
1459impl Show for Point:
1460    def show(self):
1461        return \"\"
1462";
1463        let text = errors(two);
1464        assert!(text.contains("B0382"), "{text}");
1465        assert!(text.contains("missing: tag"), "{text}");
1466
1467        // An extra method inside the same impl, rather than a second impl — which would be
1468        // B0384's business and not this test's.
1469        let extra = SHOW.replace(
1470            "    def show(self):\n        return str(self.x)\n",
1471            "    def show(self):\n        return str(self.x)\n\n    def nope(self):\n        return \"\"\n",
1472        );
1473        let text = errors(&extra);
1474        assert!(text.contains("B0382"), "{text}");
1475        assert!(text.contains("has no method `nope`"), "{text}");
1476    }
1477
1478    #[test]
1479    fn an_impl_writes_the_body_and_the_trait_writes_the_signature() {
1480        for (src, why) in [
1481            (
1482                "    def show(self: Point):\n        return \"\"\n",
1483                "a parameter type",
1484            ),
1485            (
1486                "    def show(self) -> Str:\n        return \"\"\n",
1487                "a return type",
1488            ),
1489            (
1490                "    def show(self) uses log:\n        return \"\"\n",
1491                "an effect row",
1492            ),
1493        ] {
1494            let program = SHOW.replace("    def show(self):\n        return str(self.x)\n", src);
1495            assert!(
1496                codes(&program).contains(&"B0382"),
1497                "{why}: {:?}",
1498                codes(&program)
1499            );
1500        }
1501    }
1502
1503    /// An impl may perform more than its trait declares, and the caller inherits it.
1504    ///
1505    /// This **reverses** what `docs/27` §27.7 built, and `docs/27` says why: a trait's row as a
1506    /// ceiling meant a fallible operation could not be a trait method, so `Money` could not have
1507    /// `+`. The row is now inferred per impl. Nothing is lost, because what a caller sees is what
1508    /// the impl does rather than what the trait guessed.
1509    #[test]
1510    fn an_impl_may_perform_more_than_its_trait_declares_and_the_caller_inherits_it() {
1511        let src = "\
1512trait Show:
1513    def show(self) -> Str
1514
1515model Point:
1516    x: Int
1517
1518impl Show for Point:
1519    def show(self):
1520        return str(uuid())
1521
1522def label(p: Point) -> Str:
1523    return p.show()
1524";
1525        let (program, d, map) = crate::check_str("t.beck", src);
1526        assert!(!d.has_errors(), "{}", d.render(&map));
1527        let row: Vec<String> = program
1528            .defs
1529            .get("label")
1530            .expect("label")
1531            .effects
1532            .iter()
1533            .map(|e| e.name())
1534            .collect();
1535        assert_eq!(
1536            row,
1537            vec!["nondet"],
1538            "a caller of a trait method performs what the *impl* performs"
1539        );
1540    }
1541
1542    /// And a bounded caller is polymorphic in it: the same generic definition is pure with a pure
1543    /// impl and effectful with an effectful one, which is `docs/27`'s property applied to a bound.
1544    #[test]
1545    fn a_bounded_definition_inherits_the_row_of_whichever_impl_it_is_given() {
1546        let src = "\
1547trait Show:
1548    def show(self) -> Str
1549
1550model Quiet:
1551    x: Int
1552
1553model Loud:
1554    x: Int
1555
1556impl Show for Quiet:
1557    def show(self):
1558        return str(self.x)
1559
1560impl Show for Loud:
1561    def show(self):
1562        return str(uuid())
1563
1564def label[T: Show](x: T) -> Str:
1565    return x.show()
1566
1567def quiet(q: Quiet) -> Str:
1568    return label(q)
1569
1570def loud(l: Loud) -> Str:
1571    return label(l)
1572";
1573        let (program, d, map) = crate::check_str("t.beck", src);
1574        assert!(!d.has_errors(), "{}", d.render(&map));
1575        let row = |name: &str| -> Vec<String> {
1576            program
1577                .defs
1578                .get(name)
1579                .unwrap_or_else(|| panic!("no `{name}`"))
1580                .effects
1581                .iter()
1582                .map(|e| e.name())
1583                .collect()
1584        };
1585        assert!(
1586            row("quiet").is_empty(),
1587            "a pure impl leaves its caller pure: {:?}",
1588            row("quiet")
1589        );
1590        assert_eq!(row("loud"), vec!["nondet"]);
1591    }
1592
1593    #[test]
1594    fn an_unbounded_type_parameter_cannot_call_a_trait_method() {
1595        // The distinction the diagnostic has to make: `T` is not a type with no impl, it is a type
1596        // nobody said anything about — so the fix is a bound and not an impl.
1597        let generic = format!(
1598            "{SHOW}
1599def twice[T](x: T) -> Str:
1600    return x.show()
1601"
1602        );
1603        let text = errors(&generic);
1604        assert!(text.contains("B0386"), "{text}");
1605        assert!(text.contains("not known to implement"), "{text}");
1606        assert!(text.contains("[T: Show]"), "the fix names itself:\n{text}");
1607    }
1608
1609    #[test]
1610    fn a_bound_lets_a_generic_body_call_a_trait_method() {
1611        let src = format!(
1612            "{SHOW}
1613def label[T: Show](x: T) -> Str:
1614    return \"<\" + x.show() + \">\"
1615
1616def a() -> Str:
1617    return label(Point(x=1))
1618"
1619        );
1620        assert_eq!(codes(&src), Vec::<&str>::new());
1621
1622        // The dictionary is an ordinary parameter, so the lowered definition has one more of them
1623        // than the source wrote — which is the whole implementation, visible.
1624        let (program, _, _) = check_str("t.beck", &src);
1625        let label = &program.defs["label"];
1626        assert_eq!(label.params.len(), 2, "{:?}", label.params);
1627        assert_eq!(label.params[1].1.as_ref(), "Show::show@T");
1628        assert_eq!(
1629            label.bounds,
1630            vec![(Arc::<str>::from("T"), vec![Arc::<str>::from("Show")])]
1631        );
1632    }
1633
1634    #[test]
1635    fn a_bounded_definition_passes_its_own_dictionary_through() {
1636        // The case that makes bounds compose rather than bottom out: `outer` has no idea what `U`
1637        // is, and hands `inner` the implementation it was handed itself.
1638        let src = format!(
1639            "{SHOW}
1640def inner[T: Show](x: T) -> Str:
1641    return x.show()
1642
1643def outer[U: Show](x: U) -> Str:
1644    return inner(x)
1645
1646def used() -> Str:
1647    return outer(Point(x=1))
1648"
1649        );
1650        assert_eq!(codes(&src), Vec::<&str>::new());
1651    }
1652
1653    #[test]
1654    fn a_call_takes_its_implementation_from_the_context_when_the_arguments_do_not_say() {
1655        let src = format!(
1656            "{SHOW}
1657def none_of[T: Show](xs: list[T]) -> Option[T]:
1658    return None
1659
1660def nothing() -> Option[Point]:
1661    return none_of([])
1662"
1663        );
1664        assert_eq!(
1665            codes(&src),
1666            Vec::<&str>::new(),
1667            "the element type is in the return type, not in the argument"
1668        );
1669    }
1670
1671    #[test]
1672    fn a_call_whose_type_is_undetermined_says_so() {
1673        let src = format!(
1674            "{SHOW}
1675def none_of[T: Show](xs: list[T]) -> Option[T]:
1676    return None
1677
1678def nothing() -> Int:
1679    return list_len([none_of([])])
1680"
1681        );
1682        let text = errors(&src);
1683        assert!(text.contains("B0386"), "{text}");
1684        assert!(text.contains("not determined at this call"), "{text}");
1685    }
1686
1687    #[test]
1688    fn a_bound_names_a_trait_and_nothing_else() {
1689        let src = format!(
1690            "{SHOW}
1691def label[T: Nope](x: T) -> Str:
1692    return \"\"
1693"
1694        );
1695        assert!(codes(&src).contains(&"B0383"), "{:?}", codes(&src));
1696    }
1697
1698    #[test]
1699    fn neither_a_trait_method_nor_a_bounded_definition_is_a_value() {
1700        let method = format!(
1701            "{SHOW}
1702def all(ps: list[Point]) -> list[Str]:
1703    return map_list(ps, show)
1704"
1705        );
1706        let text = errors(&method);
1707        assert!(text.contains("B0386"), "{text}");
1708        assert!(text.contains("cannot be used as a value"), "{text}");
1709
1710        // The same for a definition that carries a bound: its implementations arrive at the call
1711        // site, and a reference has no call site.
1712        let bounded = format!(
1713            "{SHOW}
1714def label[T: Show](x: T) -> Str:
1715    return x.show()
1716
1717def all(ps: list[Point]) -> list[Str]:
1718    return map_list(ps, label)
1719"
1720        );
1721        let text = errors(&bounded);
1722        assert!(text.contains("B0386"), "{text}");
1723        assert!(text.contains("has a bound"), "{text}");
1724    }
1725
1726    #[test]
1727    fn a_bounded_definition_publishes_its_bound_and_not_its_dictionaries() {
1728        // The wall docs/38 §38.6 named, from the other side: a library can publish the interesting
1729        // half of itself. What crosses is the *bound*; the parameters it was lowered with are named
1730        // `Show::show@T` and belong to the lowering rather than to the contract.
1731        let src = format!(
1732            "{SHOW}
1733def label[T: Show](x: T) -> Str:
1734    return x.show()
1735"
1736        );
1737        let (placed, d, map) = crate::compile_or_library_str("t.beck", &src);
1738        assert!(!d.has_errors(), "{}", d.render(&map));
1739        let iface = crate::iface::Interface::of(&placed.expect("compiles").program);
1740        let text = iface.render();
1741        assert!(text.contains("trait Show:"), "{text}");
1742        assert!(text.contains("    def show(self) -> Str"), "{text}");
1743        assert!(text.contains("impl Show for Point"), "{text}");
1744        assert!(text.contains("def label[T: Show](x: T) -> Str"), "{text}");
1745        assert!(
1746            !text.contains("Show::show@"),
1747            "a dictionary parameter is not part of the contract:\n{text}"
1748        );
1749    }
1750
1751    #[test]
1752    fn a_declaration_cannot_bound_its_type_parameter() {
1753        // A bound says what a body may call, and a `model` has no body. Refused rather than
1754        // accepted and ignored, which is what it was before docs/27.
1755        let src = "trait Show:\n    def show(self) -> Str\n\nmodel Box[T: Show]:\n    held: T\n";
1756        let text = errors(src);
1757        assert!(text.contains("B0316"), "{text}");
1758        assert!(text.contains("has no body"), "{text}");
1759        // Once. The reader who wrote the bound is told the one thing that is wrong with it — and
1760        // not, on top of that, that `T` is a type nobody declared, which is what came out while
1761        // the parameter was being read with `Node::as_var` and dropped from scope by the bound
1762        // that was already being reported on.
1763        assert!(
1764            !text.contains("B0310"),
1765            "the bound is the defect, and the parameter is still a parameter:\n{text}"
1766        );
1767    }
1768
1769    #[test]
1770    fn a_trait_an_impl_and_a_bound_cross_a_becki() {
1771        // The gap docs/38 §38.6 named. What the exporting module publishes is the trait, the impl
1772        // *header* and the bound; the bodies and the dictionary parameters stay behind.
1773        let lib = format!(
1774            "{SHOW}
1775def label[T: Show](x: T) -> Str:
1776    return x.show()
1777"
1778        );
1779        let (placed, d, map) = crate::compile_or_library_str("lib.beck", &lib);
1780        assert!(!d.has_errors(), "{}", d.render(&map));
1781        let published = crate::iface::Interface::of(&placed.expect("compiles").program);
1782
1783        // Through the file form, because that is what an importing module actually reads.
1784        let text = published.render();
1785        let mut m = beck_diag::SourceMap::new();
1786        let mut d = beck_diag::Diagnostics::new();
1787        let reread = crate::iface::Interface::parse("lib", &text, &mut m, &mut d);
1788        assert!(!d.has_errors(), "{}\n---\n{text}", d.render(&m));
1789        assert_eq!(published.digest(), reread.digest(), "rendered:\n{text}");
1790        assert_eq!(reread.traits.len(), 1);
1791        assert_eq!(reread.impls.len(), 1);
1792
1793        // And an importing module resolves through it: a trait method on an imported type, and a
1794        // bounded definition whose dictionary it has to rebuild from the published bound.
1795        let app = "\
1796import lib
1797
1798def one() -> Str:
1799    return Point(x=1).show()
1800
1801def two() -> Str:
1802    return label(Point(x=2))
1803";
1804        let node = {
1805            let mut map = beck_diag::SourceMap::new();
1806            let file = map.add("app.beck", app);
1807            let mut d = beck_diag::Diagnostics::new();
1808            let n = beck_syntax::parse_file(file, "app", app, &mut d);
1809            assert!(!d.has_errors(), "{}", d.render(&map));
1810            n
1811        };
1812        let mut d = beck_diag::Diagnostics::new();
1813        let imports = vec![("lib".to_string(), reread)];
1814        let mut map = beck_diag::SourceMap::new();
1815        map.add("app.beck", app);
1816        crate::check::check_module_with(&node, crate::check::Mode::Module, &imports, &mut d);
1817        assert!(!d.has_errors(), "{}", d.render(&map));
1818    }
1819
1820    // ------------------------------------------------------------------- generic arithmetic
1821
1822    const RATIONAL: &str = "\
1823model Rational:
1824    numer: Int
1825    denom: Int
1826
1827impl Num for Rational:
1828    def add(self, other):
1829        return Rational(numer=self.numer + other.numer, denom=self.denom)
1830
1831    def sub(self, other):
1832        return self
1833
1834    def mul(self, other):
1835        return self
1836
1837    def div(self, other):
1838        return self
1839";
1840
1841    #[test]
1842    fn a_user_type_joins_the_numeric_tower_through_num() {
1843        let src = format!(
1844            "{RATIONAL}
1845def sum(a: Rational, b: Rational) -> Rational:
1846    return a + b
1847
1848def rest(a: Rational, b: Rational) -> Rational:
1849    return (a - b) * (a / b)
1850"
1851        );
1852        assert_eq!(codes(&src), Vec::<&str>::new());
1853
1854        // `+` on a `Rational` is a call to the impl, not a primitive — which is what makes the
1855        // tower open rather than a list inside the compiler.
1856        let (program, _, _) = check_str("t.beck", &src);
1857        assert!(program.defs.contains_key("Num::add@Rational"));
1858    }
1859
1860    #[test]
1861    fn num_is_the_preludes_and_a_module_may_not_implement_it_for_a_type_it_does_not_own() {
1862        // `Num` arrives from the prelude, so `own_traits` does not contain it: the orphan rule's
1863        // "the trait or the type is declared here" leaves only the type, and `Int` is not.
1864        let src = "\
1865impl Num for Int:
1866    def add(self, other):
1867        return self
1868
1869    def sub(self, other):
1870        return self
1871
1872    def mul(self, other):
1873        return self
1874
1875    def div(self, other):
1876        return self
1877";
1878        assert!(codes(src).contains(&"B0385"), "{:?}", codes(src));
1879    }
1880
1881    #[test]
1882    fn a_declared_type_with_no_num_impl_is_told_how_to_join() {
1883        let src = "\
1884model Money:
1885    pence: Int
1886
1887def sum(a: Money, b: Money) -> Money:
1888    return a + b
1889";
1890        let text = errors(src);
1891        assert!(text.contains("B0387"), "{text}");
1892        assert!(text.contains("impl Num for Money"), "{text}");
1893    }
1894
1895    #[test]
1896    fn the_numeric_rule_is_unchanged_where_it_already_had_an_answer() {
1897        // The whole point of dispatching only when there is something to dispatch to. `1 + true`
1898        // is a mismatch and not a lecture about traits, and `1 + 1.0` still has no answer —
1899        // docs/27 §27.2's refusal to coerce is untouched.
1900        for (src, want) in [
1901            (
1902                "def f(n: Int, b: Bool) -> Int:\n    return n + b\n",
1903                "found `Bool`",
1904            ),
1905            (
1906                "def f(n: Int, x: Float) -> Float:\n    return n + x\n",
1907                "found `Float`",
1908            ),
1909        ] {
1910            let text = errors(src);
1911            assert!(text.contains("B0320"), "{text}");
1912            assert!(text.contains(want), "{text}");
1913        }
1914
1915        // And a `Str` still concatenates rather than looking for an impl.
1916        let ok = "def f(a: Str, b: Str) -> Str:\n    return a + b\n";
1917        assert_eq!(codes(ok), Vec::<&str>::new());
1918    }
1919
1920    #[test]
1921    fn a_bounded_type_parameter_may_use_the_operators() {
1922        // The two features meeting: `Num` is a trait like any other, so a bound on it hands the
1923        // body a dictionary and `a + b` inside a generic definition resolves to it.
1924        let src = format!(
1925            "{RATIONAL}
1926def twice[T: Num](x: T) -> T:
1927    return x + x
1928
1929def used(r: Rational) -> Rational:
1930    return twice(r)
1931"
1932        );
1933        assert_eq!(codes(&src), Vec::<&str>::new());
1934    }
1935
1936    #[test]
1937    fn a_method_name_belongs_to_one_trait() {
1938        let src = "\
1939trait Show:
1940    def show(self) -> Str
1941
1942trait Other:
1943    def show(self) -> Str
1944";
1945        assert!(codes(src).contains(&"B0381"), "{:?}", codes(src));
1946    }
1947
1948    #[test]
1949    fn a_trait_method_has_to_mention_self() {
1950        let src = "trait Show:\n    def show(n: Int) -> Str\n";
1951        let text = errors(src);
1952        assert!(text.contains("B0381"), "{text}");
1953        assert!(text.contains("nothing dispatches on it"), "{text}");
1954    }
1955
1956    #[test]
1957    fn a_trait_declares_signatures_and_not_bodies() {
1958        let src = "trait Show:\n    def show(self) -> Str:\n        return \"\"\n";
1959        let text = errors(src);
1960        assert!(text.contains("B0381"), "{text}");
1961        assert!(text.contains("has a body"), "{text}");
1962    }
1963}