Cleanup assoc parent utils

This commit is contained in:
Cameron Steffen 2025-08-12 17:57:02 -05:00
parent 8e62bfd311
commit d4eb0947f1
16 changed files with 78 additions and 63 deletions

View file

@ -677,12 +677,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// - is the trait from the local crate? If not, we can't suggest changing signatures
/// - `Span` of the argument in the trait definition
fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
let tcx = self.infcx.tcx;
if self.body.local_kind(local) != LocalKind::Arg {
return (false, false, None);
}
let my_def = self.body.source.def_id();
let Some(td) =
self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
tcx.trait_impl_of_assoc(my_def).and_then(|id| self.infcx.tcx.trait_id_of_impl(id))
else {
return (false, false, None);
};

View file

@ -1773,10 +1773,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
locations,
);
assert!(!matches!(
tcx.impl_of_assoc(def_id).map(|imp| tcx.def_kind(imp)),
Some(DefKind::Impl { of_trait: true })
));
assert_eq!(tcx.trait_impl_of_assoc(def_id), None);
self.prove_predicates(
args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())),
locations,

View file

@ -533,31 +533,26 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// First, let's see if this is a method within an inherent impl. Because
// if yes, we want to make the result subroutine DIE a child of the
// subroutine's self-type.
if let Some(impl_def_id) = cx.tcx.impl_of_assoc(instance.def_id()) {
// If the method does *not* belong to a trait, proceed
if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
instance.args,
cx.typing_env(),
cx.tcx.type_of(impl_def_id),
);
// For trait method impls we still use the "parallel namespace"
// strategy
if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
instance.args,
cx.typing_env(),
cx.tcx.type_of(imp_def_id),
);
// Only "class" methods are generally understood by LLVM,
// so avoid methods on other types (e.g., `<*mut T>::null`).
if let ty::Adt(def, ..) = impl_self_ty.kind()
&& !def.is_box()
{
// Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
{
return (type_di_node(cx, impl_self_ty), true);
} else {
return (namespace::item_namespace(cx, def.did()), false);
}
// Only "class" methods are generally understood by LLVM,
// so avoid methods on other types (e.g., `<*mut T>::null`).
if let ty::Adt(def, ..) = impl_self_ty.kind()
&& !def.is_box()
{
// Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
return (type_di_node(cx, impl_self_ty), true);
} else {
return (namespace::item_namespace(cx, def.did()), false);
}
} else {
// For trait method impls we still use the "parallel namespace"
// strategy
}
}

View file

@ -731,7 +731,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) {
let tcx = *self.tcx;
let trait_def_id = tcx.trait_of_assoc(def_id).unwrap();
let trait_def_id = tcx.parent(def_id);
let virtual_trait_ref = ty::TraitRef::from_assoc(tcx, trait_def_id, virtual_instance.args);
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);

View file

@ -445,10 +445,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m_def_id: LocalDefId,
) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> {
let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
let impl_m = tcx.associated_item(impl_m_def_id.to_def_id());
let trait_m = tcx.associated_item(impl_m.trait_item_def_id.unwrap());
let impl_trait_ref =
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
tcx.impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id())).unwrap().instantiate_identity();
// First, check a few of the same things as `compare_impl_method`,
// just so we don't ICE during instantiation later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;

View file

@ -2287,8 +2287,7 @@ fn lint_redundant_lifetimes<'tcx>(
// Proceed
}
DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
let parent_def_id = tcx.local_parent(owner_id);
if matches!(tcx.def_kind(parent_def_id), DefKind::Impl { of_trait: true }) {
if tcx.trait_impl_of_assoc(owner_id.to_def_id()).is_some() {
// Don't check for redundant lifetimes for associated items of trait
// implementations, since the signature is required to be compatible
// with the trait, even if the implementation implies some lifetimes

View file

@ -24,10 +24,8 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
if let Some(impl_did) = cx.tcx.impl_of_assoc(ty.hir_id.owner.to_def_id()) {
if cx.tcx.impl_trait_ref(impl_did).is_some() {
return;
}
if cx.tcx.trait_impl_of_assoc(ty.hir_id.owner.to_def_id()).is_some() {
return;
}
if let Some(t) = path_for_pass_by_value(cx, inner_ty) {
cx.emit_span_lint(

View file

@ -1904,10 +1904,9 @@ impl InvalidAtomicOrdering {
if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind
&& recognized_names.contains(&method_path.ident.name)
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let Some(impl_did) = cx.tcx.impl_of_assoc(m_def_id)
&& let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
// skip extension traits, only lint functions from the standard library
&& cx.tcx.trait_id_of_impl(impl_did).is_none()
&& let Some(impl_did) = cx.tcx.inherent_impl_of_assoc(m_def_id)
&& let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
&& let parent = cx.tcx.parent(adt.did())
&& cx.tcx.is_diagnostic_item(sym::atomic_mod, parent)
&& ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did()))

View file

@ -181,11 +181,7 @@ impl EffectiveVisibilities {
// nominal visibility. For some items nominal visibility doesn't make sense so we
// don't check this condition for them.
let is_impl = matches!(tcx.def_kind(def_id), DefKind::Impl { .. });
let is_associated_item_in_trait_impl = tcx
.impl_of_assoc(def_id.to_def_id())
.and_then(|impl_id| tcx.trait_id_of_impl(impl_id))
.is_some();
if !is_impl && !is_associated_item_in_trait_impl {
if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() {
let nominal_vis = tcx.visibility(def_id);
if !nominal_vis.is_at_least(ev.reachable, tcx) {
span_bug!(

View file

@ -1925,21 +1925,50 @@ impl<'tcx> TyCtxt<'tcx> {
self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
}
/// If the given `DefId` is an associated item, returns the `DefId` of the parent trait or impl.
pub fn assoc_parent(self, def_id: DefId) -> Option<DefId> {
self.def_kind(def_id).is_assoc().then(|| self.parent(def_id))
/// If the given `DefId` is an associated item, returns the `DefId` and `DefKind` of the parent trait or impl.
pub fn assoc_parent(self, def_id: DefId) -> Option<(DefId, DefKind)> {
if !self.def_kind(def_id).is_assoc() {
return None;
}
let parent = self.parent(def_id);
let def_kind = self.def_kind(parent);
Some((parent, def_kind))
}
/// If the given `DefId` is an associated item of a trait,
/// returns the `DefId` of the trait; otherwise, returns `None`.
pub fn trait_of_assoc(self, def_id: DefId) -> Option<DefId> {
self.assoc_parent(def_id).filter(|id| self.def_kind(id) == DefKind::Trait)
match self.assoc_parent(def_id) {
Some((id, DefKind::Trait)) => Some(id),
_ => None,
}
}
/// If the given `DefId` is an associated item of an impl,
/// returns the `DefId` of the impl; otherwise returns `None`.
pub fn impl_of_assoc(self, def_id: DefId) -> Option<DefId> {
self.assoc_parent(def_id).filter(|id| matches!(self.def_kind(id), DefKind::Impl { .. }))
match self.assoc_parent(def_id) {
Some((id, DefKind::Impl { .. })) => Some(id),
_ => None,
}
}
/// If the given `DefId` is an associated item of an inherent impl,
/// returns the `DefId` of the impl; otherwise, returns `None`.
pub fn inherent_impl_of_assoc(self, def_id: DefId) -> Option<DefId> {
match self.assoc_parent(def_id) {
Some((id, DefKind::Impl { of_trait: false })) => Some(id),
_ => None,
}
}
/// If the given `DefId` is an associated item of a trait impl,
/// returns the `DefId` of the impl; otherwise, returns `None`.
pub fn trait_impl_of_assoc(self, def_id: DefId) -> Option<DefId> {
match self.assoc_parent(def_id) {
Some((id, DefKind::Impl { of_trait: true })) => Some(id),
_ => None,
}
}
pub fn is_exportable(self, def_id: DefId) -> bool {

View file

@ -43,8 +43,8 @@ impl<'tcx> MirLint<'tcx> for CheckDropRecursion {
// First check if `body` is an `fn drop()` of `Drop`
if let DefKind::AssocFn = tcx.def_kind(def_id)
&& let Some(trait_ref) =
tcx.impl_of_assoc(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id))
&& let Some(impl_id) = tcx.trait_impl_of_assoc(def_id.to_def_id())
&& let trait_ref = tcx.impl_trait_ref(impl_id).unwrap()
&& tcx.is_lang_item(trait_ref.instantiate_identity().def_id, LangItem::Drop)
// avoid erroneous `Drop` impls from causing ICEs below
&& let sig = tcx.fn_sig(def_id).instantiate_identity()

View file

@ -40,7 +40,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place)
{
let def_id = self.body.source.instance.def_id();
if let Some(impl_def_id) = self.tcx.impl_of_assoc(def_id)
if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id)
&& self.tcx.is_builtin_derived(impl_def_id)
{
// If we ever reach here it means that the generated derive

View file

@ -75,7 +75,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))
}
ty::InstanceKind::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_assoc(def_id).unwrap();
let trait_ = tcx.parent(def_id);
// Supports `Fn` or `async Fn` traits.
let adjustment = match tcx
.fn_trait_kind_from_def_id(trait_)

View file

@ -650,17 +650,18 @@ fn characteristic_def_id_of_mono_item<'tcx>(
// its self-type. If the self-type does not provide a characteristic
// DefId, we use the location of the impl after all.
if tcx.trait_of_assoc(def_id).is_some() {
let assoc_parent = tcx.assoc_parent(def_id);
if let Some((_, DefKind::Trait)) = assoc_parent {
let self_ty = instance.args.type_at(0);
// This is a default implementation of a trait method.
return characteristic_def_id_of_type(self_ty).or(Some(def_id));
}
if let Some(impl_def_id) = tcx.impl_of_assoc(def_id) {
if tcx.sess.opts.incremental.is_some()
&& tcx
.trait_id_of_impl(impl_def_id)
.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Drop))
if let Some((impl_def_id, DefKind::Impl { of_trait })) = assoc_parent {
if of_trait
&& tcx.sess.opts.incremental.is_some()
&& tcx.is_lang_item(tcx.trait_id_of_impl(impl_def_id).unwrap(), LangItem::Drop)
{
// Put `Drop::drop` into the same cgu as `drop_in_place`
// since `drop_in_place` is the only thing that can

View file

@ -371,7 +371,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
/// will be ignored for the purposes of dead code analysis (see PR #85200
/// for discussion).
fn should_ignore_item(&mut self, def_id: DefId) -> bool {
if let Some(impl_of) = self.tcx.impl_of_assoc(def_id) {
if let Some(impl_of) = self.tcx.trait_impl_of_assoc(def_id) {
if !self.tcx.is_automatically_derived(impl_of) {
return false;
}

View file

@ -1507,7 +1507,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty();
let item_def_id = obligation.predicate.def_id;
let trait_def_id = tcx.trait_of_assoc(item_def_id).unwrap();
let trait_def_id = tcx.parent(item_def_id);
let args = tcx.mk_args(&[self_ty.into()]);
let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) {
let discriminant_def_id =