]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ty_utils/src/assoc.rs
Auto merge of #98203 - kckeiks:gather-body-owners-in-hir-item-queries, r=cjgillot
[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, LocalDefId};
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| match associated_item.container {
48         ty::TraitContainer(def_id) => Some(def_id),
49         ty::ImplContainer(_) => None,
50     })
51 }
52
53 fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
54     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
55     let parent_def_id = tcx.hir().get_parent_item(id);
56     let parent_item = tcx.hir().expect_item(parent_def_id);
57     match parent_item.kind {
58         hir::ItemKind::Impl(ref impl_) => {
59             if let Some(impl_item_ref) =
60                 impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
61             {
62                 let assoc_item =
63                     associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
64                 debug_assert_eq!(assoc_item.def_id, def_id);
65                 return assoc_item;
66             }
67         }
68
69         hir::ItemKind::Trait(.., ref trait_item_refs) => {
70             if let Some(trait_item_ref) =
71                 trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
72             {
73                 let assoc_item =
74                     associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
75                 debug_assert_eq!(assoc_item.def_id, def_id);
76                 return assoc_item;
77             }
78         }
79
80         _ => {}
81     }
82
83     span_bug!(
84         parent_item.span,
85         "unexpected parent of trait or impl item or item not found: {:?}",
86         parent_item.kind
87     )
88 }
89
90 fn associated_item_from_trait_item_ref(
91     tcx: TyCtxt<'_>,
92     parent_def_id: LocalDefId,
93     trait_item_ref: &hir::TraitItemRef,
94 ) -> ty::AssocItem {
95     let def_id = trait_item_ref.id.def_id;
96     let (kind, has_self) = match trait_item_ref.kind {
97         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
98         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
99         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
100     };
101
102     ty::AssocItem {
103         name: trait_item_ref.ident.name,
104         kind,
105         vis: tcx.visibility(def_id),
106         defaultness: trait_item_ref.defaultness,
107         def_id: def_id.to_def_id(),
108         trait_item_def_id: Some(def_id.to_def_id()),
109         container: ty::TraitContainer(parent_def_id.to_def_id()),
110         fn_has_self_parameter: has_self,
111     }
112 }
113
114 fn associated_item_from_impl_item_ref(
115     tcx: TyCtxt<'_>,
116     parent_def_id: LocalDefId,
117     impl_item_ref: &hir::ImplItemRef,
118 ) -> ty::AssocItem {
119     let def_id = impl_item_ref.id.def_id;
120     let (kind, has_self) = match impl_item_ref.kind {
121         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
122         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
123         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
124     };
125
126     ty::AssocItem {
127         name: impl_item_ref.ident.name,
128         kind,
129         vis: tcx.visibility(def_id),
130         defaultness: impl_item_ref.defaultness,
131         def_id: def_id.to_def_id(),
132         trait_item_def_id: impl_item_ref.trait_item_def_id,
133         container: ty::ImplContainer(parent_def_id.to_def_id()),
134         fn_has_self_parameter: has_self,
135     }
136 }