1 pub use self::AssocItemContainer::*;
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)]
13 pub enum AssocItemContainer {
14 TraitContainer(DefId),
18 impl AssocItemContainer {
19 pub fn impl_def_id(&self) -> Option<DefId> {
21 ImplContainer(id) => Some(id),
26 /// Asserts that this is the `DefId` of an associated item declared
27 /// in a trait, and returns the trait `DefId`.
28 pub fn assert_trait(&self) -> DefId {
30 TraitContainer(id) => id,
31 _ => bug!("associated item has wrong container type: {:?}", self),
35 pub fn id(&self) -> DefId {
37 TraitContainer(id) => id,
38 ImplContainer(id) => id,
43 #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
44 pub struct AssocItem {
46 #[stable_hasher(project(name))]
50 pub defaultness: hir::Defaultness,
51 pub container: AssocItemContainer,
53 /// Whether this is a method with an explicit self
54 /// as its first parameter, allowing method calls.
55 pub fn_has_self_parameter: bool,
59 pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
61 ty::AssocKind::Fn => {
62 // We skip the binder here because the binder would deanonymize all
63 // late-bound regions, and we don't want method signatures to show up
64 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
65 // regions just fine, showing `fn(&MyType)`.
66 tcx.fn_sig(self.def_id).skip_binder().to_string()
68 ty::AssocKind::Type => format!("type {};", self.ident),
69 ty::AssocKind::Const => {
70 format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id))
76 #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)]
84 pub fn namespace(&self) -> Namespace {
86 ty::AssocKind::Type => Namespace::TypeNS,
87 ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
91 pub fn as_def_kind(&self) -> DefKind {
93 AssocKind::Const => DefKind::AssocConst,
94 AssocKind::Fn => DefKind::AssocFn,
95 AssocKind::Type => DefKind::AssocTy,
100 /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
102 /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
103 /// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is
104 /// done only on items with the same name.
105 #[derive(Debug, Clone, PartialEq, HashStable)]
106 pub struct AssocItems<'tcx> {
107 pub(super) items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
110 impl<'tcx> AssocItems<'tcx> {
111 /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
112 pub fn new(items_in_def_order: impl IntoIterator<Item = &'tcx ty::AssocItem>) -> Self {
113 let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect();
117 /// Returns a slice of associated items in the order they were defined.
119 /// New code should avoid relying on definition order. If you need a particular associated item
120 /// for a known trait, make that trait a lang item instead of indexing this array.
121 pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
122 self.items.iter().map(|(_, v)| *v)
125 pub fn len(&self) -> usize {
129 /// Returns an iterator over all associated items with the given name, ignoring hygiene.
130 pub fn filter_by_name_unhygienic(
133 ) -> impl '_ + Iterator<Item = &ty::AssocItem> {
134 self.items.get_by_key(name).copied()
137 /// Returns an iterator over all associated items with the given name.
139 /// Multiple items may have the same name if they are in different `Namespace`s. For example,
140 /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*`
141 /// methods below if you know which item you are looking for.
142 pub fn filter_by_name<'a>(
146 parent_def_id: DefId,
147 ) -> impl 'a + Iterator<Item = &'a ty::AssocItem> {
148 self.filter_by_name_unhygienic(ident.name)
149 .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
152 /// Returns the associated item with the given name and `AssocKind`, if one exists.
153 pub fn find_by_name_and_kind(
158 parent_def_id: DefId,
159 ) -> Option<&ty::AssocItem> {
160 self.filter_by_name_unhygienic(ident.name)
161 .filter(|item| item.kind == kind)
162 .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
165 /// Returns the associated item with the given name in the given `Namespace`, if one exists.
166 pub fn find_by_name_and_namespace(
171 parent_def_id: DefId,
172 ) -> Option<&ty::AssocItem> {
173 self.filter_by_name_unhygienic(ident.name)
174 .filter(|item| item.kind.namespace() == ns)
175 .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))