The closest thing to a specification on reborrows so far is the NLL RFC.
Prefixes. We say that the prefixes of an lvalue are all the lvalues you get by stripping away fields and derefs. The prefixes of
*a.b
would be*a.b
,a.b
, anda
.
Note that these dereferences are built-in dereferences; Deref
implementation based references are method calls. The perspective is post-desugar, where ever dereference and reborrow, etc, is explicit.
Supporting prefixes. To define the reborrow constraints, we first introduce the idea of supporting prefixes – this definition will be useful in a few places. The supporting prefixes for an lvalue are formed by stripping away fields and derefs, except that we stop when we reach the deref of a shared reference. Inituitively, shared references are different because they are
Copy
– and hence one could always copy the shared reference into a temporary and get an equivalent path.
[...]
Reborrow constraints. Consider the case where we have a borrow (shared or mutable) of some lvaluelv_b
for the lifetime'b
:lv_l = &'b lv_b // or: lv_l = &'b mut lv_b
In that case, we compute the supporting prefixes of
lv_b
, and find every deref lvalue*lv
in the set wherelv
is a reference with lifetime'a
. We then add a constraint('a: 'b) @ P
, whereP
is the point following the borrow (that’s the point where the borrow takes effect).
In short, start from the inside and go out. Your reborrow is constrained by the lifetime of the first shared reference, or (if there is none) of the outermost reference. It can be shorter, i.e. it doesn't have to be equal (or reborrows of &mut _
would be useless).
Note also that nested references likes &'b &'a mut _
imply 'a: 'b
.