update NLL after refactorings

This commit is contained in:
Mark Mansi 2019-12-13 11:01:05 -06:00 committed by Who? Me?!
parent d1c4227fa6
commit a7d92d89ff
5 changed files with 41 additions and 48 deletions

View File

@ -11,13 +11,8 @@ enforcing a number of properties:
- That you can't mutate a place while it is immutably borrowed. - That you can't mutate a place while it is immutably borrowed.
- etc - etc
At the time of this writing, the code is in a state of transition. The The borrow checker operates on the MIR. An older implementation operated on the
"main" borrow checker still works by processing [the HIR](hir.html), HIR. Doing borrow checking on MIR has several advantages:
but that is being phased out in favor of the MIR-based borrow checker.
Accordingly, this documentation focuses on the new, MIR-based borrow
checker.
Doing borrow checking on MIR has several advantages:
- The MIR is *far* less complex than the HIR; the radical desugaring - The MIR is *far* less complex than the HIR; the radical desugaring
helps prevent bugs in the borrow checker. (If you're curious, you helps prevent bugs in the borrow checker. (If you're curious, you
@ -42,15 +37,15 @@ the [`mir_borrowck`] query.
we will modify this copy in place to modify the types and things to we will modify this copy in place to modify the types and things to
include references to the new regions that we are computing. include references to the new regions that we are computing.
- We then invoke [`replace_regions_in_mir`] to modify our local MIR. - We then invoke [`replace_regions_in_mir`] to modify our local MIR.
Among other things, this function will replace all of the [regions](./appendix/glossary.html) in Among other things, this function will replace all of the [regions](./appendix/glossary.md) in
the MIR with fresh [inference variables](./appendix/glossary.html). the MIR with fresh [inference variables](./appendix/glossary.md).
- Next, we perform a number of - Next, we perform a number of
[dataflow analyses](./appendix/background.html#dataflow) that [dataflow analyses](./appendix/background.md#dataflow) that
compute what data is moved and when. compute what data is moved and when.
- We then do a [second type check](borrow_check/type_check.html) across the MIR: - We then do a [second type check](borrow_check/type_check.md) across the MIR:
the purpose of this type check is to determine all of the constraints between the purpose of this type check is to determine all of the constraints between
different regions. different regions.
- Next, we do [region inference](borrow_check/region_inference.html), which computes - Next, we do [region inference](borrow_check/region_inference.md), which computes
the values of each region — basically, the points in the control-flow graph where the values of each region — basically, the points in the control-flow graph where
each lifetime must be valid according to the constraints we collected. each lifetime must be valid according to the constraints we collected.
- At this point, we can compute the "borrows in scope" at each point. - At this point, we can compute the "borrows in scope" at each point.

View File

@ -1,11 +1,9 @@
# Region inference (NLL) # Region inference (NLL)
The MIR-based region checking code is located in The MIR-based region checking code is located in [the `rustc_mir::borrow_check`
[the `rustc_mir::borrow_check::nll` module][nll]. (NLL, of course, module][nll].
stands for "non-lexical lifetimes", a term that will hopefully be
deprecated once they become the standard kind of lifetime.)
[nll]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/index.html [nll]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/index.html
The MIR-based region analysis consists of two major functions: The MIR-based region analysis consists of two major functions:
@ -36,12 +34,12 @@ The MIR-based region analysis consists of two major functions:
- The [NLL RFC] also includes fairly thorough (and hopefully readable) - The [NLL RFC] also includes fairly thorough (and hopefully readable)
coverage. coverage.
[cp]: ./region_inference/constraint_propagation.html [cp]: ./region_inference/constraint_propagation.md
[fvb]: ../appendix/background.html#free-vs-bound [fvb]: ../appendix/background.md#free-vs-bound
[`replace_regions_in_mir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/fn.replace_regions_in_mir.html [`replace_regions_in_mir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/fn.replace_regions_in_mir.html
[`compute_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/fn.compute_regions.html [`compute_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/fn.compute_regions.html
[`RegionInferenceContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html [`RegionInferenceContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html
[`solve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.solve [`solve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.solve
[NLL RFC]: https://rust-lang.github.io/rfcs/2094-nll.html [NLL RFC]: https://rust-lang.github.io/rfcs/2094-nll.html
[MIR type checker]: ./type_check.md [MIR type checker]: ./type_check.md
@ -68,7 +66,7 @@ the moment.
TODO: write about _how_ these regions are computed. TODO: write about _how_ these regions are computed.
[`UniversalRegions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/universal_regions/struct.UniversalRegions.html [`UniversalRegions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/universal_regions/struct.UniversalRegions.html
<a name="region-variables"></a> <a name="region-variables"></a>
@ -84,7 +82,7 @@ maintain a set storing what elements are present in its value (to make this
efficient, we give each kind of element an index, the `RegionElementIndex`, and efficient, we give each kind of element an index, the `RegionElementIndex`, and
use sparse bitsets). use sparse bitsets).
[ri]: https://github.com/rust-lang/rust/tree/master/src/librustc_mir/borrow_check/nll/region_infer/ [ri]: https://github.com/rust-lang/rust/tree/master/src/librustc_mir/borrow_check/region_infer/
The kinds of region elements are as follows: The kinds of region elements are as follows:
@ -115,7 +113,7 @@ common sorts of constraints are:
2. Liveness constraints. Each region needs to be live at points where it can be 2. Liveness constraints. Each region needs to be live at points where it can be
used. These constraints are collected by [`generate_constraints`]. used. These constraints are collected by [`generate_constraints`].
[`generate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/constraint_generation/fn.generate_constraints.html [`generate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/constraint_generation/fn.generate_constraints.html
## Inference Overview ## Inference Overview
@ -219,12 +217,12 @@ Here are some of the fields of the struct:
- [`closure_bounds_mapping`]: used for propagating region constraints from - [`closure_bounds_mapping`]: used for propagating region constraints from
closures back out to the creator of the closure. closures back out to the creator of the closure.
[`constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.constraints [`constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.constraints
[`liveness_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.liveness_constraints [`liveness_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.liveness_constraints
[`universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.universal_regions [`universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.universal_regions
[`universal_region_relations`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.universal_region_relations [`universal_region_relations`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.universal_region_relations
[`type_tests`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.type_tests [`type_tests`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.type_tests
[`closure_bounds_mapping`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.closure_bounds_mapping [`closure_bounds_mapping`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.closure_bounds_mapping
TODO: should we discuss any of the others fields? What about the SCCs? TODO: should we discuss any of the others fields? What about the SCCs?
@ -233,6 +231,6 @@ inference. This is done by calling the [`solve`] method on the context. This
is where we call [`propagate_constraints`] and then check the resulting type is where we call [`propagate_constraints`] and then check the resulting type
tests and universal regions, as discussed above. tests and universal regions, as discussed above.
[`propagate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.propagate_constraints [`propagate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.propagate_constraints
[`check_type_tests`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.check_type_tests [`check_type_tests`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.check_type_tests
[`check_universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.check_universal_regions [`check_universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.check_universal_regions

View File

@ -10,7 +10,7 @@ on one at a time (each of them is fairly independent from the others):
- outlives constraints (`R1: R2`), which arise from subtyping; - outlives constraints (`R1: R2`), which arise from subtyping;
- [member constraints][m_c] (`member R_m of [R_c...]`), which arise from impl Trait. - [member constraints][m_c] (`member R_m of [R_c...]`), which arise from impl Trait.
[`propagate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.propagate_constraints [`propagate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.propagate_constraints
[m_c]: ./member_constraints.md [m_c]: ./member_constraints.md
In this chapter, we'll explain the "heart" of constraint propagation, In this chapter, we'll explain the "heart" of constraint propagation,
@ -68,8 +68,8 @@ though; instead, we store a (sparse) bitset per region variable (of
type [`LivenessValues`]). This way we only need a single bit for each type [`LivenessValues`]). This way we only need a single bit for each
liveness constraint. liveness constraint.
[`liveness_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.liveness_constraints [`liveness_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.liveness_constraints
[`LivenessValues`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/values/struct.LivenessValues.html [`LivenessValues`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/values/struct.LivenessValues.html
One thing that is worth mentioning: All lifetime parameters are always One thing that is worth mentioning: All lifetime parameters are always
considered to be live over the entire function body. This is because considered to be live over the entire function body. This is because
@ -112,9 +112,9 @@ induces an edge `'a -> 'b`. This conversion happens in the
[`RegionInferenceContext::new`] function that creates the inference [`RegionInferenceContext::new`] function that creates the inference
context. context.
[`ConstraintSet`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/constraints/struct.OutlivesConstraintSet.html [`ConstraintSet`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/constraints/struct.OutlivesConstraintSet.html
[graph-fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/constraints/struct.OutlivesConstraintSet.html#method.graph [graph-fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/constraints/struct.OutlivesConstraintSet.html#method.graph
[`RegionInferenceContext::new`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.new [`RegionInferenceContext::new`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.new
When using a graph representation, we can detect regions that must be equal When using a graph representation, we can detect regions that must be equal
by looking for cycles. That is, if you have a constraint like by looking for cycles. That is, if you have a constraint like
@ -146,8 +146,8 @@ of fields are defined in terms of SCCs. For example, the
of a specific region `'a` then, we first figure out the SCC that the of a specific region `'a` then, we first figure out the SCC that the
region is a part of, and then find the value of that SCC. region is a part of, and then find the value of that SCC.
[`constraint_sccs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.constraint_sccs [`constraint_sccs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.constraint_sccs
[`scc_values`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.scc_values [`scc_values`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#structfield.scc_values
When we compute SCCs, we not only figure out which regions are a When we compute SCCs, we not only figure out which regions are a
member of each SCC, we also figure out the edges between them. So for example member of each SCC, we also figure out the edges between them. So for example

View File

@ -29,9 +29,9 @@ relationships to one another. So if you have e.g. `where 'a: 'b`, then
the [`UniversalRegionRelations`] struct would track that `'a: 'b` is the [`UniversalRegionRelations`] struct would track that `'a: 'b` is
known to hold (which could be tested with the [`outlives`] function. known to hold (which could be tested with the [`outlives`] function.
[`UniversalRegions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/universal_regions/struct.UniversalRegions.html [`UniversalRegions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/universal_regions/struct.UniversalRegions.html
[`UniversalRegionRelations`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/type_check/free_region_relations/struct.UniversalRegionRelations.html [`UniversalRegionRelations`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/type_check/free_region_relations/struct.UniversalRegionRelations.html
[`outlives`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/type_check/free_region_relations/struct.UniversalRegionRelations.html#method.outlives [`outlives`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/type_check/free_region_relations/struct.UniversalRegionRelations.html#method.outlives
## Everything is a region variable ## Everything is a region variable
@ -56,7 +56,7 @@ type). These subdivisions are not important for the topics discussed
here, but become important when we consider [closure constraint here, but become important when we consider [closure constraint
propagation](./closure_constraints.html), so we discuss them there. propagation](./closure_constraints.html), so we discuss them there.
[`RegionClassification`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/universal_regions/enum.RegionClassification.html#variant.Local [`RegionClassification`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/universal_regions/enum.RegionClassification.html#variant.Local
## Universal lifetimes as the elements of a region's value ## Universal lifetimes as the elements of a region's value
@ -86,7 +86,7 @@ liveness constraint (i.e., `'a` must extend until the end of
itself). In the code, these liveness constraints are setup in itself). In the code, these liveness constraints are setup in
[`init_free_and_bound_regions`]. [`init_free_and_bound_regions`].
[`init_free_and_bound_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.init_free_and_bound_regions [`init_free_and_bound_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.init_free_and_bound_regions
## Propagating outlives constraints for universal regions ## Propagating outlives constraints for universal regions
@ -122,4 +122,4 @@ not, as in our example, that is an error. This check is done in the
universal regions, inspects their final value, and tests against the universal regions, inspects their final value, and tests against the
declared [`UniversalRegionRelations`]. declared [`UniversalRegionRelations`].
[`check_universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.check_universal_regions [`check_universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.check_universal_regions

View File

@ -1,7 +1,7 @@
# The MIR type-check # The MIR type-check
A key component of the borrow check is the A key component of the borrow check is the
[MIR type-check](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/type_check/index.html). [MIR type-check](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/type_check/index.html).
This check walks the MIR and does a complete "type check" -- the same This check walks the MIR and does a complete "type check" -- the same
kind you might find in any other language. In the process of doing kind you might find in any other language. In the process of doing
this type-check, we also uncover the region constraints that apply to this type-check, we also uncover the region constraints that apply to