Skip to content
Snippets Groups Projects
Commit 38caff6e authored by Jasper Clemens Gräflich's avatar Jasper Clemens Gräflich
Browse files

Start on 1.1.5

parent ca30b6bb
No related branches found
No related tags found
No related merge requests found
Pipeline #86563 passed
......@@ -192,15 +192,15 @@ References have to agree to these rules, but the owner has to as well. While sha
\todo[inline]{
\textbf{This doesn’t not work, I have to think about this some more. I want something to throw Error E0507.}
In particular, a value may not be moved, as long as there is a reference to it because that would create a dangling pointer. This means that \inline{let y = &x; let z = *y;} doesn’t work.
%\begin{lstlisting}[language=Rust, caption={Moving out of borrowed value}]
% let x = 42;
% let xref = &x;
% let y = x;
%\end{lstlisting}
}
\subsubsection{Lexical Lifetimes and Lifetime Analysis}
......@@ -337,13 +337,13 @@ Sometimes we want to express an even stronger connection between two types. For
\subsubsection{Mutable reference conversions}
All three of the aforementioned traits work for shared references only, but their variants \inline{AsMut}, \inline{DerefMut} and \inline{BorrowMut} all take and provide an exclusive reference.
All three of the aforementioned traits work for shared references only, but their variants \inline{AsMut}, \inline{DerefMut} and \inline{BorrowMut} all take and provide a unique reference.
\subsection{Non-Lexical Lifetimes}\label{subsec:non-lexical-lifetimes}
In \autoref{lst:lexical-lifetimes} we saw how lexical lifetimes stood in our way and we had to manually wrap a reference in an additional block just to make our correct program pass the borrow checker. This was because the lifetime of any value is bound to its scope, at the end of which it is dropped. \acl{NLL} is a different approach to lifetime analysis. A reference is live for as long as it may be used later. The borrow checker determines the points of the program in which the reference is live by building a \acfi{CFG}. All nodes of the \ac{CFG} that can be reached from the point of creation until the last use of the reference are where it is live. Consider the program in \autoref{lst:non-lexical-lifetimes}.
\begin{lstlisting}[language=Rust, caption={\ac{NLL} example}, label={lst:non-lexical-lifetimes}]
\begin{lstlisting}[language=Rust, caption={Simple \ac{NLL} example}, label={lst:non-lexical-lifetimes}]
let mut x = 0;
let xref = &x;
println!("{xref}");
......@@ -371,7 +371,7 @@ Then the (simplified) \ac{CFG} looks something like \autoref{fig:cfg-non-lexical
Consider a more complicated example that includes branching in \autoref{lst:non-lexical-lifetimes-branch}.
\begin{lstlisting}[language=Rust, caption={\ac{NLL} }, label={lst:non-lexical-lifetimes-branch}]
\begin{lstlisting}[language=Rust, caption={\ac{NLL} example with braching}, label={lst:non-lexical-lifetimes-branch}]
let mut x = 0;
let xref = &x;
if xref != &0 {
......@@ -383,7 +383,7 @@ if xref != &0 {
x = 42;
\end{lstlisting}
Now the \ac{CFG} (\autoref{fig:cfg-non-lexical-lifetimes-branch}) splits up to accommodate both possible paths the program could take during execution. At the \inline{if}, the graph splits into two, but in the last node, both paths join up again. Here we can see that in the \inline{false} branch no problem occurs, but in the \inline{true} branch we try to modify \inline{x} even though \inline{xref} is used later in the same path. Modifying \inline{x} on the last line is okay, though.
Now the \ac{CFG} (\autoref{fig:cfg-non-lexical-lifetimes-branch}) splits up to accommodate both possible paths the program could take during execution. At the \inline{if}, the graph splits into two, but in the last node, both paths join up again. Here we can see that in the \inline{false} branch no problem occurs, but in the \inline{true} branch we try to modify \inline{x} even though \inline{xref} is used later in the same path. Modifying \inline{x} on the last line does not pose any problems since xref is not live anymore on any path that leads to this point.
\begin{figure}[!h]
\centering
......@@ -409,7 +409,41 @@ Now the \ac{CFG} (\autoref{fig:cfg-non-lexical-lifetimes-branch}) splits up to a
\label{fig:cfg-non-lexical-lifetimes-branch}
\end{figure}
\subsection{Reborrows, the Borrow Stack and Two-Phase Borrowing}
\subsection{Reborrows and Two-Phase Borrowing}
\ac{NLL} give us a lot more freedom when using references, but there are still programs that are clearly correct but don’t pass the borrow checker, especially if unique references are in play. It is not possible to create a new reference of some provenance as long as a unique reference with the same provenance is live. This means the code in \autoref{lst:conflicting-borrows} will not compile.
\begin{lstlisting}[language=Rust, caption={Cannot create a shared reference while a unique one exists}, label={lst:conflicting-borrows}]
let mut x = 1;
let ref1 = &mut x;
let ref2 = &x; // Error: Cannot borrow `x`
println!("{ref2}");
*ref1 = 2;
\end{lstlisting}
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 vref = &mut v;
vref.push(1);
vref.last(); // Error: Use of moved value `vref`
\end{lstlisting}
\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}.
\begin{lstlisting}[language=Rust, caption={Reborrow through a unique reference}, label={lst:simple-reborrow}]
let mut x = 1;
let ref1 = &mut x;
let ref2 = & *ref1; // Reborrow
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.
\begin{enumerate}
\item What is a reborrow?
\item Example: reborrows are correct but rejected
......@@ -418,7 +452,7 @@ Now the \ac{CFG} (\autoref{fig:cfg-non-lexical-lifetimes-branch}) splits up to a
\item Example
\item Solution: Two-Phase Borrowing
\item Note: TPB is not yet implemented
\todo[inline]{Fit in the Borrow Stack}
\todo[inline]{Fit in the Borrow Stack.}
\end{enumerate}
\subsection{Loans and Regions}
\begin{enumerate}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment