Description
Following a bug sample from @jdm, I encountered this bug. The compiler errors out in this code:
struct Parser<'i: 't, 't> {
data: &'t mut Vec<&'i String>
}
fn callback1<'i, 't, F>(parser: &mut Parser<'i, 't>, f: F)
where F: for<'tt1> FnMut(&mut Parser<'i, 'tt1>)
{
panic!()
}
fn callback2<'i, 't, F>(parser: &mut Parser<'i, 't>, mut f: F)
where F: for<'tt2> FnMut(&mut Parser<'i, 'tt2>)
{
callback1(parser, |input| {
f(input)
});
}
fn main() {
}
specifically it reports a "cannot infer" lifetime error, complaining about how the lifetime 'tt2
in the call f(input)
must be some lifetime 'x
where 'i: 'x
and 'x: 'tt1
(where 'tt1
is the lifetime that appears in the type of input
in the closure). The compiler is upset because it does not know that 'i: 'tt1
. Those constraints are correct, but in fact the compiler should be able to deduce that 'i: 'tt1
based on the type of input
, which is is &mut Parser<'i, 'tt1>
. The implied bounds for this type suggest that 'i: 'tt1
. But we fail to see it.
The problem is an interaction with inference. When we call callback1()
here, we do not specify the lifetime, and so we create a variable 'x
-- that is, the actual type of input
is &mut Parser<'x, 'tt2>
, where 'x
is the inference variable. We then recognize that this means 'x: 'tt2
, and we add a "given", which is this hacky bit of code in region inference. Then we infer that 'x
must be 'i
. But when we go to check that 'x: 'tt2
, we substitute 'x
to 'i
, and then report an error, because we never added anything that tells us that 'i: 'tt2
. If you specify callback::<'i>
manually, it will work fine.
The most straightforward fix is to use the given logic here too. The better fix is to retool this part of region inference to be more robust, which I am in the process of trying to plan out right now for other reasons anyhow.