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 upHRTB impl selection does not cover type parameters not directly related to the trait. #30867
Comments
eddyb
added
the
A-typesystem
label
Jan 13, 2016
eddyb
referenced this issue
Jan 13, 2016
Merged
Rewrite the whole combinators module to use HRTB only where necessary. #1
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis Is this the same issue as with the impls for |
eddyb
referenced this issue
Jan 14, 2016
Open
Struct and variant constructors are not generic over lifetimes like regular functions. #30904
This comment has been minimized.
This comment has been minimized.
|
I'm trying to decide if this is an actual bug :) It does seem like the "HR capture" logic is being unnecessarily conservative. Let me poke at the debug logs and see if that reveals to me why it is rejecting the impl when you include |
eddyb
referenced this issue
Jan 14, 2016
Open
"cannot relate bound region" in a concrete lifetime vs for<'a> mismatch. #30906
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis I believe it breaks for type parameters which cannot be extracted from the |
This comment has been minimized.
This comment has been minimized.
|
Hmm, the problem is a bit of a subtle one and, in this particular example, tied to the associated type projection. We start out with a trait reference to solve:
We match this against the impl
Which, internally, is lowered to:
In so doing, we first "open" the
where
Note that I think that the basic strategy here is somewhat wrong. It would be OK in the absence of variables like One possible fix here would be to recursively (and before returning) handle the projection constraints, so that If we had had lazy normalization, this would be much easier, because then we could just unify (The other solutions I can imagine are quite a bit more complicated. It seems like you would need to capture, in the tree, what variables are bound where. What makes this hard is that UPDATE: Remove sentence I don't think. I think that for this problem to arise you really need an associated type, since you need a type variable that is not found in the trait reference, which is otherwise verboten. |
This comment has been minimized.
This comment has been minimized.
|
cc @arielb1 -- this seems related to the changes you made to order projection predicates earlier in the list. Does my earlier comment make sense to you? |
This comment has been minimized.
This comment has been minimized.
|
I am not sure we should not evaluate associated type projections recursively - RFC447 basically forces this to work. Unfortunately, it will work imperfectly without lazy normalization, because we can't represent a constraint like |
This comment has been minimized.
This comment has been minimized.
|
On Thu, Jan 14, 2016 at 12:54:36PM -0800, arielb1 wrote:
Sorry, the double negative in this sentence is throwing me a bit. I'm |
This comment has been minimized.
This comment has been minimized.
|
Unfortunately, it will work imperfectly without lazy normalization, because we can't represent a constraint like `for<'a> <_ as Fn<(&'a u32,)>>::Output: Sized`.
Can you elaborate just a bit on this? When does this kind of constraint arise?
|
This comment has been minimized.
This comment has been minimized.
impl<T> Foo for Option<T> where
T: Fn(&u32),
for<'a> <T as Fn(&'a u32)>::Output: Sized
{}
// evaluate <Option<_> as Foo> |
This comment has been minimized.
This comment has been minimized.
Recursively applying constraining-projections during confirmation should work, except for the type-inference case. |
This comment has been minimized.
This comment has been minimized.
|
Sorry for not replying. I'm afraid I still don't quite follow you, so let me try and work it out. First off, I guess you meant to have impl<T> Foo for Option<T> where
for<'a> T: Fn<(&'a u32,)>,
for<'a> <T as Fn<(&'a u32,)>>::Output: Sized
{}
// evaluate <Option<_> as Foo>I'm not quite sure what the last line means, but if we were to follow the model of the original problem, we'd start with something to prove like
and hence
which we would could then cover back up as:
This all seems...OK. Ah, wait, I guess your point is that we would need to normalize the |
This comment has been minimized.
This comment has been minimized.
asajeffrey
commented
Feb 16, 2016
|
I was bitten by this bug... simplifying a lot, my code looked like this (https://play.rust-lang.org/?gist=76fd1bad2b276b335db7): trait Cast<T> {
fn cast(self) -> T;
}
impl<'a> Cast<&'a str> for &'static str {
fn cast(self) -> &'a str { self }
}
struct Const<S>(S);
pub trait IterFunction1<I>
where I: Iterator
{
fn apply(self, iter: I) -> I::Item;
}
impl<I,S,T> IterFunction1<I> for Const<S>
where I: Iterator<Item = T>, S: Cast<T>
{
fn apply(self, _: I) -> T { self.0.cast() }
}but this isn't lifetime-polymporphic: fn expects_polymorphic_function1<F>(f: F)
where F: for<'a> IterFunction1<std::vec::Drain<'a,&'a str>>
{
let mut vec = vec!["abc"];
f.apply(vec.drain(..));
}
fn main() {
expects_polymorphic_function1(Const("hi"));
}produces:
but if you make the iterator item type a type argument, then it all works: pub trait IterFunction2<I,T>
where I: Iterator<Item = T>
{
fn apply(self, iter: I) -> T;
}
impl<I,S,T> IterFunction2<I,T> for Const<S>
where I: Iterator<Item = T>, S: Cast<T>
{
fn apply(self, _: I) -> T { self.0.cast() }
}
fn expects_polymorphic_function2<F>(f: F)
where F: for<'a> IterFunction2<std::vec::Drain<'a,&'a str>, &'a str>
{
let mut vec = vec!["abc"];
f.apply(vec.drain(..));
}
fn main() {
expects_polymorphic_function2(Const("hi"));
}so I need to rewrite a lot of code to take an extra type argument in order to be lifetime-polymorphic! |
eddyb commentedJan 13, 2016
The following doesn't compile, as it tries to assign
Ua concrete&'x i32instead of&'a i32:Removing the
Utype parameter makes it work -Uis only used for the associated typeFn::Outputanyway:AFAICT, the selection results in
for<'a, U> F: Fn<(&'a i32,), Output=U>in the first case, andfor<'a> F: Fn<(&'a i32,)>in the second case, and we refuse to allowUto be parameterized by'ain the former case, even though it's only used to satisfy the sugary form of theFntrait.