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