1use rustc_data_structures::sorted_map::SortedIndexMultiMap;
2use rustc_hir as hir;
3use rustc_hir::def::{DefKind, Namespace};
4use rustc_hir::def_id::DefId;
5use rustc_macros::{Decodable, Encodable, HashStable};
6use rustc_span::{Ident, Symbol, sym};
7
8use super::{TyCtxt, Visibility};
9use crate::ty;
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
12pub enum AssocItemContainer {
13 Trait,
14 Impl,
15}
16
17#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
19pub struct AssocItem {
20 pub def_id: DefId,
21 pub kind: AssocKind,
22 pub container: AssocItemContainer,
23
24 pub trait_item_def_id: Option<DefId>,
27}
28
29impl AssocItem {
30 pub fn opt_name(&self) -> Option<Symbol> {
32 match self.kind {
33 ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name),
34 ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None,
35 ty::AssocKind::Const { name } => Some(name),
36 ty::AssocKind::Fn { name, .. } => Some(name),
37 }
38 }
39
40 pub fn name(&self) -> Symbol {
43 self.opt_name().expect("name of non-Rpitit assoc item")
44 }
45
46 pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
47 Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap())
48 }
49
50 pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
56 tcx.defaultness(self.def_id)
57 }
58
59 #[inline]
60 pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
61 tcx.visibility(self.def_id)
62 }
63
64 #[inline]
65 pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
66 tcx.parent(self.def_id)
67 }
68
69 #[inline]
70 pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
71 match self.container {
72 AssocItemContainer::Impl => None,
73 AssocItemContainer::Trait => Some(tcx.parent(self.def_id)),
74 }
75 }
76
77 #[inline]
78 pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
79 match self.container {
80 AssocItemContainer::Impl => Some(tcx.parent(self.def_id)),
81 AssocItemContainer::Trait => None,
82 }
83 }
84
85 pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
86 match self.kind {
87 ty::AssocKind::Fn { .. } => {
88 tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
93 }
94 ty::AssocKind::Type { .. } => format!("type {};", self.name()),
95 ty::AssocKind::Const { name } => {
96 format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
97 }
98 }
99 }
100
101 pub fn descr(&self) -> &'static str {
102 match self.kind {
103 ty::AssocKind::Const { .. } => "associated const",
104 ty::AssocKind::Fn { has_self: true, .. } => "method",
105 ty::AssocKind::Fn { has_self: false, .. } => "associated function",
106 ty::AssocKind::Type { .. } => "associated type",
107 }
108 }
109
110 pub fn namespace(&self) -> Namespace {
111 match self.kind {
112 ty::AssocKind::Type { .. } => Namespace::TypeNS,
113 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
114 }
115 }
116
117 pub fn as_def_kind(&self) -> DefKind {
118 match self.kind {
119 AssocKind::Const { .. } => DefKind::AssocConst,
120 AssocKind::Fn { .. } => DefKind::AssocFn,
121 AssocKind::Type { .. } => DefKind::AssocTy,
122 }
123 }
124 pub fn is_type(&self) -> bool {
125 matches!(self.kind, ty::AssocKind::Type { .. })
126 }
127
128 pub fn is_fn(&self) -> bool {
129 matches!(self.kind, ty::AssocKind::Fn { .. })
130 }
131
132 pub fn is_method(&self) -> bool {
133 matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
134 }
135
136 pub fn as_tag(&self) -> AssocTag {
137 match self.kind {
138 AssocKind::Const { .. } => AssocTag::Const,
139 AssocKind::Fn { .. } => AssocTag::Fn,
140 AssocKind::Type { .. } => AssocTag::Type,
141 }
142 }
143
144 pub fn is_impl_trait_in_trait(&self) -> bool {
145 matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
146 }
147
148 pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
153 if !matches!(self.kind, ty::AssocKind::Const { .. }) {
154 return false;
155 }
156
157 let def_id = match (self.container, self.trait_item_def_id) {
158 (AssocItemContainer::Trait, _) => self.def_id,
159 (AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did,
160 (AssocItemContainer::Impl, None) => return true,
162 };
163 tcx.has_attr(def_id, sym::type_const)
164 }
165}
166
167#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
168pub enum AssocTypeData {
169 Normal(Symbol),
170 Rpitit(ty::ImplTraitInTraitData),
174}
175
176#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
177pub enum AssocKind {
178 Const { name: Symbol },
179 Fn { name: Symbol, has_self: bool },
180 Type { data: AssocTypeData },
181}
182
183impl AssocKind {
184 pub fn namespace(&self) -> Namespace {
185 match *self {
186 ty::AssocKind::Type { .. } => Namespace::TypeNS,
187 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
188 }
189 }
190
191 pub fn as_def_kind(&self) -> DefKind {
192 match self {
193 AssocKind::Const { .. } => DefKind::AssocConst,
194 AssocKind::Fn { .. } => DefKind::AssocFn,
195 AssocKind::Type { .. } => DefKind::AssocTy,
196 }
197 }
198}
199
200impl std::fmt::Display for AssocKind {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 match self {
203 AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
204 AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
205 AssocKind::Const { .. } => write!(f, "associated const"),
206 AssocKind::Type { .. } => write!(f, "associated type"),
207 }
208 }
209}
210
211#[derive(Clone, Copy, Debug, PartialEq, Eq)]
213pub enum AssocTag {
214 Const,
215 Fn,
216 Type,
217}
218
219#[derive(Debug, Clone, PartialEq, HashStable)]
225pub struct AssocItems {
226 items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
227}
228
229impl AssocItems {
230 pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
232 let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
233 AssocItems { items }
234 }
235
236 pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
241 self.items.iter().map(|(_, v)| v)
242 }
243
244 pub fn len(&self) -> usize {
245 self.items.len()
246 }
247
248 pub fn filter_by_name_unhygienic(
252 &self,
253 name: Symbol,
254 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
255 assert!(!name.is_empty());
256 self.items.get_by_key(Some(name))
257 }
258
259 pub fn find_by_ident_and_kind(
262 &self,
263 tcx: TyCtxt<'_>,
264 ident: Ident,
265 assoc_tag: AssocTag,
266 parent_def_id: DefId,
267 ) -> Option<&ty::AssocItem> {
268 self.filter_by_name_unhygienic(ident.name)
269 .filter(|item| item.as_tag() == assoc_tag)
270 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
271 }
272
273 pub fn find_by_ident_and_namespace(
276 &self,
277 tcx: TyCtxt<'_>,
278 ident: Ident,
279 ns: Namespace,
280 parent_def_id: DefId,
281 ) -> Option<&ty::AssocItem> {
282 self.filter_by_name_unhygienic(ident.name)
283 .filter(|item| item.namespace() == ns)
284 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
285 }
286}