@@ -266,72 +266,96 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
266
266
/// ```
267
267
fn check_gat_where_clauses ( tcx : TyCtxt < ' _ > , associated_items : & [ hir:: TraitItemRef ] ) {
268
268
let mut required_bounds_by_item = FxHashMap :: default ( ) ;
269
-
270
- for gat_item in associated_items {
271
- let gat_def_id = gat_item. id . def_id ;
272
- let gat_item = tcx. associated_item ( gat_def_id) ;
273
- // If this item is not an assoc ty, or has no substs, then it's not a GAT
274
- if gat_item. kind != ty:: AssocKind :: Type {
275
- continue ;
276
- }
277
- let gat_generics = tcx. generics_of ( gat_def_id) ;
278
- if gat_generics. params . is_empty ( ) {
279
- continue ;
280
- }
281
-
282
- let mut new_required_bounds: Option < FxHashSet < ty:: Predicate < ' _ > > > = None ;
283
- for item in associated_items {
284
- let item_def_id = item. id . def_id ;
285
- // Skip our own GAT, since it would blow away the required bounds
286
- if item_def_id == gat_def_id {
269
+ loop {
270
+ let mut should_continue = false ;
271
+ for gat_item in associated_items {
272
+ let gat_def_id = gat_item. id . def_id ;
273
+ let gat_item = tcx. associated_item ( gat_def_id) ;
274
+ // If this item is not an assoc ty, or has no substs, then it's not a GAT
275
+ if gat_item. kind != ty:: AssocKind :: Type {
276
+ continue ;
277
+ }
278
+ let gat_generics = tcx. generics_of ( gat_def_id) ;
279
+ if gat_generics. params . is_empty ( ) {
287
280
continue ;
288
281
}
289
282
290
- let item_hir_id = item. id . hir_id ( ) ;
291
- let param_env = tcx. param_env ( item_def_id) ;
283
+ let mut new_required_bounds: Option < FxHashSet < ty:: Predicate < ' _ > > > = None ;
284
+ for item in associated_items {
285
+ let item_def_id = item. id . def_id ;
286
+ // Skip our own GAT, since it would blow away the required bounds
287
+ if item_def_id == gat_def_id {
288
+ continue ;
289
+ }
292
290
293
- let item_required_bounds = match item. kind {
294
- hir:: AssocItemKind :: Fn { .. } => {
295
- let sig: ty:: FnSig < ' _ > = tcx. liberate_late_bound_regions (
296
- item_def_id. to_def_id ( ) ,
297
- tcx. fn_sig ( item_def_id) ,
298
- ) ;
299
- gather_gat_bounds (
300
- tcx,
301
- param_env,
302
- item_hir_id,
303
- sig. output ( ) ,
304
- & sig. inputs ( ) . iter ( ) . copied ( ) . collect ( ) ,
305
- gat_def_id,
306
- gat_generics,
307
- )
291
+ let item_hir_id = item. id . hir_id ( ) ;
292
+ let param_env = tcx. param_env ( item_def_id) ;
293
+
294
+ let item_required_bounds = match item. kind {
295
+ hir:: AssocItemKind :: Fn { .. } => {
296
+ let sig: ty:: FnSig < ' _ > = tcx. liberate_late_bound_regions (
297
+ item_def_id. to_def_id ( ) ,
298
+ tcx. fn_sig ( item_def_id) ,
299
+ ) ;
300
+ gather_gat_bounds (
301
+ tcx,
302
+ param_env,
303
+ item_hir_id,
304
+ sig. output ( ) ,
305
+ & sig. inputs ( ) . iter ( ) . copied ( ) . collect ( ) ,
306
+ gat_def_id,
307
+ gat_generics,
308
+ )
309
+ }
310
+ hir:: AssocItemKind :: Type => {
311
+ // If our associated item is a GAT with missing bounds, add them to
312
+ // the param-env here. This allows this GAT to propagate missing bounds
313
+ // to other GATs.
314
+ let param_env = augment_param_env (
315
+ tcx,
316
+ param_env,
317
+ required_bounds_by_item. get ( & item_def_id) ,
318
+ ) ;
319
+ gather_gat_bounds (
320
+ tcx,
321
+ param_env,
322
+ item_hir_id,
323
+ tcx. explicit_item_bounds ( item_def_id)
324
+ . iter ( )
325
+ . copied ( )
326
+ . collect :: < Vec < _ > > ( ) ,
327
+ & FxHashSet :: default ( ) ,
328
+ gat_def_id,
329
+ gat_generics,
330
+ )
331
+ }
332
+ hir:: AssocItemKind :: Const => None ,
333
+ } ;
334
+
335
+ if let Some ( item_required_bounds) = item_required_bounds {
336
+ // Take the intersection of the new_required_bounds and the item_required_bounds
337
+ // for this item. This is why we use an Option<_>, since we need to distinguish
338
+ // the empty set of bounds from the uninitialized set of bounds.
339
+ if let Some ( new_required_bounds) = & mut new_required_bounds {
340
+ new_required_bounds. retain ( |b| item_required_bounds. contains ( b) ) ;
341
+ } else {
342
+ new_required_bounds = Some ( item_required_bounds) ;
343
+ }
308
344
}
309
- hir:: AssocItemKind :: Type => gather_gat_bounds (
310
- tcx,
311
- param_env,
312
- item_hir_id,
313
- tcx. explicit_item_bounds ( item_def_id) . iter ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ,
314
- & FxHashSet :: default ( ) ,
315
- gat_def_id,
316
- gat_generics,
317
- ) ,
318
- hir:: AssocItemKind :: Const => None ,
319
- } ;
345
+ }
320
346
321
- if let Some ( item_required_bounds) = item_required_bounds {
322
- // Take the intersection of the new_required_bounds and the item_required_bounds
323
- // for this item. This is why we use an Option<_>, since we need to distinguish
324
- // the empty set of bounds from the uninitialized set of bounds.
325
- if let Some ( new_required_bounds) = & mut new_required_bounds {
326
- new_required_bounds. retain ( |b| item_required_bounds. contains ( b) ) ;
327
- } else {
328
- new_required_bounds = Some ( item_required_bounds) ;
347
+ if let Some ( new_required_bounds) = new_required_bounds {
348
+ let required_bounds = required_bounds_by_item. entry ( gat_def_id) . or_default ( ) ;
349
+ if new_required_bounds != * required_bounds {
350
+ * required_bounds = new_required_bounds;
351
+ // Iterate until our required_bounds no longer change
352
+ // Since they changed here, we should continue the loop
353
+ should_continue = true ;
329
354
}
330
355
}
331
356
}
332
-
333
- if let Some ( required_bounds) = new_required_bounds {
334
- required_bounds_by_item. insert ( gat_def_id, required_bounds) ;
357
+ if !should_continue {
358
+ break ;
335
359
}
336
360
}
337
361
@@ -398,6 +422,28 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
398
422
}
399
423
}
400
424
425
+ /// Add a new set of predicates to the caller_bounds of an existing param_env,
426
+ /// and normalize the param_env afterwards
427
+ fn augment_param_env < ' tcx > (
428
+ tcx : TyCtxt < ' tcx > ,
429
+ param_env : ty:: ParamEnv < ' tcx > ,
430
+ new_predicates : Option < & FxHashSet < ty:: Predicate < ' tcx > > > ,
431
+ ) -> ty:: ParamEnv < ' tcx > {
432
+ let Some ( new_predicates) = new_predicates else {
433
+ return param_env;
434
+ } ;
435
+
436
+ if new_predicates. is_empty ( ) {
437
+ return param_env;
438
+ }
439
+
440
+ let bounds =
441
+ tcx. mk_predicates ( param_env. caller_bounds ( ) . iter ( ) . chain ( new_predicates. iter ( ) . cloned ( ) ) ) ;
442
+ // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
443
+ // i.e. traits::normalize_param_env_or_error
444
+ ty:: ParamEnv :: new ( bounds, param_env. reveal ( ) , param_env. constness ( ) )
445
+ }
446
+
401
447
fn gather_gat_bounds < ' tcx , T : TypeFoldable < ' tcx > > (
402
448
tcx : TyCtxt < ' tcx > ,
403
449
param_env : ty:: ParamEnv < ' tcx > ,
0 commit comments