Skip to content

Commit 9f43509

Browse files
committed
fill out the borrowck chapter a bit more
1 parent 5194978 commit 9f43509

File tree

1 file changed

+92
-17
lines changed

1 file changed

+92
-17
lines changed

src/borrow_check/region_inference.md

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The MIR-based region analysis consists of two major functions:
2424
- [`compute_regions`], invoked second: this is given as argument the
2525
results of move analysis. It has the job of computing values for all
2626
the inference variables that `replace_regions_in_mir` introduced.
27-
- To do that, it first runs the [MIR type checker](#mirtypeck). This
27+
- To do that, it first runs the [MIR type checker]. This
2828
is basically a normal type-checker but specialized to MIR, which
2929
is much simpler than full Rust, of course. Running the MIR type
3030
checker will however create **outlives constraints** between
@@ -44,29 +44,26 @@ The MIR-based region analysis consists of two major functions:
4444
[`RegionInferenceContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html
4545
[`solve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.solve
4646
[NLL RFC]: http://rust-lang.github.io/rfcs/2094-nll.html
47+
[MIR type checker]: ./type_check.md
4748

4849
## Universal regions
4950

50-
*to be written* – explain the `UniversalRegions` type
51+
The [`UnversalRegions`] type represents a collection of _unversal_ regions
52+
corresponding to some MIR `DefId`. It is constructed in
53+
[`replace_regions_in_mir`] when we replace all regions with fresh inference
54+
variables. [`UniversalRegions`] contains indices for all the free regions in
55+
the given MIR along with any relationships that are _known_ to hold between
56+
them (e.g. implied bounds, where clauses, etc.).
5157

52-
## Region variables and constraints
58+
TODO: is there more to write here?
5359

54-
*to be written* – describe the `RegionInferenceContext` and
55-
the role of `liveness_constraints` vs other `constraints`, plus
60+
[`UniversalRegions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/universal_regions/struct.UniversalRegions.html
5661

57-
## Closures
58-
59-
*to be written*
60-
61-
<a name="mirtypeck"></a>
62+
## Region variables
6263

63-
## The MIR type-check
64-
65-
## Representing the "values" of a region variable
66-
67-
The value of a region can be thought of as a **set**; we call the
68-
domain of this set a `RegionElement`. In the code, the value for all
69-
regions is maintained in
64+
The value of a region can be thought of as a **set** of points in the MIR where
65+
the region is valid; we call the domain of this set a `RegionElement`. In the
66+
code, the value for all regions is maintained in
7067
[the `rustc_mir::borrow_check::nll::region_infer` module][ri]. For
7168
each region we maintain a set storing what elements are present in its
7269
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:
9087
for details on placeholders, see the section
9188
[placeholders and universes](#placeholder).
9289

90+
## Constraints
91+
92+
Before we can infer the value of regions, we need to collect constraints on the
93+
regions. There are two primary types of constraints.
94+
95+
1. Outlives constraints. These are constraints that one region outlives another
96+
(e.g. `'a: 'b`). Outlives constraints are generated by the [MIR type
97+
checker].
98+
2. Liveness constraints. Each region needs to be live at points where it can be
99+
used. These constraints are collected by [`generate_constraints`].
100+
101+
[`generate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/constraint_generation/fn.generate_constraints.html
102+
103+
## Inference Overview
104+
105+
So how do we compute the contents of a region? This process is called _region
106+
inference_. The high-level idea is pretty simple, but there are some details we
107+
need to take care of.
108+
109+
The [`RegionInferenceContext`] type contains all of the information needed to
110+
do inference, including the universal regions from `replace_regions_in_mir` and
111+
the constraints computed for each region. It is constructed just after we
112+
compute the liveness constraints.
113+
114+
Here are some of the fields of the struct:
115+
116+
- `constraints`: contains all the outlives constraints.
117+
- `liveness_constraints`: contains all the liveness constraints.
118+
- `universal_regions`: contains the `UniversalRegions` returned by
119+
`replace_regions_in_mir`.
120+
- `universal_region_relations`: contains relations known to be true about
121+
universal regions. For example, if we have a where clause that `'a: 'b`, that
122+
relation is assumed to be true while borrow checking the implementation (it
123+
is checked at the caller), so `universal_region_relations` would contain `'a:
124+
'b`.
125+
- `type_tests`: contains some constraints on types that we must check after
126+
inference (e.g. `T: 'a`).
127+
- `closure_bounds_mapping`: used for propagating region constraints from
128+
closures back out to the creater of the closure.
129+
130+
TODO: should we discuss any of the others fields? What about the SCCs?
131+
132+
Ok, now that we have constructed a `RegionInferenceContext`, we can do
133+
inference. This is done by calling the [`solve`] method on the context.
134+
135+
We will start off the value of each region with the liveness constraints (the
136+
places we already know must be in the region). We will then use the outlives
137+
constraints to widen each region until all constraints are met. This is done in
138+
[`propagate_constraints`]. For each region, if `'a: 'b`, we add all elements of
139+
`'b` to `'a`.
140+
141+
Then, we will check for errors. We first check that type tests are satisfied by
142+
calling [`check_type_tests`]. This checks constraints like `T: 'a`. Second, we
143+
check that universal regions are not "too big". This is done by calling
144+
[`check_universal_regions`]. This checks that for each region `'a` if `'a`
145+
contains the element `end('b)`, then we must already know that `'a: 'b` holds
146+
(e.g. from a where clause). If we don't already know this, that is an error...
147+
well, almost.
148+
149+
[`propagate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.propagate_constraints
150+
[`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
151+
[`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
152+
153+
## Closures
154+
155+
When we are checking the type tests and universal regions, we may come across a
156+
constraint that we can't prove yet if we are in a closure body! However, the
157+
necessary constraints may actually hold (we just don't know it yet). Thus, if
158+
we are inside a closure, we just collect all the constraints we can't prove yet
159+
and return them. Later, when we are borrow check the MIR node that created the
160+
closure, we can also check that these constraints hold. At that time, if we
161+
can't prove they hold, we report an error.
162+
93163
## Causal tracking
94164

95165
*to be written* – describe how we can extend the values of a variable
96166
with causal tracking etc
97167

168+
TODO: is this what I described above or something else?
169+
98170
<a name="placeholder"></a>
99171

100172
## Placeholders and universes
@@ -541,3 +613,6 @@ Now constraint propagation is done, but when we check the outlives
541613
relationships, we find that `V2` includes this new element `placeholder(1)`,
542614
so we report an error.
543615

616+
## Borrow Checker Errors
617+
618+
TODO: we should discuss how to generate errors from the results of these analyses.

0 commit comments

Comments
 (0)