about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-01-15 11:28:25 +0100
committerGitHub <noreply@github.com>2022-01-15 11:28:25 +0100
commitcd93be0094a135c55533cb0eba342e5aa1324f00 (patch)
tree0b0bbf3ce48cd8099b03af10135faf4bb909de99
parentd878ad0559ed1be0d0a0e3cdc2a62a9480e42cb8 (diff)
parente8e32e48c4c52a53d0885ddd8eb972829bbda8e5 (diff)
downloadrust-cd93be0094a135c55533cb0eba342e5aa1324f00.tar.gz
rust-cd93be0094a135c55533cb0eba342e5aa1324f00.zip
Rollup merge of #92865 - jackh726:gats-outlives-no-static, r=nikomatsakis
Ignore static lifetimes for GATs outlives lint

cc https://github.com/rust-lang/rust/issues/87479#issuecomment-1010484170

Also included a bit of cleanup of `ty_known_to_outlive` and `region_known_to_outlive`

r? `@nikomatsakis`
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs94
-rw-r--r--src/test/ui/generic-associated-types/self-outlives-lint.rs13
2 files changed, 61 insertions, 46 deletions
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 7c4f5d16abc..fbc446e3ea4 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::ItemKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::outlives::obligations::TypeOutlives;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
+use rustc_infer::infer::region_constraints::GenericKind;
+use rustc_infer::infer::{self, RegionckMode};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -332,6 +333,12 @@ fn check_gat_where_clauses(
         // outlives relationship (`Self: 'a`), then we want to ensure that is
         // reflected in a where clause on the GAT itself.
         for (region, region_idx) in &regions {
+            // Ignore `'static` lifetimes for the purpose of this lint: it's
+            // because we know it outlives everything and so doesn't give meaninful
+            // clues
+            if let ty::ReStatic = region {
+                continue;
+            }
             for (ty, ty_idx) in &types {
                 // In our example, requires that Self: 'a
                 if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
@@ -371,10 +378,19 @@ fn check_gat_where_clauses(
         // 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 &regions {
+            // Ignore `'static` lifetimes for the purpose of this lint: it's
+            // because we know it outlives everything and so doesn't give meaninful
+            // clues
+            if let ty::ReStatic = region_a {
+                continue;
+            }
             for (region_b, region_b_idx) in &regions {
                 if region_a == region_b {
                     continue;
                 }
+                if let ty::ReStatic = region_b {
+                    continue;
+                }
 
                 if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
                     debug!(?region_a_idx, ?region_b_idx);
@@ -502,8 +518,6 @@ fn check_gat_where_clauses(
     }
 }
 
-// FIXME(jackh726): refactor some of the shared logic between the two functions below
-
 /// Given a known `param_env` and a set of well formed types, can we prove that
 /// `ty` outlives `region`.
 fn ty_known_to_outlive<'tcx>(
@@ -514,47 +528,21 @@ fn ty_known_to_outlive<'tcx>(
     ty: Ty<'tcx>,
     region: ty::Region<'tcx>,
 ) -> bool {
-    // Unfortunately, we have to use a new `InferCtxt` each call, because
-    // region constraints get added and solved there and we need to test each
-    // call 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 region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
-
-        let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
-
-        let sup_type = ty;
-        let sub_region = region;
-
-        let origin = SubregionOrigin::from_obligation_cause(&cause, || {
-            infer::RelateParamBound(cause.span, sup_type, None)
-        });
-
+    resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| {
+        let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
         let outlives = &mut TypeOutlives::new(
-            &infcx,
+            infcx,
             tcx,
-            &region_bound_pairs,
+            region_bound_pairs,
             Some(infcx.tcx.lifetimes.re_root_empty),
             param_env,
         );
-        outlives.type_must_outlive(origin, sup_type, sub_region);
-
-        let errors = infcx.resolve_regions(
-            id.expect_owner().to_def_id(),
-            &outlives_environment,
-            RegionckMode::default(),
-        );
-
-        debug!(?errors, "errors");
-
-        // If we were able to prove that the type outlives the region without
-        // an error, it must be because of the implied or explicit bounds...
-        errors.is_empty()
+        outlives.type_must_outlive(origin, ty, region);
     })
 }
 
+/// Given a known `param_env` and a set of well formed types, can we prove that
+/// `region_a` outlives `region_b`
 fn region_known_to_outlive<'tcx>(
     tcx: TyCtxt<'tcx>,
     id: hir::HirId,
@@ -563,6 +551,27 @@ fn region_known_to_outlive<'tcx>(
     region_a: ty::Region<'tcx>,
     region_b: ty::Region<'tcx>,
 ) -> bool {
+    resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |mut infcx, _| {
+        use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
+        let origin = infer::RelateRegionParamBound(DUMMY_SP);
+        // `region_a: region_b` -> `region_b <= region_a`
+        infcx.push_sub_region_constraint(origin, region_b, region_a);
+    })
+}
+
+/// Given a known `param_env` and a set of well formed types, set up an
+/// `InferCtxt`, call the passed function (to e.g. set up region constraints
+/// to be tested), then resolve region and return errors
+fn resolve_regions_with_wf_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    id: hir::HirId,
+    param_env: ty::ParamEnv<'tcx>,
+    wf_tys: &FxHashSet<Ty<'tcx>>,
+    add_constraints: impl for<'a> FnOnce(
+        &'a InferCtxt<'a, 'tcx>,
+        &'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>,
+    ),
+) -> bool {
     // Unfortunately, we have to use a new `InferCtxt` each call, because
     // region constraints get added and solved there and we need to test each
     // call individually.
@@ -570,16 +579,9 @@ fn region_known_to_outlive<'tcx>(
         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 region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
 
-        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;
-        // `region_a: region_b` -> `region_b <= region_a`
-        (&infcx).push_sub_region_constraint(origin, region_b, region_a);
+        add_constraints(&infcx, region_bound_pairs);
 
         let errors = infcx.resolve_regions(
             id.expect_owner().to_def_id(),
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs
index 37b3a6155d5..fcc53b4ede0 100644
--- a/src/test/ui/generic-associated-types/self-outlives-lint.rs
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs
@@ -189,4 +189,17 @@ trait Trait: 'static {
     fn make_assoc(_: &u32) -> Self::Assoc<'_>;
 }
 
+// We ignore `'static` lifetimes for any lints
+trait StaticReturn<'a> {
+    type Y<'b>;
+    fn foo(&self) -> Self::Y<'static>;
+}
+
+// Same as above, but with extra method that takes GAT - just make sure this works
+trait StaticReturnAndTakes<'a> {
+    type Y<'b>;
+    fn foo(&self) -> Self::Y<'static>;
+    fn bar<'b>(&self, arg: Self::Y<'b>);
+}
+
 fn main() {}