@@ -69,8 +69,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
6969
7070 // Visit MIR and accumululate used generic parameters.
7171 let body = tcx. optimized_mir ( def_id) ;
72- let mut vis =
73- UsedGenericParametersVisitor { tcx, def_id, unused_parameters : & mut unused_parameters } ;
72+ let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters : & mut unused_parameters } ;
7473 vis. visit_body ( body) ;
7574 debug ! ( "unused_generic_params: (after visitor) unused_parameters={:?}" , unused_parameters) ;
7675
@@ -120,45 +119,101 @@ fn mark_used_by_predicates<'tcx>(
120119 def_id : DefId ,
121120 unused_parameters : & mut FiniteBitSet < u32 > ,
122121) {
123- let def_id = tcx. closure_base_def_id ( def_id) ;
124-
125- let is_self_ty_used = |unused_parameters : & mut FiniteBitSet < u32 > , self_ty : Ty < ' tcx > | {
126- debug ! ( "unused_generic_params: self_ty={:?}" , self_ty) ;
127- if let ty:: Param ( param) = self_ty. kind {
128- !unused_parameters. contains ( param. index ) . unwrap_or ( false )
129- } else {
130- false
131- }
122+ let is_ty_used = |unused_parameters : & FiniteBitSet < u32 > , ty : Ty < ' tcx > | -> bool {
123+ let mut vis = IsUsedGenericParams { unused_parameters } ;
124+ ty. visit_with ( & mut vis)
132125 } ;
133126
134127 let mark_ty = |unused_parameters : & mut FiniteBitSet < u32 > , ty : Ty < ' tcx > | {
135- let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters } ;
128+ let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters } ;
136129 ty. visit_with ( & mut vis) ;
137130 } ;
138131
132+ let def_id = tcx. closure_base_def_id ( def_id) ;
139133 let predicates = tcx. explicit_predicates_of ( def_id) ;
140- debug ! ( "mark_parameters_used_in_predicates: predicates_of={:?}" , predicates) ;
141- for ( predicate, _) in predicates. predicates {
142- match predicate. skip_binders ( ) {
143- ty:: PredicateAtom :: Trait ( predicate, ..) => {
144- let trait_ref = predicate. trait_ref ;
145- if is_self_ty_used ( unused_parameters, trait_ref. self_ty ( ) ) {
134+ debug ! ( "mark_used_by_predicates: predicates_of={:?}" , predicates) ;
135+
136+ let mut current_unused_parameters = FiniteBitSet :: new_empty ( ) ;
137+ // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty
138+ // bit set so that this is skipped if all parameters are already used.
139+ while current_unused_parameters != * unused_parameters {
140+ debug ! (
141+ "mark_used_by_predicates: current_unused_parameters={:?} = unused_parameters={:?}" ,
142+ current_unused_parameters, unused_parameters
143+ ) ;
144+ current_unused_parameters = * unused_parameters;
145+
146+ for ( predicate, _) in predicates. predicates {
147+ match predicate. skip_binders ( ) {
148+ ty:: PredicateAtom :: Trait ( predicate, ..) => {
149+ let trait_ref = predicate. trait_ref ;
150+ debug ! ( "mark_used_by_predicates: (trait) trait_ref={:?}" , trait_ref) ;
151+
152+ // Consider `T` used if `I` is used in predicates of the form
153+ // `I: Iterator<Item = T>`
154+ debug ! ( "mark_used_by_predicates: checking self" ) ;
155+ if is_ty_used ( unused_parameters, trait_ref. self_ty ( ) ) {
156+ debug ! ( "mark_used_by_predicates: used!" ) ;
157+ for ty in trait_ref. substs . types ( ) {
158+ mark_ty ( unused_parameters, ty) ;
159+ }
160+
161+ // No need to check for a type being used in the substs if `self_ty` was
162+ // used.
163+ continue ;
164+ }
165+
166+ // Consider `I` used if `T` is used in predicates of the form
167+ // `I: Iterator<Item = &'a (T, E)>` (see rust-lang/rust#75326)
168+ debug ! ( "mark_used_by_predicates: checking substs" ) ;
146169 for ty in trait_ref. substs . types ( ) {
147- debug ! ( "unused_generic_params: (trait) ty={:?}" , ty) ;
148- mark_ty ( unused_parameters, ty) ;
170+ if is_ty_used ( unused_parameters, ty) {
171+ debug ! ( "mark_used_by_predicates: used!" ) ;
172+ mark_ty ( unused_parameters, trait_ref. self_ty ( ) ) ;
173+ }
149174 }
150175 }
151- }
152- ty:: PredicateAtom :: Projection ( proj, ..) => {
153- let self_ty = proj. projection_ty . self_ty ( ) ;
154- if is_self_ty_used ( unused_parameters, self_ty) {
155- debug ! ( "unused_generic_params: (projection ty={:?}" , proj. ty) ;
156- mark_ty ( unused_parameters, proj. ty ) ;
176+ ty:: PredicateAtom :: Projection ( proj, ..) => {
177+ let self_ty = proj. projection_ty . self_ty ( ) ;
178+ debug ! (
179+ "mark_used_by_predicates: (projection) self_ty={:?} proj.ty={:?}" ,
180+ self_ty, proj. ty
181+ ) ;
182+
183+ // Consider `T` used if `I` is used in predicates of the form
184+ // `<I as Iterator>::Item = T`
185+ debug ! ( "mark_used_by_predicates: checking self" ) ;
186+ if is_ty_used ( unused_parameters, self_ty) {
187+ debug ! ( "mark_used_by_predicates: used!" ) ;
188+ mark_ty ( unused_parameters, proj. ty ) ;
189+
190+ // No need to check for projection type being used if `self_ty` was used.
191+ continue ;
192+ }
193+
194+ // Consider `I` used if `T` is used in predicates of the form
195+ // `<I as Iterator>::Item = &'a (T, E)` (see rust-lang/rust#75326)
196+ debug ! ( "mark_used_by_predicates: checking projection ty" ) ;
197+ if is_ty_used ( unused_parameters, proj. ty ) {
198+ debug ! ( "mark_used_by_predicates: used!" ) ;
199+ mark_ty ( unused_parameters, self_ty) ;
200+ }
157201 }
202+ ty:: PredicateAtom :: RegionOutlives ( ..)
203+ | ty:: PredicateAtom :: TypeOutlives ( ..)
204+ | ty:: PredicateAtom :: WellFormed ( ..)
205+ | ty:: PredicateAtom :: ObjectSafe ( ..)
206+ | ty:: PredicateAtom :: ClosureKind ( ..)
207+ | ty:: PredicateAtom :: Subtype ( ..)
208+ | ty:: PredicateAtom :: ConstEvaluatable ( ..)
209+ | ty:: PredicateAtom :: ConstEquate ( ..) => ( ) ,
158210 }
159- _ => ( ) ,
160211 }
161212 }
213+
214+ if let Some ( parent) = predicates. parent {
215+ mark_used_by_predicates ( tcx, parent, unused_parameters) ;
216+ }
162217}
163218
164219/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
@@ -204,13 +259,13 @@ fn emit_unused_generic_params_error<'tcx>(
204259}
205260
206261/// Visitor used to aggregate generic parameter uses.
207- struct UsedGenericParametersVisitor < ' a , ' tcx > {
262+ struct MarkUsedGenericParams < ' a , ' tcx > {
208263 tcx : TyCtxt < ' tcx > ,
209264 def_id : DefId ,
210265 unused_parameters : & ' a mut FiniteBitSet < u32 > ,
211266}
212267
213- impl < ' a , ' tcx > UsedGenericParametersVisitor < ' a , ' tcx > {
268+ impl < ' a , ' tcx > MarkUsedGenericParams < ' a , ' tcx > {
214269 /// Invoke `unused_generic_params` on a body contained within the current item (e.g.
215270 /// a closure, generator or constant).
216271 fn visit_child_body ( & mut self , def_id : DefId , substs : SubstsRef < ' tcx > ) {
@@ -229,7 +284,7 @@ impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> {
229284 }
230285}
231286
232- impl < ' a , ' tcx > Visitor < ' tcx > for UsedGenericParametersVisitor < ' a , ' tcx > {
287+ impl < ' a , ' tcx > Visitor < ' tcx > for MarkUsedGenericParams < ' a , ' tcx > {
233288 fn visit_local_decl ( & mut self , local : Local , local_decl : & LocalDecl < ' tcx > ) {
234289 debug ! ( "visit_local_decl: local_decl={:?}" , local_decl) ;
235290 if local == Local :: from_usize ( 1 ) {
@@ -256,7 +311,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
256311 }
257312}
258313
259- impl < ' a , ' tcx > TypeVisitor < ' tcx > for UsedGenericParametersVisitor < ' a , ' tcx > {
314+ impl < ' a , ' tcx > TypeVisitor < ' tcx > for MarkUsedGenericParams < ' a , ' tcx > {
260315 fn visit_const ( & mut self , c : & ' tcx Const < ' tcx > ) -> bool {
261316 debug ! ( "visit_const: c={:?}" , c) ;
262317 if !c. has_param_types_or_consts ( ) {
@@ -318,3 +373,36 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
318373 }
319374 }
320375}
376+
377+ /// Visitor used to check if a generic parameter is used.
378+ struct IsUsedGenericParams < ' a > {
379+ unused_parameters : & ' a FiniteBitSet < u32 > ,
380+ }
381+
382+ impl < ' a , ' tcx > TypeVisitor < ' tcx > for IsUsedGenericParams < ' a > {
383+ fn visit_const ( & mut self , c : & ' tcx Const < ' tcx > ) -> bool {
384+ debug ! ( "visit_const: c={:?}" , c) ;
385+ if !c. has_param_types_or_consts ( ) {
386+ return false ;
387+ }
388+
389+ match c. val {
390+ ty:: ConstKind :: Param ( param) => {
391+ !self . unused_parameters . contains ( param. index ) . unwrap_or ( false )
392+ }
393+ _ => c. super_visit_with ( self ) ,
394+ }
395+ }
396+
397+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
398+ debug ! ( "visit_ty: ty={:?}" , ty) ;
399+ if !ty. has_param_types_or_consts ( ) {
400+ return false ;
401+ }
402+
403+ match ty. kind {
404+ ty:: Param ( param) => !self . unused_parameters . contains ( param. index ) . unwrap_or ( false ) ,
405+ _ => ty. super_visit_with ( self ) ,
406+ }
407+ }
408+ }
0 commit comments