1use std::collections::{HashMap, HashSet, VecDeque};
23
24use bock_air::{AIRNode, NodeKind};
25use bock_ast::TypePath;
26use bock_errors::{DiagnosticBag, DiagnosticCode};
27
28use crate::{GenericType, NamedType, PrimitiveType, Type};
29
30const E_COHERENCE_OVERLAP: DiagnosticCode = DiagnosticCode {
33 prefix: 'E',
34 number: 4010,
35};
36
37pub type ImplId = u32;
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
46pub struct TraitRef {
47 pub name: String,
49}
50
51impl TraitRef {
52 #[must_use]
54 pub fn new(name: impl Into<String>) -> Self {
55 Self { name: name.into() }
56 }
57
58 fn from_path(path: &TypePath) -> Self {
59 let name = path
60 .segments
61 .iter()
62 .map(|s| s.name.as_str())
63 .collect::<Vec<_>>()
64 .join(".");
65 Self { name }
66 }
67}
68
69#[derive(Debug, Clone)]
71pub struct ResolvedMethod {
72 pub impl_id: ImplId,
74 pub trait_ref: Option<TraitRef>,
76 pub method: String,
78}
79
80#[derive(Debug, Clone)]
84pub struct ImplEntry {
85 pub id: ImplId,
87 pub trait_ref: Option<TraitRef>,
89 pub type_key: String,
91 pub methods: Vec<String>,
93 pub is_generic: bool,
97}
98
99pub struct ImplTable {
115 entries: HashMap<ImplId, ImplEntry>,
117 trait_impl_index: HashMap<(String, String), ImplId>,
119 inherent_impl_index: HashMap<String, ImplId>,
121 supertraits: HashMap<String, Vec<String>>,
123 assoc_types: HashMap<(ImplId, String), Type>,
125 next_id: u32,
127 pub diags: DiagnosticBag,
129}
130
131impl ImplTable {
132 #[must_use]
134 pub fn new() -> Self {
135 Self {
136 entries: HashMap::new(),
137 trait_impl_index: HashMap::new(),
138 inherent_impl_index: HashMap::new(),
139 supertraits: HashMap::new(),
140 assoc_types: HashMap::new(),
141 next_id: 0,
142 diags: DiagnosticBag::new(),
143 }
144 }
145
146 #[must_use]
153 pub fn build_from(module: &AIRNode) -> Self {
154 let mut table = Self::new();
155 if let NodeKind::Module { items, .. } = &module.kind {
156 for item in items {
157 table.visit_item(item);
158 }
159 }
160 table
161 }
162
163 fn visit_item(&mut self, node: &AIRNode) {
164 match &node.kind {
165 NodeKind::ImplBlock {
166 trait_path,
167 target,
168 methods,
169 generic_params,
170 ..
171 } => {
172 let trait_ref = trait_path.as_ref().map(TraitRef::from_path);
173 let type_key = type_key_from_node(target);
174 let is_generic = !generic_params.is_empty();
175
176 if !is_generic {
178 if let Some(tr) = &trait_ref {
179 let index_key = (tr.name.clone(), type_key.clone());
180 if self.trait_impl_index.contains_key(&index_key) {
181 self.diags.error(
182 E_COHERENCE_OVERLAP,
183 format!(
184 "conflicting implementations of trait `{}` for type `{}`",
185 tr.name, type_key,
186 ),
187 node.span,
188 );
189 return;
190 }
191 }
192 }
193
194 let id = self.alloc_id();
195
196 let mut method_names = Vec::new();
198 for m in methods {
199 match &m.kind {
200 NodeKind::FnDecl { name, .. } => {
201 method_names.push(name.name.clone());
202 }
203 NodeKind::TypeAlias { name, ty, .. } => {
204 let resolved = type_from_node(ty);
206 self.assoc_types.insert((id, name.name.clone()), resolved);
207 }
208 _ => {}
209 }
210 }
211
212 if let Some(tr) = &trait_ref {
214 if !is_generic {
215 self.trait_impl_index
216 .insert((tr.name.clone(), type_key.clone()), id);
217 }
218 } else {
219 self.inherent_impl_index.insert(type_key.clone(), id);
221 }
222
223 self.entries.insert(
224 id,
225 ImplEntry {
226 id,
227 trait_ref,
228 type_key,
229 methods: method_names,
230 is_generic,
231 },
232 );
233 }
234
235 NodeKind::TraitDecl {
236 name,
237 generic_params,
238 ..
239 } => {
240 for param in generic_params {
243 if param.name.name == "Self" {
244 for bound in ¶m.bounds {
245 let supertrait = trait_name_from_path(bound);
246 self.register_supertrait(name.name.clone(), supertrait);
247 }
248 }
249 }
250 }
251
252 _ => {}
253 }
254 }
255
256 fn alloc_id(&mut self) -> ImplId {
257 let id = self.next_id;
258 self.next_id += 1;
259 id
260 }
261
262 pub fn register_supertrait(
265 &mut self,
266 sub_trait: impl Into<String>,
267 super_trait: impl Into<String>,
268 ) {
269 self.supertraits
270 .entry(sub_trait.into())
271 .or_default()
272 .push(super_trait.into());
273 }
274
275 pub fn register_trait_impl(&mut self, trait_name: impl Into<String>, ty: &Type) -> ImplId {
280 let id = self.alloc_id();
281 let trait_name = trait_name.into();
282 let key = type_key(ty);
283 self.entries.insert(
284 id,
285 ImplEntry {
286 id,
287 trait_ref: Some(TraitRef::new(&trait_name)),
288 type_key: key.clone(),
289 methods: vec![],
290 is_generic: false,
291 },
292 );
293 self.trait_impl_index.insert((trait_name, key), id);
294 id
295 }
296
297 pub fn register_assoc_type(&mut self, impl_id: ImplId, name: impl Into<String>, ty: Type) {
301 self.assoc_types.insert((impl_id, name.into()), ty);
302 }
303
304 #[must_use]
308 pub fn resolve_assoc_type(&self, impl_id: ImplId, name: &str) -> Option<&Type> {
309 self.assoc_types.get(&(impl_id, name.to_owned()))
310 }
311
312 #[must_use]
318 pub fn all_supertraits(&self, trait_name: &str) -> Vec<String> {
319 let mut result = Vec::new();
320 let mut visited: HashSet<String> = HashSet::new();
321 let mut queue: VecDeque<String> = VecDeque::new();
322
323 if let Some(direct) = self.supertraits.get(trait_name) {
324 for st in direct {
325 if visited.insert(st.clone()) {
326 queue.push_back(st.clone());
327 }
328 }
329 }
330
331 while let Some(name) = queue.pop_front() {
332 result.push(name.clone());
333 if let Some(supers) = self.supertraits.get(&name) {
334 for st in supers {
335 if visited.insert(st.clone()) {
336 queue.push_back(st.clone());
337 }
338 }
339 }
340 }
341
342 result
343 }
344
345 #[must_use]
347 pub fn get_entry(&self, id: ImplId) -> Option<&ImplEntry> {
348 self.entries.get(&id)
349 }
350
351 pub fn entries(&self) -> impl Iterator<Item = &ImplEntry> {
353 self.entries.values()
354 }
355
356 fn find_trait_impl(&self, trait_name: &str, type_key: &str) -> Option<ImplId> {
359 self.trait_impl_index
360 .get(&(trait_name.to_owned(), type_key.to_owned()))
361 .copied()
362 }
363
364 fn find_inherent_impl(&self, type_key: &str) -> Option<ImplId> {
365 self.inherent_impl_index.get(type_key).copied()
366 }
367}
368
369impl Default for ImplTable {
370 fn default() -> Self {
371 Self::new()
372 }
373}
374
375#[must_use]
386pub fn resolve_impl(trait_ref: &TraitRef, ty: &Type, impls: &ImplTable) -> Option<ImplId> {
387 let key = type_key(ty);
388 impls.find_trait_impl(&trait_ref.name, &key)
389}
390
391#[must_use]
397pub fn check_supertrait_obligations(trait_ref: &TraitRef, ty: &Type, impls: &ImplTable) -> bool {
398 let key = type_key(ty);
399 for supertrait in impls.all_supertraits(&trait_ref.name) {
400 if impls.find_trait_impl(&supertrait, &key).is_none() {
401 return false;
402 }
403 }
404 true
405}
406
407#[must_use]
415pub fn resolve_method(receiver: &Type, method: &str, impls: &ImplTable) -> Option<ResolvedMethod> {
416 let key = type_key(receiver);
417
418 if let Some(impl_id) = impls.find_inherent_impl(&key) {
420 if let Some(entry) = impls.get_entry(impl_id) {
421 if entry.methods.iter().any(|m| m == method) {
422 return Some(ResolvedMethod {
423 impl_id,
424 trait_ref: None,
425 method: method.to_owned(),
426 });
427 }
428 }
429 }
430
431 for entry in impls.entries() {
433 if entry.type_key == key
434 && entry.trait_ref.is_some()
435 && entry.methods.iter().any(|m| m == method)
436 {
437 return Some(ResolvedMethod {
438 impl_id: entry.id,
439 trait_ref: entry.trait_ref.clone(),
440 method: method.to_owned(),
441 });
442 }
443 }
444
445 None
446}
447
448#[must_use]
456pub fn type_key(ty: &Type) -> String {
457 match ty {
458 Type::Primitive(p) => format!("{p:?}"),
459 Type::Named(n) => n.name.clone(),
460 Type::Generic(g) => {
461 let args = g.args.iter().map(type_key).collect::<Vec<_>>().join(", ");
462 format!("{}[{}]", g.constructor, args)
463 }
464 Type::Tuple(elems) => {
465 let elems = elems.iter().map(type_key).collect::<Vec<_>>().join(", ");
466 format!("({})", elems)
467 }
468 Type::Function(f) => {
469 let params = f.params.iter().map(type_key).collect::<Vec<_>>().join(", ");
470 format!("Fn({}) -> {}", params, type_key(&f.ret))
471 }
472 Type::Optional(inner) => format!("{}?", type_key(inner)),
473 Type::Result(ok, err) => format!("Result[{}, {}]", type_key(ok), type_key(err)),
474 Type::TypeVar(id) => format!("?{id}"),
475 Type::Refined(base, _) => type_key(base),
476 Type::Flexible(_) => "Flexible".to_string(),
477 Type::Error => "Error".to_string(),
478 }
479}
480
481fn trait_name_from_path(path: &TypePath) -> String {
483 path.segments
484 .iter()
485 .map(|s| s.name.as_str())
486 .collect::<Vec<_>>()
487 .join(".")
488}
489
490fn type_key_from_node(node: &AIRNode) -> String {
494 match &node.kind {
495 NodeKind::TypeNamed { path, args } => {
496 let name = path
497 .segments
498 .iter()
499 .map(|s| s.name.as_str())
500 .collect::<Vec<_>>()
501 .join(".");
502 if args.is_empty() {
503 name
504 } else {
505 let arg_keys: Vec<_> = args.iter().map(type_key_from_node).collect();
506 format!("{}[{}]", name, arg_keys.join(", "))
507 }
508 }
509 NodeKind::TypeTuple { elems } => {
510 let elem_keys: Vec<_> = elems.iter().map(type_key_from_node).collect();
511 format!("({})", elem_keys.join(", "))
512 }
513 NodeKind::TypeOptional { inner } => format!("{}?", type_key_from_node(inner)),
514 NodeKind::TypeFunction { params, ret, .. } => {
515 let param_keys: Vec<_> = params.iter().map(type_key_from_node).collect();
516 format!(
517 "Fn({}) -> {}",
518 param_keys.join(", "),
519 type_key_from_node(ret)
520 )
521 }
522 NodeKind::TypeSelf => "Self".to_string(),
523 _ => "Unknown".to_string(),
524 }
525}
526
527fn type_from_node(node: &AIRNode) -> Type {
532 match &node.kind {
533 NodeKind::TypeNamed { path, args } => {
534 let name = path
535 .segments
536 .iter()
537 .map(|s| s.name.as_str())
538 .collect::<Vec<_>>()
539 .join(".");
540 if args.is_empty() {
541 match name.as_str() {
542 "Int" => Type::Primitive(PrimitiveType::Int),
543 "Float" => Type::Primitive(PrimitiveType::Float),
544 "Bool" => Type::Primitive(PrimitiveType::Bool),
545 "String" => Type::Primitive(PrimitiveType::String),
546 "Char" => Type::Primitive(PrimitiveType::Char),
547 "Void" => Type::Primitive(PrimitiveType::Void),
548 "Never" => Type::Primitive(PrimitiveType::Never),
549 _ => Type::Named(NamedType { name }),
550 }
551 } else {
552 let type_args: Vec<_> = args.iter().map(type_from_node).collect();
553 Type::Generic(GenericType {
554 constructor: name,
555 args: type_args,
556 })
557 }
558 }
559 NodeKind::TypeOptional { inner } => Type::Optional(Box::new(type_from_node(inner))),
560 NodeKind::TypeTuple { elems } => Type::Tuple(elems.iter().map(type_from_node).collect()),
561 NodeKind::TypeSelf => Type::Named(NamedType {
562 name: "Self".to_owned(),
563 }),
564 _ => Type::Error,
565 }
566}
567
568#[cfg(test)]
571mod tests {
572 use super::*;
573 use crate::{NamedType, PrimitiveType, Type};
574
575 fn named(name: &str) -> Type {
578 Type::Named(NamedType {
579 name: name.to_owned(),
580 })
581 }
582
583 fn int() -> Type {
584 Type::Primitive(PrimitiveType::Int)
585 }
586
587 fn bool_ty() -> Type {
588 Type::Primitive(PrimitiveType::Bool)
589 }
590
591 fn dummy_span() -> bock_errors::Span {
592 use bock_errors::{FileId, Span};
593 Span {
594 file: FileId(0),
595 start: 0,
596 end: 0,
597 }
598 }
599
600 fn make_air_node(kind: NodeKind) -> AIRNode {
601 AIRNode::new(0, dummy_span(), kind)
602 }
603
604 fn make_module(items: Vec<AIRNode>) -> AIRNode {
605 make_air_node(NodeKind::Module {
606 path: None,
607 annotations: vec![],
608 imports: vec![],
609 items,
610 })
611 }
612
613 fn make_type_named(name: &str) -> AIRNode {
614 use bock_ast::{Ident, TypePath};
615 let ident = Ident {
616 name: name.to_owned(),
617 span: dummy_span(),
618 };
619 make_air_node(NodeKind::TypeNamed {
620 path: TypePath {
621 segments: vec![ident],
622 span: dummy_span(),
623 },
624 args: vec![],
625 })
626 }
627
628 fn make_fn_decl(name: &str) -> AIRNode {
629 use bock_ast::{Ident, Visibility};
630 let body = make_air_node(NodeKind::Block {
631 stmts: vec![],
632 tail: None,
633 });
634 make_air_node(NodeKind::FnDecl {
635 annotations: vec![],
636 visibility: Visibility::Private,
637 is_async: false,
638 name: Ident {
639 name: name.to_owned(),
640 span: dummy_span(),
641 },
642 generic_params: vec![],
643 params: vec![],
644 return_type: None,
645 effect_clause: vec![],
646 where_clause: vec![],
647 body: Box::new(body),
648 })
649 }
650
651 fn make_impl_block(
652 trait_name: Option<&str>,
653 target_name: &str,
654 methods: Vec<AIRNode>,
655 ) -> AIRNode {
656 use bock_ast::{Ident, TypePath};
657 let trait_path = trait_name.map(|n| TypePath {
658 segments: vec![Ident {
659 name: n.to_owned(),
660 span: dummy_span(),
661 }],
662 span: dummy_span(),
663 });
664 make_air_node(NodeKind::ImplBlock {
665 annotations: vec![],
666 generic_params: vec![],
667 trait_path,
668 target: Box::new(make_type_named(target_name)),
669 where_clause: vec![],
670 methods,
671 })
672 }
673
674 #[test]
677 fn type_key_primitive() {
678 assert_eq!(type_key(&int()), "Int");
679 assert_eq!(type_key(&bool_ty()), "Bool");
680 }
681
682 #[test]
683 fn type_key_named() {
684 assert_eq!(type_key(&named("User")), "User");
685 }
686
687 #[test]
688 fn type_key_generic() {
689 use crate::GenericType;
690 let ty = Type::Generic(GenericType {
691 constructor: "List".to_owned(),
692 args: vec![int()],
693 });
694 assert_eq!(type_key(&ty), "List[Int]");
695 }
696
697 #[test]
698 fn type_key_optional() {
699 assert_eq!(type_key(&Type::Optional(Box::new(int()))), "Int?");
700 }
701
702 #[test]
703 fn type_key_result() {
704 assert_eq!(
705 type_key(&Type::Result(Box::new(int()), Box::new(named("Err")))),
706 "Result[Int, Err]"
707 );
708 }
709
710 #[test]
713 fn build_empty_module() {
714 let module = make_module(vec![]);
715 let table = ImplTable::build_from(&module);
716 assert!(!table.diags.has_errors());
717 assert_eq!(table.entries.len(), 0);
718 }
719
720 #[test]
721 fn build_registers_trait_impl() {
722 let eq_method = make_fn_decl("equals");
723 let impl_block = make_impl_block(Some("Equatable"), "User", vec![eq_method]);
724 let module = make_module(vec![impl_block]);
725 let table = ImplTable::build_from(&module);
726 assert!(!table.diags.has_errors());
727 let id = resolve_impl(&TraitRef::new("Equatable"), &named("User"), &table);
728 assert!(id.is_some());
729 }
730
731 #[test]
732 fn build_registers_inherent_impl() {
733 let method = make_fn_decl("greet");
734 let impl_block = make_impl_block(None, "User", vec![method]);
735 let module = make_module(vec![impl_block]);
736 let table = ImplTable::build_from(&module);
737 let result = resolve_method(&named("User"), "greet", &table);
738 assert!(result.is_some());
739 let r = result.unwrap();
740 assert!(r.trait_ref.is_none());
741 assert_eq!(r.method, "greet");
742 }
743
744 #[test]
747 fn resolve_impl_found() {
748 let mut table = ImplTable::new();
749 let id = table.alloc_id();
750 table.entries.insert(
751 id,
752 ImplEntry {
753 id,
754 trait_ref: Some(TraitRef::new("Printable")),
755 type_key: "Int".to_owned(),
756 methods: vec!["print".to_owned()],
757 is_generic: false,
758 },
759 );
760 table
761 .trait_impl_index
762 .insert(("Printable".to_owned(), "Int".to_owned()), id);
763
764 assert_eq!(
765 resolve_impl(&TraitRef::new("Printable"), &int(), &table),
766 Some(id)
767 );
768 }
769
770 #[test]
771 fn resolve_impl_not_found() {
772 let table = ImplTable::new();
773 assert_eq!(
774 resolve_impl(&TraitRef::new("Printable"), &int(), &table),
775 None
776 );
777 }
778
779 #[test]
780 fn resolve_impl_wrong_type() {
781 let mut table = ImplTable::new();
782 let id = table.alloc_id();
783 table.entries.insert(
784 id,
785 ImplEntry {
786 id,
787 trait_ref: Some(TraitRef::new("Printable")),
788 type_key: "Int".to_owned(),
789 methods: vec!["print".to_owned()],
790 is_generic: false,
791 },
792 );
793 table
794 .trait_impl_index
795 .insert(("Printable".to_owned(), "Int".to_owned()), id);
796
797 assert_eq!(
799 resolve_impl(&TraitRef::new("Printable"), &bool_ty(), &table),
800 None
801 );
802 }
803
804 #[test]
807 fn resolve_method_inherent() {
808 let method = make_fn_decl("to_string");
809 let impl_block = make_impl_block(None, "User", vec![method]);
810 let module = make_module(vec![impl_block]);
811 let table = ImplTable::build_from(&module);
812
813 let r = resolve_method(&named("User"), "to_string", &table);
814 assert!(r.is_some());
815 let r = r.unwrap();
816 assert!(r.trait_ref.is_none());
817 assert_eq!(r.method, "to_string");
818 }
819
820 #[test]
821 fn resolve_method_from_trait_impl() {
822 let method = make_fn_decl("serialize");
823 let impl_block = make_impl_block(Some("Serializable"), "User", vec![method]);
824 let module = make_module(vec![impl_block]);
825 let table = ImplTable::build_from(&module);
826
827 let r = resolve_method(&named("User"), "serialize", &table);
828 assert!(r.is_some());
829 let r = r.unwrap();
830 assert_eq!(
831 r.trait_ref.as_ref().map(|t| t.name.as_str()),
832 Some("Serializable")
833 );
834 assert_eq!(r.method, "serialize");
835 }
836
837 #[test]
838 fn resolve_method_not_found() {
839 let table = ImplTable::new();
840 assert!(resolve_method(&int(), "foo", &table).is_none());
841 }
842
843 #[test]
844 fn resolve_method_inherent_takes_priority_over_trait() {
845 let inherent_method = make_fn_decl("display");
846 let trait_method = make_fn_decl("display");
847 let inherent_impl = make_impl_block(None, "User", vec![inherent_method]);
848 let trait_impl = make_impl_block(Some("Display"), "User", vec![trait_method]);
849 let module = make_module(vec![inherent_impl, trait_impl]);
850 let table = ImplTable::build_from(&module);
851
852 let r = resolve_method(&named("User"), "display", &table).unwrap();
853 assert!(r.trait_ref.is_none());
855 }
856
857 #[test]
860 fn coherence_detects_exact_overlap() {
861 let impl1 = make_impl_block(Some("Equatable"), "Point", vec![make_fn_decl("equals")]);
862 let impl2 = make_impl_block(Some("Equatable"), "Point", vec![make_fn_decl("equals")]);
863 let module = make_module(vec![impl1, impl2]);
864 let table = ImplTable::build_from(&module);
865
866 assert!(table.diags.has_errors());
867 assert_eq!(table.diags.error_count(), 1);
868 }
869
870 #[test]
871 fn coherence_allows_different_types() {
872 let impl1 = make_impl_block(Some("Equatable"), "Int", vec![make_fn_decl("equals")]);
873 let impl2 = make_impl_block(Some("Equatable"), "Bool", vec![make_fn_decl("equals")]);
874 let module = make_module(vec![impl1, impl2]);
875 let table = ImplTable::build_from(&module);
876
877 assert!(!table.diags.has_errors());
878 }
879
880 #[test]
881 fn coherence_allows_different_traits() {
882 let impl1 = make_impl_block(Some("Equatable"), "Point", vec![make_fn_decl("equals")]);
883 let impl2 = make_impl_block(Some("Comparable"), "Point", vec![make_fn_decl("compare")]);
884 let module = make_module(vec![impl1, impl2]);
885 let table = ImplTable::build_from(&module);
886
887 assert!(!table.diags.has_errors());
888 }
889
890 #[test]
891 fn coherence_skips_generic_impls() {
892 use bock_ast::{GenericParam, Ident, TypePath};
893
894 let generic_param = GenericParam {
895 id: 0,
896 span: dummy_span(),
897 name: Ident {
898 name: "T".to_owned(),
899 span: dummy_span(),
900 },
901 bounds: vec![],
902 };
903 let impl1 = make_air_node(NodeKind::ImplBlock {
904 annotations: vec![],
905 generic_params: vec![generic_param.clone()],
906 trait_path: Some(TypePath {
907 segments: vec![Ident {
908 name: "Printable".to_owned(),
909 span: dummy_span(),
910 }],
911 span: dummy_span(),
912 }),
913 target: Box::new(make_type_named("T")),
914 where_clause: vec![],
915 methods: vec![],
916 });
917 let impl2 = make_air_node(NodeKind::ImplBlock {
918 annotations: vec![],
919 generic_params: vec![generic_param],
920 trait_path: Some(TypePath {
921 segments: vec![Ident {
922 name: "Printable".to_owned(),
923 span: dummy_span(),
924 }],
925 span: dummy_span(),
926 }),
927 target: Box::new(make_type_named("T")),
928 where_clause: vec![],
929 methods: vec![],
930 });
931 let module = make_module(vec![impl1, impl2]);
932 let table = ImplTable::build_from(&module);
933
934 assert!(!table.diags.has_errors());
936 }
937
938 #[test]
941 fn supertrait_registration_and_lookup() {
942 let mut table = ImplTable::new();
943 table.register_supertrait("Hashable", "Equatable");
944 let supers = table.all_supertraits("Hashable");
945 assert_eq!(supers, vec!["Equatable"]);
946 }
947
948 #[test]
949 fn supertrait_transitive() {
950 let mut table = ImplTable::new();
951 table.register_supertrait("C", "B");
952 table.register_supertrait("B", "A");
953 let supers = table.all_supertraits("C");
954 assert_eq!(supers, vec!["B", "A"]);
955 }
956
957 #[test]
958 fn check_supertrait_obligations_satisfied() {
959 let mut table = ImplTable::new();
960 table.register_supertrait("Hashable", "Equatable");
961
962 let eq_method = make_fn_decl("equals");
964 let hash_method = make_fn_decl("hash");
965 let eq_impl = make_impl_block(Some("Equatable"), "User", vec![eq_method]);
966 let hash_impl = make_impl_block(Some("Hashable"), "User", vec![hash_method]);
967 let module = make_module(vec![eq_impl, hash_impl]);
968 let table_built = ImplTable::build_from(&module);
969
970 let mut full_table = table_built;
972 full_table.register_supertrait("Hashable", "Equatable");
973
974 assert!(check_supertrait_obligations(
975 &TraitRef::new("Hashable"),
976 &named("User"),
977 &full_table
978 ));
979 }
980
981 #[test]
982 fn check_supertrait_obligations_missing() {
983 let mut table = ImplTable::new();
984 table.register_supertrait("Hashable", "Equatable");
985
986 let hash_method = make_fn_decl("hash");
988 let hash_impl = make_impl_block(Some("Hashable"), "User", vec![hash_method]);
989 let module = make_module(vec![hash_impl]);
990 let table_built = ImplTable::build_from(&module);
991 let mut full_table = table_built;
992 full_table.register_supertrait("Hashable", "Equatable");
993
994 assert!(!check_supertrait_obligations(
996 &TraitRef::new("Hashable"),
997 &named("User"),
998 &full_table
999 ));
1000 }
1001
1002 #[test]
1005 fn assoc_type_manual_registration() {
1006 let mut table = ImplTable::new();
1007 let impl_id = table.alloc_id();
1008 table.register_assoc_type(impl_id, "Item", int());
1009
1010 assert_eq!(table.resolve_assoc_type(impl_id, "Item"), Some(&int()));
1011 assert_eq!(table.resolve_assoc_type(impl_id, "Missing"), None);
1012 }
1013
1014 #[test]
1015 fn assoc_type_not_found_for_other_impl() {
1016 let mut table = ImplTable::new();
1017 let id1 = table.alloc_id();
1018 let id2 = table.alloc_id();
1019 table.register_assoc_type(id1, "Item", int());
1020
1021 assert_eq!(table.resolve_assoc_type(id2, "Item"), None);
1022 }
1023
1024 #[test]
1027 fn resolve_method_on_generic_type() {
1028 let method = make_fn_decl("push");
1029 let impl_block = make_impl_block(None, "List", vec![method]);
1030 let module = make_module(vec![impl_block]);
1031 let table = ImplTable::build_from(&module);
1032
1033 let receiver = Type::Named(NamedType {
1037 name: "List".to_owned(),
1038 });
1039 let r = resolve_method(&receiver, "push", &table);
1040 assert!(r.is_some());
1041 }
1042}