update NLL after refactorings
This commit is contained in:
parent
d1c4227fa6
commit
a7d92d89ff
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue