@@ -298,145 +298,49 @@ fn check_gat_where_clauses(
298298 for item in
299299 associated_items. in_definition_order ( ) . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) )
300300 {
301- // The clauses we that we would require from this function
302- let mut function_clauses = FxHashSet :: default ( ) ;
303-
304301 let id = hir:: HirId :: make_owner ( item. def_id . expect_local ( ) ) ;
305302 let param_env = tcx. param_env ( item. def_id . expect_local ( ) ) ;
306303
307- let sig = tcx. fn_sig ( item. def_id ) ;
308304 // Get the signature using placeholders. In our example, this would
309305 // convert the late-bound 'a into a free region.
310- let sig = tcx. liberate_late_bound_regions ( item. def_id , sig) ;
311- // Collect the arguments that are given to this GAT in the return type
312- // of the function signature. In our example, the GAT in the return
313- // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
314- let ( regions, types) =
315- GATSubstCollector :: visit ( tcx, trait_item. def_id . to_def_id ( ) , sig. output ( ) ) ;
316-
317- // If both regions and types are empty, then this GAT isn't in the
318- // return type, and we shouldn't try to do clause analysis
319- // (particularly, doing so would end up with an empty set of clauses,
320- // since the current method would require none, and we take the
321- // intersection of requirements of all methods)
322- if types. is_empty ( ) && regions. is_empty ( ) {
323- continue ;
324- }
306+ let sig = tcx. liberate_late_bound_regions ( item. def_id , tcx. fn_sig ( item. def_id ) ) ;
325307
326308 // The types we can assume to be well-formed. In our example, this
327309 // would be &'a mut Self, from the first argument.
328310 let mut wf_tys = FxHashSet :: default ( ) ;
329311 wf_tys. extend ( sig. inputs ( ) ) ;
330312
331- // For each region argument (e.g., 'a in our example), check for a
332- // relationship to the type arguments (e.g., Self). If there is an
333- // outlives relationship (`Self: 'a`), then we want to ensure that is
334- // reflected in a where clause on the GAT itself.
335- for ( region, region_idx) in & regions {
336- // Ignore `'static` lifetimes for the purpose of this lint: it's
337- // because we know it outlives everything and so doesn't give meaninful
338- // clues
339- if region. is_static ( ) {
340- continue ;
341- }
342- for ( ty, ty_idx) in & types {
343- // In our example, requires that Self: 'a
344- if ty_known_to_outlive ( tcx, id, param_env, & wf_tys, * ty, * region) {
345- debug ! ( ?ty_idx, ?region_idx) ;
346- debug ! ( "required clause: {} must outlive {}" , ty, region) ;
347- // Translate into the generic parameters of the GAT. In
348- // our example, the type was Self, which will also be
349- // Self in the GAT.
350- let ty_param = generics. param_at ( * ty_idx, tcx) ;
351- let ty_param = tcx. mk_ty ( ty:: Param ( ty:: ParamTy {
352- index : ty_param. index ,
353- name : ty_param. name ,
354- } ) ) ;
355- // Same for the region. In our example, 'a corresponds
356- // to the 'me parameter.
357- let region_param = generics. param_at ( * region_idx, tcx) ;
358- let region_param = tcx. mk_region ( ty:: ReEarlyBound ( ty:: EarlyBoundRegion {
359- def_id : region_param. def_id ,
360- index : region_param. index ,
361- name : region_param. name ,
362- } ) ) ;
363- // The predicate we expect to see. (In our example,
364- // `Self: 'me`.)
365- let clause = ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate (
366- ty_param,
367- region_param,
368- ) ) ;
369- let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
370- function_clauses. insert ( clause) ;
371- }
372- }
373- }
313+ // The clauses we that we would require from this function
314+ let function_clauses = gather_gat_bounds (
315+ tcx,
316+ param_env,
317+ id,
318+ sig. output ( ) ,
319+ & wf_tys,
320+ trait_item. def_id ,
321+ generics,
322+ ) ;
374323
375- // For each region argument (e.g., 'a in our example), also check for a
376- // relationship to the other region arguments. If there is an
377- // outlives relationship, then we want to ensure that is
378- // reflected in a where clause on the GAT itself.
379- for ( region_a, region_a_idx) in & regions {
380- // Ignore `'static` lifetimes for the purpose of this lint: it's
381- // because we know it outlives everything and so doesn't give meaninful
382- // clues
383- if region_a. is_static ( ) {
384- continue ;
385- }
386- for ( region_b, region_b_idx) in & regions {
387- if region_a == region_b {
388- continue ;
389- }
390- if region_b. is_static ( ) {
391- continue ;
324+ if let Some ( function_clauses) = function_clauses {
325+ // Imagine we have:
326+ // ```
327+ // trait Foo {
328+ // type Bar<'me>;
329+ // fn gimme(&self) -> Self::Bar<'_>;
330+ // fn gimme_default(&self) -> Self::Bar<'static>;
331+ // }
332+ // ```
333+ // We only want to require clauses on `Bar` that we can prove from *all* functions (in this
334+ // case, `'me` can be `static` from `gimme_default`)
335+ match clauses. as_mut ( ) {
336+ Some ( clauses) => {
337+ clauses. drain_filter ( |p| !function_clauses. contains ( p) ) ;
392338 }
393-
394- if region_known_to_outlive ( tcx, id, param_env, & wf_tys, * region_a, * region_b) {
395- debug ! ( ?region_a_idx, ?region_b_idx) ;
396- debug ! ( "required clause: {} must outlive {}" , region_a, region_b) ;
397- // Translate into the generic parameters of the GAT.
398- let region_a_param = generics. param_at ( * region_a_idx, tcx) ;
399- let region_a_param = tcx. mk_region ( ty:: ReEarlyBound ( ty:: EarlyBoundRegion {
400- def_id : region_a_param. def_id ,
401- index : region_a_param. index ,
402- name : region_a_param. name ,
403- } ) ) ;
404- // Same for the region.
405- let region_b_param = generics. param_at ( * region_b_idx, tcx) ;
406- let region_b_param = tcx. mk_region ( ty:: ReEarlyBound ( ty:: EarlyBoundRegion {
407- def_id : region_b_param. def_id ,
408- index : region_b_param. index ,
409- name : region_b_param. name ,
410- } ) ) ;
411- // The predicate we expect to see.
412- let clause = ty:: PredicateKind :: RegionOutlives ( ty:: OutlivesPredicate (
413- region_a_param,
414- region_b_param,
415- ) ) ;
416- let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
417- function_clauses. insert ( clause) ;
339+ None => {
340+ clauses = Some ( function_clauses) ;
418341 }
419342 }
420343 }
421-
422- // Imagine we have:
423- // ```
424- // trait Foo {
425- // type Bar<'me>;
426- // fn gimme(&self) -> Self::Bar<'_>;
427- // fn gimme_default(&self) -> Self::Bar<'static>;
428- // }
429- // ```
430- // We only want to require clauses on `Bar` that we can prove from *all* functions (in this
431- // case, `'me` can be `static` from `gimme_default`)
432- match clauses. as_mut ( ) {
433- Some ( clauses) => {
434- clauses. drain_filter ( |p| !function_clauses. contains ( p) ) ;
435- }
436- None => {
437- clauses = Some ( function_clauses) ;
438- }
439- }
440344 }
441345
442346 // If there are any clauses that aren't provable, emit an error
@@ -515,6 +419,110 @@ fn check_gat_where_clauses(
515419 }
516420}
517421
422+ fn gather_gat_bounds < ' tcx , T : TypeFoldable < ' tcx > > (
423+ tcx : TyCtxt < ' tcx > ,
424+ param_env : ty:: ParamEnv < ' tcx > ,
425+ item_hir : hir:: HirId ,
426+ to_check : T ,
427+ wf_tys : & FxHashSet < Ty < ' tcx > > ,
428+ gat_def_id : LocalDefId ,
429+ gat_generics : & ' tcx ty:: Generics ,
430+ ) -> Option < FxHashSet < ty:: Predicate < ' tcx > > > {
431+ // The bounds we that we would require from this function
432+ let mut bounds = FxHashSet :: default ( ) ;
433+
434+ let ( regions, types) = GATSubstCollector :: visit ( tcx, gat_def_id. to_def_id ( ) , to_check) ;
435+
436+ // If both regions and types are empty, then this GAT isn't in the
437+ // return type, and we shouldn't try to do clause analysis
438+ // (particularly, doing so would end up with an empty set of clauses,
439+ // since the current method would require none, and we take the
440+ // intersection of requirements of all methods)
441+ if types. is_empty ( ) && regions. is_empty ( ) {
442+ return None ;
443+ }
444+
445+ for ( region_a, region_a_idx) in & regions {
446+ // Ignore `'static` lifetimes for the purpose of this lint: it's
447+ // because we know it outlives everything and so doesn't give meaninful
448+ // clues
449+ if let ty:: ReStatic = * * region_a {
450+ continue ;
451+ }
452+ // For each region argument (e.g., 'a in our example), check for a
453+ // relationship to the type arguments (e.g., Self). If there is an
454+ // outlives relationship (`Self: 'a`), then we want to ensure that is
455+ // reflected in a where clause on the GAT itself.
456+ for ( ty, ty_idx) in & types {
457+ // In our example, requires that Self: 'a
458+ if ty_known_to_outlive ( tcx, item_hir, param_env, & wf_tys, * ty, * region_a) {
459+ debug ! ( ?ty_idx, ?region_a_idx) ;
460+ debug ! ( "required clause: {} must outlive {}" , ty, region_a) ;
461+ // Translate into the generic parameters of the GAT. In
462+ // our example, the type was Self, which will also be
463+ // Self in the GAT.
464+ let ty_param = gat_generics. param_at ( * ty_idx, tcx) ;
465+ let ty_param = tcx
466+ . mk_ty ( ty:: Param ( ty:: ParamTy { index : ty_param. index , name : ty_param. name } ) ) ;
467+ // Same for the region. In our example, 'a corresponds
468+ // to the 'me parameter.
469+ let region_param = gat_generics. param_at ( * region_a_idx, tcx) ;
470+ let region_param =
471+ tcx. mk_region ( ty:: RegionKind :: ReEarlyBound ( ty:: EarlyBoundRegion {
472+ def_id : region_param. def_id ,
473+ index : region_param. index ,
474+ name : region_param. name ,
475+ } ) ) ;
476+ // The predicate we expect to see. (In our example,
477+ // `Self: 'me`.)
478+ let clause =
479+ ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate ( ty_param, region_param) ) ;
480+ let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
481+ bounds. insert ( clause) ;
482+ }
483+ }
484+
485+ // For each region argument (e.g., 'a in our example), also check for a
486+ // relationship to the other region arguments. If there is an
487+ // outlives relationship, then we want to ensure that is
488+ // reflected in a where clause on the GAT itself.
489+ for ( region_b, region_b_idx) in & regions {
490+ if ty:: ReStatic == * * region_b || region_a == region_b {
491+ continue ;
492+ }
493+ if region_known_to_outlive ( tcx, item_hir, param_env, & wf_tys, * region_a, * region_b) {
494+ debug ! ( ?region_a_idx, ?region_b_idx) ;
495+ debug ! ( "required clause: {} must outlive {}" , region_a, region_b) ;
496+ // Translate into the generic parameters of the GAT.
497+ let region_a_param = gat_generics. param_at ( * region_a_idx, tcx) ;
498+ let region_a_param =
499+ tcx. mk_region ( ty:: RegionKind :: ReEarlyBound ( ty:: EarlyBoundRegion {
500+ def_id : region_a_param. def_id ,
501+ index : region_a_param. index ,
502+ name : region_a_param. name ,
503+ } ) ) ;
504+ // Same for the region.
505+ let region_b_param = gat_generics. param_at ( * region_b_idx, tcx) ;
506+ let region_b_param =
507+ tcx. mk_region ( ty:: RegionKind :: ReEarlyBound ( ty:: EarlyBoundRegion {
508+ def_id : region_b_param. def_id ,
509+ index : region_b_param. index ,
510+ name : region_b_param. name ,
511+ } ) ) ;
512+ // The predicate we expect to see.
513+ let clause = ty:: PredicateKind :: RegionOutlives ( ty:: OutlivesPredicate (
514+ region_a_param,
515+ region_b_param,
516+ ) ) ;
517+ let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
518+ bounds. insert ( clause) ;
519+ }
520+ }
521+ }
522+
523+ Some ( bounds)
524+ }
525+
518526/// Given a known `param_env` and a set of well formed types, can we prove that
519527/// `ty` outlives `region`.
520528fn ty_known_to_outlive < ' tcx > (
0 commit comments