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_macros::{Decodable, Encodable, HashStable};
use rustc_span::symbol::{Ident, Symbol};
use super::{TyCtxt, Visibility};
use crate::ty;
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
pub enum AssocItemContainer {
Trait,
Impl,
}
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
pub struct AssocItem {
pub def_id: DefId,
pub name: Symbol,
pub kind: AssocKind,
pub container: AssocItemContainer,
pub trait_item_def_id: Option<DefId>,
pub fn_has_self_parameter: bool,
pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
}
impl AssocItem {
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
}
pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
tcx.defaultness(self.def_id)
}
#[inline]
pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
tcx.visibility(self.def_id)
}
#[inline]
pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
tcx.parent(self.def_id)
}
#[inline]
pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
match self.container {
AssocItemContainer::Impl => None,
AssocItemContainer::Trait => Some(tcx.parent(self.def_id)),
}
}
#[inline]
pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
match self.container {
AssocItemContainer::Impl => Some(tcx.parent(self.def_id)),
AssocItemContainer::Trait => None,
}
}
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
match self.kind {
ty::AssocKind::Fn => {
tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
}
ty::AssocKind::Type => format!("type {};", self.name),
ty::AssocKind::Const => {
format!(
"const {}: {:?};",
self.name,
tcx.type_of(self.def_id).instantiate_identity()
)
}
}
}
pub fn descr(&self) -> &'static str {
match self.kind {
ty::AssocKind::Const => "const",
ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
ty::AssocKind::Fn => "associated function",
ty::AssocKind::Type => "type",
}
}
pub fn is_impl_trait_in_trait(&self) -> bool {
self.opt_rpitit_info.is_some()
}
}
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
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 std::fmt::Display for AssocKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AssocKind::Fn => write!(f, "method"),
AssocKind::Const => write!(f, "associated const"),
AssocKind::Type => write!(f, "associated type"),
}
}
}
#[derive(Debug, Clone, PartialEq, HashStable)]
pub struct AssocItems {
items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>,
}
impl AssocItems {
pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
AssocItems { items }
}
pub fn in_definition_order(&self) -> impl '_ + Iterator<Item = &ty::AssocItem> {
self.items.iter().map(|(_, v)| v)
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn filter_by_name_unhygienic(
&self,
name: Symbol,
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
self.items.get_by_key(name)
}
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(tcx), parent_def_id))
}
pub fn find_by_name_and_kinds(
&self,
tcx: TyCtxt<'_>,
ident: Ident,
kinds: &[AssocKind],
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
}
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(tcx), parent_def_id))
}
}