• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 pub use self::AssocItemContainer::*;
2 
3 use crate::ty;
4 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
5 use rustc_hir as hir;
6 use rustc_hir::def::{DefKind, Namespace};
7 use rustc_hir::def_id::DefId;
8 use rustc_span::symbol::{Ident, Symbol};
9 
10 use super::{TyCtxt, Visibility};
11 
12 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
13 pub enum AssocItemContainer {
14     TraitContainer,
15     ImplContainer,
16 }
17 
18 /// Information about an associated item
19 #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
20 pub struct AssocItem {
21     pub def_id: DefId,
22     pub name: Symbol,
23     pub kind: AssocKind,
24     pub container: AssocItemContainer,
25 
26     /// If this is an item in an impl of a trait then this is the `DefId` of
27     /// the associated item on the trait that this implements.
28     pub trait_item_def_id: Option<DefId>,
29 
30     /// Whether this is a method with an explicit self
31     /// as its first parameter, allowing method calls.
32     pub fn_has_self_parameter: bool,
33 
34     /// `Some` if the associated item (an associated type) comes from the
35     /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
36     /// provides additional information about its source.
37     pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
38 }
39 
40 impl AssocItem {
ident(&self, tcx: TyCtxt<'_>) -> Ident41     pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
42         Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
43     }
44 
45     /// Gets the defaultness of the associated item.
46     /// To get the default associated type, use the [`type_of`] query on the
47     /// [`DefId`] of the type.
48     ///
49     /// [`type_of`]: crate::ty::TyCtxt::type_of
defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness50     pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
51         tcx.defaultness(self.def_id)
52     }
53 
54     #[inline]
visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId>55     pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
56         tcx.visibility(self.def_id)
57     }
58 
59     #[inline]
container_id(&self, tcx: TyCtxt<'_>) -> DefId60     pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
61         tcx.parent(self.def_id)
62     }
63 
64     #[inline]
trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId>65     pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
66         match self.container {
67             AssocItemContainer::ImplContainer => None,
68             AssocItemContainer::TraitContainer => Some(tcx.parent(self.def_id)),
69         }
70     }
71 
72     #[inline]
impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId>73     pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
74         match self.container {
75             AssocItemContainer::ImplContainer => Some(tcx.parent(self.def_id)),
76             AssocItemContainer::TraitContainer => None,
77         }
78     }
79 
signature(&self, tcx: TyCtxt<'_>) -> String80     pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
81         match self.kind {
82             ty::AssocKind::Fn => {
83                 // We skip the binder here because the binder would deanonymize all
84                 // late-bound regions, and we don't want method signatures to show up
85                 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
86                 // regions just fine, showing `fn(&MyType)`.
87                 tcx.fn_sig(self.def_id).subst_identity().skip_binder().to_string()
88             }
89             ty::AssocKind::Type => format!("type {};", self.name),
90             ty::AssocKind::Const => {
91                 format!("const {}: {:?};", self.name, tcx.type_of(self.def_id).subst_identity())
92             }
93         }
94     }
95 }
96 
97 #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
98 pub enum AssocKind {
99     Const,
100     Fn,
101     Type,
102 }
103 
104 impl AssocKind {
namespace(&self) -> Namespace105     pub fn namespace(&self) -> Namespace {
106         match *self {
107             ty::AssocKind::Type => Namespace::TypeNS,
108             ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
109         }
110     }
111 
as_def_kind(&self) -> DefKind112     pub fn as_def_kind(&self) -> DefKind {
113         match self {
114             AssocKind::Const => DefKind::AssocConst,
115             AssocKind::Fn => DefKind::AssocFn,
116             AssocKind::Type => DefKind::AssocTy,
117         }
118     }
119 }
120 
121 impl std::fmt::Display for AssocKind {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result122     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123         match self {
124             AssocKind::Fn => write!(f, "method"),
125             AssocKind::Const => write!(f, "associated const"),
126             AssocKind::Type => write!(f, "associated type"),
127         }
128     }
129 }
130 
131 /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
132 ///
133 /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
134 /// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is
135 /// done only on items with the same name.
136 #[derive(Debug, Clone, PartialEq, HashStable)]
137 pub struct AssocItems {
138     items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>,
139 }
140 
141 impl AssocItems {
142     /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self143     pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
144         let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
145         AssocItems { items }
146     }
147 
148     /// Returns a slice of associated items in the order they were defined.
149     ///
150     /// New code should avoid relying on definition order. If you need a particular associated item
151     /// for a known trait, make that trait a lang item instead of indexing this array.
in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem>152     pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
153         self.items.iter().map(|(_, v)| v)
154     }
155 
len(&self) -> usize156     pub fn len(&self) -> usize {
157         self.items.len()
158     }
159 
160     /// Returns an iterator over all associated items with the given name, ignoring hygiene.
filter_by_name_unhygienic( &self, name: Symbol, ) -> impl '_ + Iterator<Item = &ty::AssocItem>161     pub fn filter_by_name_unhygienic(
162         &self,
163         name: Symbol,
164     ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
165         self.items.get_by_key(name)
166     }
167 
168     /// Returns the associated item with the given name and `AssocKind`, if one exists.
find_by_name_and_kind( &self, tcx: TyCtxt<'_>, ident: Ident, kind: AssocKind, parent_def_id: DefId, ) -> Option<&ty::AssocItem>169     pub fn find_by_name_and_kind(
170         &self,
171         tcx: TyCtxt<'_>,
172         ident: Ident,
173         kind: AssocKind,
174         parent_def_id: DefId,
175     ) -> Option<&ty::AssocItem> {
176         self.filter_by_name_unhygienic(ident.name)
177             .filter(|item| item.kind == kind)
178             .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
179     }
180 
181     /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
find_by_name_and_kinds( &self, tcx: TyCtxt<'_>, ident: Ident, kinds: &[AssocKind], parent_def_id: DefId, ) -> Option<&ty::AssocItem>182     pub fn find_by_name_and_kinds(
183         &self,
184         tcx: TyCtxt<'_>,
185         ident: Ident,
186         // Sorted in order of what kinds to look at
187         kinds: &[AssocKind],
188         parent_def_id: DefId,
189     ) -> Option<&ty::AssocItem> {
190         kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
191     }
192 
193     /// Returns the associated item with the given name in the given `Namespace`, if one exists.
find_by_name_and_namespace( &self, tcx: TyCtxt<'_>, ident: Ident, ns: Namespace, parent_def_id: DefId, ) -> Option<&ty::AssocItem>194     pub fn find_by_name_and_namespace(
195         &self,
196         tcx: TyCtxt<'_>,
197         ident: Ident,
198         ns: Namespace,
199         parent_def_id: DefId,
200     ) -> Option<&ty::AssocItem> {
201         self.filter_by_name_unhygienic(ident.name)
202             .filter(|item| item.kind.namespace() == ns)
203             .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
204     }
205 }
206