The compiler requires 'a:'r and it passes if we changed to that.
But why we need 'a:'r for this? I think it should be all right that &mut self, &mut Ctx and the closure live shorter than 'r.
In fact such code can be compiled
// Open these gates:
// #![feature(unboxed_closures)]
// #![feature(fn_traits)]
impl Foo{
fn func_cl<'a, 'r: 'a>(&'a mut self, ctx: &'a mut Ctx<'r>) -> impl FnMut() -> usize + 'a + 'r {
Closure { ctx, foo: self }
}
}
struct Closure<'a, 'r: 'a> {
ctx: &'a mut Ctx<'r>,
foo: &'a mut Foo,
}
impl FnOnce<()> for Closure<'_, '_> {
type Output = usize;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
let id = self.foo.get_value();
self.ctx.insert(id);
id
}
}
impl FnMut<()> for Closure<'_, '_> {
extern "rust-call" fn call_mut(&mut self, _args: ()) -> usize {
let id = self.foo.get_value();
self.ctx.insert(id);
id
}
}
I guess something similar to #60670 holds it but cannot clarify the reason inside. (If we change all references here to immutable references all will pass).
First let's note that 'r: 'a is implied, and in combination with 'a: 'r, this means the lifetimes must be the same. And &'a mut Thing<'a> is pretty much never what you want.
In edition 2021, RPIT like -> impl FnMut() -> usize implicitly captures any generic types that are inputs to the function, but does not capture any generic lifetimes that are inputs to the function. This will change in edition 2024, so that the generic lifetimes are also implicitly captured.[1] And you can see here that the example compiles on edition 2024 with no + 'a + 'r.
So what's the difference between the implicit capturing and + 'a + 'r? An outlives bound like X: 'x is a bound that requires X to be valid for at least 'x, and + 'r + 'a is applying such a bound to the opaque return type. But (when the lifetimes are not equal) the return type is not actually valid for 'r, it is only valid for the shorter lifetime 'a -- it can't use the captured values after 'a. So an outlives bound is not what you want. But you can't just let the lifetime relationship go unmentioned -- that would basically be the function doing something not declared by the signature / API contract, like cloning a generic type without a Clone bound.
// This trait conveys no *functionality*, and every type implements it
// for every lifetime. It's just a way to convey the relationship of
// a lifetime to the opaque type of an RPIT.
trait Captures<'a> {}
impl<T: ?Sized> Captures<'_> for T {}
// ...
fn func<'a, 'r: 'a>(&'a mut self, ctx: &'a mut Ctx<'r>)
-> impl FnMut() -> usize + Captures<'r> + Captures<'a>
{