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