@@ -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
7168each region we maintain a set storing what elements are present in its
7269value (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
541613relationships, we find that ` V2 ` includes this new element ` placeholder(1) ` ,
542614so 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