Rollup merge of #139669 - nnethercote:overhaul-AssocItem, r=oli-obk
Overhaul `AssocItem` `AssocItem` has multiple fields that only make sense some of the time. E.g. the `name` can be empty if it's an RPITIT associated type. It's clearer and less error prone if these fields are moved to the relevant `kind` variants. r? ``@fee1-dead``
This commit is contained in:
commit
13cd5256ac
86 changed files with 609 additions and 546 deletions
|
@ -1636,8 +1636,8 @@ pub fn find_self_call<'tcx>(
|
|||
&body[block].terminator
|
||||
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
|
||||
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
|
||||
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||
tcx.opt_associated_item(def_id)
|
||||
&& let Some(item) = tcx.opt_associated_item(def_id)
|
||||
&& item.is_method()
|
||||
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
|
||||
**args
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::{Ty, TyCtxt};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub enum PointerCoercion {
|
||||
|
@ -133,7 +133,7 @@ impl OverloadedDeref {
|
|||
};
|
||||
tcx.associated_items(trait_def_id)
|
||||
.in_definition_order()
|
||||
.find(|m| m.kind == ty::AssocKind::Fn)
|
||||
.find(|item| item.is_fn())
|
||||
.unwrap()
|
||||
.def_id
|
||||
}
|
||||
|
|
|
@ -18,27 +18,33 @@ pub enum AssocItemContainer {
|
|||
#[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,
|
||||
|
||||
/// If this is an item in an impl of a trait then this is the `DefId` of
|
||||
/// the associated item on the trait that this implements.
|
||||
pub trait_item_def_id: Option<DefId>,
|
||||
|
||||
/// Whether this is a method with an explicit self
|
||||
/// as its first parameter, allowing method calls.
|
||||
pub fn_has_self_parameter: bool,
|
||||
|
||||
/// `Some` if the associated item (an associated type) comes from the
|
||||
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
|
||||
/// provides additional information about its source.
|
||||
pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
|
||||
}
|
||||
|
||||
impl AssocItem {
|
||||
// Gets the identifier, if it has one.
|
||||
pub fn opt_name(&self) -> Option<Symbol> {
|
||||
match self.kind {
|
||||
ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name),
|
||||
ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None,
|
||||
ty::AssocKind::Const { name } => Some(name),
|
||||
ty::AssocKind::Fn { name, .. } => Some(name),
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the identifier name. Aborts if it lacks one, i.e. is an RPITIT
|
||||
// associated type.
|
||||
pub fn name(&self) -> Symbol {
|
||||
self.opt_name().expect("name of non-Rpitit assoc item")
|
||||
}
|
||||
|
||||
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
|
||||
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
|
||||
Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap())
|
||||
}
|
||||
|
||||
/// Gets the defaultness of the associated item.
|
||||
|
@ -78,35 +84,65 @@ impl AssocItem {
|
|||
|
||||
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
|
||||
match self.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
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).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()
|
||||
)
|
||||
ty::AssocKind::Type { .. } => format!("type {};", self.name()),
|
||||
ty::AssocKind::Const { name } => {
|
||||
format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self.kind {
|
||||
ty::AssocKind::Const => "associated const",
|
||||
ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
|
||||
ty::AssocKind::Fn => "associated function",
|
||||
ty::AssocKind::Type => "associated type",
|
||||
ty::AssocKind::Const { .. } => "associated const",
|
||||
ty::AssocKind::Fn { has_self: true, .. } => "method",
|
||||
ty::AssocKind::Fn { has_self: false, .. } => "associated function",
|
||||
ty::AssocKind::Type { .. } => "associated type",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn namespace(&self) -> Namespace {
|
||||
match self.kind {
|
||||
ty::AssocKind::Type { .. } => Namespace::TypeNS,
|
||||
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_def_kind(&self) -> DefKind {
|
||||
match self.kind {
|
||||
AssocKind::Const { .. } => DefKind::AssocConst,
|
||||
AssocKind::Fn { .. } => DefKind::AssocFn,
|
||||
AssocKind::Type { .. } => DefKind::AssocTy,
|
||||
}
|
||||
}
|
||||
pub fn is_type(&self) -> bool {
|
||||
matches!(self.kind, ty::AssocKind::Type { .. })
|
||||
}
|
||||
|
||||
pub fn is_fn(&self) -> bool {
|
||||
matches!(self.kind, ty::AssocKind::Fn { .. })
|
||||
}
|
||||
|
||||
pub fn is_method(&self) -> bool {
|
||||
matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
|
||||
}
|
||||
|
||||
pub fn as_tag(&self) -> AssocTag {
|
||||
match self.kind {
|
||||
AssocKind::Const { .. } => AssocTag::Const,
|
||||
AssocKind::Fn { .. } => AssocTag::Fn,
|
||||
AssocKind::Type { .. } => AssocTag::Type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_impl_trait_in_trait(&self) -> bool {
|
||||
self.opt_rpitit_info.is_some()
|
||||
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
||||
}
|
||||
|
||||
/// Returns true if:
|
||||
|
@ -114,7 +150,7 @@ impl AssocItem {
|
|||
/// - If it is in a trait impl, the item from the original trait has this attribute, or
|
||||
/// - It is an inherent assoc const.
|
||||
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
|
||||
if self.kind != ty::AssocKind::Const {
|
||||
if !matches!(self.kind, ty::AssocKind::Const { .. }) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -128,26 +164,35 @@ impl AssocItem {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum AssocTypeData {
|
||||
Normal(Symbol),
|
||||
/// The associated type comes from an RPITIT. It has no name, and the
|
||||
/// `ImplTraitInTraitData` provides additional information about its
|
||||
/// source.
|
||||
Rpitit(ty::ImplTraitInTraitData),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum AssocKind {
|
||||
Const,
|
||||
Fn,
|
||||
Type,
|
||||
Const { name: Symbol },
|
||||
Fn { name: Symbol, has_self: bool },
|
||||
Type { data: AssocTypeData },
|
||||
}
|
||||
|
||||
impl AssocKind {
|
||||
pub fn namespace(&self) -> Namespace {
|
||||
match *self {
|
||||
ty::AssocKind::Type => Namespace::TypeNS,
|
||||
ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
|
||||
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,
|
||||
AssocKind::Const { .. } => DefKind::AssocConst,
|
||||
AssocKind::Fn { .. } => DefKind::AssocFn,
|
||||
AssocKind::Type { .. } => DefKind::AssocTy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,15 +200,22 @@ impl AssocKind {
|
|||
impl std::fmt::Display for AssocKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
// FIXME: fails to distinguish between "associated function" and
|
||||
// "method" because `has_self` isn't known here.
|
||||
AssocKind::Fn => write!(f, "method"),
|
||||
AssocKind::Const => write!(f, "associated const"),
|
||||
AssocKind::Type => write!(f, "associated type"),
|
||||
AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
|
||||
AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
|
||||
AssocKind::Const { .. } => write!(f, "associated const"),
|
||||
AssocKind::Type { .. } => write!(f, "associated type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum AssocTag {
|
||||
Const,
|
||||
Fn,
|
||||
Type,
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
@ -171,17 +223,17 @@ impl std::fmt::Display for AssocKind {
|
|||
/// done only on items with the same name.
|
||||
#[derive(Debug, Clone, PartialEq, HashStable)]
|
||||
pub struct AssocItems {
|
||||
items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>,
|
||||
items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
|
||||
}
|
||||
|
||||
impl AssocItems {
|
||||
/// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
|
||||
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();
|
||||
let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
|
||||
AssocItems { items }
|
||||
}
|
||||
|
||||
/// Returns a slice of associated items in the order they were defined.
|
||||
/// Returns an iterator over 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.
|
||||
|
@ -198,7 +250,8 @@ impl AssocItems {
|
|||
&self,
|
||||
name: Symbol,
|
||||
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
|
||||
self.items.get_by_key(name)
|
||||
assert!(!name.is_empty());
|
||||
self.items.get_by_key(Some(name))
|
||||
}
|
||||
|
||||
/// Returns the associated item with the given identifier and `AssocKind`, if one exists.
|
||||
|
@ -207,27 +260,14 @@ impl AssocItems {
|
|||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
ident: Ident,
|
||||
kind: AssocKind,
|
||||
assoc_tag: AssocTag,
|
||||
parent_def_id: DefId,
|
||||
) -> Option<&ty::AssocItem> {
|
||||
self.filter_by_name_unhygienic(ident.name)
|
||||
.filter(|item| item.kind == kind)
|
||||
.filter(|item| item.as_tag() == assoc_tag)
|
||||
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
|
||||
}
|
||||
|
||||
/// Returns the associated item with the given identifier and any of `AssocKind`, if one
|
||||
/// exists. The identifier is matched hygienically.
|
||||
pub fn find_by_ident_and_kinds(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
ident: Ident,
|
||||
// Sorted in order of what kinds to look at
|
||||
kinds: &[AssocKind],
|
||||
parent_def_id: DefId,
|
||||
) -> Option<&ty::AssocItem> {
|
||||
kinds.iter().find_map(|kind| self.find_by_ident_and_kind(tcx, ident, *kind, parent_def_id))
|
||||
}
|
||||
|
||||
/// Returns the associated item with the given identifier in the given `Namespace`, if one
|
||||
/// exists. The identifier is matched hygienically.
|
||||
pub fn find_by_ident_and_namespace(
|
||||
|
@ -238,7 +278,7 @@ impl AssocItems {
|
|||
parent_def_id: DefId,
|
||||
) -> Option<&ty::AssocItem> {
|
||||
self.filter_by_name_unhygienic(ident.name)
|
||||
.filter(|item| item.kind.namespace() == ns)
|
||||
.filter(|item| item.namespace() == ns)
|
||||
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -464,7 +464,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
self.associated_items(def_id)
|
||||
.in_definition_order()
|
||||
.filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
|
||||
.filter(|assoc_item| assoc_item.is_type())
|
||||
.map(|assoc_item| assoc_item.def_id)
|
||||
}
|
||||
|
||||
|
|
|
@ -746,7 +746,7 @@ impl<'tcx> Instance<'tcx> {
|
|||
let call_once = tcx
|
||||
.associated_items(fn_once)
|
||||
.in_definition_order()
|
||||
.find(|it| it.kind == ty::AssocKind::Fn)
|
||||
.find(|it| it.is_fn())
|
||||
.unwrap()
|
||||
.def_id;
|
||||
let track_caller =
|
||||
|
|
|
@ -1462,7 +1462,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
|
||||
self.associated_items(id)
|
||||
.in_definition_order()
|
||||
.filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
|
||||
.filter(move |item| item.is_fn() && item.defaultness(self).has_value())
|
||||
}
|
||||
|
||||
pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
|
||||
|
@ -1608,8 +1608,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// return-position `impl Trait` from a trait, then provide the source info
|
||||
/// about where that RPITIT came from.
|
||||
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
|
||||
if let DefKind::AssocTy = self.def_kind(def_id) {
|
||||
self.associated_item(def_id).opt_rpitit_info
|
||||
if let DefKind::AssocTy = self.def_kind(def_id)
|
||||
&& let AssocKind::Type { data: AssocTypeData::Rpitit(rpitit_info) } =
|
||||
self.associated_item(def_id).kind
|
||||
{
|
||||
Some(rpitit_info)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -1214,7 +1214,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
&& assoc
|
||||
.trait_container(tcx)
|
||||
.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
|
||||
&& assoc.name == rustc_span::sym::Return
|
||||
&& assoc.opt_name() == Some(rustc_span::sym::Return)
|
||||
{
|
||||
if let ty::Coroutine(_, args) = args.type_at(0).kind() {
|
||||
let return_ty = args.as_coroutine().return_ty();
|
||||
|
@ -1237,7 +1237,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
p!(", ");
|
||||
}
|
||||
|
||||
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
|
||||
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name()));
|
||||
|
||||
match term.unpack() {
|
||||
TermKind::Ty(ty) => p!(print(ty)),
|
||||
|
@ -3291,7 +3291,7 @@ define_print! {
|
|||
}
|
||||
|
||||
ty::ExistentialProjection<'tcx> {
|
||||
let name = cx.tcx().associated_item(self.def_id).name;
|
||||
let name = cx.tcx().associated_item(self.def_id).name();
|
||||
// The args don't contain the self ty (as it has been erased) but the corresp.
|
||||
// generics do as the trait always has a self ty param. We need to offset.
|
||||
let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];
|
||||
|
|
|
@ -735,7 +735,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
.map(|principal| {
|
||||
tcx.associated_items(principal.def_id())
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.filter(|item| item.is_type())
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||
.count()
|
||||
|
|
|
@ -819,7 +819,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Get an English description for the item's kind.
|
||||
pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str {
|
||||
match def_kind {
|
||||
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method",
|
||||
DefKind::AssocFn if self.associated_item(def_id).is_method() => "method",
|
||||
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
||||
match coroutine_kind {
|
||||
hir::CoroutineKind::Desugared(
|
||||
|
@ -873,7 +873,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Gets an English article for the [`TyCtxt::def_kind_descr`].
|
||||
pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str {
|
||||
match def_kind {
|
||||
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a",
|
||||
DefKind::AssocFn if self.associated_item(def_id).is_method() => "a",
|
||||
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
|
||||
match coroutine_kind {
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue