1# MIR borrow check 2 3The borrow check is Rust's "secret sauce" – it is tasked with 4enforcing 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 immutably borrowed. 12- etc 13 14The borrow checker operates on the MIR. An older implementation operated on the 15HIR. Doing borrow checking on MIR has several advantages: 16 17- The MIR is *far* less complex than the HIR; the radical desugaring 18 helps prevent bugs in the borrow checker. (If you're curious, you 19 can see 20 [a list of bugs that the MIR-based borrow checker fixes here][47366].) 21- Even more importantly, using the MIR enables ["non-lexical lifetimes"][nll], 22 which are regions derived from the control-flow graph. 23 24[47366]: https://github.com/rust-lang/rust/issues/47366 25[nll]: https://rust-lang.github.io/rfcs/2094-nll.html 26 27### Major phases of the borrow checker 28 29The borrow checker source is found in 30[the `rustc_borrow_ck` crate][b_c]. The main entry point is 31the [`mir_borrowck`] query. 32 33[b_c]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/index.html 34[`mir_borrowck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/fn.mir_borrowck.html 35 36- We first create a **local copy** of the MIR. In the coming steps, 37 we will modify this copy in place to modify the types and things to 38 include references to the new regions that we are computing. 39- We then invoke [`replace_regions_in_mir`] to modify our local MIR. 40 Among other things, this function will replace all of the [regions](./appendix/glossary.md#region) 41 in the MIR with fresh [inference variables](./appendix/glossary.md#inf-var). 42- Next, we perform a number of 43 [dataflow analyses](./appendix/background.md#dataflow) that 44 compute what data is moved and when. 45- We then do a [second type check](borrow_check/type_check.md) across the MIR: 46 the purpose of this type check is to determine all of the constraints between 47 different regions. 48- Next, we do [region inference](borrow_check/region_inference.md), which computes 49 the values of each region — basically, the points in the control-flow graph where 50 each lifetime must be valid according to the constraints we collected. 51- At this point, we can compute the "borrows in scope" at each point. 52- Finally, we do a second walk over the MIR, looking at the actions it 53 does and reporting errors. For example, if we see a statement like 54 `*a + 1`, then we would check that the variable `a` is initialized 55 and that it is not mutably borrowed, as either of those would 56 require an error to be reported. Doing this check requires the results of all 57 the previous analyses. 58 59[`replace_regions_in_mir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/nll/fn.replace_regions_in_mir.html 60