fill out the borrowck chapter a bit more
This commit is contained in:
parent
5194978cc7
commit
9f435099c1
|
|
@ -24,7 +24,7 @@ The MIR-based region analysis consists of two major functions:
|
||||||
- [`compute_regions`], invoked second: this is given as argument the
|
- [`compute_regions`], invoked second: this is given as argument the
|
||||||
results of move analysis. It has the job of computing values for all
|
results of move analysis. It has the job of computing values for all
|
||||||
the inference variables that `replace_regions_in_mir` introduced.
|
the inference variables that `replace_regions_in_mir` introduced.
|
||||||
- To do that, it first runs the [MIR type checker](#mirtypeck). This
|
- To do that, it first runs the [MIR type checker]. This
|
||||||
is basically a normal type-checker but specialized to MIR, which
|
is basically a normal type-checker but specialized to MIR, which
|
||||||
is much simpler than full Rust, of course. Running the MIR type
|
is much simpler than full Rust, of course. Running the MIR type
|
||||||
checker will however create **outlives constraints** between
|
checker will however create **outlives constraints** between
|
||||||
|
|
@ -44,29 +44,26 @@ The MIR-based region analysis consists of two major functions:
|
||||||
[`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/nll/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/nll/region_infer/struct.RegionInferenceContext.html#method.solve
|
||||||
[NLL RFC]: http://rust-lang.github.io/rfcs/2094-nll.html
|
[NLL RFC]: http://rust-lang.github.io/rfcs/2094-nll.html
|
||||||
|
[MIR type checker]: ./type_check.md
|
||||||
|
|
||||||
## Universal regions
|
## Universal regions
|
||||||
|
|
||||||
*to be written* – explain the `UniversalRegions` type
|
The [`UnversalRegions`] type represents a collection of _unversal_ regions
|
||||||
|
corresponding to some MIR `DefId`. It is constructed in
|
||||||
|
[`replace_regions_in_mir`] when we replace all regions with fresh inference
|
||||||
|
variables. [`UniversalRegions`] contains indices for all the free regions in
|
||||||
|
the given MIR along with any relationships that are _known_ to hold between
|
||||||
|
them (e.g. implied bounds, where clauses, etc.).
|
||||||
|
|
||||||
## Region variables and constraints
|
TODO: is there more to write here?
|
||||||
|
|
||||||
*to be written* – describe the `RegionInferenceContext` and
|
[`UniversalRegions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/universal_regions/struct.UniversalRegions.html
|
||||||
the role of `liveness_constraints` vs other `constraints`, plus
|
|
||||||
|
|
||||||
## Closures
|
## Region variables
|
||||||
|
|
||||||
*to be written*
|
The value of a region can be thought of as a **set** of points in the MIR where
|
||||||
|
the region is valid; we call the domain of this set a `RegionElement`. In the
|
||||||
<a name="mirtypeck"></a>
|
code, the value for all regions is maintained in
|
||||||
|
|
||||||
## The MIR type-check
|
|
||||||
|
|
||||||
## Representing the "values" of a region variable
|
|
||||||
|
|
||||||
The value of a region can be thought of as a **set**; we call the
|
|
||||||
domain of this set a `RegionElement`. In the code, the value for all
|
|
||||||
regions is maintained in
|
|
||||||
[the `rustc_mir::borrow_check::nll::region_infer` module][ri]. For
|
[the `rustc_mir::borrow_check::nll::region_infer` module][ri]. For
|
||||||
each region we maintain a set storing what elements are present in its
|
each region we maintain a set storing what elements are present in its
|
||||||
value (to make this efficient, we give each kind of element an index,
|
value (to make this efficient, we give each kind of element an index,
|
||||||
|
|
@ -90,11 +87,86 @@ The kinds of region elements are as follows:
|
||||||
for details on placeholders, see the section
|
for details on placeholders, see the section
|
||||||
[placeholders and universes](#placeholder).
|
[placeholders and universes](#placeholder).
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
Before we can infer the value of regions, we need to collect constraints on the
|
||||||
|
regions. There are two primary types of constraints.
|
||||||
|
|
||||||
|
1. Outlives constraints. These are constraints that one region outlives another
|
||||||
|
(e.g. `'a: 'b`). Outlives constraints are generated by the [MIR type
|
||||||
|
checker].
|
||||||
|
2. Liveness constraints. Each region needs to be live at points where it can be
|
||||||
|
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
|
||||||
|
|
||||||
|
## Inference Overview
|
||||||
|
|
||||||
|
So how do we compute the contents of a region? This process is called _region
|
||||||
|
inference_. The high-level idea is pretty simple, but there are some details we
|
||||||
|
need to take care of.
|
||||||
|
|
||||||
|
The [`RegionInferenceContext`] type contains all of the information needed to
|
||||||
|
do inference, including the universal regions from `replace_regions_in_mir` and
|
||||||
|
the constraints computed for each region. It is constructed just after we
|
||||||
|
compute the liveness constraints.
|
||||||
|
|
||||||
|
Here are some of the fields of the struct:
|
||||||
|
|
||||||
|
- `constraints`: contains all the outlives constraints.
|
||||||
|
- `liveness_constraints`: contains all the liveness constraints.
|
||||||
|
- `universal_regions`: contains the `UniversalRegions` returned by
|
||||||
|
`replace_regions_in_mir`.
|
||||||
|
- `universal_region_relations`: contains relations known to be true about
|
||||||
|
universal regions. For example, if we have a where clause that `'a: 'b`, that
|
||||||
|
relation is assumed to be true while borrow checking the implementation (it
|
||||||
|
is checked at the caller), so `universal_region_relations` would contain `'a:
|
||||||
|
'b`.
|
||||||
|
- `type_tests`: contains some constraints on types that we must check after
|
||||||
|
inference (e.g. `T: 'a`).
|
||||||
|
- `closure_bounds_mapping`: used for propagating region constraints from
|
||||||
|
closures back out to the creater of the closure.
|
||||||
|
|
||||||
|
TODO: should we discuss any of the others fields? What about the SCCs?
|
||||||
|
|
||||||
|
Ok, now that we have constructed a `RegionInferenceContext`, we can do
|
||||||
|
inference. This is done by calling the [`solve`] method on the context.
|
||||||
|
|
||||||
|
We will start off the value of each region with the liveness constraints (the
|
||||||
|
places we already know must be in the region). We will then use the outlives
|
||||||
|
constraints to widen each region until all constraints are met. This is done in
|
||||||
|
[`propagate_constraints`]. For each region, if `'a: 'b`, we add all elements of
|
||||||
|
`'b` to `'a`.
|
||||||
|
|
||||||
|
Then, we will check for errors. We first check that type tests are satisfied by
|
||||||
|
calling [`check_type_tests`]. This checks constraints like `T: 'a`. Second, we
|
||||||
|
check that universal regions are not "too big". This is done by calling
|
||||||
|
[`check_universal_regions`]. This checks that for each region `'a` if `'a`
|
||||||
|
contains the element `end('b)`, then we must already know that `'a: 'b` holds
|
||||||
|
(e.g. from a where clause). If we don't already know this, that is an error...
|
||||||
|
well, almost.
|
||||||
|
|
||||||
|
[`propagate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/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_universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.check_universal_regions
|
||||||
|
|
||||||
|
## Closures
|
||||||
|
|
||||||
|
When we are checking the type tests and universal regions, we may come across a
|
||||||
|
constraint that we can't prove yet if we are in a closure body! However, the
|
||||||
|
necessary constraints may actually hold (we just don't know it yet). Thus, if
|
||||||
|
we are inside a closure, we just collect all the constraints we can't prove yet
|
||||||
|
and return them. Later, when we are borrow check the MIR node that created the
|
||||||
|
closure, we can also check that these constraints hold. At that time, if we
|
||||||
|
can't prove they hold, we report an error.
|
||||||
|
|
||||||
## Causal tracking
|
## Causal tracking
|
||||||
|
|
||||||
*to be written* – describe how we can extend the values of a variable
|
*to be written* – describe how we can extend the values of a variable
|
||||||
with causal tracking etc
|
with causal tracking etc
|
||||||
|
|
||||||
|
TODO: is this what I described above or something else?
|
||||||
|
|
||||||
<a name="placeholder"></a>
|
<a name="placeholder"></a>
|
||||||
|
|
||||||
## Placeholders and universes
|
## Placeholders and universes
|
||||||
|
|
@ -541,3 +613,6 @@ Now constraint propagation is done, but when we check the outlives
|
||||||
relationships, we find that `V2` includes this new element `placeholder(1)`,
|
relationships, we find that `V2` includes this new element `placeholder(1)`,
|
||||||
so we report an error.
|
so we report an error.
|
||||||
|
|
||||||
|
## Borrow Checker Errors
|
||||||
|
|
||||||
|
TODO: we should discuss how to generate errors from the results of these analyses.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue