From 18b86e94065ff3e493406a7fb811115a85dc57ce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 19 Sep 2018 12:52:17 -0400 Subject: [PATCH] introduce `VerifyBound::IfEq` (presently unused) --- .../infer/lexical_region_resolve/mod.rs | 19 ++- src/librustc/infer/region_constraints/mod.rs | 113 ++++++++++++++---- .../nll/type_check/constraint_conversion.rs | 5 + 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 50198406e847..727b257f6f27 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 0297340e402f..9e12ed0b52f7 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: /// - /// 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. + /// 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 >::Item: 'b` in our where clauses. If we are + /// generating the verify-bound for `>::Item`, then + /// this where-clause is only relevant if `'0` winds up inferred + /// to `'a`. + /// + /// So we would compile to a verify-bound like + /// + /// IfEq(>::Item, AnyRegion('a)) + /// + /// meaning, if the subject G is equal to `>::Item` + /// (after inference), and `'a: min`, then `G: min`. + IfEq(Ty<'tcx>, Box>), + + /// 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>), - /// 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>), - /// 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>), - /// 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>), } @@ -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 220cbfe4fff3..37a6022469ec 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(), ),