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