]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/assoc.rs
Auto merge of #107241 - clubby789:bootstrap-lto-off, r=simulacrum
[rust.git] / compiler / rustc_middle / src / ty / assoc.rs
1 pub use self::AssocItemContainer::*;
2
3 use crate::ty::{self, DefIdTree};
4 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
5 use rustc_hir as hir;
6 use rustc_hir::def::{DefKind, Namespace};
7 use rustc_hir::def_id::DefId;
8 use rustc_span::symbol::{Ident, Symbol};
9
10 use super::{TyCtxt, Visibility};
11
12 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
13 pub enum AssocItemContainer {
14     TraitContainer,
15     ImplContainer,
16 }
17
18 /// Information about an associated item
19 #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
20 pub struct AssocItem {
21     pub def_id: DefId,
22     pub name: Symbol,
23     pub kind: AssocKind,
24     pub container: AssocItemContainer,
25
26     /// If this is an item in an impl of a trait then this is the `DefId` of
27     /// the associated item on the trait that this implements.
28     pub trait_item_def_id: Option<DefId>,
29
30     /// Whether this is a method with an explicit self
31     /// as its first parameter, allowing method calls.
32     pub fn_has_self_parameter: bool,
33 }
34
35 impl AssocItem {
36     pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
37         Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
38     }
39
40     /// Gets the defaultness of the associated item.
41     /// To get the default associated type, use the [`type_of`] query on the
42     /// [`DefId`] of the type.
43     ///
44     /// [`type_of`]: crate::ty::TyCtxt::type_of
45     pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
46         tcx.impl_defaultness(self.def_id)
47     }
48
49     #[inline]
50     pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
51         tcx.visibility(self.def_id)
52     }
53
54     #[inline]
55     pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
56         tcx.parent(self.def_id)
57     }
58
59     #[inline]
60     pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
61         match self.container {
62             AssocItemContainer::ImplContainer => None,
63             AssocItemContainer::TraitContainer => Some(tcx.parent(self.def_id)),
64         }
65     }
66
67     #[inline]
68     pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
69         match self.container {
70             AssocItemContainer::ImplContainer => Some(tcx.parent(self.def_id)),
71             AssocItemContainer::TraitContainer => None,
72         }
73     }
74
75     pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
76         match self.kind {
77             ty::AssocKind::Fn => {
78                 // We skip the binder here because the binder would deanonymize all
79                 // late-bound regions, and we don't want method signatures to show up
80                 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
81                 // regions just fine, showing `fn(&MyType)`.
82                 tcx.fn_sig(self.def_id).subst_identity().skip_binder().to_string()
83             }
84             ty::AssocKind::Type => format!("type {};", self.name),
85             ty::AssocKind::Const => {
86                 format!("const {}: {:?};", self.name, tcx.type_of(self.def_id))
87             }
88         }
89     }
90 }
91
92 #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
93 pub enum AssocKind {
94     Const,
95     Fn,
96     Type,
97 }
98
99 impl AssocKind {
100     pub fn namespace(&self) -> Namespace {
101         match *self {
102             ty::AssocKind::Type => Namespace::TypeNS,
103             ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
104         }
105     }
106
107     pub fn as_def_kind(&self) -> DefKind {
108         match self {
109             AssocKind::Const => DefKind::AssocConst,
110             AssocKind::Fn => DefKind::AssocFn,
111             AssocKind::Type => DefKind::AssocTy,
112         }
113     }
114 }
115
116 impl std::fmt::Display for AssocKind {
117     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118         match self {
119             AssocKind::Fn => write!(f, "method"),
120             AssocKind::Const => write!(f, "associated const"),
121             AssocKind::Type => write!(f, "associated type"),
122         }
123     }
124 }
125
126 /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
127 ///
128 /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
129 /// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is
130 /// done only on items with the same name.
131 #[derive(Debug, Clone, PartialEq, HashStable)]
132 pub struct AssocItems<'tcx> {
133     items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
134 }
135
136 impl<'tcx> AssocItems<'tcx> {
137     /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
138     pub fn new(items_in_def_order: impl IntoIterator<Item = &'tcx ty::AssocItem>) -> Self {
139         let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
140         AssocItems { items }
141     }
142
143     /// Returns a slice of associated items in the order they were defined.
144     ///
145     /// New code should avoid relying on definition order. If you need a particular associated item
146     /// for a known trait, make that trait a lang item instead of indexing this array.
147     pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
148         self.items.iter().map(|(_, v)| *v)
149     }
150
151     pub fn len(&self) -> usize {
152         self.items.len()
153     }
154
155     /// Returns an iterator over all associated items with the given name, ignoring hygiene.
156     pub fn filter_by_name_unhygienic(
157         &self,
158         name: Symbol,
159     ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
160         self.items.get_by_key(name).copied()
161     }
162
163     /// Returns the associated item with the given name and `AssocKind`, if one exists.
164     pub fn find_by_name_and_kind(
165         &self,
166         tcx: TyCtxt<'_>,
167         ident: Ident,
168         kind: AssocKind,
169         parent_def_id: DefId,
170     ) -> Option<&ty::AssocItem> {
171         self.filter_by_name_unhygienic(ident.name)
172             .filter(|item| item.kind == kind)
173             .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
174     }
175
176     /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
177     pub fn find_by_name_and_kinds(
178         &self,
179         tcx: TyCtxt<'_>,
180         ident: Ident,
181         // Sorted in order of what kinds to look at
182         kinds: &[AssocKind],
183         parent_def_id: DefId,
184     ) -> Option<&ty::AssocItem> {
185         kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
186     }
187
188     /// Returns the associated item with the given name in the given `Namespace`, if one exists.
189     pub fn find_by_name_and_namespace(
190         &self,
191         tcx: TyCtxt<'_>,
192         ident: Ident,
193         ns: Namespace,
194         parent_def_id: DefId,
195     ) -> Option<&ty::AssocItem> {
196         self.filter_by_name_unhygienic(ident.name)
197             .filter(|item| item.kind.namespace() == ns)
198             .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
199     }
200 }