self.raw.len()
}
+ /// Gives the next index that will be assigned when `push` is
+ /// called.
+ #[inline]
+ pub fn next_index(&self) -> I {
+ I::new(self.len())
+ }
+
#[inline]
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
/// visible from this index.
scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
+ /// Contains a "representative" from each SCC. This will be the
+ /// minimal RegionVid belonging to that universe. It is used as a
+ /// kind of hacky way to manage checking outlives relationships,
+ /// since we can 'canonicalize' each region to the representative
+ /// of its SCC and be sure that -- if they have the same repr --
+ /// they *must* be equal (though not having the same repr does not
+ /// mean they are unequal).
+ scc_representatives: IndexVec<ConstraintSccIndex, ty::RegionVid>,
+
/// The final inferred values of the region variables; we compute
/// one value per SCC. To get the value for any given *region*,
/// you first find which scc it is a part of.
let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions);
+ let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
+
let mut result = Self {
definitions,
liveness_constraints,
constraint_graph,
constraint_sccs,
scc_universes,
+ scc_representatives,
scc_values,
type_tests,
universal_regions,
scc_universes
}
+ /// For each SCC, we compute a unique `RegionVid` (in fact, the
+ /// minimal one that belongs to the SCC). See
+ /// `scc_representatives` field of `RegionInferenceContext` for
+ /// more details.
+ fn compute_scc_representatives(
+ constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
+ definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
+ ) -> IndexVec<ConstraintSccIndex, ty::RegionVid> {
+ let num_sccs = constraints_scc.num_sccs();
+ let next_region_vid = definitions.next_index();
+ let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs);
+
+ for region_vid in definitions.indices() {
+ let scc = constraints_scc.scc(region_vid);
+ let prev_min = scc_representatives[scc];
+ scc_representatives[scc] = region_vid.min(prev_min);
+ }
+
+ scc_representatives
+ }
+
/// Initializes the region variables for each universally
/// quantified region (lifetime parameter). The first N variables
/// always correspond to the regions appearing in the function
for type_test in &self.type_tests {
debug!("check_type_test: {:?}", type_test);
- if self.eval_verify_bound(mir, type_test.lower_bound, &type_test.verify_bound) {
+ let generic_ty = type_test.generic_kind.to_ty(tcx);
+ if self.eval_verify_bound(
+ tcx,
+ mir,
+ generic_ty,
+ type_test.lower_bound,
+ &type_test.verify_bound,
+ ) {
continue;
}
// where `ur` is a local bound -- we are sometimes in a
// position to prove things that our caller cannot. See
// #53570 for an example.
- if self.eval_verify_bound(mir, ur, &type_test.verify_bound) {
+ if self.eval_verify_bound(tcx, mir, generic_ty, ur, &type_test.verify_bound) {
continue;
}
/// `point`, and returns true or false.
fn eval_verify_bound(
&self,
+ tcx: TyCtxt<'_, '_, 'tcx>,
mir: &Mir<'tcx>,
+ generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_bound: &VerifyBound<'tcx>,
) -> bool {
);
match verify_bound {
- VerifyBound::IfEq(..) => false, // FIXME
+ VerifyBound::IfEq(test_ty, verify_bound1) => {
+ self.eval_if_eq(tcx, mir, generic_ty, lower_bound, test_ty, verify_bound1)
+ }
VerifyBound::OutlivedBy(r) => {
let r_vid = self.to_region_vid(r);
self.eval_outlives(mir, r_vid, lower_bound)
}
- VerifyBound::AnyBound(verify_bounds) => verify_bounds
- .iter()
- .any(|verify_bound| self.eval_verify_bound(mir, lower_bound, verify_bound)),
+ VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
+ self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
+ }),
- VerifyBound::AllBounds(verify_bounds) => verify_bounds
- .iter()
- .all(|verify_bound| self.eval_verify_bound(mir, lower_bound, verify_bound)),
+ VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
+ self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
+ }),
}
}
+ fn eval_if_eq(
+ &self,
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ mir: &Mir<'tcx>,
+ generic_ty: Ty<'tcx>,
+ lower_bound: RegionVid,
+ test_ty: Ty<'tcx>,
+ verify_bound: &VerifyBound<'tcx>,
+ ) -> bool {
+ let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty);
+ let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty);
+ if generic_ty_normalized == test_ty_normalized {
+ self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
+ } else {
+ false
+ }
+ }
+
+ /// This is a conservative normalization procedure. It takes every
+ /// free region in `value` and replaces it with the
+ /// "representative" of its SCC (see `scc_representatives` field).
+ /// We are guaranteed that if two values normalize to the same
+ /// thing, then they are equal; this is a conservative check in
+ /// that they could still be equal even if they normalize to
+ /// different results. (For example, there might be two regions
+ /// with the same value that are not in the same SCC).
+ ///
+ /// NB. This is not an ideal approach and I would like to revisit
+ /// it. However, it works pretty well in practice. In particular,
+ /// this is needed to deal with projection outlives bounds like
+ ///
+ /// <T as Foo<'0>>::Item: '1
+ ///
+ /// In particular, this routine winds up being important when
+ /// there are bounds like `where <T as Foo<'a>>::Item: 'b` in the
+ /// environment. In this case, if we can show that `'0 == 'a`,
+ /// and that `'b: '1`, then we know that the clause is
+ /// satisfied. In such cases, particularly due to limitations of
+ /// the trait solver =), we usually wind up with a where-clause like
+ /// `T: Foo<'a>` in scope, which thus forces `'0 == 'a` to be added as
+ /// a constraint, and thus ensures that they are in the same SCC.
+ ///
+ /// So why can't we do a more correct routine? Well, we could
+ /// *almost* use the `relate_tys` code, but the way it is
+ /// currently setup it creates inference variables to deal with
+ /// higher-ranked things and so forth, and right now the inference
+ /// context is not permitted to make more inference variables. So
+ /// we use this kind of hacky solution.
+ fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ tcx.fold_regions(&value, &mut false, |r, _db| {
+ let vid = self.to_region_vid(r);
+ let scc = self.constraint_sccs.scc(vid);
+ let repr = self.scc_representatives[scc];
+ tcx.mk_region(ty::ReVar(repr))
+ })
+ }
+
// Evaluate whether `sup_region: sub_region @ point`.
fn eval_outlives(
&self,
--- /dev/null
+// Regression test for #53789.
+//
+// compile-pass
+
+#![feature(nll)]
+#![allow(unused_variables)]
+
+use std::collections::BTreeMap;
+
+trait ValueTree {
+ type Value;
+}
+
+trait Strategy {
+ type Value: ValueTree;
+}
+
+type StrategyFor<A> = StrategyType<'static, A>;
+type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
+
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V) {
+ type Value = TupleValueTree<(K, V)>;
+}
+
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> {
+ type Value = BTreeMapValueTree<K, V>;
+}
+
+struct TupleValueTree<T> {
+ tree: T,
+}
+
+struct BTreeMapStrategy<K, V>(std::marker::PhantomData<(K, V)>)
+where
+ K: Strategy,
+ V: Strategy;
+
+struct BTreeMapValueTree<K, V>(std::marker::PhantomData<(K, V)>)
+where
+ K: ValueTree,
+ V: ValueTree;
+
+impl<K, V> Strategy for BTreeMapStrategy<K, V>
+where
+ K: Strategy,
+ V: Strategy,
+{
+ type Value = BTreeMapValueTree<K::Value, V::Value>;
+}
+
+impl<K, V> ValueTree for BTreeMapValueTree<K, V>
+where
+ K: ValueTree,
+ V: ValueTree,
+{
+ type Value = BTreeMap<K::Value, V::Value>;
+}
+
+trait Arbitrary<'a>: Sized {
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
+ type Parameters;
+ type Strategy: Strategy<Value = Self::ValueTree>;
+ type ValueTree: ValueTree<Value = Self>;
+}
+
+impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
+where
+ A: Arbitrary<'static>,
+ B: Arbitrary<'static>,
+ StrategyFor<A>: 'static,
+ StrategyFor<B>: 'static,
+{
+ type ValueTree = <Self::Strategy as Strategy>::Value;
+ type Parameters = (A::Parameters, B::Parameters);
+ type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
+ fn arbitrary_with(args: Self::Parameters) -> BTreeMapStrategy<A::Strategy, B::Strategy> {
+ let (a, b) = args;
+ btree_map(any_with::<A>(a), any_with::<B>(b))
+ }
+}
+
+fn btree_map<K: Strategy + 'static, V: Strategy>(key: K, value: V) -> BTreeMapStrategy<K, V> {
+ unimplemented!()
+}
+
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
+ unimplemented!()
+}
+
+fn main() { }
+
--- /dev/null
+// Regression test for #53789.
+//
+// compile-pass
+
+#![feature(nll)]
+#![allow(unused_variables)]
+
+use std::collections::BTreeMap;
+use std::ops::Range;
+use std::cmp::Ord;
+
+macro_rules! valuetree {
+ () => {
+ type ValueTree =
+ <Self::Strategy as $crate::Strategy>::Value;
+ };
+}
+
+macro_rules! product_unpack {
+ ($factor: pat) => {
+ ($factor,)
+ };
+ ($($factor: pat),*) => {
+ ( $( $factor ),* )
+ };
+ ($($factor: pat),*,) => {
+ ( $( $factor ),* )
+ };
+}
+
+macro_rules! product_type {
+ ($factor: ty) => {
+ ($factor,)
+ };
+ ($($factor: ty),*) => {
+ ( $( $factor, )* )
+ };
+ ($($factor: ty),*,) => {
+ ( $( $factor, )* )
+ };
+}
+
+macro_rules! default {
+ ($type: ty, $val: expr) => {
+ impl Default for $type {
+ fn default() -> Self { $val.into() }
+ }
+ };
+}
+
+// Pervasive internal sugar
+macro_rules! mapfn {
+ ($(#[$meta:meta])* [$($vis:tt)*]
+ fn $name:ident[$($gen:tt)*]($parm:ident: $input:ty) -> $output:ty {
+ $($body:tt)*
+ }) => {
+ $(#[$meta])*
+ #[derive(Clone, Copy)]
+ $($vis)* struct $name;
+ impl $($gen)* statics::MapFn<$input> for $name {
+ type Output = $output;
+ }
+ }
+}
+
+macro_rules! opaque_strategy_wrapper {
+ ($(#[$smeta:meta])* pub struct $stratname:ident
+ [$($sgen:tt)*][$($swhere:tt)*]
+ ($innerstrat:ty) -> $stratvtty:ty;
+
+ $(#[$vmeta:meta])* pub struct $vtname:ident
+ [$($vgen:tt)*][$($vwhere:tt)*]
+ ($innervt:ty) -> $actualty:ty;
+ ) => {
+ $(#[$smeta])* struct $stratname $($sgen)* (std::marker::PhantomData<(K, V)>)
+ $($swhere)*;
+
+ $(#[$vmeta])* struct $vtname $($vgen)* ($innervt) $($vwhere)*;
+
+ impl $($sgen)* Strategy for $stratname $($sgen)* $($swhere)* {
+ type Value = $stratvtty;
+ }
+
+ impl $($vgen)* ValueTree for $vtname $($vgen)* $($vwhere)* {
+ type Value = $actualty;
+ }
+ }
+}
+
+trait ValueTree {
+ type Value;
+}
+
+trait Strategy {
+ type Value : ValueTree;
+}
+
+#[derive(Clone)]
+struct VecStrategy<T : Strategy> {
+ element: T,
+ size: Range<usize>,
+}
+
+fn vec<T : Strategy>(element: T, size: Range<usize>)
+ -> VecStrategy<T> {
+ VecStrategy {
+ element: element,
+ size: size,
+ }
+}
+
+type ValueFor<S> = <<S as Strategy>::Value as ValueTree>::Value;
+
+trait Arbitrary<'a>: Sized {
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
+
+ type Parameters: Default;
+ type Strategy: Strategy<Value = Self::ValueTree>;
+ type ValueTree: ValueTree<Value = Self>;
+}
+
+type StrategyFor<A> = StrategyType<'static, A>;
+type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
+
+//#[derive(Clone, PartialEq, Eq, Hash, Debug, From, Into)]
+struct SizeBounds(Range<usize>);
+default!(SizeBounds, 0..100);
+
+
+impl From<Range<usize>> for SizeBounds {
+ fn from(high: Range<usize>) -> Self {
+ unimplemented!()
+ }
+}
+
+impl From<SizeBounds> for Range<usize> {
+ fn from(high: SizeBounds) -> Self {
+ unimplemented!()
+ }
+}
+
+
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters)
+ -> StrategyType<'a, A> {
+ unimplemented!()
+}
+
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V) where
+ <K as ValueTree>::Value: Ord {
+ type Value = TupleValueTree<(K, V)>;
+}
+
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> where
+ <K as ValueTree>::Value: Ord {
+ type Value = BTreeMapValueTree<K, V>;
+}
+
+#[derive(Clone)]
+struct VecValueTree<T : ValueTree> {
+ elements: Vec<T>,
+}
+
+#[derive(Clone, Copy)]
+struct TupleValueTree<T> {
+ tree: T,
+}
+
+opaque_strategy_wrapper! {
+ #[derive(Clone)]
+ pub struct BTreeMapStrategy[<K, V>]
+ [where K : Strategy, V : Strategy, ValueFor<K> : Ord](
+ statics::Filter<statics::Map<VecStrategy<(K,V)>,
+ VecToBTreeMap>, MinSize>)
+ -> BTreeMapValueTree<K::Value, V::Value>;
+
+ #[derive(Clone)]
+ pub struct BTreeMapValueTree[<K, V>]
+ [where K : ValueTree, V : ValueTree, K::Value : Ord](
+ statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>,
+ VecToBTreeMap>, MinSize>)
+ -> BTreeMap<K::Value, V::Value>;
+}
+
+type RangedParams2<A, B> = product_type![SizeBounds, A, B];
+
+impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
+where
+ A: Arbitrary<'static> + Ord,
+ B: Arbitrary<'static>,
+StrategyFor<A>: 'static,
+StrategyFor<B>: 'static,
+{
+ valuetree!();
+ type Parameters = RangedParams2<A::Parameters, B::Parameters>;
+ type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
+ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
+ let product_unpack![range, a, b] = args;
+ btree_map(any_with::<A>(a), any_with::<B>(b), range.into())
+ }
+}
+
+#[derive(Clone, Copy)]
+struct MinSize(usize);
+
+mapfn! {
+ [] fn VecToBTreeMap[<K : Ord, V>]
+ (vec: Vec<(K, V)>) -> BTreeMap<K, V>
+ {
+ vec.into_iter().collect()
+ }
+}
+
+fn btree_map<K : Strategy + 'static, V : Strategy + 'static>
+ (key: K, value: V, size: Range<usize>)
+ -> BTreeMapStrategy<K, V>
+where ValueFor<K> : Ord {
+ unimplemented!()
+}
+
+mod statics {
+ pub(super) trait MapFn<T> {
+ type Output;
+ }
+
+ #[derive(Clone)]
+ pub struct Filter<S, F> {
+ source: S,
+ fun: F,
+ }
+
+ impl<S, F> Filter<S, F> {
+ pub fn new(source: S, whence: String, filter: F) -> Self {
+ unimplemented!()
+ }
+ }
+
+ #[derive(Clone)]
+ pub struct Map<S, F> {
+ source: S,
+ fun: F,
+ }
+
+ impl<S, F> Map<S, F> {
+ pub fn new(source: S, fun: F) -> Self {
+ unimplemented!()
+ }
+ }
+}
+
+fn main() { }
+
--- /dev/null
+// Test that when we infer the lifetime to a subset of the fn body, it
+// works out.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<T>()
+where
+ for<'x> T: MyTrait<'x>,
+{
+ // Here the region `'c` in `<T as MyTrait<'c>>::Output` will be
+ // inferred to a subset of the fn body.
+ let x = bar::<T::Output>();
+ drop(x);
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
--- /dev/null
+#![feature(nll)]
+
+// Test that we are able to establish that `<T as
+// MyTrait<'a>>::Output` outlives `'b` here. We need to prove however
+// that `<T as MyTrait<'a>>::Output` outlives `'a`, so we also have to
+// prove that `'b: 'a`.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<'a, 'b, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'b,
+{
+ bar::<T::Output>() //~ ERROR may not live long enough
+}
+
+fn foo2<'a, 'b, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'b,
+ 'b: 'a,
+{
+ bar::<T::Output>() // OK
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
--- /dev/null
+// Test that if we need to prove that `<T as MyTrait<'a>>::Output:
+// 'a`, but we only know that `<T as MyTrait<'b>>::Output: 'a`, that
+// doesn't suffice.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo1<'a, 'b, T>() -> &'a ()
+where
+ for<'x> T: MyTrait<'x>,
+ <T as MyTrait<'b>>::Output: 'a,
+{
+ bar::<<T as MyTrait<'a>>::Output>() //~ ERROR the associated type `<T as MyTrait<'a>>::Output` may not live long enough
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
--- /dev/null
+#![feature(nll)]
+
+// Test that when we have a `<T as MyTrait<'a>>::Output: 'a`
+// relationship in the environment we take advantage of it. In this
+// case, that means we **don't** have to prove that `T: 'a`.
+//
+// Regression test for #53121.
+//
+// compile-pass
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+ <T as MyTrait<'a>>::Output: 'a,
+{
+ bar::<T::Output>()
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
--- /dev/null
+#![feature(nll)]
+
+// Test that we are NOT able to establish that `<T as
+// MyTrait<'a>>::Output: 'a` outlives `'a` here -- we have only one
+// recourse, which is to prove that `T: 'a` and `'a: 'a`, but we don't
+// know that `T: 'a`.
+
+trait MyTrait<'a> {
+ type Output;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+{
+ bar::<T::Output>() //~ ERROR the parameter type `T` may not live long enough
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}
--- /dev/null
+#![feature(nll)]
+
+// Test that we are able to establish that `<T as
+// MyTrait<'a>>::Output: 'a` outlives `'a` (because the trait says
+// so).
+//
+// compile-pass
+
+trait MyTrait<'a> {
+ type Output: 'a;
+}
+
+fn foo<'a, T>() -> &'a ()
+where
+ T: MyTrait<'a>,
+{
+ bar::<T::Output>()
+}
+
+fn bar<'a, T>() -> &'a ()
+where
+ T: 'a,
+{
+ &()
+}
+
+fn main() {}