@@ -263,7 +263,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
263263 check_gat_where_clauses ( tcx, trait_item, encl_trait_def_id) ;
264264}
265265
266- /// Require that the user writes as where clauses on GATs the implicit
266+ /// Require that the user writes where clauses on GATs for the implicit
267267/// outlives bounds involving trait parameters in trait functions and
268268/// lifetimes passed as GAT substs. See `self-outlives-lint` test.
269269///
@@ -288,6 +288,7 @@ fn check_gat_where_clauses(
288288 }
289289 let generics: & ty:: Generics = tcx. generics_of ( trait_item. def_id ) ;
290290 // If the current associated type doesn't have any (own) params, it's not a GAT
291+ // FIXME(jackh726): we can also warn in the more general case
291292 if generics. params . len ( ) == 0 {
292293 return ;
293294 }
@@ -311,20 +312,15 @@ fn check_gat_where_clauses(
311312 // Collect the arguments that are given to this GAT in the return type
312313 // of the function signature. In our example, the GAT in the return
313314 // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
314- let mut visitor = GATSubstCollector {
315- tcx,
316- gat : trait_item. def_id . to_def_id ( ) ,
317- regions : FxHashSet :: default ( ) ,
318- types : FxHashSet :: default ( ) ,
319- } ;
320- sig. output ( ) . visit_with ( & mut visitor) ;
315+ let ( regions, types) =
316+ GATSubstCollector :: visit ( tcx, trait_item. def_id . to_def_id ( ) , sig. output ( ) ) ;
321317
322318 // If both regions and types are empty, then this GAT isn't in the
323319 // return type, and we shouldn't try to do clause analysis
324320 // (particularly, doing so would end up with an empty set of clauses,
325321 // since the current method would require none, and we take the
326322 // intersection of requirements of all methods)
327- if visitor . types . is_empty ( ) && visitor . regions . is_empty ( ) {
323+ if types. is_empty ( ) && regions. is_empty ( ) {
328324 continue ;
329325 }
330326
@@ -337,8 +333,8 @@ fn check_gat_where_clauses(
337333 // relationship to the type arguments (e.g., Self). If there is an
338334 // outlives relationship (`Self: 'a`), then we want to ensure that is
339335 // reflected in a where clause on the GAT itself.
340- for ( region, region_idx) in & visitor . regions {
341- for ( ty, ty_idx) in & visitor . types {
336+ for ( region, region_idx) in & regions {
337+ for ( ty, ty_idx) in & types {
342338 // In our example, requires that Self: 'a
343339 if ty_known_to_outlive ( tcx, id, param_env, & wf_tys, * ty, * region) {
344340 debug ! ( ?ty_idx, ?region_idx) ;
@@ -376,8 +372,8 @@ fn check_gat_where_clauses(
376372 // relationship to the other region arguments. If there is an
377373 // outlives relationship, then we want to ensure that is
378374 // reflected in a where clause on the GAT itself.
379- for ( region_a, region_a_idx) in & visitor . regions {
380- for ( region_b, region_b_idx) in & visitor . regions {
375+ for ( region_a, region_a_idx) in & regions {
376+ for ( region_b, region_b_idx) in & regions {
381377 if region_a == region_b {
382378 continue ;
383379 }
@@ -412,6 +408,16 @@ fn check_gat_where_clauses(
412408 }
413409 }
414410
411+ // Imagine we have:
412+ // ```
413+ // trait Foo {
414+ // type Bar<'me>;
415+ // fn gimme(&self) -> Self::Bar<'_>;
416+ // fn gimme_default(&self) -> Self::Bar<'static>;
417+ // }
418+ // ```
419+ // We only want to require clauses on `Bar` that we can prove from *all* functions (in this
420+ // case, `'me` can be `static` from `gimme_default`)
415421 match clauses. as_mut ( ) {
416422 Some ( clauses) => {
417423 clauses. drain_filter ( |p| !function_clauses. contains ( p) ) ;
@@ -428,12 +434,14 @@ fn check_gat_where_clauses(
428434 if !clauses. is_empty ( ) {
429435 let written_predicates: ty:: GenericPredicates < ' _ > =
430436 tcx. explicit_predicates_of ( trait_item. def_id ) ;
431- let clauses: Vec < _ > = clauses
437+ let mut clauses: Vec < _ > = clauses
432438 . drain_filter ( |clause| {
433439 written_predicates. predicates . iter ( ) . find ( |p| & p. 0 == clause) . is_none ( )
434440 } )
435441 . map ( |clause| format ! ( "{}" , clause) )
436442 . collect ( ) ;
443+ // We sort so that order is predictable
444+ clauses. sort ( ) ;
437445 if !clauses. is_empty ( ) {
438446 let mut err = tcx. sess . struct_span_err (
439447 trait_item. span ,
@@ -461,6 +469,8 @@ fn check_gat_where_clauses(
461469 }
462470}
463471
472+ // FIXME(jackh726): refactor some of the shared logic between the two functions below
473+
464474/// Given a known `param_env` and a set of well formed types, can we prove that
465475/// `ty` outlives `region`.
466476fn ty_known_to_outlive < ' tcx > (
@@ -564,6 +574,23 @@ struct GATSubstCollector<'tcx> {
564574 types : FxHashSet < ( Ty < ' tcx > , usize ) > ,
565575}
566576
577+ impl < ' tcx > GATSubstCollector < ' tcx > {
578+ fn visit < T : TypeFoldable < ' tcx > > (
579+ tcx : TyCtxt < ' tcx > ,
580+ gat : DefId ,
581+ t : T ,
582+ ) -> ( FxHashSet < ( ty:: Region < ' tcx > , usize ) > , FxHashSet < ( Ty < ' tcx > , usize ) > ) {
583+ let mut visitor = GATSubstCollector {
584+ tcx,
585+ gat,
586+ regions : FxHashSet :: default ( ) ,
587+ types : FxHashSet :: default ( ) ,
588+ } ;
589+ t. visit_with ( & mut visitor) ;
590+ ( visitor. regions , visitor. types )
591+ }
592+ }
593+
567594impl < ' tcx > TypeVisitor < ' tcx > for GATSubstCollector < ' tcx > {
568595 type BreakTy = !;
569596
0 commit comments