@@ -263,7 +263,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
263
263
check_gat_where_clauses ( tcx, trait_item, encl_trait_def_id) ;
264
264
}
265
265
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
267
267
/// outlives bounds involving trait parameters in trait functions and
268
268
/// lifetimes passed as GAT substs. See `self-outlives-lint` test.
269
269
///
@@ -288,6 +288,7 @@ fn check_gat_where_clauses(
288
288
}
289
289
let generics: & ty:: Generics = tcx. generics_of ( trait_item. def_id ) ;
290
290
// 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
291
292
if generics. params . len ( ) == 0 {
292
293
return ;
293
294
}
@@ -311,20 +312,15 @@ fn check_gat_where_clauses(
311
312
// Collect the arguments that are given to this GAT in the return type
312
313
// of the function signature. In our example, the GAT in the return
313
314
// 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 ( ) ) ;
321
317
322
318
// If both regions and types are empty, then this GAT isn't in the
323
319
// return type, and we shouldn't try to do clause analysis
324
320
// (particularly, doing so would end up with an empty set of clauses,
325
321
// since the current method would require none, and we take the
326
322
// intersection of requirements of all methods)
327
- if visitor . types . is_empty ( ) && visitor . regions . is_empty ( ) {
323
+ if types. is_empty ( ) && regions. is_empty ( ) {
328
324
continue ;
329
325
}
330
326
@@ -337,8 +333,8 @@ fn check_gat_where_clauses(
337
333
// relationship to the type arguments (e.g., Self). If there is an
338
334
// outlives relationship (`Self: 'a`), then we want to ensure that is
339
335
// 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 {
342
338
// In our example, requires that Self: 'a
343
339
if ty_known_to_outlive ( tcx, id, param_env, & wf_tys, * ty, * region) {
344
340
debug ! ( ?ty_idx, ?region_idx) ;
@@ -376,8 +372,8 @@ fn check_gat_where_clauses(
376
372
// relationship to the other region arguments. If there is an
377
373
// outlives relationship, then we want to ensure that is
378
374
// 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 {
381
377
if region_a == region_b {
382
378
continue ;
383
379
}
@@ -412,6 +408,16 @@ fn check_gat_where_clauses(
412
408
}
413
409
}
414
410
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`)
415
421
match clauses. as_mut ( ) {
416
422
Some ( clauses) => {
417
423
clauses. drain_filter ( |p| !function_clauses. contains ( p) ) ;
@@ -428,12 +434,14 @@ fn check_gat_where_clauses(
428
434
if !clauses. is_empty ( ) {
429
435
let written_predicates: ty:: GenericPredicates < ' _ > =
430
436
tcx. explicit_predicates_of ( trait_item. def_id ) ;
431
- let clauses: Vec < _ > = clauses
437
+ let mut clauses: Vec < _ > = clauses
432
438
. drain_filter ( |clause| {
433
439
written_predicates. predicates . iter ( ) . find ( |p| & p. 0 == clause) . is_none ( )
434
440
} )
435
441
. map ( |clause| format ! ( "{}" , clause) )
436
442
. collect ( ) ;
443
+ // We sort so that order is predictable
444
+ clauses. sort ( ) ;
437
445
if !clauses. is_empty ( ) {
438
446
let mut err = tcx. sess . struct_span_err (
439
447
trait_item. span ,
@@ -461,6 +469,8 @@ fn check_gat_where_clauses(
461
469
}
462
470
}
463
471
472
+ // FIXME(jackh726): refactor some of the shared logic between the two functions below
473
+
464
474
/// Given a known `param_env` and a set of well formed types, can we prove that
465
475
/// `ty` outlives `region`.
466
476
fn ty_known_to_outlive < ' tcx > (
@@ -564,6 +574,23 @@ struct GATSubstCollector<'tcx> {
564
574
types : FxHashSet < ( Ty < ' tcx > , usize ) > ,
565
575
}
566
576
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
+
567
594
impl < ' tcx > TypeVisitor < ' tcx > for GATSubstCollector < ' tcx > {
568
595
type BreakTy = !;
569
596
0 commit comments