introduce VerifyBound::IfEq (presently unused)

This commit is contained in:
Niko Matsakis 2018-09-19 12:52:17 -04:00
parent 58fd6fad24
commit 18b86e9406
3 changed files with 111 additions and 26 deletions

View file

@ -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)),
}
}
}

View file

@ -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 <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
///
/// 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()),
}
}

View file

@ -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(),
),