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