More long lines
This commit is contained in:
parent
42ef2ad0b8
commit
2bb61a3f59
|
|
@ -69,11 +69,11 @@ want the `TypeckTables` node for some particular fn, so you might write:
|
|||
RUST_DEP_GRAPH_FILTER='-> TypeckTables & bar'
|
||||
```
|
||||
|
||||
This will select only the predecessors of `TypeckTables` nodes for functions with
|
||||
`bar` in their name.
|
||||
This will select only the predecessors of `TypeckTables` nodes for functions
|
||||
with `bar` in their name.
|
||||
|
||||
Perhaps you are finding that when you change `foo` you need to re-type-check `bar`,
|
||||
but you don't think you should have to. In that case, you might do:
|
||||
Perhaps you are finding that when you change `foo` you need to re-type-check
|
||||
`bar`, but you don't think you should have to. In that case, you might do:
|
||||
|
||||
```
|
||||
RUST_DEP_GRAPH_FILTER='Hir & foo -> TypeckTables & bar'
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ enforcing a number of properties:
|
|||
- That all variables are initialized before they are used.
|
||||
- That you can't move the same value twice.
|
||||
- That you can't move a value while it is borrowed.
|
||||
- That you can't access a place while it is mutably borrowed (except through the reference).
|
||||
- That you can't access a place while it is mutably borrowed (except through
|
||||
the reference).
|
||||
- That you can't mutate a place while it is shared borrowed.
|
||||
- etc
|
||||
|
||||
|
|
@ -44,10 +45,12 @@ The overall flow of the borrow checker is as follows:
|
|||
Among other things, this function will replace all of the regions in
|
||||
the MIR with fresh [inference variables](./appendix-glossary.html).
|
||||
- (More details can be found in [the regionck section](./mir-regionck.html).)
|
||||
- Next, we perform a number of [dataflow analyses](./appendix-background.html#dataflow)
|
||||
- Next, we perform a number of [dataflow
|
||||
analyses](./appendix-background.html#dataflow)
|
||||
that compute what data is moved and when. The results of these analyses
|
||||
are needed to do both borrow checking and region inference.
|
||||
- Using the move data, we can then compute the values of all the regions in the MIR.
|
||||
- Using the move data, we can then compute the values of all the regions in the
|
||||
MIR.
|
||||
- (More details can be found in [the NLL section](./mir-regionck.html).)
|
||||
- Finally, the borrow checker itself runs, taking as input (a) the
|
||||
results of move analysis and (b) the regions computed by the region
|
||||
|
|
|
|||
|
|
@ -15,16 +15,19 @@ transformations. These suites represent useful intermediate points
|
|||
where we want to access the MIR for type checking or other purposes:
|
||||
|
||||
- `mir_build(D)` – not a query, but this constructs the initial MIR
|
||||
- `mir_const(D)` – applies some simple transformations to make MIR ready for constant evaluation;
|
||||
- `mir_validated(D)` – applies some more transformations, making MIR ready for borrow checking;
|
||||
- `optimized_mir(D)` – the final state, after all optimizations have been performed.
|
||||
- `mir_const(D)` – applies some simple transformations to make MIR ready for
|
||||
constant evaluation;
|
||||
- `mir_validated(D)` – applies some more transformations, making MIR ready for
|
||||
borrow checking;
|
||||
- `optimized_mir(D)` – the final state, after all optimizations have been
|
||||
performed.
|
||||
|
||||
### Seeing how the MIR changes as the compiler executes
|
||||
|
||||
`-Zdump-mir=F` is a handy compiler options that will let you view the MIR
|
||||
for each function at each stage of compilation. `-Zdump-mir` takes a **filter**
|
||||
`F` which allows you to control which functions and which passes you are interesting
|
||||
in. For example:
|
||||
`-Zdump-mir=F` is a handy compiler options that will let you view the MIR for
|
||||
each function at each stage of compilation. `-Zdump-mir` takes a **filter** `F`
|
||||
which allows you to control which functions and which passes you are
|
||||
interesting in. For example:
|
||||
|
||||
```bash
|
||||
> rustc -Zdump-mir=foo ...
|
||||
|
|
@ -58,8 +61,9 @@ rustc.main.000-000.CleanEndRegions.after.mir
|
|||
def-path to the function etc being dumped
|
||||
```
|
||||
|
||||
You can also make more selective filters. For example, `main & CleanEndRegions` will select
|
||||
for things that reference *both* `main` and the pass `CleanEndRegions`:
|
||||
You can also make more selective filters. For example, `main & CleanEndRegions`
|
||||
will select for things that reference *both* `main` and the pass
|
||||
`CleanEndRegions`:
|
||||
|
||||
```bash
|
||||
> rustc -Zdump-mir='main & CleanEndRegions' foo.rs
|
||||
|
|
|
|||
|
|
@ -418,16 +418,15 @@ variable `'?3`, but the variable `'?3` is not forced to outlive
|
|||
anything else. Therefore, it simply starts and ends as the empty set
|
||||
of elements, and hence the type-check succeeds here.
|
||||
|
||||
(This should surprise you a little. It surprised me when I first
|
||||
realized it. We are saying that if we are a fn that **needs both of
|
||||
its arguments to have the same region**, we can accept being called
|
||||
with **arguments with two distinct regions**. That seems intuitively
|
||||
unsound. But in fact, it's fine, as I
|
||||
[tried to explain in this issue on the Rust issue tracker long ago][ohdeargoditsallbroken].
|
||||
The reason is that even if we get called with arguments of two
|
||||
distinct lifetimes, those two lifetimes have some intersection (the
|
||||
call itself), and that intersection can be our value of `'a` that we
|
||||
use as the common lifetime of our arguments. -nmatsakis)
|
||||
(This should surprise you a little. It surprised me when I first realized it.
|
||||
We are saying that if we are a fn that **needs both of its arguments to have
|
||||
the same region**, we can accept being called with **arguments with two
|
||||
distinct regions**. That seems intuitively unsound. But in fact, it's fine, as
|
||||
I tried to explain in [this issue][ohdeargoditsallbroken] on the Rust issue
|
||||
tracker long ago. The reason is that even if we get called with arguments of
|
||||
two distinct lifetimes, those two lifetimes have some intersection (the call
|
||||
itself), and that intersection can be our value of `'a` that we use as the
|
||||
common lifetime of our arguments. -nmatsakis)
|
||||
|
||||
[ohdeargoditsallbroken]: https://github.com/rust-lang/rust/issues/32330#issuecomment-202536977
|
||||
|
||||
|
|
@ -440,10 +439,10 @@ a return type:
|
|||
<:
|
||||
for<'b, 'c> fn(&'b u32, &'c u32) -> &'b u32
|
||||
|
||||
Despite seeming very similar to the previous example, this case is
|
||||
going to get an error. That's good: the problem is that we've gone
|
||||
from a fn that promises to return one of its two arguments, to a fn
|
||||
that is promising to return the first one. That is unsound. Let's see how it plays out.
|
||||
Despite seeming very similar to the previous example, this case is going to get
|
||||
an error. That's good: the problem is that we've gone from a fn that promises
|
||||
to return one of its two arguments, to a fn that is promising to return the
|
||||
first one. That is unsound. Let's see how it plays out.
|
||||
|
||||
First, we skolemize the supertype:
|
||||
|
||||
|
|
@ -463,8 +462,8 @@ And now we create the subtyping relationships:
|
|||
&'!2 u32 <: &'?3 u32 // arg 2
|
||||
&'?3 u32 <: &'!1 u32 // return type
|
||||
|
||||
And finally the outlives relationships. Here, let V1, V2, and V3 be the variables
|
||||
we assign to `!1`, `!2`, and `?3` respectively:
|
||||
And finally the outlives relationships. Here, let V1, V2, and V3 be the
|
||||
variables we assign to `!1`, `!2`, and `?3` respectively:
|
||||
|
||||
V1: V3
|
||||
V2: V3
|
||||
|
|
@ -476,8 +475,8 @@ Those variables will have these initial values:
|
|||
V2 in U2 = {skol(2)}
|
||||
V3 in U2 = {}
|
||||
|
||||
Now because of the `V3: V1` constraint, we have to add `skol(1)` into `V3` (and indeed
|
||||
it is visible from `V3`), so we get:
|
||||
Now because of the `V3: V1` constraint, we have to add `skol(1)` into `V3` (and
|
||||
indeed it is visible from `V3`), so we get:
|
||||
|
||||
V3 in U2 = {skol(1)}
|
||||
|
||||
|
|
|
|||
25
src/mir.md
25
src/mir.md
|
|
@ -34,14 +34,17 @@ This section introduces the key concepts of MIR, summarized here:
|
|||
|
||||
- **Basic blocks**: units of the control-flow graph, consisting of:
|
||||
- **statements:** actions with one successor
|
||||
- **terminators:** actions with potentially multiple successors; always at the end of a block
|
||||
- (if you're not familiar with the term *basic block*, see the [background chapter][cfg])
|
||||
- **terminators:** actions with potentially multiple successors; always at
|
||||
the end of a block
|
||||
- (if you're not familiar with the term *basic block*, see the [background
|
||||
chapter][cfg])
|
||||
- **Locals:** Memory locations alloated on the stack (conceptually, at
|
||||
least), such as function arguments, local variables, and
|
||||
temporaries. These are identified by an index, written with a
|
||||
leading underscore, like `_1`. There is also a special "local"
|
||||
(`_0`) allocated to store the return value.
|
||||
- **Places:** expressions that identify a location in memory, like `_1` or `_1.f`.
|
||||
- **Places:** expressions that identify a location in memory, like `_1` or
|
||||
`_1.f`.
|
||||
- **Rvalues:** expressions that produce a value. The "R" stands for
|
||||
the fact that these are the "right-hand side" of an assignment.
|
||||
- **Operands:** the arguments to an rvalue, which can either be a
|
||||
|
|
@ -100,8 +103,9 @@ you their original name (`// "vec" in scope 1...`). The "scope" blocks
|
|||
(e.g., `scope 1 { .. }`) describe the lexical structure of the source
|
||||
program (which names were in scope when).
|
||||
|
||||
**Basic blocks.** Reading further, we see our first **basic block** (naturally it may look
|
||||
slightly different when you view it, and I am ignoring some of the comments):
|
||||
**Basic blocks.** Reading further, we see our first **basic block** (naturally
|
||||
it may look slightly different when you view it, and I am ignoring some of the
|
||||
comments):
|
||||
|
||||
```
|
||||
bb0: {
|
||||
|
|
@ -110,8 +114,8 @@ bb0: {
|
|||
}
|
||||
```
|
||||
|
||||
A basic block is defined by a series of **statements** and a final **terminator**.
|
||||
In this case, there is one statement:
|
||||
A basic block is defined by a series of **statements** and a final
|
||||
**terminator**. In this case, there is one statement:
|
||||
|
||||
```
|
||||
StorageLive(_1);
|
||||
|
|
@ -146,8 +150,8 @@ bb2: {
|
|||
}
|
||||
```
|
||||
|
||||
Here there are two statements: another `StorageLive`, introducing the `_3` temporary,
|
||||
and then an assignment:
|
||||
Here there are two statements: another `StorageLive`, introducing the `_3`
|
||||
temporary, and then an assignment:
|
||||
|
||||
```
|
||||
_3 = &mut _1;
|
||||
|
|
@ -189,7 +193,8 @@ TMP1 = a + b
|
|||
x = TMP1 + c
|
||||
```
|
||||
|
||||
([Try it and see, though you may want to do release mode to skip over the overflow checks.][play-abc])
|
||||
([Try it and see][play-abc], though you may want to do release mode to skip
|
||||
over the overflow checks.)
|
||||
|
||||
[play-abc]: https://play.rust-lang.org/?gist=1751196d63b2a71f8208119e59d8a5b6&version=stable
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue