From d199a7c5d1bffb0b1dc69e38e9a43eabbd40a82b Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 13 Dec 2019 11:01:05 -0600 Subject: [PATCH] update NLL after refactorings --- src/borrow_check.md | 19 ++++----- src/borrow_check/region_inference.md | 40 +++++++++---------- .../constraint_propagation.md | 16 ++++---- .../region_inference/lifetime_parameters.md | 12 +++--- src/borrow_check/type_check.md | 2 +- 5 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/borrow_check.md b/src/borrow_check.md index 0ceb21d72..034c36253 100644 --- a/src/borrow_check.md +++ b/src/borrow_check.md @@ -11,13 +11,8 @@ enforcing a number of properties: - That you can't mutate a place while it is immutably borrowed. - etc -At the time of this writing, the code is in a state of transition. The -"main" borrow checker still works by processing [the HIR](hir.html), -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 borrow checker operates on the MIR. An older implementation operated on the +HIR. Doing borrow checking on MIR has several advantages: - The MIR is *far* less complex than the HIR; the radical desugaring 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 include references to the new regions that we are computing. - 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 - the MIR with fresh [inference variables](./appendix/glossary.html). + Among other things, this function will replace all of the [regions](./appendix/glossary.md) in + the MIR with fresh [inference variables](./appendix/glossary.md). - 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. -- 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 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 each lifetime must be valid according to the constraints we collected. - At this point, we can compute the "borrows in scope" at each point. diff --git a/src/borrow_check/region_inference.md b/src/borrow_check/region_inference.md index 5ae096574..84d30bdb4 100644 --- a/src/borrow_check/region_inference.md +++ b/src/borrow_check/region_inference.md @@ -1,11 +1,9 @@ # Region inference (NLL) -The MIR-based region checking code is located in -[the `rustc_mir::borrow_check::nll` module][nll]. (NLL, of course, -stands for "non-lexical lifetimes", a term that will hopefully be -deprecated once they become the standard kind of lifetime.) +The MIR-based region checking code is located in [the `rustc_mir::borrow_check` +module][nll]. -[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: @@ -36,12 +34,12 @@ The MIR-based region analysis consists of two major functions: - The [NLL RFC] also includes fairly thorough (and hopefully readable) coverage. -[cp]: ./region_inference/constraint_propagation.html -[fvb]: ../appendix/background.html#free-vs-bound +[cp]: ./region_inference/constraint_propagation.md +[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 [`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 -[`solve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.solve +[`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/region_infer/struct.RegionInferenceContext.html#method.solve [NLL RFC]: https://rust-lang.github.io/rfcs/2094-nll.html [MIR type checker]: ./type_check.md @@ -68,7 +66,7 @@ the moment. 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 @@ -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 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: @@ -115,7 +113,7 @@ common sorts of constraints are: 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 +[`generate_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/constraint_generation/fn.generate_constraints.html ## Inference Overview @@ -219,12 +217,12 @@ Here are some of the fields of the struct: - [`closure_bounds_mapping`]: used for propagating region constraints from 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 -[`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 +[`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/region_infer/struct.RegionInferenceContext.html#structfield.liveness_constraints +[`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/region_infer/struct.RegionInferenceContext.html#structfield.universal_region_relations +[`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/region_infer/struct.RegionInferenceContext.html#structfield.closure_bounds_mapping 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 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 -[`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 +[`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/region_infer/struct.RegionInferenceContext.html#method.check_type_tests +[`check_universal_regions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/region_infer/struct.RegionInferenceContext.html#method.check_universal_regions diff --git a/src/borrow_check/region_inference/constraint_propagation.md b/src/borrow_check/region_inference/constraint_propagation.md index 5f3b29c6d..ee86ae148 100644 --- a/src/borrow_check/region_inference/constraint_propagation.md +++ b/src/borrow_check/region_inference/constraint_propagation.md @@ -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; - [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 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 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 -[`LivenessValues`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/values/struct.LivenessValues.html +[`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/region_infer/values/struct.LivenessValues.html One thing that is worth mentioning: All lifetime parameters are always 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 context. -[`ConstraintSet`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/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 -[`RegionInferenceContext::new`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#method.new +[`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/constraints/struct.OutlivesConstraintSet.html#method.graph +[`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 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 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 -[`scc_values`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/region_infer/struct.RegionInferenceContext.html#structfield.scc_values +[`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/region_infer/struct.RegionInferenceContext.html#structfield.scc_values 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 diff --git a/src/borrow_check/region_inference/lifetime_parameters.md b/src/borrow_check/region_inference/lifetime_parameters.md index 0d5219aa9..4086b71ef 100644 --- a/src/borrow_check/region_inference/lifetime_parameters.md +++ b/src/borrow_check/region_inference/lifetime_parameters.md @@ -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 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 -[`UniversalRegionRelations`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/borrow_check/nll/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 +[`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/type_check/free_region_relations/struct.UniversalRegionRelations.html +[`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 @@ -56,7 +56,7 @@ type). These subdivisions are not important for the topics discussed here, but become important when we consider [closure constraint 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 @@ -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 [`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 @@ -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 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 diff --git a/src/borrow_check/type_check.md b/src/borrow_check/type_check.md index ee955d971..0db895619 100644 --- a/src/borrow_check/type_check.md +++ b/src/borrow_check/type_check.md @@ -1,7 +1,7 @@ # The MIR type-check 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 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