@@ -266,72 +266,96 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
266266/// ```
267267fn check_gat_where_clauses ( tcx : TyCtxt < ' _ > , associated_items : & [ hir:: TraitItemRef ] ) {
268268 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 ( ) {
287280 continue ;
288281 }
289282
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+ }
292290
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+ }
308344 }
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+ }
320346
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 ;
329354 }
330355 }
331356 }
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 ;
335359 }
336360 }
337361
@@ -398,6 +422,28 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
398422 }
399423}
400424
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+
401447fn gather_gat_bounds < ' tcx , T : TypeFoldable < ' tcx > > (
402448 tcx : TyCtxt < ' tcx > ,
403449 param_env : ty:: ParamEnv < ' tcx > ,
0 commit comments