-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[nll] spurious outlives requirement in shred-0.7.0 #53121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
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. |
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. |
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) |
Not an RC blocker: the migration strategy means this will be a warning anyway. |
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!()
} |
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() {} |
Fix in #54453 |
…=pnkfelix rework how we handle outlives relationships When we encounter an outlives relationship involving a projection, we use to over-constrain in some cases with region constraints. We also used to evaluate whether the where-clauses in the environment might apply **before** running inference. We now avoid doing both of those things: - If there are where-clauses in the environment that might be useful, we add no constraints. - After inference is done, we check if we wound up inferring values compatible with the where-clause, and make use of them if so. I realize now that this PR includes some meandering commits and refactorings from when I expected to go in a different direction. If desired, I could try to remove some of those. Fixes #53121 Fixes #53789 r? @pnkfelix
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
.The text was updated successfully, but these errors were encountered: