diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs new file mode 100644 index 00000000000..d3770fa416b --- /dev/null +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -0,0 +1,170 @@ +pub use self::AssocItemContainer::*; + +use crate::ty; +use rustc_data_structures::sorted_map::SortedIndexMultiMap; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Namespace}; +use rustc_hir::def_id::DefId; +use rustc_span::symbol::{Ident, Symbol}; + +use super::{TyCtxt, Visibility}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)] +pub enum AssocItemContainer { + TraitContainer(DefId), + ImplContainer(DefId), +} + +impl AssocItemContainer { + /// Asserts that this is the `DefId` of an associated item declared + /// in a trait, and returns the trait `DefId`. + pub fn assert_trait(&self) -> DefId { + match *self { + TraitContainer(id) => id, + _ => bug!("associated item has wrong container type: {:?}", self), + } + } + + pub fn id(&self) -> DefId { + match *self { + TraitContainer(id) => id, + ImplContainer(id) => id, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)] +pub struct AssocItem { + pub def_id: DefId, + #[stable_hasher(project(name))] + pub ident: Ident, + pub kind: AssocKind, + pub vis: Visibility, + pub defaultness: hir::Defaultness, + pub container: AssocItemContainer, + + /// Whether this is a method with an explicit self + /// as its first parameter, allowing method calls. + pub fn_has_self_parameter: bool, +} + +impl AssocItem { + pub fn signature(&self, tcx: TyCtxt<'_>) -> String { + match self.kind { + ty::AssocKind::Fn => { + // We skip the binder here because the binder would deanonymize all + // late-bound regions, and we don't want method signatures to show up + // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound + // regions just fine, showing `fn(&MyType)`. + tcx.fn_sig(self.def_id).skip_binder().to_string() + } + ty::AssocKind::Type => format!("type {};", self.ident), + ty::AssocKind::Const => { + format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id)) + } + } + } +} + +#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)] +pub enum AssocKind { + Const, + Fn, + Type, +} + +impl AssocKind { + pub fn namespace(&self) -> Namespace { + match *self { + ty::AssocKind::Type => Namespace::TypeNS, + ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS, + } + } + + pub fn as_def_kind(&self) -> DefKind { + match self { + AssocKind::Const => DefKind::AssocConst, + AssocKind::Fn => DefKind::AssocFn, + AssocKind::Type => DefKind::AssocTy, + } + } +} + +/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. +/// +/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since +/// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is +/// done only on items with the same name. +#[derive(Debug, Clone, PartialEq, HashStable)] +pub struct AssociatedItems<'tcx> { + pub(super) items: SortedIndexMultiMap, +} + +impl<'tcx> AssociatedItems<'tcx> { + /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. + pub fn new(items_in_def_order: impl IntoIterator) -> Self { + let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect(); + AssociatedItems { items } + } + + /// Returns a slice of associated items in the order they were defined. + /// + /// New code should avoid relying on definition order. If you need a particular associated item + /// for a known trait, make that trait a lang item instead of indexing this array. + pub fn in_definition_order(&self) -> impl '_ + Iterator { + self.items.iter().map(|(_, v)| *v) + } + + pub fn len(&self) -> usize { + self.items.len() + } + + /// Returns an iterator over all associated items with the given name, ignoring hygiene. + pub fn filter_by_name_unhygienic( + &self, + name: Symbol, + ) -> impl '_ + Iterator { + self.items.get_by_key(&name).copied() + } + + /// Returns an iterator over all associated items with the given name. + /// + /// Multiple items may have the same name if they are in different `Namespace`s. For example, + /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*` + /// methods below if you know which item you are looking for. + pub fn filter_by_name( + &'a self, + tcx: TyCtxt<'a>, + ident: Ident, + parent_def_id: DefId, + ) -> impl 'a + Iterator { + self.filter_by_name_unhygienic(ident.name) + .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + } + + /// Returns the associated item with the given name and `AssocKind`, if one exists. + pub fn find_by_name_and_kind( + &self, + tcx: TyCtxt<'_>, + ident: Ident, + kind: AssocKind, + parent_def_id: DefId, + ) -> Option<&ty::AssocItem> { + self.filter_by_name_unhygienic(ident.name) + .filter(|item| item.kind == kind) + .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + } + + /// Returns the associated item with the given name in the given `Namespace`, if one exists. + pub fn find_by_name_and_namespace( + &self, + tcx: TyCtxt<'_>, + ident: Ident, + ns: Namespace, + parent_def_id: DefId, + ) -> Option<&ty::AssocItem> { + self.filter_by_name_unhygienic(ident.name) + .filter(|item| item.kind.namespace() == ns) + .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 88c6a2166df..f380a9b4b81 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -14,6 +14,7 @@ pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::Variance::*; +pub use assoc::*; pub use generics::*; pub use upvar::*; @@ -34,13 +35,12 @@ use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{self, par_iter, ParallelIterator}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_errors::ErrorReported; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::lang_items::LangItem; use rustc_hir::{Constness, Node}; @@ -107,6 +107,7 @@ pub mod trait_def; pub mod util; pub mod walk; +mod assoc; mod consts; mod context; mod diagnostics; @@ -134,30 +135,6 @@ pub struct ResolverOutputs { pub extern_prelude: FxHashMap, } -#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)] -pub enum AssocItemContainer { - TraitContainer(DefId), - ImplContainer(DefId), -} - -impl AssocItemContainer { - /// Asserts that this is the `DefId` of an associated item declared - /// in a trait, and returns the trait `DefId`. - pub fn assert_trait(&self) -> DefId { - match *self { - TraitContainer(id) => id, - _ => bug!("associated item has wrong container type: {:?}", self), - } - } - - pub fn id(&self) -> DefId { - match *self { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - /// The "header" of an impl is everything outside the body: a Self type, a trait /// ref (in the case of a trait impl), and a set of predicates (from the /// bounds / where-clauses). @@ -182,142 +159,6 @@ pub enum ImplPolarity { Reservation, } -#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)] -pub struct AssocItem { - pub def_id: DefId, - #[stable_hasher(project(name))] - pub ident: Ident, - pub kind: AssocKind, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub container: AssocItemContainer, - - /// Whether this is a method with an explicit self - /// as its first parameter, allowing method calls. - pub fn_has_self_parameter: bool, -} - -#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)] -pub enum AssocKind { - Const, - Fn, - Type, -} - -impl AssocKind { - pub fn namespace(&self) -> Namespace { - match *self { - ty::AssocKind::Type => Namespace::TypeNS, - ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS, - } - } - - pub fn as_def_kind(&self) -> DefKind { - match self { - AssocKind::Const => DefKind::AssocConst, - AssocKind::Fn => DefKind::AssocFn, - AssocKind::Type => DefKind::AssocTy, - } - } -} - -impl AssocItem { - pub fn signature(&self, tcx: TyCtxt<'_>) -> String { - match self.kind { - ty::AssocKind::Fn => { - // We skip the binder here because the binder would deanonymize all - // late-bound regions, and we don't want method signatures to show up - // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound - // regions just fine, showing `fn(&MyType)`. - tcx.fn_sig(self.def_id).skip_binder().to_string() - } - ty::AssocKind::Type => format!("type {};", self.ident), - ty::AssocKind::Const => { - format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id)) - } - } - } -} - -/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. -/// -/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since -/// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is -/// done only on items with the same name. -#[derive(Debug, Clone, PartialEq, HashStable)] -pub struct AssociatedItems<'tcx> { - items: SortedIndexMultiMap, -} - -impl<'tcx> AssociatedItems<'tcx> { - /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. - pub fn new(items_in_def_order: impl IntoIterator) -> Self { - let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect(); - AssociatedItems { items } - } - - /// Returns a slice of associated items in the order they were defined. - /// - /// New code should avoid relying on definition order. If you need a particular associated item - /// for a known trait, make that trait a lang item instead of indexing this array. - pub fn in_definition_order(&self) -> impl '_ + Iterator { - self.items.iter().map(|(_, v)| *v) - } - - pub fn len(&self) -> usize { - self.items.len() - } - - /// Returns an iterator over all associated items with the given name, ignoring hygiene. - pub fn filter_by_name_unhygienic( - &self, - name: Symbol, - ) -> impl '_ + Iterator { - self.items.get_by_key(&name).copied() - } - - /// Returns an iterator over all associated items with the given name. - /// - /// Multiple items may have the same name if they are in different `Namespace`s. For example, - /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*` - /// methods below if you know which item you are looking for. - pub fn filter_by_name( - &'a self, - tcx: TyCtxt<'a>, - ident: Ident, - parent_def_id: DefId, - ) -> impl 'a + Iterator { - self.filter_by_name_unhygienic(ident.name) - .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) - } - - /// Returns the associated item with the given name and `AssocKind`, if one exists. - pub fn find_by_name_and_kind( - &self, - tcx: TyCtxt<'_>, - ident: Ident, - kind: AssocKind, - parent_def_id: DefId, - ) -> Option<&ty::AssocItem> { - self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind == kind) - .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) - } - - /// Returns the associated item with the given name in the given `Namespace`, if one exists. - pub fn find_by_name_and_namespace( - &self, - tcx: TyCtxt<'_>, - ident: Ident, - ns: Namespace, - parent_def_id: DefId, - ) -> Option<&ty::AssocItem> { - self.filter_by_name_unhygienic(ident.name) - .filter(|item| item.kind.namespace() == ns) - .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) - } -} - #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)] pub enum Visibility { /// Visible everywhere (including in other crates).