From dc6c3300fcf520b2931355e922caa66758becb71 Mon Sep 17 00:00:00 2001 From: bohan Date: Fri, 11 Jul 2025 20:11:49 +0800 Subject: [PATCH 1/3] compute all rpitit of a trait --- compiler/rustc_middle/src/query/mod.rs | 6 + compiler/rustc_ty_utils/src/assoc.rs | 112 +++++++++--------- ...tit-duplicate-associated-fn-with-nested.rs | 13 ++ ...duplicate-associated-fn-with-nested.stderr | 23 +++- 4 files changed, 97 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9af5683ff75b0..49c36a3ff1692 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1091,6 +1091,12 @@ rustc_queries! { separate_provide_extern } + query associated_types_for_impl_traits_in_trait(trait_id: DefId) -> &'tcx DefIdMap<&'tcx [DefId]> { + arena_cache + desc { |tcx| "creating associated items for trait `{}`", tcx.def_path_str(trait_id) } + separate_provide_extern + } + /// Given an `impl_id`, return the trait it implements along with some header information. /// Return `None` if this is an inherent impl. query impl_trait_header(impl_id: DefId) -> Option> { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 6a9461f2b43a7..c9fbc8b023342 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,3 +1,6 @@ +use std::collections::hash_map::Entry; + +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; @@ -6,12 +9,14 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; 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 { associated_item, associated_item_def_ids, associated_items, + associated_types_for_impl_traits_in_trait, associated_types_for_impl_traits_in_associated_fn, impl_item_implementor_ids, ..*providers @@ -163,10 +168,12 @@ struct RPITVisitor<'tcx> { synthetics: Vec, data: DefPathData, disambiguator: DisambiguatorState, + depth: u32, } 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( self.tcx, opaque.def_id, @@ -177,17 +184,6 @@ impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { } } -struct DisambiguatorIdxVisitor { - depth: u32, -} - -impl<'tcx> Visitor<'tcx> for DisambiguatorIdxVisitor { - fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result { - self.depth += 1; - intravisit::walk_opaque_ty(self, opaque) - } -} - /// 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 @@ -205,51 +201,7 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { - let def_path_id = |def_id: LocalDefId| tcx.item_name(def_id.to_def_id()); - let def_path_data = def_path_id(fn_def_id); - - let (.., trait_item_refs) = tcx.hir_expect_item(parent_def_id).expect_trait(); - // The purpose of `disambiguator_idx` is to ensure there are - // no duplicate `def_id` in certain cases, such as: - // ``` - // trait Foo { - // fn bar() -> impl Trait; - // fn bar() -> impl Trait; - // // ~~~~~~~~~~ It will generate the same ID if we don’t disambiguate it. - // } - // ``` - let disambiguator_idx = trait_item_refs - .iter() - .take_while(|item| item.id.owner_id.def_id != fn_def_id) - .filter(|item| { - matches!(item.kind, hir::AssocItemKind::Fn { .. }) - && def_path_id(item.id.owner_id.def_id) == def_path_data - }) - .last() - .map(|item| { - let output = tcx.hir_get_fn_output(item.id.owner_id.def_id).unwrap(); - let mut visitor = DisambiguatorIdxVisitor { depth: 0 }; - visitor.visit_fn_ret_ty(output); - tcx.def_key(item.id.owner_id.def_id).disambiguated_data.disambiguator - + visitor.depth - }) - .unwrap_or_default(); - - let data = DefPathData::AnonAssocTy(def_path_data); - let mut visitor = RPITVisitor { - tcx, - synthetics: vec![], - data, - disambiguator: DisambiguatorState::with(parent_def_id, data, disambiguator_idx), - }; - visitor.visit_fn_ret_ty(output); - tcx.arena.alloc_from_iter( - visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()), - ) - } else { - &[] - } + tcx.associated_types_for_impl_traits_in_trait(parent_def_id)[&fn_def_id.to_def_id()] } DefKind::Impl { .. } => { @@ -274,6 +226,54 @@ fn associated_types_for_impl_traits_in_associated_fn( } } +fn associated_types_for_impl_traits_in_trait<'tcx>( + tcx: TyCtxt<'tcx>, + trait_id: LocalDefId, +) -> DefIdMap<&'tcx [DefId]> { + let (.., trait_item_refs) = tcx.hir_expect_item(trait_id).expect_trait(); + + let mut disambiguator_idx_map = FxHashMap::default(); + let find_disambiguator_idx = |map: &mut FxHashMap, name| match map.entry(name) { + Entry::Occupied(occ) => *occ.get() + 1, + Entry::Vacant(vac) => { + vac.insert(0); + 0 + } + }; + let update_disambiguator_idx = |map: &mut FxHashMap, name, offset: u32| { + *map.get_mut(&name).unwrap() += offset + }; + + 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(), &[] as &[DefId])); + }; + 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(trait_id, data, disambiguator_idx), + }; + visitor.visit_fn_ret_ty(output); + update_disambiguator_idx(&mut disambiguator_idx_map, def_name, visitor.depth); + let defs = tcx + .arena + .alloc_from_iter(visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id())); + Some((fn_def_id.to_def_id(), defs)) + }) + .collect() +} + /// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated /// function from a trait, synthesize an associated type for that `impl Trait` /// that inherits properties that we infer from the method and the opaque type. diff --git a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.rs b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.rs index e3dc22c1992d5..9c9cef24a9656 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.rs @@ -43,4 +43,17 @@ trait Qux { //~^^^^ ERROR: the name `foo` is defined multiple times } +trait T0 { + type Target; +} +trait T1 {} + +trait X { + fn a() -> impl T0<(), Target = impl T1<()>>; + fn a() -> impl T0<(), Target = impl T1<()>>; + //~^ ERROR the name `a` is defined multiple times + fn a() -> impl T0<(), Target = impl T1<()>>; + //~^ ERROR the name `a` is defined multiple times +} + fn main() {} diff --git a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.stderr b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.stderr index f4e73dc17988b..8356f94f2aa7a 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.stderr +++ b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.stderr @@ -44,6 +44,27 @@ LL | | >; | = note: `foo` must be defined only once in the value namespace of this trait -error: aborting due to 4 previous errors +error[E0428]: the name `a` is defined multiple times + --> $DIR/rpitit-duplicate-associated-fn-with-nested.rs:53:5 + | +LL | fn a() -> impl T0<(), Target = impl T1<()>>; + | -------------------------------------------- previous definition of the value `a` here +LL | fn a() -> impl T0<(), Target = impl T1<()>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `a` redefined here + | + = note: `a` must be defined only once in the value namespace of this trait + +error[E0428]: the name `a` is defined multiple times + --> $DIR/rpitit-duplicate-associated-fn-with-nested.rs:55:5 + | +LL | fn a() -> impl T0<(), Target = impl T1<()>>; + | -------------------------------------------- previous definition of the value `a` here +... +LL | fn a() -> impl T0<(), Target = impl T1<()>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `a` redefined here + | + = note: `a` must be defined only once in the value namespace of this trait + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0428`. From 47e15d90e13b5238117971298a3573ddebd87a40 Mon Sep 17 00:00:00 2001 From: bohan Date: Sun, 13 Jul 2025 02:52:03 +0800 Subject: [PATCH 2/3] query RPITIT in a trait or impl --- .../src/check/compare_impl_item.rs | 6 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 6 +- .../src/hir_ty_lowering/mod.rs | 4 +- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 17 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 16 +- compiler/rustc_middle/src/ty/assoc.rs | 21 ++ compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_ty_utils/src/assoc.rs | 216 +++++++++--------- 11 files changed, 143 insertions(+), 151 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 87db80f2423d6..379ce69bdeab5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -15,6 +15,7 @@ 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}; @@ -757,7 +758,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // returning `-> Missing`, 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 tcx.associated_types_for_impl_traits_in_associated_fn(trait_m.def_id) { + for assoc_item in associated_types_for_impl_traits_in_associated_fn(tcx, trait_m.def_id) { if !remapped_types.contains_key(assoc_item) { remapped_types.insert( *assoc_item, @@ -2448,8 +2449,7 @@ fn param_env_with_gat_bounds<'tcx>( ty::ImplTraitInTraitData::Impl { fn_def_id } | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, ), - } => tcx - .associated_types_for_impl_traits_in_associated_fn(fn_def_id) + } => associated_types_for_impl_traits_in_associated_fn(tcx, fn_def_id) .iter() .map(|def_id| tcx.associated_item(*def_id)) .collect(), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 428d627ad6f2d..3d3fdd899d3f3 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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, + Upcast, associated_types_for_impl_traits_in_associated_fn, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -326,7 +326,9 @@ pub(crate) fn check_trait_item<'tcx>( let mut res = Ok(()); if matches!(tcx.def_kind(def_id), DefKind::AssocFn) { - for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { + for &assoc_ty_def_id in + associated_types_for_impl_traits_in_associated_fn(tcx, def_id.to_def_id()) + { res = res.and(check_associated_item(tcx, assoc_ty_def_id.expect_local())); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 20d165897e2a3..ae56f0c5160fc 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -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, fold_regions, + TypingMode, Upcast, associated_types_for_impl_traits_in_associated_fn, 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 { - *tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id) + *associated_types_for_impl_traits_in_associated_fn(tcx, parent_def_id.to_def_id()) .iter() .find(|rpitit| match tcx.opt_rpitit_info(**rpitit) { Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 6943d4198df43..19954459cb597 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -326,7 +326,7 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } - associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } + associated_types_for_impl_traits_in_trait_or_impl => { table } visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b0ec605a85fe5..b50453cb0dfde 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1382,17 +1382,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - if let Some(assoc_item) = tcx.opt_associated_item(def_id) - && assoc_item.container == ty::AssocItemContainer::Trait - && assoc_item.is_fn() - { - true - } else { - false - } -} - impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let tcx = self.tcx; @@ -1617,9 +1606,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } - if should_encode_fn_impl_trait_in_trait(tcx, def_id) { - let table = tcx.associated_types_for_impl_traits_in_associated_fn(def_id); - record_defaulted_array!(self.tables.associated_types_for_impl_traits_in_associated_fn[def_id] <- table); + if let DefKind::Impl { .. } | DefKind::Trait = def_kind { + let table = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id); + record!(self.tables.associated_types_for_impl_traits_in_trait_or_impl[def_id] <- table); } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a962a787a4287..213090d7d47e8 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -403,7 +403,6 @@ define_tables! { explicit_implied_predicates_of: Table, Span)>>, explicit_implied_const_bounds: Table, Span)>>, inherent_impls: Table>, - associated_types_for_impl_traits_in_associated_fn: Table>, opt_rpitit_info: Table>>, // Reexported names are not associated with individual `DefId`s, // e.g. a glob import can introduce a lot of names, all with the same `DefId`. @@ -482,6 +481,7 @@ define_tables! { assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, anon_const_kind: Table>, + associated_types_for_impl_traits_in_trait_or_impl: Table>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 49c36a3ff1692..3da6c6f5fe117 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1079,21 +1079,9 @@ rustc_queries! { desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) } } - /// Given `fn_def_id` of a trait or of an impl that implements a given trait: - /// if `fn_def_id` is the def id of a function defined inside a trait, then it creates and returns - /// the associated items that correspond to each impl trait in return position for that trait. - /// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it - /// creates and returns the associated items that correspond to each impl trait in return position - /// of the implemented trait. - query associated_types_for_impl_traits_in_associated_fn(fn_def_id: DefId) -> &'tcx [DefId] { - desc { |tcx| "creating associated items for opaque types returned by `{}`", tcx.def_path_str(fn_def_id) } - cache_on_disk_if { fn_def_id.is_local() } - separate_provide_extern - } - - query associated_types_for_impl_traits_in_trait(trait_id: DefId) -> &'tcx DefIdMap<&'tcx [DefId]> { + query associated_types_for_impl_traits_in_trait_or_impl(did: DefId) -> &'tcx ty::AssocTyForImplTraitInTraitOrImpl { arena_cache - desc { |tcx| "creating associated items for trait `{}`", tcx.def_path_str(trait_id) } + desc { |tcx| "creating rpitit for `{}`", tcx.def_path_str(did) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 344a81f5e24d1..99714171c72de 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -1,4 +1,5 @@ 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}; @@ -285,3 +286,23 @@ impl AssocItems { .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id)) } } + +#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable)] +pub struct AssocTyForImplTraitInTraitOrImpl(pub FxIndexMap>); + +/// 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] +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0177a95498bcd..e1b11e4f54add 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2194,8 +2194,7 @@ impl<'tcx> TyCtxt<'tcx> { return false; }; - return !self - .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id) + return !associated_types_for_impl_traits_in_associated_fn(self, trait_item_def_id) .is_empty(); } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 3858778bfc8fb..88f6e717af45b 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -67,6 +67,7 @@ trivially_parameterized_over_tcx! { crate::mir::ConstQualifs, ty::AsyncDestructor, ty::AssocItemContainer, + ty::AssocTyForImplTraitInTraitOrImpl, ty::Asyncness, ty::AnonConstKind, ty::DeducedParamAttrs, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index c9fbc8b023342..400158496b5b7 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,13 +1,13 @@ use std::collections::hash_map::Entry; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; +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, ImplTraitInTraitData, TyCtxt}; +use rustc_middle::ty::{self, AssocTyForImplTraitInTraitOrImpl, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Symbol; @@ -16,8 +16,7 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item, associated_item_def_ids, associated_items, - associated_types_for_impl_traits_in_trait, - associated_types_for_impl_traits_in_associated_fn, + associated_types_for_impl_traits_in_trait_or_impl, impl_item_implementor_ids, ..*providers }; @@ -28,24 +27,17 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { 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_associated_fn + // corresponding associated item using 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( - trait_item_refs - .iter() - .filter(|trait_item_ref| { - matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. }) - }) - .flat_map(|trait_item_ref| { - let trait_fn_def_id = trait_item_ref.id.owner_id.def_id.to_def_id(); - tcx.associated_types_for_impl_traits_in_associated_fn( - trait_fn_def_id, - ) - }) + tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id) + .0 + .values() + .flatten() .copied(), ), ) @@ -53,25 +45,17 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { 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_associated_fn query. + // 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(|_| { - impl_ - .items - .iter() - .filter(|impl_item_ref| { - matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. }) - }) - .flat_map(|impl_item_ref| { - let impl_fn_def_id = impl_item_ref.id.owner_id.def_id.to_def_id(); - tcx.associated_types_for_impl_traits_in_associated_fn( - impl_fn_def_id, - ) - }) + tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id) + .0 + .values() + .flatten() .copied() })), ) @@ -184,94 +168,102 @@ impl<'tcx> Visitor<'tcx> for RPITVisitor<'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. -fn associated_types_for_impl_traits_in_associated_fn( - tcx: TyCtxt<'_>, - fn_def_id: LocalDefId, -) -> &'_ [DefId] { - let parent_def_id = tcx.local_parent(fn_def_id); +fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> AssocTyForImplTraitInTraitOrImpl { + let item = tcx.hir_expect_item(def_id); + match item.kind { + ItemKind::Trait(.., trait_item_refs) => { + let mut disambiguator_idx_map = FxHashMap::default(); + let find_disambiguator_idx = + |map: &mut FxHashMap, name| match map.entry(name) { + Entry::Occupied(occ) => *occ.get() + 1, + Entry::Vacant(vac) => { + vac.insert(0); + 0 + } + }; + let update_disambiguator_idx = |map: &mut FxHashMap, name, offset: u32| { + *map.get_mut(&name).unwrap() += offset + }; - match tcx.def_kind(parent_def_id) { - DefKind::Trait => { - tcx.associated_types_for_impl_traits_in_trait(parent_def_id)[&fn_def_id.to_def_id()] + 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::>(); + Some((fn_def_id.to_def_id(), defs)) + }) + .collect::>(), + ) } - - DefKind::Impl { .. } => { - let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { - return &[]; + 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()); }; - tcx.arena.alloc_from_iter( - tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map( - move |&trait_assoc_def_id| { - associated_type_for_impl_trait_in_impl(tcx, trait_assoc_def_id, fn_def_id) - .to_def_id() - }, - ), + 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::>(), ) } - - def_kind => bug!( - "associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}", - parent_def_id, - def_kind - ), - } -} - -fn associated_types_for_impl_traits_in_trait<'tcx>( - tcx: TyCtxt<'tcx>, - trait_id: LocalDefId, -) -> DefIdMap<&'tcx [DefId]> { - let (.., trait_item_refs) = tcx.hir_expect_item(trait_id).expect_trait(); - - let mut disambiguator_idx_map = FxHashMap::default(); - let find_disambiguator_idx = |map: &mut FxHashMap, name| match map.entry(name) { - Entry::Occupied(occ) => *occ.get() + 1, - Entry::Vacant(vac) => { - vac.insert(0); - 0 + _ => { + bug!( + "associated_types_for_impl_traits_in_trait_or_impl: {:?} should be Trait or Impl but is {:?}", + def_id, + tcx.def_kind(def_id) + ) } - }; - let update_disambiguator_idx = |map: &mut FxHashMap, name, offset: u32| { - *map.get_mut(&name).unwrap() += offset - }; - - 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(), &[] as &[DefId])); - }; - 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(trait_id, data, disambiguator_idx), - }; - visitor.visit_fn_ret_ty(output); - update_disambiguator_idx(&mut disambiguator_idx_map, def_name, visitor.depth); - let defs = tcx - .arena - .alloc_from_iter(visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id())); - Some((fn_def_id.to_def_id(), defs)) - }) - .collect() + } } /// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated From 736bfa12de73155633261ca6682b9d5e72d32c6d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 12 Jul 2025 19:31:15 +0000 Subject: [PATCH 3/3] Clean up implementation of RPITIT assoc item lowering --- .../src/check/compare_impl_item.rs | 6 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +- .../src/hir_ty_lowering/mod.rs | 4 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 6 +- compiler/rustc_middle/src/ty/assoc.rs | 36 ++-- compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_middle/src/ty/parameterized.rs | 5 +- compiler/rustc_ty_utils/src/assoc.rs | 190 +++++++----------- 9 files changed, 110 insertions(+), 146 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 379ce69bdeab5..87db80f2423d6 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -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`, 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(), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 3d3fdd899d3f3..607028f4d9aef 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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())); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ae56f0c5160fc..a5bd7c1a34aef 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -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, .. }) => { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 213090d7d47e8..8347626080e6c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -481,7 +481,7 @@ define_tables! { assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, anon_const_kind: Table>, - associated_types_for_impl_traits_in_trait_or_impl: Table>, + associated_types_for_impl_traits_in_trait_or_impl: Table>>>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3da6c6f5fe117..842d118449a55 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -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> { 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 } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 99714171c72de..9534d45e495b2 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -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>); - -/// 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] + } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e1b11e4f54add..0177a95498bcd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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(); } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 88f6e717af45b..3d601fc05338c 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -23,6 +23,10 @@ impl ParameterizedOverTcx for type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>); } +impl ParameterizedOverTcx for Vec { + type Value<'tcx> = Vec>; +} + impl ParameterizedOverTcx for IndexVec { type Value<'tcx> = IndexVec>; } @@ -67,7 +71,6 @@ trivially_parameterized_over_tcx! { crate::mir::ConstQualifs, ty::AsyncDestructor, ty::AssocItemContainer, - ty::AssocTyForImplTraitInTraitOrImpl, ty::Asyncness, ty::AnonConstKind, ty::DeducedParamAttrs, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 400158496b5b7..66c44f72f4e82 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -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, 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> { 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, 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, 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::>(); - Some((fn_def_id.to_def_id(), defs)) - }) - .collect::>(), - ) - } + 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::>(); + 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::>(), - ) + 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();