1use 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
82pub(crate) fn mangle(trait_name: &str, method: &str, target: &str) -> Arc<str> {
88 Arc::from(format!("{trait_name}::{method}@{target}"))
89}
90
91pub fn is_impl_method(name: &str) -> bool {
93 name.contains("::") && name.contains('@')
94}
95
96#[derive(Clone, Debug)]
102pub(super) struct TraitDecl {
103 pub methods: Vec<TraitMethod>,
104 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#[derive(Clone, Debug)]
122pub(super) struct ImplDecl {
123 pub target: Arc<str>,
126 pub sig: ImplSig,
128 pub span: Span,
129}
130
131const SELF: &str = "Self";
133
134const FN_TYPE: &str = "fn-type";
136
137#[derive(Clone, Debug)]
139pub(super) struct DictParam {
140 pub param: Arc<str>,
142 pub trait_name: Arc<str>,
143 pub method: Arc<str>,
144}
145
146pub(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
158pub(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 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 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 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 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 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 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 ¶ms.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 (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 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 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 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 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 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 effects: Vec::new(),
533 }
534 };
535
536 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 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 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 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 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 let mut fn_ty: Vec<Node> = m
789 .params
790 .args
791 .iter()
792 .map(|p| substitute_self(&p.args[1], ¶m_node))
793 .collect();
794 fn_ty.push(substitute_self(&m.returns.args[0], ¶m_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 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 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 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, ¶m_tys[..ordinary]);
890 if let Some(want) = expected {
891 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 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 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 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 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 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 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 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 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
1182fn 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 Ty::Var(_) => Node::sym(Ty::UNIT, span),
1206 }
1207}
1208
1209fn mentions(n: &Node, name: &str) -> bool {
1211 n.head_name() == Some(name) || n.args.iter().any(|a| mentions(a, name))
1212}
1213
1214fn 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
1231fn 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 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 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 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 let src = "\
1363impl Show for Int:
1364 def show(self):
1365 return \"\"
1366";
1367 assert!(codes(src).contains(&"B0383"), "{:?}", codes(src));
1369
1370 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 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 #[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 #[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}