@@ -75,14 +75,16 @@ pub trait DefIdVisitor<'tcx> {
7575 }
7676
7777 fn tcx ( & self ) -> TyCtxt < ' tcx > ;
78+ /// NOTE: Def-id visiting should be idempotent, because `DefIdVisitorSkeleton` will avoid
79+ /// visiting duplicate def-ids. All the current visitors follow this rule.
7880 fn visit_def_id ( & mut self , def_id : DefId , kind : & str , descr : & dyn fmt:: Display )
7981 -> Self :: Result ;
8082
8183 /// Not overridden, but used to actually visit types and traits.
8284 fn skeleton ( & mut self ) -> DefIdVisitorSkeleton < ' _ , ' tcx , Self > {
8385 DefIdVisitorSkeleton {
8486 def_id_visitor : self ,
85- visited_opaque_tys : Default :: default ( ) ,
87+ visited_def_ids : Default :: default ( ) ,
8688 dummy : Default :: default ( ) ,
8789 }
8890 }
@@ -102,7 +104,7 @@ pub trait DefIdVisitor<'tcx> {
102104
103105pub struct DefIdVisitorSkeleton < ' v , ' tcx , V : ?Sized > {
104106 def_id_visitor : & ' v mut V ,
105- visited_opaque_tys : FxHashSet < DefId > ,
107+ visited_def_ids : FxHashSet < DefId > ,
106108 dummy : PhantomData < TyCtxt < ' tcx > > ,
107109}
108110
@@ -112,11 +114,13 @@ where
112114{
113115 fn visit_trait ( & mut self , trait_ref : TraitRef < ' tcx > ) -> V :: Result {
114116 let TraitRef { def_id, args, .. } = trait_ref;
115- try_visit ! ( self . def_id_visitor. visit_def_id(
116- def_id,
117- "trait" ,
118- & trait_ref. print_only_trait_path( )
119- ) ) ;
117+ if self . visited_def_ids . insert ( def_id) {
118+ try_visit ! ( self . def_id_visitor. visit_def_id(
119+ def_id,
120+ "trait" ,
121+ & trait_ref. print_only_trait_path( )
122+ ) ) ;
123+ }
120124 if V :: SHALLOW { V :: Result :: output ( ) } else { args. visit_with ( self ) }
121125 }
122126
@@ -190,7 +194,9 @@ where
190194 | ty:: Closure ( def_id, ..)
191195 | ty:: CoroutineClosure ( def_id, ..)
192196 | ty:: Coroutine ( def_id, ..) => {
193- try_visit ! ( self . def_id_visitor. visit_def_id( def_id, "type" , & ty) ) ;
197+ if self . visited_def_ids . insert ( def_id) {
198+ try_visit ! ( self . def_id_visitor. visit_def_id( def_id, "type" , & ty) ) ;
199+ }
194200 if V :: SHALLOW {
195201 return V :: Result :: output ( ) ;
196202 }
@@ -221,15 +227,17 @@ where
221227 return V :: Result :: output ( ) ;
222228 }
223229
224- try_visit ! ( self . def_id_visitor. visit_def_id(
225- data. def_id,
226- match kind {
227- ty:: Inherent | ty:: Projection => "associated type" ,
228- ty:: Free => "type alias" ,
229- ty:: Opaque => unreachable!( ) ,
230- } ,
231- & LazyDefPathStr { def_id: data. def_id, tcx } ,
232- ) ) ;
230+ if self . visited_def_ids . insert ( data. def_id ) {
231+ try_visit ! ( self . def_id_visitor. visit_def_id(
232+ data. def_id,
233+ match kind {
234+ ty:: Inherent | ty:: Projection => "associated type" ,
235+ ty:: Free => "type alias" ,
236+ ty:: Opaque => unreachable!( ) ,
237+ } ,
238+ & LazyDefPathStr { def_id: data. def_id, tcx } ,
239+ ) ) ;
240+ }
233241
234242 // This will also visit args if necessary, so we don't need to recurse.
235243 return if V :: SHALLOW {
@@ -254,12 +262,14 @@ where
254262 }
255263 } ;
256264 let ty:: ExistentialTraitRef { def_id, .. } = trait_ref;
257- try_visit ! ( self . def_id_visitor. visit_def_id( def_id, "trait" , & trait_ref) ) ;
265+ if self . visited_def_ids . insert ( def_id) {
266+ try_visit ! ( self . def_id_visitor. visit_def_id( def_id, "trait" , & trait_ref) ) ;
267+ }
258268 }
259269 }
260270 ty:: Alias ( ty:: Opaque , ty:: AliasTy { def_id, .. } ) => {
261271 // Skip repeated `Opaque`s to avoid infinite recursion.
262- if self . visited_opaque_tys . insert ( def_id) {
272+ if self . visited_def_ids . insert ( def_id) {
263273 // The intent is to treat `impl Trait1 + Trait2` identically to
264274 // `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
265275 // (it either has no visibility, or its visibility is insignificant, like
0 commit comments