about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs69
-rw-r--r--src/test/ui/generic-associated-types/self-outlives-lint.stderr10
2 files changed, 78 insertions, 1 deletions
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 36dbc04d0a6..5d884edfe18 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -412,6 +412,75 @@ fn check_gat_where_clauses(
             }
         }
 
+        // For each region argument (e.g., 'a in our example), also check for a
+        // relationship to the other region arguments. If there is an
+        // outlives relationship, then we want to ensure that is
+        // reflected in a where clause on the GAT itself.
+        for (region_a, region_a_idx) in &visitor.regions {
+            for (region_b, region_b_idx) in &visitor.regions {
+                if region_a == region_b {
+                    continue;
+                }
+
+                // Unfortunately, we have to use a new `InferCtxt` for each
+                // pair, because region constraints get added and solved there,
+                // and we need to test each pair individually.
+                tcx.infer_ctxt().enter(|infcx| {
+                    let mut outlives_environment = OutlivesEnvironment::new(param_env);
+                    outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
+                    outlives_environment.save_implied_bounds(id);
+
+                    let cause =
+                        ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
+
+                    let origin = SubregionOrigin::from_obligation_cause(&cause, || {
+                        infer::RelateRegionParamBound(cause.span)
+                    });
+
+                    use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
+                    (&infcx).push_sub_region_constraint(origin, region_a, region_b);
+
+                    let errors = infcx.resolve_regions(
+                        trait_item.def_id.to_def_id(),
+                        &outlives_environment,
+                        RegionckMode::default(),
+                    );
+
+                    debug!(?errors, "errors");
+
+                    // If we were able to prove that Self: 'a without an error,
+                    // it must be because of the implied or explicit bounds...
+                    if errors.is_empty() {
+                        debug!(?region_a_idx, ?region_b_idx);
+                        debug!("required clause: {} must outlive {}", region_a, region_b);
+                        // Translate into the generic parameters of the GAT.
+                        let region_a_param = generics.param_at(*region_a_idx, tcx);
+                        let region_a_param =
+                            tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+                                def_id: region_a_param.def_id,
+                                index: region_a_param.index,
+                                name: region_a_param.name,
+                            }));
+                        // Same for the region.
+                        let region_b_param = generics.param_at(*region_b_idx, tcx);
+                        let region_b_param =
+                            tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+                                def_id: region_b_param.def_id,
+                                index: region_b_param.index,
+                                name: region_b_param.name,
+                            }));
+                        // The predicate we expect to see.
+                        let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+                            region_a_param,
+                            region_b_param,
+                        ));
+                        let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+                        function_clauses.insert(clause);
+                    }
+                });
+            }
+        }
+
         match clauses.as_mut() {
             Some(clauses) => {
                 clauses.drain_filter(|p| !function_clauses.contains(p));
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
index acccbf24319..df858c27cd3 100644
--- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
@@ -86,5 +86,13 @@ LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
    |                                                       |
    |                                                       help: add the required where clauses: `where Self: 'a`
 
-error: aborting due to 11 previous errors
+error: Missing required bounds on Bar
+  --> $DIR/self-outlives-lint.rs:148:5
+   |
+LL |     type Bar<'a, 'b>;
+   |     ^^^^^^^^^^^^^^^^-
+   |                     |
+   |                     help: add the required where clauses: `where 'a: 'b`
+
+error: aborting due to 12 previous errors