@@ -266,6 +266,16 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
266
266
/// Require that the user writes as where clauses on GATs 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
+ ///
270
+ /// This trait will be our running example. We are currently WF checking the `Item` item...
271
+ ///
272
+ /// ```rust
273
+ /// trait LendingIterator {
274
+ /// type Item<'me>; // <-- WF checking this trait item
275
+ ///
276
+ /// fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
277
+ /// }
278
+ /// ```
269
279
fn check_gat_where_clauses (
270
280
tcx : TyCtxt < ' _ > ,
271
281
trait_item : & hir:: TraitItem < ' _ > ,
@@ -282,28 +292,56 @@ fn check_gat_where_clauses(
282
292
return ;
283
293
}
284
294
let associated_items: & ty:: AssocItems < ' _ > = tcx. associated_items ( encl_trait_def_id) ;
285
- let mut clauses = FxHashSet :: default ( ) ;
295
+ let mut clauses: Option < FxHashSet < ty :: Predicate < ' _ > > > = None ;
286
296
// For every function in this trait...
297
+ // In our example, this would be the `next` method
287
298
for item in
288
299
associated_items. in_definition_order ( ) . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) )
289
300
{
301
+ // The clauses we that we would require from this function
302
+ let mut function_clauses = FxHashSet :: default ( ) ;
303
+
290
304
let id = hir:: HirId :: make_owner ( item. def_id . expect_local ( ) ) ;
291
305
let param_env = tcx. param_env ( item. def_id . expect_local ( ) ) ;
292
306
293
307
let sig = tcx. fn_sig ( item. def_id ) ;
308
+ // Get the signature using placeholders. In our example, this would
309
+ // convert the late-bound 'a into a free region.
294
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.
295
314
let mut visitor = GATSubstCollector {
296
315
tcx,
297
316
gat : trait_item. def_id . to_def_id ( ) ,
298
317
regions : FxHashSet :: default ( ) ,
299
318
types : FxHashSet :: default ( ) ,
300
319
} ;
301
320
sig. output ( ) . visit_with ( & mut visitor) ;
321
+
322
+ // If both regions and types are empty, then this GAT isn't in the
323
+ // return type, and we shouldn't try to do clause analysis
324
+ // (particularly, doing so would end up with an empty set of clauses,
325
+ // since the current method would require none, and we take the
326
+ // intersection of requirements of all methods)
327
+ if visitor. types . is_empty ( ) && visitor. regions . is_empty ( ) {
328
+ continue ;
329
+ }
330
+
331
+ // The types we can assume to be well-formed. In our example, this
332
+ // would be &'a mut Self, from the first argument.
302
333
let mut wf_tys = FxHashSet :: default ( ) ;
303
334
wf_tys. extend ( sig. inputs ( ) ) ;
304
335
336
+ // For each region argument (e.g., 'a in our example), check for a
337
+ // relationship to the type arguments (e.g., Self). If there is an
338
+ // outlives relationship (`Self: 'a`), then we want to ensure that is
339
+ // reflected in a where clause on the GAT itself.
305
340
for ( region, region_idx) in & visitor. regions {
306
341
for ( ty, ty_idx) in & visitor. types {
342
+ // Unfortunately, we have to use a new `InferCtxt` for each
343
+ // pair, because region constraints get added and solved there,
344
+ // and we need to test each pair individually.
307
345
tcx. infer_ctxt ( ) . enter ( |infcx| {
308
346
let mut outlives_environment = OutlivesEnvironment :: new ( param_env) ;
309
347
outlives_environment. add_implied_bounds ( & infcx, wf_tys. clone ( ) , id, DUMMY_SP ) ;
@@ -328,6 +366,7 @@ fn check_gat_where_clauses(
328
366
Some ( tcx. lifetimes . re_root_empty ) ,
329
367
param_env,
330
368
) ;
369
+ // In our example, requires that Self: 'a
331
370
outlives. type_must_outlive ( origin, sup_type, sub_region) ;
332
371
333
372
let errors = infcx. resolve_regions (
@@ -338,37 +377,57 @@ fn check_gat_where_clauses(
338
377
339
378
debug ! ( ?errors, "errors" ) ;
340
379
380
+ // If we were able to prove that Self: 'a without an error,
381
+ // it must be because of the implied or explicit bounds...
341
382
if errors. is_empty ( ) {
342
383
debug ! ( ?ty_idx, ?region_idx) ;
343
384
debug ! ( "required clause: {} must outlive {}" , ty, region) ;
385
+ // Translate into the generic parameters of the GAT. In
386
+ // our example, the type was Self, which will also be
387
+ // Self in the GAT.
344
388
let ty_param = generics. param_at ( * ty_idx, tcx) ;
345
389
let ty_param = tcx. mk_ty ( ty:: Param ( ty:: ParamTy {
346
390
index : ty_param. index ,
347
391
name : ty_param. name ,
348
392
} ) ) ;
393
+ // Same for the region. In our example, 'a corresponds
394
+ // to the 'me parameter.
349
395
let region_param = generics. param_at ( * region_idx, tcx) ;
350
396
let region_param =
351
397
tcx. mk_region ( ty:: RegionKind :: ReEarlyBound ( ty:: EarlyBoundRegion {
352
398
def_id : region_param. def_id ,
353
399
index : region_param. index ,
354
400
name : region_param. name ,
355
401
} ) ) ;
402
+ // The predicate we expect to see. (In our example,
403
+ // `Self: 'me`.)
356
404
let clause = ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate (
357
405
ty_param,
358
406
region_param,
359
407
) ) ;
360
408
let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
361
- clauses . insert ( clause) ;
409
+ function_clauses . insert ( clause) ;
362
410
}
363
411
} ) ;
364
412
}
365
413
}
414
+
415
+ match clauses. as_mut ( ) {
416
+ Some ( clauses) => {
417
+ clauses. drain_filter ( |p| !function_clauses. contains ( p) ) ;
418
+ }
419
+ None => {
420
+ clauses = Some ( function_clauses) ;
421
+ }
422
+ }
366
423
}
367
424
368
425
// If there are any missing clauses, emit an error
426
+ let mut clauses = clauses. unwrap_or_default ( ) ;
369
427
debug ! ( ?clauses) ;
370
428
if !clauses. is_empty ( ) {
371
- let written_predicates: ty:: GenericPredicates < ' _ > = tcx. predicates_of ( trait_item. def_id ) ;
429
+ let written_predicates: ty:: GenericPredicates < ' _ > =
430
+ tcx. explicit_predicates_of ( trait_item. def_id ) ;
372
431
let clauses: Vec < _ > = clauses
373
432
. drain_filter ( |clause| {
374
433
written_predicates. predicates . iter ( ) . find ( |p| & p. 0 == clause) . is_none ( )
@@ -402,6 +461,10 @@ fn check_gat_where_clauses(
402
461
}
403
462
}
404
463
464
+ /// TypeVisitor that looks for uses of GATs like
465
+ /// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
466
+ /// the two vectors, `regions` and `types` (depending on their kind). For each
467
+ /// parameter `Pi` also track the index `i`.
405
468
struct GATSubstCollector < ' tcx > {
406
469
tcx : TyCtxt < ' tcx > ,
407
470
gat : DefId ,
0 commit comments