added example, reworked inference section
This commit is contained in:
parent
53ab47354e
commit
b1f84cf70b
|
|
@ -120,37 +120,12 @@ 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
|
inference_. The high-level idea is pretty simple, but there are some details we
|
||||||
need to take care of.
|
need to take care of.
|
||||||
|
|
||||||
The [`RegionInferenceContext`] type contains all of the information needed to
|
Here is the high-level idea: we start off each region with the MIR locations we
|
||||||
do inference, including the universal regions from `replace_regions_in_mir` and
|
know must be in it from the liveness constraints. From there, we use all of the
|
||||||
the constraints computed for each region. It is constructed just after we
|
outlives constraints computed from the type checker to _propagate_ the
|
||||||
compute the liveness constraints.
|
constraints: for each region `'a`, if `'a: 'b`, then we add all elements of
|
||||||
|
`'b` to `'a`, including `end('b)`. This all happens in
|
||||||
Here are some of the fields of the struct:
|
[`propagate_constraints`].
|
||||||
|
|
||||||
- `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
|
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
|
calling [`check_type_tests`]. This checks constraints like `T: 'a`. Second, we
|
||||||
|
|
@ -158,7 +133,102 @@ 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`
|
[`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
|
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...
|
(e.g. from a where clause). If we don't already know this, that is an error...
|
||||||
well, almost.
|
well, almost. There is some special handling for closures that we will discuss
|
||||||
|
later.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
Consider the following example:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
fn foo<'a, 'b>(x: &'a usize) -> &'b usize {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Clearly, this should not compile because we don't know if `'a` outlives `'b`
|
||||||
|
(if it doesn't then the return value could be a dangling reference).
|
||||||
|
|
||||||
|
Let's back up a bit. We need to introduce some free inference variables (as is
|
||||||
|
done in [`replace_regions_in_mir`]). This example doesn't use the exact regions
|
||||||
|
produced, but it (hopefully) is enough to get the idea across.
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
fn foo<'a, 'b>(x: &'a /* '#1 */ usize) -> &'b /* '#3 */ usize {
|
||||||
|
x // '#2, location L1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Some notation: `'#1`, `'#3`, and `'#2` represent the universal regions for the
|
||||||
|
argument, return value, and the expression `x`, respectively. Additionally, I
|
||||||
|
will call the location of the expression `x` `L1`.
|
||||||
|
|
||||||
|
So now we can use the liveness constraints to get the following starting points:
|
||||||
|
|
||||||
|
Region | Contents
|
||||||
|
--------|----------
|
||||||
|
'#1 |
|
||||||
|
'#2 | `L1`
|
||||||
|
'#3 | `L1`
|
||||||
|
|
||||||
|
Now we use the outlives constraints to expand each region. Specifically, we
|
||||||
|
know that `'#2: '#3` ...
|
||||||
|
|
||||||
|
Region | Contents
|
||||||
|
--------|----------
|
||||||
|
'#1 | `L1`
|
||||||
|
'#2 | `L1, end('#3) // add contents of '#3 and end('#3)`
|
||||||
|
'#3 | `L1`
|
||||||
|
|
||||||
|
... and `'#1: '#2`, so ...
|
||||||
|
|
||||||
|
Region | Contents
|
||||||
|
--------|----------
|
||||||
|
'#1 | `L1, end('#2), end('#3) // add contents of '#2 and end('#2)`
|
||||||
|
'#2 | `L1, end('#3)`
|
||||||
|
'#3 | `L1`
|
||||||
|
|
||||||
|
Now, we need to check that no regions were too big (we don't have any type
|
||||||
|
tests to check in this case). Notice that `'#1` now contains `end('#3)`, but
|
||||||
|
we have no `where` clause or implied bound to say that `'a: 'b`... that's an
|
||||||
|
error!
|
||||||
|
|
||||||
|
### Some details
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
[`constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/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
|
||||||
|
[`universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/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
|
||||||
|
[`type_tests`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/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
|
||||||
|
|
||||||
|
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. This
|
||||||
|
is where we call [`propagate_constraints`] and then check the resulting type
|
||||||
|
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/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_type_tests`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.check_type_tests
|
||||||
|
|
@ -174,15 +244,6 @@ 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
|
closure, we can also check that these constraints hold. At that time, if we
|
||||||
can't prove they hold, we report an error.
|
can't prove they hold, we report an error.
|
||||||
|
|
||||||
## Causal tracking
|
|
||||||
|
|
||||||
*to be written* – describe how we can extend the values of a variable
|
|
||||||
with causal tracking etc
|
|
||||||
|
|
||||||
TODO: is this what I described above or something else?
|
|
||||||
|
|
||||||
<a name="placeholder"></a>
|
|
||||||
|
|
||||||
## Placeholders and universes
|
## Placeholders and universes
|
||||||
|
|
||||||
(This section describes ongoing work that hasn't landed yet.)
|
(This section describes ongoing work that hasn't landed yet.)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue