1 pub use self::AssocItemContainer::*;
3 use crate::ty::{self, DefIdTree};
4 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
6 use rustc_hir::def::{DefKind, Namespace};
7 use rustc_hir::def_id::DefId;
8 use rustc_span::symbol::{Ident, Symbol};
10 use super::{TyCtxt, Visibility};
12 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
13 pub enum AssocItemContainer {
18 /// Information about an associated item
19 #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
20 pub struct AssocItem {
24 pub container: AssocItemContainer,
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>,
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,
36 pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
37 Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
40 pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
41 tcx.impl_defaultness(self.def_id)
45 pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
46 tcx.visibility(self.def_id)
50 pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
51 tcx.parent(self.def_id)
55 pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
56 match self.container {
57 AssocItemContainer::ImplContainer => None,
58 AssocItemContainer::TraitContainer => Some(tcx.parent(self.def_id)),
63 pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
64 match self.container {
65 AssocItemContainer::ImplContainer => Some(tcx.parent(self.def_id)),
66 AssocItemContainer::TraitContainer => None,
70 pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
72 ty::AssocKind::Fn => {
73 // We skip the binder here because the binder would deanonymize all
74 // late-bound regions, and we don't want method signatures to show up
75 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
76 // regions just fine, showing `fn(&MyType)`.
77 tcx.fn_sig(self.def_id).skip_binder().to_string()
79 ty::AssocKind::Type => format!("type {};", self.name),
80 ty::AssocKind::Const => {
81 format!("const {}: {:?};", self.name, tcx.type_of(self.def_id))
87 #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
95 pub fn namespace(&self) -> Namespace {
97 ty::AssocKind::Type => Namespace::TypeNS,
98 ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
102 pub fn as_def_kind(&self) -> DefKind {
104 AssocKind::Const => DefKind::AssocConst,
105 AssocKind::Fn => DefKind::AssocFn,
106 AssocKind::Type => DefKind::AssocTy,
111 impl std::fmt::Display for AssocKind {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 AssocKind::Fn => write!(f, "method"),
115 AssocKind::Const => write!(f, "associated const"),
116 AssocKind::Type => write!(f, "associated type"),
121 /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
123 /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
124 /// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is
125 /// done only on items with the same name.
126 #[derive(Debug, Clone, PartialEq, HashStable)]
127 pub struct AssocItems<'tcx> {
128 pub(super) items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
131 impl<'tcx> AssocItems<'tcx> {
132 /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
133 pub fn new(items_in_def_order: impl IntoIterator<Item = &'tcx ty::AssocItem>) -> Self {
134 let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
138 /// Returns a slice of associated items in the order they were defined.
140 /// New code should avoid relying on definition order. If you need a particular associated item
141 /// for a known trait, make that trait a lang item instead of indexing this array.
142 pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
143 self.items.iter().map(|(_, v)| *v)
146 pub fn len(&self) -> usize {
150 /// Returns an iterator over all associated items with the given name, ignoring hygiene.
151 pub fn filter_by_name_unhygienic(
154 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
155 self.items.get_by_key(name).copied()
158 /// Returns the associated item with the given name and `AssocKind`, if one exists.
159 pub fn find_by_name_and_kind(
164 parent_def_id: DefId,
165 ) -> Option<&ty::AssocItem> {
166 self.filter_by_name_unhygienic(ident.name)
167 .filter(|item| item.kind == kind)
168 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
171 /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
172 pub fn find_by_name_and_kinds(
176 // Sorted in order of what kinds to look at
178 parent_def_id: DefId,
179 ) -> Option<&ty::AssocItem> {
180 kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
183 /// Returns the associated item with the given name in the given `Namespace`, if one exists.
184 pub fn find_by_name_and_namespace(
189 parent_def_id: DefId,
190 ) -> Option<&ty::AssocItem> {
191 self.filter_by_name_unhygienic(ident.name)
192 .filter(|item| item.kind.namespace() == ns)
193 .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))