]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ty_utils/src/assoc.rs
db4f53aace4dbd7d83c74675dcda069a715808d8
[rust.git] / compiler / rustc_ty_utils / src / assoc.rs
1 use rustc_data_structures::fx::FxHashMap;
2 use rustc_hir as hir;
3 use rustc_hir::def_id::DefId;
4 use rustc_middle::ty::{self, TyCtxt};
5
6 pub fn provide(providers: &mut ty::query::Providers) {
7     *providers = ty::query::Providers {
8         associated_item,
9         associated_item_def_ids,
10         associated_items,
11         impl_item_implementor_ids,
12         trait_of_item,
13         ..*providers
14     };
15 }
16
17 fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
18     let item = tcx.hir().expect_item(def_id.expect_local());
19     match item.kind {
20         hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
21             trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
22         ),
23         hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
24             impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
25         ),
26         hir::ItemKind::TraitAlias(..) => &[],
27         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
28     }
29 }
30
31 fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
32     let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
33     ty::AssocItems::new(items)
34 }
35
36 fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
37     tcx.associated_items(impl_id)
38         .in_definition_order()
39         .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
40         .collect()
41 }
42
43 /// If the given `DefId` describes an item belonging to a trait,
44 /// returns the `DefId` of the trait that the trait item belongs to;
45 /// otherwise, returns `None`.
46 fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
47     tcx.opt_associated_item(def_id).and_then(|associated_item| associated_item.trait_container(tcx))
48 }
49
50 fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
51     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
52     let parent_def_id = tcx.hir().get_parent_item(id);
53     let parent_item = tcx.hir().expect_item(parent_def_id);
54     match parent_item.kind {
55         hir::ItemKind::Impl(ref impl_) => {
56             if let Some(impl_item_ref) =
57                 impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
58             {
59                 let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
60                 debug_assert_eq!(assoc_item.def_id, def_id);
61                 return assoc_item;
62             }
63         }
64
65         hir::ItemKind::Trait(.., ref trait_item_refs) => {
66             if let Some(trait_item_ref) =
67                 trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
68             {
69                 let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
70                 debug_assert_eq!(assoc_item.def_id, def_id);
71                 return assoc_item;
72             }
73         }
74
75         _ => {}
76     }
77
78     span_bug!(
79         parent_item.span,
80         "unexpected parent of trait or impl item or item not found: {:?}",
81         parent_item.kind
82     )
83 }
84
85 fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
86     let def_id = trait_item_ref.id.def_id;
87     let (kind, has_self) = match trait_item_ref.kind {
88         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
89         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
90         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
91     };
92
93     ty::AssocItem {
94         name: trait_item_ref.ident.name,
95         kind,
96         def_id: def_id.to_def_id(),
97         trait_item_def_id: Some(def_id.to_def_id()),
98         container: ty::TraitContainer,
99         fn_has_self_parameter: has_self,
100     }
101 }
102
103 fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
104     let def_id = impl_item_ref.id.def_id;
105     let (kind, has_self) = match impl_item_ref.kind {
106         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
107         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
108         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
109     };
110
111     ty::AssocItem {
112         name: impl_item_ref.ident.name,
113         kind,
114         def_id: def_id.to_def_id(),
115         trait_item_def_id: impl_item_ref.trait_item_def_id,
116         container: ty::ImplContainer,
117         fn_has_self_parameter: has_self,
118     }
119 }