about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-09-19 12:52:17 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-09-26 09:38:26 -0400
commit18b86e94065ff3e493406a7fb811115a85dc57ce (patch)
treeb914d011eb3efd992f320645c45223060c91f488
parent58fd6fad24334ca5061dd864cb063bcf7030ecef (diff)
downloadrust-18b86e94065ff3e493406a7fb811115a85dc57ce.tar.gz
rust-18b86e94065ff3e493406a7fb811115a85dc57ce.zip
introduce `VerifyBound::IfEq` (presently unused)
-rw-r--r--src/librustc/infer/lexical_region_resolve/mod.rs19
-rw-r--r--src/librustc/infer/region_constraints/mod.rs113
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs5
3 files changed, 111 insertions, 26 deletions
diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs
index 50198406e84..727b257f6f2 100644
--- a/src/librustc/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc/infer/lexical_region_resolve/mod.rs
@@ -25,11 +25,11 @@ use rustc_data_structures::graph::implementation::{
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use std::fmt;
 use std::u32;
-use ty::{self, TyCtxt};
+use ty::fold::TypeFoldable;
+use ty::{self, Ty, TyCtxt};
 use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
 use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
 use ty::{Region, RegionVid};
-use ty::fold::TypeFoldable;
 
 mod graphviz;
 
@@ -421,7 +421,8 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
                 continue;
             }
 
-            if self.bound_is_met(&verify.bound, var_data, sub) {
+            let verify_kind_ty = verify.kind.to_ty(self.tcx());
+            if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
                 continue;
             }
 
@@ -713,9 +714,15 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
         &self,
         bound: &VerifyBound<'tcx>,
         var_values: &LexicalRegionResolutions<'tcx>,
+        generic_ty: Ty<'tcx>,
         min: ty::Region<'tcx>,
     ) -> bool {
         match bound {
+            VerifyBound::IfEq(k, b) => {
+                (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
+                    && self.bound_is_met(b, var_values, generic_ty, min)
+            }
+
             VerifyBound::AnyRegion(rs) => rs.iter()
                 .map(|&r| var_values.normalize(self.tcx(), r))
                 .any(|r| self.region_rels.is_subregion_of(min, r)),
@@ -724,9 +731,11 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
                 .map(|&r| var_values.normalize(self.tcx(), r))
                 .all(|r| self.region_rels.is_subregion_of(min, r)),
 
-            VerifyBound::AnyBound(bs) => bs.iter().any(|b| self.bound_is_met(b, var_values, min)),
+            VerifyBound::AnyBound(bs) => bs.iter()
+                .any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
 
-            VerifyBound::AllBounds(bs) => bs.iter().all(|b| self.bound_is_met(b, var_values, min)),
+            VerifyBound::AllBounds(bs) => bs.iter()
+                .all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
         }
     }
 }
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index 0297340e402..9e12ed0b52f 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -155,29 +155,98 @@ pub enum GenericKind<'tcx> {
     Projection(ty::ProjectionTy<'tcx>),
 }
 
-/// When we introduce a verification step, we wish to test that a
-/// particular region (let's call it `'min`) meets some bound.
-/// The bound is described the by the following grammar:
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for GenericKind<'tcx> {
+        (GenericKind::Param)(a),
+        (GenericKind::Projection)(a),
+    }
+}
+
+/// Describes the things that some `GenericKind` value G is known to
+/// outlive. Each variant of `VerifyBound` can be thought of as a
+/// function:
+///
+///     fn(min: Region) -> bool { .. }
+///
+/// where `true` means that the region `min` meets that `G: min`.
+/// (False means nothing.)
+///
+/// So, for example, if we have the type `T` and we have in scope that
+/// `T: 'a` and `T: 'b`, then the verify bound might be:
+///
+///     fn(min: Region) -> bool {
+///        ('a: min) || ('b: min)
+///     }
+///
+/// This is described with a `AnyRegion('a, 'b)` node.
 #[derive(Debug, Clone)]
 pub enum VerifyBound<'tcx> {
-    /// B = exists {R} --> some 'r in {R} must outlive 'min
+    /// Given a kind K and a bound B, expands to a function like the
+    /// following, where `G` is the generic for which this verify
+    /// bound was created:
+    ///
+    ///     fn(min) -> bool {
+    ///       if G == K {
+    ///         B(min)
+    ///       } else {
+    ///         false
+    ///       }
+    ///     }
+    ///
+    /// In other words, if the generic `G` that we are checking is
+    /// equal to `K`, then check the associated verify bound
+    /// (otherwise, false).
+    ///
+    /// This is used when we have something in the environment that
+    /// may or may not be relevant, depending on the region inference
+    /// results. For example, we may have `where <T as
+    /// Trait<'a>>::Item: 'b` in our where clauses. If we are
+    /// generating the verify-bound for `<T as Trait<'0>>::Item`, then
+    /// this where-clause is only relevant if `'0` winds up inferred
+    /// to `'a`.
+    ///
+    /// So we would compile to a verify-bound like
     ///
-    /// Put another way, the subject value is known to outlive all
-    /// regions in {R}, so if any of those outlives 'min, then the
-    /// bound is met.
+    ///     IfEq(<T as Trait<'a>>::Item, AnyRegion('a))
+    ///
+    /// meaning, if the subject G is equal to `<T as Trait<'a>>::Item`
+    /// (after inference), and `'a: min`, then `G: min`.
+    IfEq(Ty<'tcx>, Box<VerifyBound<'tcx>>),
+
+    /// Given a set of regions `R`, expands to the function:
+    ///
+    ///     fn(min) -> bool {
+    ///       exists (r in R) { r: min }
+    ///     }
+    ///
+    /// In other words, if some r in R outlives min, then G outlives
+    /// min.  This is used when G is known to outlive all the regions
+    /// in R.
     AnyRegion(Vec<Region<'tcx>>),
 
-    /// B = forall {R} --> all 'r in {R} must outlive 'min
+    /// Given a set of regions `R`, expands to the function:
     ///
-    /// Put another way, the subject value is known to outlive some
-    /// region in {R}, so if all of those outlives 'min, then the bound
-    /// is met.
+    ///     fn(min) -> bool {
+    ///       forall (r in R) { r: min }
+    ///     }
+    ///
+    /// In other words, if all r in R outlives min, then G outlives
+    /// min. This is used when G is known to outlive some region in
+    /// R, but we don't know which.
     AllRegions(Vec<Region<'tcx>>),
 
-    /// B = exists {B} --> 'min must meet some bound b in {B}
+    /// Given a set of bounds `B`, expands to the function:
+    ///
+    ///     fn(min) -> bool {
+    ///       exists (b in B) { b(min) }
+    ///     }
     AnyBound(Vec<VerifyBound<'tcx>>),
 
-    /// B = forall {B} --> 'min must meet all bounds b in {B}
+    /// Given a set of bounds `B`, expands to the function:
+    ///
+    ///     fn(min) -> bool {
+    ///       forall (b in B) { b(min) }
+    ///     }
     AllBounds(Vec<VerifyBound<'tcx>>),
 }
 
@@ -884,19 +953,21 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> {
 impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
     pub fn must_hold(&self) -> bool {
         match self {
-            &VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic),
-            &VerifyBound::AllRegions(ref bs) => bs.is_empty(),
-            &VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
-            &VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
+            VerifyBound::IfEq(..) => false,
+            VerifyBound::AnyRegion(bs) => bs.contains(&&ty::ReStatic),
+            VerifyBound::AllRegions(bs) => bs.is_empty(),
+            VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
+            VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
         }
     }
 
     pub fn cannot_hold(&self) -> bool {
         match self {
-            &VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
-            &VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty),
-            &VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
-            &VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
+            VerifyBound::IfEq(_, b) => b.cannot_hold(),
+            VerifyBound::AnyRegion(bs) => bs.is_empty(),
+            VerifyBound::AllRegions(bs) => bs.contains(&&ty::ReEmpty),
+            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/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index 220cbfe4fff..37a6022469e 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -156,6 +156,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
 
     fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest {
         match verify_bound {
+            VerifyBound::IfEq(..) => {
+                // FIXME: always false right now
+                RegionTest::IsOutlivedByAnyRegionIn(vec![])
+            }
+
             VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn(
                 regions.iter().map(|r| self.to_region_vid(r)).collect(),
             ),