|
| 1 | +# MIR borrow check |
| 2 | + |
| 3 | +The borrow check is Rust's "secret sauce" – it is tasked with |
| 4 | +enforcing a number of properties: |
| 5 | + |
| 6 | +- That all variables are initialized before they are used. |
| 7 | +- That you can't move the same value twice. |
| 8 | +- That you can't move a value while it is borrowed. |
| 9 | +- That you can't access a place while it is mutably borrowed (except through |
| 10 | + the reference). |
| 11 | +- That you can't mutate a place while it is shared borrowed. |
| 12 | +- etc |
| 13 | + |
| 14 | +At the time of this writing, the code is in a state of transition. The |
| 15 | +"main" borrow checker still works by processing [the HIR](hir.html), |
| 16 | +but that is being phased out in favor of the MIR-based borrow checker. |
| 17 | +Doing borrow checking on MIR has two key advantages: |
| 18 | + |
| 19 | +- The MIR is *far* less complex than the HIR; the radical desugaring |
| 20 | + helps prevent bugs in the borrow checker. (If you're curious, you |
| 21 | + can see |
| 22 | + [a list of bugs that the MIR-based borrow checker fixes here][47366].) |
| 23 | +- Even more importantly, using the MIR enables ["non-lexical lifetimes"][nll], |
| 24 | + which are regions derived from the control-flow graph. |
| 25 | + |
| 26 | +[47366]: https://github.com/rust-lang/rust/issues/47366 |
| 27 | +[nll]: http://rust-lang.github.io/rfcs/2094-nll.html |
| 28 | + |
| 29 | +### Major phases of the borrow checker |
| 30 | + |
| 31 | +The borrow checker source is found in |
| 32 | +[the `rustc_mir::borrow_check` module][b_c]. The main entry point is |
| 33 | +the `mir_borrowck` query. At the time of this writing, MIR borrowck can operate |
| 34 | +in several modes, but this text will describe only the mode when NLL is enabled |
| 35 | +(what you get with `#![feature(nll)]`). |
| 36 | + |
| 37 | +[b_c]: https://github.com/rust-lang/rust/tree/master/src/librustc_mir/borrow_check |
| 38 | + |
| 39 | +The overall flow of the borrow checker is as follows: |
| 40 | + |
| 41 | +- We first create a **local copy** C of the MIR. In the coming steps, |
| 42 | + we will modify this copy in place to modify the types and things to |
| 43 | + include references to the new regions that we are computing. |
| 44 | +- We then invoke `nll::replace_regions_in_mir` to modify this copy C. |
| 45 | + Among other things, this function will replace all of the regions in |
| 46 | + the MIR with fresh [inference variables](./appendix/glossary.html). |
| 47 | + - (More details can be found in [the regionck section](./mir/regionck.html).) |
| 48 | +- Next, we perform a number of [dataflow |
| 49 | + analyses](./appendix/background.html#dataflow) |
| 50 | + that compute what data is moved and when. The results of these analyses |
| 51 | + are needed to do both borrow checking and region inference. |
| 52 | +- Using the move data, we can then compute the values of all the regions in the |
| 53 | + MIR. |
| 54 | + - (More details can be found in [the NLL section](./mir/regionck.html).) |
| 55 | +- Finally, the borrow checker itself runs, taking as input (a) the |
| 56 | + results of move analysis and (b) the regions computed by the region |
| 57 | + checker. This allows us to figure out which loans are still in scope |
| 58 | + at any particular point. |
| 59 | + |
0 commit comments