That was a point of interest for me two. Initially it seems like mixing two independent concerns. On the other hand, the key point for soundness of a LCellOwner
is that its lifetime is unique, and e.g. the Holder
API should ensure that lifetime 'x
passed to the F: for<'x> FnOnce(OperateIn<'x, T>) -> R,
from different invocations are always distinguished. It’s necessary for the soundness of Holder
itself, because the Holder
doesn’t statically know its own lifetime; the “real” lifetime for 'x
would be something like “until Holder
is dropped” which is a dynamic concept, so static typing will always approximate/generalize this, and work with universally quantified lifetimes to stay sound.
One notable exception though in the following context of possible future API changes: I think I’ve suggested that previously, and also I haven’t actually reviewed whether I’m certain that this would be actually sound, but there’s this potential improvement of the selfref::Holder
API. The current API
pub fn operate_in<'i, F, R>(self: Pin<&'i Self>, f: F) -> R
where
F: for<'x> FnOnce(OperateIn<'x, T>) -> R,
does not convey to F
the information that self
is borrowed at least for 'i
, and thus it would be safe for F
to assume that 'x: 'i
. This can be useful because it would allow R
to borrow from self
, at least if Pin<&'x T::Kind<'x>>
allows you to extract some Foo<'x>
data that’s covariant in 'x
, so it can be converted to Foo<'i>
and returned from the closure.
One way to convey this bound to the closure would be to add a &'i &'x ()
phantom argument; or perhaps to add 'i
as a new extra lifetime argument to OperateIn
, and give it a 'x: 'i
on the type definition of OperateIn
.
Now, if this API change is sound for selfref
, the same thing would still not be true for an analogous change to srce
, because of the additional requirement of the lcell owner to be unique. With the API
pub fn open_rw<'i, F, R>(self: Pin<&'i mut Self>, f: F) -> R
where
F: for<'a, 'id> FnOnce(&'a mut LCellOwner<'id>, OperateIn<'id, T>) -> R,
if: the closure F
got the additional information that 'id: 'i
, then this information has the potential to nail down the 'id
lifetime in one specific case so it’s no longer a “unique” lifetime: if 'i
was 'static
! And of course, by leaking the LCellEnvironment
, a Pin<&'static Self>
can be constructed; the closure, if provided the additional 'id: 'i
(so in that case 'id: 'static
) bound, would then have access to a &'a mut LCellOwner<'static>
, the process could be repeated twice in a nested manner, and ultimately there would be two usable &mut LCellOwner<'static>
values co-existing.
I don’t immediately see the same kind of issue with the analogue change to open_ro
though, because even a &LCellOwner<'static>
seems unproblematic, since it’s a shared reference only.
Haven’t tested it, but that sounds like it might work, good observation!