]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ty_utils/src/assoc.rs
Avoid locking the global context across the `after_expansion` callback
[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         ..*providers
13     };
14 }
15
16 fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
17     let item = tcx.hir().expect_item(def_id.expect_local());
18     match item.kind {
19         hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
20             trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()),
21         ),
22         hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
23             impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
24         ),
25         hir::ItemKind::TraitAlias(..) => &[],
26         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
27     }
28 }
29
30 fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
31     let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
32     ty::AssocItems::new(items)
33 }
34
35 fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
36     tcx.associated_items(impl_id)
37         .in_definition_order()
38         .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
39         .collect()
40 }
41
42 fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
43     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
44     let parent_def_id = tcx.hir().get_parent_item(id);
45     let parent_item = tcx.hir().expect_item(parent_def_id.def_id);
46     match parent_item.kind {
47         hir::ItemKind::Impl(ref impl_) => {
48             if let Some(impl_item_ref) =
49                 impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
50             {
51                 let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
52                 debug_assert_eq!(assoc_item.def_id, def_id);
53                 return assoc_item;
54             }
55         }
56
57         hir::ItemKind::Trait(.., ref trait_item_refs) => {
58             if let Some(trait_item_ref) =
59                 trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
60             {
61                 let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
62                 debug_assert_eq!(assoc_item.def_id, def_id);
63                 return assoc_item;
64             }
65         }
66
67         _ => {}
68     }
69
70     span_bug!(
71         parent_item.span,
72         "unexpected parent of trait or impl item or item not found: {:?}",
73         parent_item.kind
74     )
75 }
76
77 fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
78     let owner_id = trait_item_ref.id.owner_id;
79     let (kind, has_self) = match trait_item_ref.kind {
80         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
81         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
82         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
83     };
84
85     ty::AssocItem {
86         name: trait_item_ref.ident.name,
87         kind,
88         def_id: owner_id.to_def_id(),
89         trait_item_def_id: Some(owner_id.to_def_id()),
90         container: ty::TraitContainer,
91         fn_has_self_parameter: has_self,
92     }
93 }
94
95 fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
96     let def_id = impl_item_ref.id.owner_id;
97     let (kind, has_self) = match impl_item_ref.kind {
98         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
99         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
100         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
101     };
102
103     ty::AssocItem {
104         name: impl_item_ref.ident.name,
105         kind,
106         def_id: def_id.to_def_id(),
107         trait_item_def_id: impl_item_ref.trait_item_def_id,
108         container: ty::ImplContainer,
109         fn_has_self_parameter: has_self,
110     }
111 }