make NLL handle IfEq bounds by using SCC normalization

This commit is contained in:
Niko Matsakis 2018-09-21 19:26:24 -04:00
parent 0f5dae0322
commit 0b4791e60b
10 changed files with 630 additions and 9 deletions

View file

@ -0,0 +1,91 @@
// 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() { }

View file

@ -0,0 +1,251 @@
// 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() { }

View file

@ -0,0 +1,25 @@
// 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() {}

View file

@ -0,0 +1,36 @@
#![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() {}

View file

@ -0,0 +1,24 @@
// 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() {}

View file

@ -0,0 +1,30 @@
#![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() {}

View file

@ -0,0 +1,26 @@
#![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() {}

View file

@ -0,0 +1,27 @@
#![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() {}