@@ -75,14 +75,16 @@ pub trait DefIdVisitor<'tcx> {
75
75
}
76
76
77
77
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.
78
80
fn visit_def_id ( & mut self , def_id : DefId , kind : & str , descr : & dyn fmt:: Display )
79
81
-> Self :: Result ;
80
82
81
83
/// Not overridden, but used to actually visit types and traits.
82
84
fn skeleton ( & mut self ) -> DefIdVisitorSkeleton < ' _ , ' tcx , Self > {
83
85
DefIdVisitorSkeleton {
84
86
def_id_visitor : self ,
85
- visited_opaque_tys : Default :: default ( ) ,
87
+ visited_def_ids : Default :: default ( ) ,
86
88
dummy : Default :: default ( ) ,
87
89
}
88
90
}
@@ -102,7 +104,7 @@ pub trait DefIdVisitor<'tcx> {
102
104
103
105
pub struct DefIdVisitorSkeleton < ' v , ' tcx , V : ?Sized > {
104
106
def_id_visitor : & ' v mut V ,
105
- visited_opaque_tys : FxHashSet < DefId > ,
107
+ visited_def_ids : FxHashSet < DefId > ,
106
108
dummy : PhantomData < TyCtxt < ' tcx > > ,
107
109
}
108
110
@@ -112,11 +114,13 @@ where
112
114
{
113
115
fn visit_trait ( & mut self , trait_ref : TraitRef < ' tcx > ) -> V :: Result {
114
116
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
+ }
120
124
if V :: SHALLOW { V :: Result :: output ( ) } else { args. visit_with ( self ) }
121
125
}
122
126
@@ -190,7 +194,9 @@ where
190
194
| ty:: Closure ( def_id, ..)
191
195
| ty:: CoroutineClosure ( def_id, ..)
192
196
| 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
+ }
194
200
if V :: SHALLOW {
195
201
return V :: Result :: output ( ) ;
196
202
}
@@ -221,15 +227,17 @@ where
221
227
return V :: Result :: output ( ) ;
222
228
}
223
229
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
+ }
233
241
234
242
// This will also visit args if necessary, so we don't need to recurse.
235
243
return if V :: SHALLOW {
@@ -254,12 +262,14 @@ where
254
262
}
255
263
} ;
256
264
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
+ }
258
268
}
259
269
}
260
270
ty:: Alias ( ty:: Opaque , ty:: AliasTy { def_id, .. } ) => {
261
271
// 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) {
263
273
// The intent is to treat `impl Trait1 + Trait2` identically to
264
274
// `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
265
275
// (it either has no visibility, or its visibility is insignificant, like
0 commit comments