@@ -266,6 +266,16 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
266266/// Require that the user writes as where clauses on GATs the implicit
267267/// outlives bounds involving trait parameters in trait functions and
268268/// 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+ /// ```
269279fn check_gat_where_clauses (
270280 tcx : TyCtxt < ' _ > ,
271281 trait_item : & hir:: TraitItem < ' _ > ,
@@ -282,28 +292,56 @@ fn check_gat_where_clauses(
282292 return ;
283293 }
284294 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 ;
286296 // For every function in this trait...
297+ // In our example, this would be the `next` method
287298 for item in
288299 associated_items. in_definition_order ( ) . filter ( |item| matches ! ( item. kind, ty:: AssocKind :: Fn ) )
289300 {
301+ // The clauses we that we would require from this function
302+ let mut function_clauses = FxHashSet :: default ( ) ;
303+
290304 let id = hir:: HirId :: make_owner ( item. def_id . expect_local ( ) ) ;
291305 let param_env = tcx. param_env ( item. def_id . expect_local ( ) ) ;
292306
293307 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.
294310 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.
295314 let mut visitor = GATSubstCollector {
296315 tcx,
297316 gat : trait_item. def_id . to_def_id ( ) ,
298317 regions : FxHashSet :: default ( ) ,
299318 types : FxHashSet :: default ( ) ,
300319 } ;
301320 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.
302333 let mut wf_tys = FxHashSet :: default ( ) ;
303334 wf_tys. extend ( sig. inputs ( ) ) ;
304335
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.
305340 for ( region, region_idx) in & visitor. regions {
306341 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.
307345 tcx. infer_ctxt ( ) . enter ( |infcx| {
308346 let mut outlives_environment = OutlivesEnvironment :: new ( param_env) ;
309347 outlives_environment. add_implied_bounds ( & infcx, wf_tys. clone ( ) , id, DUMMY_SP ) ;
@@ -328,6 +366,7 @@ fn check_gat_where_clauses(
328366 Some ( tcx. lifetimes . re_root_empty ) ,
329367 param_env,
330368 ) ;
369+ // In our example, requires that Self: 'a
331370 outlives. type_must_outlive ( origin, sup_type, sub_region) ;
332371
333372 let errors = infcx. resolve_regions (
@@ -338,37 +377,57 @@ fn check_gat_where_clauses(
338377
339378 debug ! ( ?errors, "errors" ) ;
340379
380+ // If we were able to prove that Self: 'a without an error,
381+ // it must be because of the implied or explicit bounds...
341382 if errors. is_empty ( ) {
342383 debug ! ( ?ty_idx, ?region_idx) ;
343384 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.
344388 let ty_param = generics. param_at ( * ty_idx, tcx) ;
345389 let ty_param = tcx. mk_ty ( ty:: Param ( ty:: ParamTy {
346390 index : ty_param. index ,
347391 name : ty_param. name ,
348392 } ) ) ;
393+ // Same for the region. In our example, 'a corresponds
394+ // to the 'me parameter.
349395 let region_param = generics. param_at ( * region_idx, tcx) ;
350396 let region_param =
351397 tcx. mk_region ( ty:: RegionKind :: ReEarlyBound ( ty:: EarlyBoundRegion {
352398 def_id : region_param. def_id ,
353399 index : region_param. index ,
354400 name : region_param. name ,
355401 } ) ) ;
402+ // The predicate we expect to see. (In our example,
403+ // `Self: 'me`.)
356404 let clause = ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate (
357405 ty_param,
358406 region_param,
359407 ) ) ;
360408 let clause = tcx. mk_predicate ( ty:: Binder :: dummy ( clause) ) ;
361- clauses . insert ( clause) ;
409+ function_clauses . insert ( clause) ;
362410 }
363411 } ) ;
364412 }
365413 }
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+ }
366423 }
367424
368425 // If there are any missing clauses, emit an error
426+ let mut clauses = clauses. unwrap_or_default ( ) ;
369427 debug ! ( ?clauses) ;
370428 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 ) ;
372431 let clauses: Vec < _ > = clauses
373432 . drain_filter ( |clause| {
374433 written_predicates. predicates . iter ( ) . find ( |p| & p. 0 == clause) . is_none ( )
@@ -402,6 +461,10 @@ fn check_gat_where_clauses(
402461 }
403462}
404463
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`.
405468struct GATSubstCollector < ' tcx > {
406469 tcx : TyCtxt < ' tcx > ,
407470 gat : DefId ,
0 commit comments