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::{ErrorGuaranteed, Ident, Symbol};
7
8use super::{TyCtxt, Visibility};
9use crate::ty;
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
12pub enum AssocContainer {
13 Trait,
14 InherentImpl,
15 TraitImpl(Result<DefId, ErrorGuaranteed>),
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: AssocContainer,
25}
26
27impl AssocItem {
28 pub fn opt_name(&self) -> Option<Symbol> {
30 match self.kind {
31 ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name),
32 ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None,
33 ty::AssocKind::Const { name } => Some(name),
34 ty::AssocKind::Fn { name, .. } => Some(name),
35 }
36 }
37
38 pub fn name(&self) -> Symbol {
41 self.opt_name().expect("name of non-Rpitit assoc item")
42 }
43
44 pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
45 Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap())
46 }
47
48 pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
54 match self.container {
55 AssocContainer::InherentImpl => hir::Defaultness::Final,
56 AssocContainer::Trait | AssocContainer::TraitImpl(_) => tcx.defaultness(self.def_id),
57 }
58 }
59
60 pub fn expect_trait_impl(&self) -> Result<DefId, ErrorGuaranteed> {
61 let AssocContainer::TraitImpl(trait_item_id) = self.container else {
62 bug!("expected item to be in a trait impl: {:?}", self.def_id);
63 };
64 trait_item_id
65 }
66
67 pub fn trait_item_or_self(&self) -> Result<DefId, ErrorGuaranteed> {
71 match self.container {
72 AssocContainer::TraitImpl(id) => id,
73 AssocContainer::Trait | AssocContainer::InherentImpl => Ok(self.def_id),
74 }
75 }
76
77 pub fn trait_item_def_id(&self) -> Option<DefId> {
78 match self.container {
79 AssocContainer::TraitImpl(Ok(id)) => Some(id),
80 _ => None,
81 }
82 }
83
84 #[inline]
85 pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
86 tcx.visibility(self.def_id)
87 }
88
89 #[inline]
90 pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
91 tcx.parent(self.def_id)
92 }
93
94 #[inline]
95 pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
96 match self.container {
97 AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => None,
98 AssocContainer::Trait => Some(tcx.parent(self.def_id)),
99 }
100 }
101
102 #[inline]
103 pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
104 match self.container {
105 AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => {
106 Some(tcx.parent(self.def_id))
107 }
108 AssocContainer::Trait => None,
109 }
110 }
111
112 pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
113 match self.kind {
114 ty::AssocKind::Fn { .. } => {
115 tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
120 }
121 ty::AssocKind::Type { .. } => format!("type {};", self.name()),
122 ty::AssocKind::Const { name } => {
123 format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
124 }
125 }
126 }
127
128 pub fn descr(&self) -> &'static str {
129 match self.kind {
130 ty::AssocKind::Const { .. } => "associated const",
131 ty::AssocKind::Fn { has_self: true, .. } => "method",
132 ty::AssocKind::Fn { has_self: false, .. } => "associated function",
133 ty::AssocKind::Type { .. } => "associated type",
134 }
135 }
136
137 pub fn namespace(&self) -> Namespace {
138 match self.kind {
139 ty::AssocKind::Type { .. } => Namespace::TypeNS,
140 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
141 }
142 }
143
144 pub fn as_def_kind(&self) -> DefKind {
145 match self.kind {
146 AssocKind::Const { .. } => DefKind::AssocConst,
147 AssocKind::Fn { .. } => DefKind::AssocFn,
148 AssocKind::Type { .. } => DefKind::AssocTy,
149 }
150 }
151 pub fn is_type(&self) -> bool {
152 matches!(self.kind, ty::AssocKind::Type { .. })
153 }
154
155 pub fn is_fn(&self) -> bool {
156 matches!(self.kind, ty::AssocKind::Fn { .. })
157 }
158
159 pub fn is_method(&self) -> bool {
160 matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
161 }
162
163 pub fn as_tag(&self) -> AssocTag {
164 match self.kind {
165 AssocKind::Const { .. } => AssocTag::Const,
166 AssocKind::Fn { .. } => AssocTag::Fn,
167 AssocKind::Type { .. } => AssocTag::Type,
168 }
169 }
170
171 pub fn is_impl_trait_in_trait(&self) -> bool {
172 matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
173 }
174}
175
176#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
177pub enum AssocTypeData {
178 Normal(Symbol),
179 Rpitit(ty::ImplTraitInTraitData),
183}
184
185#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
186pub enum AssocKind {
187 Const { name: Symbol },
188 Fn { name: Symbol, has_self: bool },
189 Type { data: AssocTypeData },
190}
191
192impl AssocKind {
193 pub fn namespace(&self) -> Namespace {
194 match *self {
195 ty::AssocKind::Type { .. } => Namespace::TypeNS,
196 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
197 }
198 }
199
200 pub fn as_def_kind(&self) -> DefKind {
201 match self {
202 AssocKind::Const { .. } => DefKind::AssocConst,
203 AssocKind::Fn { .. } => DefKind::AssocFn,
204 AssocKind::Type { .. } => DefKind::AssocTy,
205 }
206 }
207}
208
209impl std::fmt::Display for AssocKind {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 match self {
212 AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
213 AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
214 AssocKind::Const { .. } => write!(f, "associated const"),
215 AssocKind::Type { .. } => write!(f, "associated type"),
216 }
217 }
218}
219
220#[derive(Clone, Copy, Debug, PartialEq, Eq)]
222pub enum AssocTag {
223 Const,
224 Fn,
225 Type,
226}
227
228#[derive(Debug, Clone, PartialEq, HashStable)]
234pub struct AssocItems {
235 items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
236}
237
238impl AssocItems {
239 pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
241 let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
242 AssocItems { items }
243 }
244
245 pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
250 self.items.iter().map(|(_, v)| v)
251 }
252
253 pub fn len(&self) -> usize {
254 self.items.len()
255 }
256
257 pub fn filter_by_name_unhygienic(
261 &self,
262 name: Symbol,
263 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
264 assert!(!name.is_empty());
265 self.items.get_by_key(Some(name))
266 }
267
268 pub fn filter_by_name_unhygienic_and_kind(
271 &self,
272 name: Symbol,
273 assoc_tag: AssocTag,
274 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
275 self.filter_by_name_unhygienic(name).filter(move |item| item.as_tag() == assoc_tag)
276 }
277
278 pub fn find_by_ident_and_kind(
281 &self,
282 tcx: TyCtxt<'_>,
283 ident: Ident,
284 assoc_tag: AssocTag,
285 parent_def_id: DefId,
286 ) -> Option<&ty::AssocItem> {
287 self.filter_by_name_unhygienic(ident.name)
288 .filter(|item| item.as_tag() == assoc_tag)
289 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
290 }
291
292 pub fn find_by_ident_and_namespace(
295 &self,
296 tcx: TyCtxt<'_>,
297 ident: Ident,
298 ns: Namespace,
299 parent_def_id: DefId,
300 ) -> Option<&ty::AssocItem> {
301 self.filter_by_name_unhygienic(ident.name)
302 .filter(|item| item.namespace() == ns)
303 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
304 }
305}
306
307impl<'tcx> TyCtxt<'tcx> {
308 pub fn associated_types_for_impl_traits_in_associated_fn(
318 self,
319 fn_def_id: DefId,
320 ) -> &'tcx [DefId] {
321 let parent_def_id = self.parent(fn_def_id);
322 &self.associated_types_for_impl_traits_in_trait_or_impl(parent_def_id)[&fn_def_id]
323 }
324}