1use rustc_data_structures::sorted_map::SortedIndexMultiMap;
2use rustc_hir as hir;
3use rustc_hir::attrs::AttributeKind;
4use rustc_hir::def::{DefKind, Namespace};
5use rustc_hir::def_id::DefId;
6use rustc_hir::find_attr;
7use rustc_macros::{Decodable, Encodable, HashStable};
8use rustc_span::{ErrorGuaranteed, Ident, Symbol};
9
10use super::{TyCtxt, Visibility};
11use crate::ty;
12
13#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
14pub enum AssocContainer {
15 Trait,
16 InherentImpl,
17 TraitImpl(Result<DefId, ErrorGuaranteed>),
19}
20
21#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
23pub struct AssocItem {
24 pub def_id: DefId,
25 pub kind: AssocKind,
26 pub container: AssocContainer,
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 match self.container {
57 AssocContainer::InherentImpl => hir::Defaultness::Final,
58 AssocContainer::Trait | AssocContainer::TraitImpl(_) => tcx.defaultness(self.def_id),
59 }
60 }
61
62 pub fn expect_trait_impl(&self) -> Result<DefId, ErrorGuaranteed> {
63 let AssocContainer::TraitImpl(trait_item_id) = self.container else {
64 bug!("expected item to be in a trait impl: {:?}", self.def_id);
65 };
66 trait_item_id
67 }
68
69 pub fn trait_item_or_self(&self) -> Result<DefId, ErrorGuaranteed> {
73 match self.container {
74 AssocContainer::TraitImpl(id) => id,
75 AssocContainer::Trait | AssocContainer::InherentImpl => Ok(self.def_id),
76 }
77 }
78
79 pub fn trait_item_def_id(&self) -> Option<DefId> {
80 match self.container {
81 AssocContainer::TraitImpl(Ok(id)) => Some(id),
82 _ => None,
83 }
84 }
85
86 #[inline]
87 pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
88 tcx.visibility(self.def_id)
89 }
90
91 #[inline]
92 pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
93 tcx.parent(self.def_id)
94 }
95
96 #[inline]
97 pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
98 match self.container {
99 AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => None,
100 AssocContainer::Trait => Some(tcx.parent(self.def_id)),
101 }
102 }
103
104 #[inline]
105 pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
106 match self.container {
107 AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => {
108 Some(tcx.parent(self.def_id))
109 }
110 AssocContainer::Trait => None,
111 }
112 }
113
114 pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
115 match self.kind {
116 ty::AssocKind::Fn { .. } => {
117 tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
122 }
123 ty::AssocKind::Type { .. } => format!("type {};", self.name()),
124 ty::AssocKind::Const { name } => {
125 format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
126 }
127 }
128 }
129
130 pub fn descr(&self) -> &'static str {
131 match self.kind {
132 ty::AssocKind::Const { .. } => "associated const",
133 ty::AssocKind::Fn { has_self: true, .. } => "method",
134 ty::AssocKind::Fn { has_self: false, .. } => "associated function",
135 ty::AssocKind::Type { .. } => "associated type",
136 }
137 }
138
139 pub fn namespace(&self) -> Namespace {
140 match self.kind {
141 ty::AssocKind::Type { .. } => Namespace::TypeNS,
142 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
143 }
144 }
145
146 pub fn as_def_kind(&self) -> DefKind {
147 match self.kind {
148 AssocKind::Const { .. } => DefKind::AssocConst,
149 AssocKind::Fn { .. } => DefKind::AssocFn,
150 AssocKind::Type { .. } => DefKind::AssocTy,
151 }
152 }
153 pub fn is_type(&self) -> bool {
154 matches!(self.kind, ty::AssocKind::Type { .. })
155 }
156
157 pub fn is_fn(&self) -> bool {
158 matches!(self.kind, ty::AssocKind::Fn { .. })
159 }
160
161 pub fn is_method(&self) -> bool {
162 matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
163 }
164
165 pub fn as_tag(&self) -> AssocTag {
166 match self.kind {
167 AssocKind::Const { .. } => AssocTag::Const,
168 AssocKind::Fn { .. } => AssocTag::Fn,
169 AssocKind::Type { .. } => AssocTag::Type,
170 }
171 }
172
173 pub fn is_impl_trait_in_trait(&self) -> bool {
174 matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
175 }
176
177 pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
182 if !matches!(self.kind, ty::AssocKind::Const { .. }) {
183 return false;
184 }
185
186 let def_id = match self.container {
187 AssocContainer::Trait => self.def_id,
188 AssocContainer::TraitImpl(Ok(trait_item_did)) => trait_item_did,
189 AssocContainer::TraitImpl(Err(_)) => return false,
190 AssocContainer::InherentImpl => return true,
191 };
192 find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_))
193 }
194}
195
196#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
197pub enum AssocTypeData {
198 Normal(Symbol),
199 Rpitit(ty::ImplTraitInTraitData),
203}
204
205#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
206pub enum AssocKind {
207 Const { name: Symbol },
208 Fn { name: Symbol, has_self: bool },
209 Type { data: AssocTypeData },
210}
211
212impl AssocKind {
213 pub fn namespace(&self) -> Namespace {
214 match *self {
215 ty::AssocKind::Type { .. } => Namespace::TypeNS,
216 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
217 }
218 }
219
220 pub fn as_def_kind(&self) -> DefKind {
221 match self {
222 AssocKind::Const { .. } => DefKind::AssocConst,
223 AssocKind::Fn { .. } => DefKind::AssocFn,
224 AssocKind::Type { .. } => DefKind::AssocTy,
225 }
226 }
227}
228
229impl std::fmt::Display for AssocKind {
230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 match self {
232 AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
233 AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
234 AssocKind::Const { .. } => write!(f, "associated const"),
235 AssocKind::Type { .. } => write!(f, "associated type"),
236 }
237 }
238}
239
240#[derive(Clone, Copy, Debug, PartialEq, Eq)]
242pub enum AssocTag {
243 Const,
244 Fn,
245 Type,
246}
247
248#[derive(Debug, Clone, PartialEq, HashStable)]
254pub struct AssocItems {
255 items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
256}
257
258impl AssocItems {
259 pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
261 let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
262 AssocItems { items }
263 }
264
265 pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
270 self.items.iter().map(|(_, v)| v)
271 }
272
273 pub fn len(&self) -> usize {
274 self.items.len()
275 }
276
277 pub fn filter_by_name_unhygienic(
281 &self,
282 name: Symbol,
283 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
284 assert!(!name.is_empty());
285 self.items.get_by_key(Some(name))
286 }
287
288 pub fn filter_by_name_unhygienic_and_kind(
291 &self,
292 name: Symbol,
293 assoc_tag: AssocTag,
294 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
295 self.filter_by_name_unhygienic(name).filter(move |item| item.as_tag() == assoc_tag)
296 }
297
298 pub fn find_by_ident_and_kind(
301 &self,
302 tcx: TyCtxt<'_>,
303 ident: Ident,
304 assoc_tag: AssocTag,
305 parent_def_id: DefId,
306 ) -> Option<&ty::AssocItem> {
307 self.filter_by_name_unhygienic(ident.name)
308 .filter(|item| item.as_tag() == assoc_tag)
309 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
310 }
311
312 pub fn find_by_ident_and_namespace(
315 &self,
316 tcx: TyCtxt<'_>,
317 ident: Ident,
318 ns: Namespace,
319 parent_def_id: DefId,
320 ) -> Option<&ty::AssocItem> {
321 self.filter_by_name_unhygienic(ident.name)
322 .filter(|item| item.namespace() == ns)
323 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
324 }
325}
326
327impl<'tcx> TyCtxt<'tcx> {
328 pub fn associated_types_for_impl_traits_in_associated_fn(
338 self,
339 fn_def_id: DefId,
340 ) -> &'tcx [DefId] {
341 let parent_def_id = self.parent(fn_def_id);
342 &self.associated_types_for_impl_traits_in_trait_or_impl(parent_def_id)[&fn_def_id]
343 }
344}