1+ use std:: collections:: hash_map:: Entry ;
2+
3+ use rustc_data_structures:: fx:: FxHashMap ;
14use rustc_hir as hir;
25use rustc_hir:: def:: DefKind ;
36use rustc_hir:: def_id:: { DefId , DefIdMap , LocalDefId } ;
@@ -6,12 +9,14 @@ use rustc_hir::intravisit::{self, Visitor};
69use rustc_middle:: query:: Providers ;
710use rustc_middle:: ty:: { self , ImplTraitInTraitData , TyCtxt } ;
811use rustc_middle:: { bug, span_bug} ;
12+ use rustc_span:: Symbol ;
913
1014pub ( crate ) fn provide ( providers : & mut Providers ) {
1115 * providers = Providers {
1216 associated_item,
1317 associated_item_def_ids,
1418 associated_items,
19+ associated_types_for_impl_traits_in_trait,
1520 associated_types_for_impl_traits_in_associated_fn,
1621 impl_item_implementor_ids,
1722 ..* providers
@@ -163,10 +168,12 @@ struct RPITVisitor<'tcx> {
163168 synthetics : Vec < LocalDefId > ,
164169 data : DefPathData ,
165170 disambiguator : DisambiguatorState ,
171+ depth : u32 ,
166172}
167173
168174impl < ' tcx > Visitor < ' tcx > for RPITVisitor < ' tcx > {
169175 fn visit_opaque_ty ( & mut self , opaque : & ' tcx hir:: OpaqueTy < ' tcx > ) -> Self :: Result {
176+ self . depth += 1 ;
170177 self . synthetics . push ( associated_type_for_impl_trait_in_trait (
171178 self . tcx ,
172179 opaque. def_id ,
@@ -177,17 +184,6 @@ impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
177184 }
178185}
179186
180- struct DisambiguatorIdxVisitor {
181- depth : u32 ,
182- }
183-
184- impl < ' tcx > Visitor < ' tcx > for DisambiguatorIdxVisitor {
185- fn visit_opaque_ty ( & mut self , opaque : & ' tcx hir:: OpaqueTy < ' tcx > ) -> Self :: Result {
186- self . depth += 1 ;
187- intravisit:: walk_opaque_ty ( self , opaque)
188- }
189- }
190-
191187/// Given an `fn_def_id` of a trait or a trait implementation:
192188///
193189/// 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(
205201
206202 match tcx. def_kind ( parent_def_id) {
207203 DefKind :: Trait => {
208- if let Some ( output) = tcx. hir_get_fn_output ( fn_def_id) {
209- let def_path_id = |def_id : LocalDefId | tcx. item_name ( def_id. to_def_id ( ) ) ;
210- let def_path_data = def_path_id ( fn_def_id) ;
211-
212- let ( .., trait_item_refs) = tcx. hir_expect_item ( parent_def_id) . expect_trait ( ) ;
213- // The purpose of `disambiguator_idx` is to ensure there are
214- // no duplicate `def_id` in certain cases, such as:
215- // ```
216- // trait Foo {
217- // fn bar() -> impl Trait;
218- // fn bar() -> impl Trait;
219- // // ~~~~~~~~~~ It will generate the same ID if we don’t disambiguate it.
220- // }
221- // ```
222- let disambiguator_idx = trait_item_refs
223- . iter ( )
224- . take_while ( |item| item. id . owner_id . def_id != fn_def_id)
225- . filter ( |item| {
226- matches ! ( item. kind, hir:: AssocItemKind :: Fn { .. } )
227- && def_path_id ( item. id . owner_id . def_id ) == def_path_data
228- } )
229- . last ( )
230- . map ( |item| {
231- let output = tcx. hir_get_fn_output ( item. id . owner_id . def_id ) . unwrap ( ) ;
232- let mut visitor = DisambiguatorIdxVisitor { depth : 0 } ;
233- visitor. visit_fn_ret_ty ( output) ;
234- tcx. def_key ( item. id . owner_id . def_id ) . disambiguated_data . disambiguator
235- + visitor. depth
236- } )
237- . unwrap_or_default ( ) ;
238-
239- let data = DefPathData :: AnonAssocTy ( def_path_data) ;
240- let mut visitor = RPITVisitor {
241- tcx,
242- synthetics : vec ! [ ] ,
243- data,
244- disambiguator : DisambiguatorState :: with ( parent_def_id, data, disambiguator_idx) ,
245- } ;
246- visitor. visit_fn_ret_ty ( output) ;
247- tcx. arena . alloc_from_iter (
248- visitor. synthetics . into_iter ( ) . map ( |def_id| def_id. to_def_id ( ) ) ,
249- )
250- } else {
251- & [ ]
252- }
204+ tcx. associated_types_for_impl_traits_in_trait ( parent_def_id) [ & fn_def_id. to_def_id ( ) ]
253205 }
254206
255207 DefKind :: Impl { .. } => {
@@ -274,6 +226,54 @@ fn associated_types_for_impl_traits_in_associated_fn(
274226 }
275227}
276228
229+ fn associated_types_for_impl_traits_in_trait < ' tcx > (
230+ tcx : TyCtxt < ' tcx > ,
231+ trait_id : LocalDefId ,
232+ ) -> DefIdMap < & ' tcx [ DefId ] > {
233+ let ( .., trait_item_refs) = tcx. hir_expect_item ( trait_id) . expect_trait ( ) ;
234+
235+ let mut disambiguator_idx_map = FxHashMap :: default ( ) ;
236+ let find_disambiguator_idx = |map : & mut FxHashMap < Symbol , u32 > , name| match map. entry ( name) {
237+ Entry :: Occupied ( occ) => * occ. get ( ) + 1 ,
238+ Entry :: Vacant ( vac) => {
239+ vac. insert ( 0 ) ;
240+ 0
241+ }
242+ } ;
243+ let update_disambiguator_idx = |map : & mut FxHashMap < Symbol , u32 > , name, offset : u32 | {
244+ * map. get_mut ( & name) . unwrap ( ) += offset
245+ } ;
246+
247+ trait_item_refs
248+ . iter ( )
249+ . filter_map ( move |item| {
250+ if !matches ! ( item. kind, hir:: AssocItemKind :: Fn { .. } ) {
251+ return None ;
252+ }
253+ let fn_def_id = item. id . owner_id . def_id ;
254+ let Some ( output) = tcx. hir_get_fn_output ( fn_def_id) else {
255+ return Some ( ( fn_def_id. to_def_id ( ) , & [ ] as & [ DefId ] ) ) ;
256+ } ;
257+ let def_name = tcx. item_name ( fn_def_id. to_def_id ( ) ) ;
258+ let disambiguator_idx = find_disambiguator_idx ( & mut disambiguator_idx_map, def_name) ;
259+ let data = DefPathData :: AnonAssocTy ( def_name) ;
260+ let mut visitor = RPITVisitor {
261+ tcx,
262+ synthetics : vec ! [ ] ,
263+ data,
264+ depth : 0 ,
265+ disambiguator : DisambiguatorState :: with ( trait_id, data, disambiguator_idx) ,
266+ } ;
267+ visitor. visit_fn_ret_ty ( output) ;
268+ update_disambiguator_idx ( & mut disambiguator_idx_map, def_name, visitor. depth ) ;
269+ let defs = tcx
270+ . arena
271+ . alloc_from_iter ( visitor. synthetics . into_iter ( ) . map ( |def_id| def_id. to_def_id ( ) ) ) ;
272+ Some ( ( fn_def_id. to_def_id ( ) , defs) )
273+ } )
274+ . collect ( )
275+ }
276+
277277/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
278278/// function from a trait, synthesize an associated type for that `impl Trait`
279279/// that inherits properties that we infer from the method and the opaque type.
0 commit comments