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