about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2019-10-08 05:06:21 -0400
committerNiko Matsakis <niko@alum.mit.edu>2020-02-06 15:51:02 -0500
commit65fc086dba3cd20e7e3d75c698c5816d82b7bbc7 (patch)
tree5c7a9ed1cc953965c18c90d4498ab581c68d6cc5 /src
parent82c143561f2d9115263e774b0caf75af462f6fcb (diff)
downloadrust-65fc086dba3cd20e7e3d75c698c5816d82b7bbc7.tar.gz
rust-65fc086dba3cd20e7e3d75c698c5816d82b7bbc7.zip
add a `IsEmpty` for use in verified bounds
We currently have a kind of arbitrary check for `Verify` conditions
which says that if the "test region" is `'empty`, then the check
passes. This was added to fix #42467 -- it happens to be correct for
the purposes that we use verify bounds for, but it doesn't feel
generally correct. Replace with a more principled test.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/lexical_region_resolve/mod.rs14
-rw-r--r--src/librustc/infer/outlives/verify.rs13
-rw-r--r--src/librustc/infer/region_constraints/mod.rs6
-rw-r--r--src/librustc_mir/borrow_check/region_infer/mod.rs5
4 files changed, 30 insertions, 8 deletions
diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs
index 4b1f8a5be14..b0a9e0afa70 100644
--- a/src/librustc/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc/infer/lexical_region_resolve/mod.rs
@@ -592,12 +592,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
             debug!("collect_errors: verify={:?}", verify);
             let sub = var_data.normalize(self.tcx(), verify.region);
 
-            // This was an inference variable which didn't get
-            // constrained, therefore it can be assume to hold.
-            if let ty::ReEmpty = *sub {
-                continue;
-            }
-
             let verify_kind_ty = verify.kind.to_ty(self.tcx());
             if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
                 continue;
@@ -893,6 +887,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
             }
 
+            VerifyBound::IsEmpty => {
+                if let ty::ReEmpty = min {
+                    true
+                } else {
+                    false
+                }
+            }
+
             VerifyBound::AnyBound(bs) => {
                 bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
             }
diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs
index 8ee8482e79d..9d6c3f30aa7 100644
--- a/src/librustc/infer/outlives/verify.rs
+++ b/src/librustc/infer/outlives/verify.rs
@@ -60,7 +60,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         // scope type parameters:
         let param_bounds = param_bounds.chain(self.implicit_region_bound);
 
-        VerifyBound::AnyBound(param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect())
+        let any_bounds: Vec<_> = param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect();
+
+        if any_bounds.is_empty() {
+            // We know that all types `T` outlive `'empty`, so if we
+            // can find no other bound, then check that the region
+            // being tested is `'empty`.
+            VerifyBound::IsEmpty
+        } else {
+            // If we can find any other bound R such that `T: R`, then
+            // we don't need to check for `'empty`, because `R: 'empty`.
+            VerifyBound::AnyBound(any_bounds)
+        }
     }
 
     /// Given a projection like `T::Item`, searches the environment
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index 410058b70b5..667a4c3a7e2 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -233,6 +233,9 @@ pub enum VerifyBound<'tcx> {
     /// if `R: min`, then by transitivity `G: min`.
     OutlivedBy(Region<'tcx>),
 
+    /// Given a region `R`, true if it is `'empty`.
+    IsEmpty,
+
     /// Given a set of bounds `B`, expands to the function:
     ///
     /// ```rust
@@ -867,6 +870,7 @@ impl<'tcx> VerifyBound<'tcx> {
             VerifyBound::IfEq(..) => false,
             VerifyBound::OutlivedBy(ty::ReStatic) => true,
             VerifyBound::OutlivedBy(_) => false,
+            VerifyBound::IsEmpty => false,
             VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
             VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
         }
@@ -875,7 +879,7 @@ impl<'tcx> VerifyBound<'tcx> {
     pub fn cannot_hold(&self) -> bool {
         match self {
             VerifyBound::IfEq(_, b) => b.cannot_hold(),
-            VerifyBound::OutlivedBy(ty::ReEmpty) => true,
+            VerifyBound::IsEmpty => false,
             VerifyBound::OutlivedBy(_) => false,
             VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
             VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()),
diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs
index 26d9cf2e045..6abca481eac 100644
--- a/src/librustc_mir/borrow_check/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/region_infer/mod.rs
@@ -1108,6 +1108,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1)
             }
 
+            VerifyBound::IsEmpty => {
+                let lower_bound_scc = self.constraint_sccs.scc(lower_bound);
+                self.scc_values.elements_contained_in(lower_bound_scc).next().is_none()
+            }
+
             VerifyBound::OutlivedBy(r) => {
                 let r_vid = self.to_region_vid(r);
                 self.eval_outlives(r_vid, lower_bound)