Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up[nll] spurious outlives requirement in shred-0.7.0 #53121
Comments
nikomatsakis
added
T-compiler
WG-compiler-nll
NLL-complete
labels
Aug 6, 2018
nikomatsakis
added this to the Rust 2018 RC milestone
Aug 6, 2018
nikomatsakis
changed the title
[nll]
[nll] spurious outlives requirement in shred-0.7.0
Aug 6, 2018
This comment has been minimized.
This comment has been minimized.
|
OK so I've dug into this a bit more. The NLL behavior here is buggy, I think, but I'm having trouble isolating it to a nicer test case because in general our behavior here is not that strong. I think that this struct ought to be well-formed as is -- requiring that I think that the problem is that the NLL code is hitting this "fallback" in the code that handles obligations like rust/src/librustc/infer/outlives/obligations.rs Lines 383 to 410 in cf84056 In particular, if we encounter an obligation to prove Anyway, since NLL uses region inference variables everywhere, it basically always hits this case, which makes us overly conservative in this example. I'm not sure yet the right fix. I suppose that in NLL we could avoid going down this path, but I think this will likely cause other failures. |
nikomatsakis
added
I-nominated
A-NLL
and removed
WG-compiler-nll
labels
Aug 27, 2018
This comment has been minimized.
This comment has been minimized.
|
I was thinking about this. I think maybe the best fix is that we should not be so eager to convert "outlives bounds" into type tests and constraints. We could hold off on that, do inference, and then do the type test conversion. This second round may of course add new constraints, and we can deal with that. This will be a bit of a pain, though, since we currently compute the SCCs etc based on the previous set of obligations, and this would introduce new edges into the graph. Not sure how to deal with that. Gah, still not entirely sure what to do here. |
nikomatsakis
referenced this issue
Aug 29, 2018
Closed
[NLL] Possible proptest-arbitrary-0.2.2 regression #53789
This comment has been minimized.
This comment has been minimized.
|
visited at meeting. assigning to niko to try to write up a plan of attack. (Also, we need to decide whether it is really an RC blocker or not) |
pnkfelix
assigned
nikomatsakis
Sep 4, 2018
pnkfelix
removed
the
I-nominated
label
Sep 4, 2018
nikomatsakis
modified the milestones:
Rust 2018 RC,
Edition 2018 RC 2
Sep 10, 2018
This comment has been minimized.
This comment has been minimized.
|
Not an RC blocker: the migration strategy means this will be a warning anyway. |
This comment has been minimized.
This comment has been minimized.
|
OK, so, for the record: the reason that this errors out only with I note though that we skip comparable struct constructors: rust/src/librustc_mir/borrow_check/mod.rs Lines 89 to 112 in 7ee7207 but anyway we should fix this bug. I believe that this example, from #53789, is the same underlying problem: #![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!()
} |
This comment has been minimized.
This comment has been minimized.
|
Minimized test showing the core problem: 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() {} |
nikomatsakis
referenced this issue
Sep 21, 2018
Merged
rework how we handle outlives relationships #54453
This comment has been minimized.
This comment has been minimized.
|
Fix in #54453 |
nikomatsakis commentedAug 6, 2018
The following snippet, extracted from the crate shred v0.7.0, fails to compile with NLL, but only when compiled with
--crate-type lib:yields
I'm not entirely sure what is going on here, but it seems very fishy, particularly since it is specific to
--crate-type lib.