\node[ultra thick] (B) at (0,6) {\inline{let xref = &x;}};
\node[ultra thick] (C) at (0,4.5) {\inline{if xref != &0 }};
...
...
@@ -426,7 +426,7 @@ println!("{ref2}");
But since \inline{xs} is not live anymore when \inline{xu} is used, aliasing is never occurring, and if we hadn’t used a unique reference but modified the value directly, Rust would have been able to see this. Not being able to create references in this manner is a big thing. Consider the code in \autoref{lst:moved-borrow}. Here, we create a reference to an empty \inline{Vec} and then use it to \inline{push} a value. This moves the reference into the \inline{push} method so that it is dropped when the method returns. It is no longer valid to use it again in the next line since it has already been dropped. But in fact this code compiles because Rust implicitly inserts a \emph{reborrow} for us.
\begin{lstlisting}[language=Rust, caption={Move a borrow into a function}, label={lst:moved-borrow}]
let mut v = vec::new();
let mut v = Vec::new();
let vref = &mut v;
vref.push(1);
vref.last(); // Error: Use of moved value `vref`
...
...
@@ -434,7 +434,7 @@ vref.last(); // Error: Use of moved value `vref`
\subsubsection{Reborrows}
Let’s get back to the example in \autoref{lst:conflicting-borrows} for now. The compiler complains because we try to create two conflicting references with the same provenance. But we can tell the compiler to temporarily deactivate a reference by borrowing \emph{through this reference} directly. This is done in \autoref{lst:simple-reborrow}.
Let’s get back to the example in \autoref{lst:conflicting-borrows} for now. The compiler complains because we try to create two conflicting references with the same provenance. But we can tell the compiler to temporarily deactivate a reference by borrowing \emph{through this reference}. This is done in \autoref{lst:simple-reborrow}.
\begin{lstlisting}[language=Rust, caption={Reborrow through a unique reference}, label={lst:simple-reborrow}]
let mut x = 1;
...
...
@@ -444,18 +444,33 @@ println!("{ref2}");
*ref1 = 2;
\end{lstlisting}
Now we can create and use the \inline{ref2} as long as it is not live anymore when we use \inline{ref1} again. If the last two lines were swapped, the borrow checker would correctly find the interleaved use and throw an error. It is possible to nest reborrows, as long as they are never used interleaved.
Now we can create and use the \inline{ref2} as long as it is not live anymore when we use \inline{ref1} again. If the last two lines were swapped, the borrow checker would correctly find the interleaved use and throw an error. It is possible to nest reborrows, as long as they are never used interleaved. These reborrows can be imagined as a stack: when creating a reborrow, the new reference is pushed to the stack, and when using a reference, the stack is popped until it is on the topmost position. Trying to access a reference that has already been popped indicates an interleaved use and is a borrow error. The owner of the value can then be thought of as the bottom element of the stack, and when it goes out of scope, the whole stack is unwound so that the \inline{drop} function can access it. In fact, this is exactly how reborrows are modelled in Miri, which is an interpreter for Rusts \acfi{MIR}. \todo{Source, e. g. Rustonomicon} Miri even has borrow stacks for raw pointers.
But why does the code in \autoref{lst:moved-borrow} work? The compiler can insert borrows and reborrows in function calls, so-called \emph{autorefs}. This is because it can be sure that the function returns before the reference is accessed again, meaning that the borrow stack is kept intact. In fact, if the compiler can’t proof that the borrow stack is valid, it will complain. This can for example happen when using \inline{std::thread::spawn} which creates a new thread. Because the child thread could outlive the main thread, Rust can’t verify that all references are used in the correct order, in particular that the owner is not dropped too early.
\subsubsection{Two-Phase Borrowing}
Reborrows won’t solve every problem, though. Consider the code in \autoref{lst:two-phase-borrow}. Here we create a vector and then push its length onto it.
\begin{lstlisting}[language=Rust, caption={Borrow twice in one method call}, label={lst:two-phase-borrow}]
let mut v = Vec::new();
v.push(v.len());
\end{lstlisting}
The problem lies in the second line. The first argument to \inline{push} is an \inline{&mut self}, and so the compiler implicitly borrows from \inline{v}. But then another (shared) reference is created for the call to \inline{len}. This is not allowed, and a reborrow doesn’t help either since the \inline{&mut self} is currently used. On the other hand, it is clear that the call to \inline{len} will definitely return before the unique reference is ever accessed. In fact, we can work around this problem if we save the result of \inline{v.len()} in a temporary variable, as shown in \autoref{lst:two-phase-borrow-workaround}.
\begin{lstlisting}[language=Rust, caption={Borrow twice in one method call}, label={lst:two-phase-borrow-workaround}]
let mut v = Vec::new();
let vlen = v.len();
v.push(vlen);
\end{lstlisting}
This pattern—calling a method with a unique reference but also using shared references in the arguments—is very common and the workaround is unwieldy. Therefore \acs{RFC} 2025 \todo{Add reference for RFC 2025} introduces the concept of a \ac{TPB}. In it, the lifetime of a unique reference is split up into two phases. During the \emph{reservation phase}, it is treated like a shared reference, meaning more shared references can be created and reads are possible. The \emph{activation} happens as soon as the reference is first used to perform a mutation. From this point on, it is treated as a full unique reference.
Right now, two-phase borrowing works only for method calls where the first argument is \inline{&mut self}, and it is not resolved if generalized \ac{TPB} should even be supported. \todo{Point to Issue \#49434 for generalized TPB.}
\todo[inline]{Excourse on multi-phase borrowing}
\begin{enumerate}
\item What is a reborrow?
\item Example: reborrows are correct but rejected
\item Solution: Allow for reborrows
\item Using shared references after creating a unique one is correct but rejected
\item Example
\item Solution: Two-Phase Borrowing
\item Note: TPB is not yet implemented
\todo[inline]{Fit in the Borrow Stack.}
\end{enumerate}
\subsection{Loans and Regions}
\begin{enumerate}
\item What are loans and regions?
...
...
@@ -531,4 +546,6 @@ Now we can create and use the \inline{ref2} as long as it is not live anymore wh
\item non-totality is an effect, but do termination metrics fit in?
\item Weakening and Contraction are effects, but what about borrowing?