Clean up implementation of RPITIT assoc item lowering

This commit is contained in:
Michael Goulet 2025-07-12 19:31:15 +00:00
parent 47e15d90e1
commit 736bfa12de
9 changed files with 110 additions and 146 deletions

View file

@ -15,7 +15,6 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{
self, BottomUpFolder, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
associated_types_for_impl_traits_in_associated_fn,
};
use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Span};
@ -758,7 +757,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// returning `-> Missing<impl Sized>`, that gets converted to `-> {type error}`,
// and when walking through the signature we end up never collecting the def id
// of the `impl Sized`. Insert that here, so we don't ICE later.
for assoc_item in associated_types_for_impl_traits_in_associated_fn(tcx, trait_m.def_id) {
for assoc_item in tcx.associated_types_for_impl_traits_in_associated_fn(trait_m.def_id) {
if !remapped_types.contains_key(assoc_item) {
remapped_types.insert(
*assoc_item,
@ -2449,7 +2448,8 @@ fn param_env_with_gat_bounds<'tcx>(
ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
),
} => associated_types_for_impl_traits_in_associated_fn(tcx, fn_def_id)
} => tcx
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
.iter()
.map(|def_id| tcx.associated_item(*def_id))
.collect(),

View file

@ -20,7 +20,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags,
TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
Upcast, associated_types_for_impl_traits_in_associated_fn,
Upcast,
};
use rustc_middle::{bug, span_bug};
use rustc_session::parse::feature_err;
@ -327,7 +327,7 @@ pub(crate) fn check_trait_item<'tcx>(
if matches!(tcx.def_kind(def_id), DefKind::AssocFn) {
for &assoc_ty_def_id in
associated_types_for_impl_traits_in_associated_fn(tcx, def_id.to_def_id())
tcx.associated_types_for_impl_traits_in_associated_fn(def_id.to_def_id())
{
res = res.and(check_associated_item(tcx, assoc_ty_def_id.expect_local()));
}

View file

@ -40,7 +40,7 @@ use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
TypingMode, Upcast, associated_types_for_impl_traits_in_associated_fn, fold_regions,
TypingMode, Upcast, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@ -2602,7 +2602,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// do a linear search to map this to the synthetic associated type that
// it will be lowered to.
let def_id = if let Some(parent_def_id) = in_trait {
*associated_types_for_impl_traits_in_associated_fn(tcx, parent_def_id.to_def_id())
*tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id.to_def_id())
.iter()
.find(|rpitit| match tcx.opt_rpitit_info(**rpitit) {
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {

View file

@ -481,7 +481,7 @@ define_tables! {
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
associated_types_for_impl_traits_in_trait_or_impl: Table<DefIndex, LazyValue<ty::AssocTyForImplTraitInTraitOrImpl>>,
associated_types_for_impl_traits_in_trait_or_impl: Table<DefIndex, LazyValue<DefIdMap<Vec<DefId>>>>,
}
#[derive(TyEncodable, TyDecodable)]

View file

@ -1079,9 +1079,11 @@ rustc_queries! {
desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
}
query associated_types_for_impl_traits_in_trait_or_impl(did: DefId) -> &'tcx ty::AssocTyForImplTraitInTraitOrImpl {
/// Given the `item_def_id` of a trait or impl, return a mapping from associated fn def id
/// to its associated type items that correspond to the RPITITs in its signature.
query associated_types_for_impl_traits_in_trait_or_impl(item_def_id: DefId) -> &'tcx DefIdMap<Vec<DefId>> {
arena_cache
desc { |tcx| "creating rpitit for `{}`", tcx.def_path_str(did) }
desc { |tcx| "synthesizing RPITIT items for the opaque types for methods in `{}`", tcx.def_path_str(item_def_id) }
separate_provide_extern
}

View file

@ -1,5 +1,4 @@
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
@ -287,22 +286,21 @@ impl AssocItems {
}
}
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable)]
pub struct AssocTyForImplTraitInTraitOrImpl(pub FxIndexMap<DefId, Vec<DefId>>);
/// Given an `fn_def_id` of a trait or a trait implementation:
///
/// if `fn_def_id` is a function defined inside a trait, then it synthesizes
/// a new def id corresponding to a new associated type for each return-
/// position `impl Trait` in the signature.
///
/// if `fn_def_id` is a function inside of an impl, then for each synthetic
/// associated type generated for the corresponding trait function described
/// above, synthesize a corresponding associated type in the impl.
pub fn associated_types_for_impl_traits_in_associated_fn(
tcx: TyCtxt<'_>,
fn_def_id: DefId,
) -> &'_ [DefId] {
let parent_def_id = tcx.parent(fn_def_id);
&tcx.associated_types_for_impl_traits_in_trait_or_impl(parent_def_id).0[&fn_def_id]
impl<'tcx> TyCtxt<'tcx> {
/// Given an `fn_def_id` of a trait or a trait implementation:
///
/// if `fn_def_id` is a function defined inside a trait, then it synthesizes
/// a new def id corresponding to a new associated type for each return-
/// position `impl Trait` in the signature.
///
/// if `fn_def_id` is a function inside of an impl, then for each synthetic
/// associated type generated for the corresponding trait function described
/// above, synthesize a corresponding associated type in the impl.
pub fn associated_types_for_impl_traits_in_associated_fn(
self,
fn_def_id: DefId,
) -> &'tcx [DefId] {
let parent_def_id = self.parent(fn_def_id);
&self.associated_types_for_impl_traits_in_trait_or_impl(parent_def_id)[&fn_def_id]
}
}

View file

@ -2194,7 +2194,8 @@ impl<'tcx> TyCtxt<'tcx> {
return false;
};
return !associated_types_for_impl_traits_in_associated_fn(self, trait_item_def_id)
return !self
.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id)
.is_empty();
}
}

View file

@ -23,6 +23,10 @@ impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for
type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>);
}
impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Vec<T> {
type Value<'tcx> = Vec<T::Value<'tcx>>;
}
impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> {
type Value<'tcx> = IndexVec<I, T::Value<'tcx>>;
}
@ -67,7 +71,6 @@ trivially_parameterized_over_tcx! {
crate::mir::ConstQualifs,
ty::AsyncDestructor,
ty::AssocItemContainer,
ty::AssocTyForImplTraitInTraitOrImpl,
ty::Asyncness,
ty::AnonConstKind,
ty::DeducedParamAttrs,

View file

@ -1,15 +1,11 @@
use std::collections::hash_map::Entry;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, ItemKind};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, AssocTyForImplTraitInTraitOrImpl, ImplTraitInTraitData, TyCtxt};
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::Symbol;
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
@ -26,39 +22,28 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
let item = tcx.hir_expect_item(def_id);
match item.kind {
hir::ItemKind::Trait(.., trait_item_refs) => {
// We collect RPITITs for each trait method's return type and create a
// corresponding associated item using associated_types_for_impl_traits_in_trait_or_impl
// We collect RPITITs for each trait method's return type and create a corresponding
// associated item using the associated_types_for_impl_traits_in_trait_or_impl
// query.
tcx.arena.alloc_from_iter(
trait_item_refs
.iter()
.map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id())
.chain(
tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id)
.0
.values()
.flatten()
.copied(),
),
)
let rpitit_items = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id);
tcx.arena.alloc_from_iter(trait_item_refs.iter().flat_map(|trait_item_ref| {
let item_def_id = trait_item_ref.id.owner_id.to_def_id();
[item_def_id]
.into_iter()
.chain(rpitit_items.get(&item_def_id).into_iter().flatten().copied())
}))
}
hir::ItemKind::Impl(impl_) => {
// We collect RPITITs for each trait method's return type, on the impl side too and
// create a corresponding associated item using
// associated_types_for_impl_traits_in_trait_or_impl query.
tcx.arena.alloc_from_iter(
impl_
.items
.iter()
.map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id())
.chain(impl_.of_trait.iter().flat_map(|_| {
tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id)
.0
.values()
.flatten()
.copied()
})),
)
let rpitit_items = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id);
tcx.arena.alloc_from_iter(impl_.items.iter().flat_map(|impl_item_ref| {
let item_def_id = impl_item_ref.id.owner_id.to_def_id();
[item_def_id]
.into_iter()
.chain(rpitit_items.get(&item_def_id).into_iter().flatten().copied())
}))
}
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
}
@ -147,15 +132,15 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
container: ty::AssocItemContainer::Impl,
}
}
struct RPITVisitor<'tcx> {
struct RPITVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
synthetics: Vec<LocalDefId>,
data: DefPathData,
disambiguator: DisambiguatorState,
disambiguator: &'a mut DisambiguatorState,
depth: u32,
}
impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> {
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
self.depth += 1;
self.synthetics.push(associated_type_for_impl_trait_in_trait(
@ -171,90 +156,64 @@ impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> AssocTyForImplTraitInTraitOrImpl {
) -> DefIdMap<Vec<DefId>> {
let item = tcx.hir_expect_item(def_id);
let disambiguator = &mut DisambiguatorState::new();
match item.kind {
ItemKind::Trait(.., trait_item_refs) => {
let mut disambiguator_idx_map = FxHashMap::default();
let find_disambiguator_idx =
|map: &mut FxHashMap<Symbol, u32>, name| match map.entry(name) {
Entry::Occupied(occ) => *occ.get() + 1,
Entry::Vacant(vac) => {
vac.insert(0);
0
}
ItemKind::Trait(.., trait_item_refs) => trait_item_refs
.iter()
.filter_map(move |item| {
if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) {
return None;
}
let fn_def_id = item.id.owner_id.def_id;
let Some(output) = tcx.hir_get_fn_output(fn_def_id) else {
return Some((fn_def_id.to_def_id(), vec![]));
};
let update_disambiguator_idx = |map: &mut FxHashMap<Symbol, u32>, name, offset: u32| {
*map.get_mut(&name).unwrap() += offset
};
ty::AssocTyForImplTraitInTraitOrImpl(
trait_item_refs
.iter()
.filter_map(move |item| {
if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) {
return None;
}
let fn_def_id = item.id.owner_id.def_id;
let Some(output) = tcx.hir_get_fn_output(fn_def_id) else {
return Some((fn_def_id.to_def_id(), vec![]));
};
let def_name = tcx.item_name(fn_def_id.to_def_id());
let disambiguator_idx =
find_disambiguator_idx(&mut disambiguator_idx_map, def_name);
let data = DefPathData::AnonAssocTy(def_name);
let mut visitor = RPITVisitor {
tcx,
synthetics: vec![],
data,
depth: 0,
disambiguator: DisambiguatorState::with(
def_id,
data,
disambiguator_idx,
),
};
visitor.visit_fn_ret_ty(output);
update_disambiguator_idx(
&mut disambiguator_idx_map,
def_name,
visitor.depth,
);
let defs = visitor
.synthetics
.into_iter()
.map(|def_id| def_id.to_def_id())
.collect::<Vec<_>>();
Some((fn_def_id.to_def_id(), defs))
})
.collect::<FxIndexMap<_, _>>(),
)
}
let def_name = tcx.item_name(fn_def_id.to_def_id());
let data = DefPathData::AnonAssocTy(def_name);
let mut visitor =
RPITVisitor { tcx, synthetics: vec![], data, depth: 0, disambiguator };
visitor.visit_fn_ret_ty(output);
let defs = visitor
.synthetics
.into_iter()
.map(|def_id| def_id.to_def_id())
.collect::<Vec<_>>();
Some((fn_def_id.to_def_id(), defs))
})
.collect(),
ItemKind::Impl(impl_) => {
let Some(trait_did) = tcx.impl_trait_ref(def_id).map(|t| t.skip_binder().def_id) else {
return ty::AssocTyForImplTraitInTraitOrImpl(Default::default());
let Some(trait_ref) = impl_.of_trait else {
return Default::default();
};
let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_did);
ty::AssocTyForImplTraitInTraitOrImpl(
impl_
.items
.iter()
.filter_map(|item| {
if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) {
return None;
}
let did = item.id.owner_id.def_id.to_def_id();
let Some(trait_item_def_id) = item.trait_item_def_id else {
return Some((did, vec![]));
};
let iter = in_trait_def.0[&trait_item_def_id].iter().map(|&id| {
associated_type_for_impl_trait_in_impl(tcx, id, item.id.owner_id.def_id)
.to_def_id()
});
Some((did, iter.collect()))
})
.collect::<FxIndexMap<_, _>>(),
)
let Some(trait_def_id) = trait_ref.trait_def_id() else {
return Default::default();
};
let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id);
impl_
.items
.iter()
.filter_map(|item| {
if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) {
return None;
}
let did = item.id.owner_id.def_id.to_def_id();
let Some(trait_item_def_id) = item.trait_item_def_id else {
return Some((did, vec![]));
};
let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| {
associated_type_for_impl_trait_in_impl(
tcx,
id,
item.id.owner_id.def_id,
disambiguator,
)
.to_def_id()
});
Some((did, iter.collect()))
})
.collect()
}
_ => {
bug!(
@ -336,6 +295,7 @@ fn associated_type_for_impl_trait_in_impl(
tcx: TyCtxt<'_>,
trait_assoc_def_id: DefId,
impl_fn_def_id: LocalDefId,
disambiguator: &mut DisambiguatorState,
) -> LocalDefId {
let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
@ -358,7 +318,7 @@ fn associated_type_for_impl_trait_in_impl(
None,
DefKind::AssocTy,
Some(data),
&mut DisambiguatorState::with(impl_local_def_id, data, disambiguated_data.disambiguator),
disambiguator,
);
let local_def_id = impl_assoc_ty.def_id();