The following doesn't compile at the moment:
fn f<'a, 'b>(x: &'a mut &'b String) -> impl FnOnce() + 'a + 'b {
move || drop(x)
}
Why is that? Is the code subtly wrong, or is it just a limitation of the borrow checker?
The following doesn't compile at the moment:
fn f<'a, 'b>(x: &'a mut &'b String) -> impl FnOnce() + 'a + 'b {
move || drop(x)
}
Why is that? Is the code subtly wrong, or is it just a limitation of the borrow checker?
I don't think it is -- that issue is about impl trait capturing lifetimes of generic parameters in scope. In the above example, there are no generic parameters.
+ 'lt
means "an owned instance of this type can be used at least for the span 'lt
.
Thus, + 'a + 'b
means it can be used for the span 'a
and the span 'b
, i.e., the union.
But your x
is constrained not to outlive either of 'a
or 'b
, it can thus only be used within the intersection.
You'd thus need an intersection operator, which in Rust does not exist but can be expressed with a (not-so-)free parameter:
fn f<'a, 'b, 'inter> (
x: &'a mut &'b String,
) -> impl FnOnce() + 'inter
where
'a : /* ⊇ */ 'inter,
'b : /* ⊇ */ 'inter,
{
move || drop(x)
}
Note that in this very example, we have 'b ⊇ 'a
, and thus we can directly use 'a
for 'inter
; but if we had x: (Cell<&'a ()>, Cell<&'b ()>)
then the 'inter
idiom would be necessary.
Yeah, it also seemed to me that perhaps saying just
fn f<'a, 'b>(x: &'a mut &'b String) -> impl FnOnce() + 'a {
move || drop(x)
}
would be fine, but that fails with hidden type for
impl Trait captures lifetime that does not appear in bounds
Yeah that's then the infamous bug tackled by:
The TL,DR: is that when Rust sees -> impl FnOnce() + 'a
, it tries to define an internal type Ret<'a> = impl FnOnce() + 'a
and use -> Ret<'a>
, except the real type, &'a mut &'b String
, can not be named with 'a
exclusively (in the non-mut
case, by covariance, &'a &'b String
will shrink to &'a &'a String
and dodge the issue). So we need to nudge Rust into adding a <'b>
parameter for the existential's definition, which is achieved by the Captures<'b>
hack.
You can notice it's something distinct in that if you Box
the closure, and replace impl
with dyn
, using 'a
works
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.