@@ -298,145 +298,49 @@ fn check_gat_where_clauses(
298
298
for item in
299
299
associated_items. in_definition_order ( ) . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) )
300
300
{
301
- // The clauses we that we would require from this function
302
- let mut function_clauses = FxHashSet :: default ( ) ;
303
-
304
301
let id = hir:: HirId :: make_owner ( item. def_id . expect_local ( ) ) ;
305
302
let param_env = tcx. param_env ( item. def_id . expect_local ( ) ) ;
306
303
307
- let sig = tcx. fn_sig ( item. def_id ) ;
308
304
// Get the signature using placeholders. In our example, this would
309
305
// 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 ) ) ;
325
307
326
308
// The types we can assume to be well-formed. In our example, this
327
309
// would be &'a mut Self, from the first argument.
328
310
let mut wf_tys = FxHashSet :: default ( ) ;
329
311
wf_tys. extend ( sig. inputs ( ) ) ;
330
312
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
+ ) ;
374
323
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) ) ;
392
338
}
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) ;
418
341
}
419
342
}
420
343
}
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
- }
440
344
}
441
345
442
346
// If there are any clauses that aren't provable, emit an error
@@ -515,6 +419,110 @@ fn check_gat_where_clauses(
515
419
}
516
420
}
517
421
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
+
518
526
/// Given a known `param_env` and a set of well formed types, can we prove that
519
527
/// `ty` outlives `region`.
520
528
fn ty_known_to_outlive < ' tcx > (
0 commit comments