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 name: Symbol,
22 pub kind: AssocKind,
23 pub container: AssocItemContainer,
24
25 pub trait_item_def_id: Option<DefId>,
28
29 pub fn_has_self_parameter: bool,
32
33 pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
37}
38
39impl AssocItem {
40 pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
41 Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
42 }
43
44 pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
50 tcx.defaultness(self.def_id)
51 }
52
53 #[inline]
54 pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
55 tcx.visibility(self.def_id)
56 }
57
58 #[inline]
59 pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
60 tcx.parent(self.def_id)
61 }
62
63 #[inline]
64 pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
65 match self.container {
66 AssocItemContainer::Impl => None,
67 AssocItemContainer::Trait => Some(tcx.parent(self.def_id)),
68 }
69 }
70
71 #[inline]
72 pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
73 match self.container {
74 AssocItemContainer::Impl => Some(tcx.parent(self.def_id)),
75 AssocItemContainer::Trait => None,
76 }
77 }
78
79 pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
80 match self.kind {
81 ty::AssocKind::Fn => {
82 tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
87 }
88 ty::AssocKind::Type => format!("type {};", self.name),
89 ty::AssocKind::Const => {
90 format!(
91 "const {}: {:?};",
92 self.name,
93 tcx.type_of(self.def_id).instantiate_identity()
94 )
95 }
96 }
97 }
98
99 pub fn descr(&self) -> &'static str {
100 match self.kind {
101 ty::AssocKind::Const => "const",
102 ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
103 ty::AssocKind::Fn => "associated function",
104 ty::AssocKind::Type => "type",
105 }
106 }
107
108 pub fn is_impl_trait_in_trait(&self) -> bool {
109 self.opt_rpitit_info.is_some()
110 }
111
112 pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
117 if self.kind != ty::AssocKind::Const {
118 return false;
119 }
120
121 let def_id = match (self.container, self.trait_item_def_id) {
122 (AssocItemContainer::Trait, _) => self.def_id,
123 (AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did,
124 (AssocItemContainer::Impl, None) => return true,
126 };
127 tcx.has_attr(def_id, sym::type_const)
128 }
129}
130
131#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
132pub enum AssocKind {
133 Const,
134 Fn,
135 Type,
136}
137
138impl AssocKind {
139 pub fn namespace(&self) -> Namespace {
140 match *self {
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 {
148 AssocKind::Const => DefKind::AssocConst,
149 AssocKind::Fn => DefKind::AssocFn,
150 AssocKind::Type => DefKind::AssocTy,
151 }
152 }
153}
154
155impl std::fmt::Display for AssocKind {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 match self {
158 AssocKind::Fn => write!(f, "method"),
159 AssocKind::Const => write!(f, "associated const"),
160 AssocKind::Type => write!(f, "associated type"),
161 }
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, HashStable)]
171pub struct AssocItems {
172 items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>,
173}
174
175impl AssocItems {
176 pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
178 let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
179 AssocItems { items }
180 }
181
182 pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
187 self.items.iter().map(|(_, v)| v)
188 }
189
190 pub fn len(&self) -> usize {
191 self.items.len()
192 }
193
194 pub fn filter_by_name_unhygienic(
196 &self,
197 name: Symbol,
198 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
199 self.items.get_by_key(name)
200 }
201
202 pub fn find_by_name_and_kind(
204 &self,
205 tcx: TyCtxt<'_>,
206 ident: Ident,
207 kind: AssocKind,
208 parent_def_id: DefId,
209 ) -> Option<&ty::AssocItem> {
210 self.filter_by_name_unhygienic(ident.name)
211 .filter(|item| item.kind == kind)
212 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
213 }
214
215 pub fn find_by_name_and_kinds(
217 &self,
218 tcx: TyCtxt<'_>,
219 ident: Ident,
220 kinds: &[AssocKind],
222 parent_def_id: DefId,
223 ) -> Option<&ty::AssocItem> {
224 kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
225 }
226
227 pub fn find_by_name_and_namespace(
229 &self,
230 tcx: TyCtxt<'_>,
231 ident: Ident,
232 ns: Namespace,
233 parent_def_id: DefId,
234 ) -> Option<&ty::AssocItem> {
235 self.filter_by_name_unhygienic(ident.name)
236 .filter(|item| item.kind.namespace() == ns)
237 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
238 }
239}