fix all the not-en-dashes
This commit is contained in:
parent
b52a3f6659
commit
8a49eb7686
|
|
@ -18,8 +18,8 @@ Once it gets more complete, the plan is probably to move it into the
|
||||||
If you'd like to help finish the guide, we'd love to have you! The
|
If you'd like to help finish the guide, we'd love to have you! The
|
||||||
main tracking issue for the guide
|
main tracking issue for the guide
|
||||||
[can be found here](https://github.com/rust-lang-nursery/rustc-guide/issues/6). From
|
[can be found here](https://github.com/rust-lang-nursery/rustc-guide/issues/6). From
|
||||||
there, you can find a list of all the planned chapters and subsections
|
there, you can find a list of all the planned chapters and subsections.
|
||||||
-- if you think something is missing, please open an issue about it!
|
If you think something is missing, please open an issue about it!
|
||||||
Otherwise, find a chapter that sounds interesting to you and then go
|
Otherwise, find a chapter that sounds interesting to you and then go
|
||||||
to its associated issue. There should be a list of things to do.
|
to its associated issue. There should be a list of things to do.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ exposes the underlying control flow in a very clear way.
|
||||||
|
|
||||||
A control-flow graph is structured as a set of **basic blocks**
|
A control-flow graph is structured as a set of **basic blocks**
|
||||||
connected by edges. The key idea of a basic block is that it is a set
|
connected by edges. The key idea of a basic block is that it is a set
|
||||||
of statements that execute "together" -- that is, whenever you branch
|
of statements that execute "together" – that is, whenever you branch
|
||||||
to a basic block, you start at the first statement and then execute
|
to a basic block, you start at the first statement and then execute
|
||||||
all the remainder. Only at the end of the block is there the
|
all the remainder. Only at the end of the block is there the
|
||||||
possibility of branching to more than one place (in MIR, we call that
|
possibility of branching to more than one place (in MIR, we call that
|
||||||
|
|
@ -119,7 +119,7 @@ variables, since that's the thing we're most familiar with.
|
||||||
So there you have it: a variable "appears free" in some
|
So there you have it: a variable "appears free" in some
|
||||||
expression/statement/whatever if it refers to something defined
|
expression/statement/whatever if it refers to something defined
|
||||||
outside of that expressions/statement/whatever. Equivalently, we can
|
outside of that expressions/statement/whatever. Equivalently, we can
|
||||||
then refer to the "free variables" of an expression -- which is just
|
then refer to the "free variables" of an expression – which is just
|
||||||
the set of variables that "appear free".
|
the set of variables that "appear free".
|
||||||
|
|
||||||
So what does this have to do with regions? Well, we can apply the
|
So what does this have to do with regions? Well, we can apply the
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ expect, and more. If you are unfamiliar with the compiler testing framework,
|
||||||
see [this chapter](./tests/intro.html) for additional background.
|
see [this chapter](./tests/intro.html) for additional background.
|
||||||
|
|
||||||
The tests themselves are typically (but not always) organized into
|
The tests themselves are typically (but not always) organized into
|
||||||
"suites"--for example, `run-pass`, a folder representing tests that should
|
"suites" – for example, `run-pass`, a folder representing tests that should
|
||||||
succeed, `run-fail`, a folder holding tests that should compile successfully,
|
succeed, `run-fail`, a folder holding tests that should compile successfully,
|
||||||
but return a failure (non-zero status), `compile-fail`, a folder holding tests
|
but return a failure (non-zero status), `compile-fail`, a folder holding tests
|
||||||
that should fail to compile, and many more. The various suites are defined in
|
that should fail to compile, and many more. The various suites are defined in
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@ current year if you like, but you don't have to.
|
||||||
Lines should be at most 100 characters. It's even better if you can
|
Lines should be at most 100 characters. It's even better if you can
|
||||||
keep things to 80.
|
keep things to 80.
|
||||||
|
|
||||||
**Ignoring the line length limit.** Sometimes -- in particular for
|
**Ignoring the line length limit.** Sometimes – in particular for
|
||||||
tests -- it can be necessary to exempt yourself from this limit. In
|
tests – it can be necessary to exempt yourself from this limit. In
|
||||||
that case, you can add a comment towards the top of the file (after
|
that case, you can add a comment towards the top of the file (after
|
||||||
the copyright notice) like so:
|
the copyright notice) like so:
|
||||||
|
|
||||||
|
|
@ -141,7 +141,7 @@ command like `git rebase -i rust-lang/master` (presuming you use the
|
||||||
name `rust-lang` for your remote).
|
name `rust-lang` for your remote).
|
||||||
|
|
||||||
**Individual commits do not have to build (but it's nice).** We do not
|
**Individual commits do not have to build (but it's nice).** We do not
|
||||||
require that every intermediate commit successfully builds -- we only
|
require that every intermediate commit successfully builds – we only
|
||||||
expect to be able to bisect at a PR level. However, if you *can* make
|
expect to be able to bisect at a PR level. However, if you *can* make
|
||||||
individual commits build, that is always helpful.
|
individual commits build, that is always helpful.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ path that should not exist, but you will not be quite sure how it came
|
||||||
to be. **When the compiler is built with debug assertions,** it can
|
to be. **When the compiler is built with debug assertions,** it can
|
||||||
help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE`
|
help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE`
|
||||||
environment variable to a filter. Every edge created in the dep-graph
|
environment variable to a filter. Every edge created in the dep-graph
|
||||||
will be tested against that filter -- if it matches, a `bug!` is
|
will be tested against that filter – if it matches, a `bug!` is
|
||||||
reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`).
|
reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`).
|
||||||
|
|
||||||
The syntax for these filters is the same as described in the previous
|
The syntax for these filters is the same as described in the previous
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# MIR borrow check
|
# MIR borrow check
|
||||||
|
|
||||||
The borrow check is Rust's "secret sauce" -- it is tasked with
|
The borrow check is Rust's "secret sauce" – it is tasked with
|
||||||
enforcing a number of properties:
|
enforcing a number of properties:
|
||||||
|
|
||||||
- That all variables are initialized before they are used.
|
- That all variables are initialized before they are used.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
MIR is Rust's _Mid-level Intermediate Representation_. It is
|
MIR is Rust's _Mid-level Intermediate Representation_. It is
|
||||||
constructed from [HIR](./hir.html). MIR was introduced in
|
constructed from [HIR](./hir.html). MIR was introduced in
|
||||||
[RFC 1211]. It is a radically simplified form of Rust that is used for
|
[RFC 1211]. It is a radically simplified form of Rust that is used for
|
||||||
certain flow-sensitive safety checks -- notably the borrow checker! --
|
certain flow-sensitive safety checks – notably the borrow checker! –
|
||||||
and also for optimization and code generation.
|
and also for optimization and code generation.
|
||||||
|
|
||||||
If you'd like a very high-level introduction to MIR, as well as some
|
If you'd like a very high-level introduction to MIR, as well as some
|
||||||
|
|
@ -122,7 +122,7 @@ StorageLive(_1);
|
||||||
```
|
```
|
||||||
|
|
||||||
This statement indicates that the variable `_1` is "live", meaning
|
This statement indicates that the variable `_1` is "live", meaning
|
||||||
that it may be used later -- this will persist until we encounter a
|
that it may be used later – this will persist until we encounter a
|
||||||
`StorageDead(_1)` statement, which indicates that the variable `_1` is
|
`StorageDead(_1)` statement, which indicates that the variable `_1` is
|
||||||
done being used. These "storage statements" are used by LLVM to
|
done being used. These "storage statements" are used by LLVM to
|
||||||
allocate stack space.
|
allocate stack space.
|
||||||
|
|
@ -134,7 +134,7 @@ _1 = const <std::vec::Vec<T>>::new() -> bb2;
|
||||||
```
|
```
|
||||||
|
|
||||||
Terminators are different from statements because they can have more
|
Terminators are different from statements because they can have more
|
||||||
than one successor -- that is, control may flow to different
|
than one successor – that is, control may flow to different
|
||||||
places. Function calls like the call to `Vec::new` are always
|
places. Function calls like the call to `Vec::new` are always
|
||||||
terminators because of the possibility of unwinding, although in the
|
terminators because of the possibility of unwinding, although in the
|
||||||
case of `Vec::new` we are able to see that indeed unwinding is not
|
case of `Vec::new` we are able to see that indeed unwinding is not
|
||||||
|
|
@ -163,7 +163,7 @@ Assignments in general have the form:
|
||||||
<Place> = <Rvalue>
|
<Place> = <Rvalue>
|
||||||
```
|
```
|
||||||
|
|
||||||
A place is an expression like `_3`, `_3.f` or `*_3` -- it denotes a
|
A place is an expression like `_3`, `_3.f` or `*_3` – it denotes a
|
||||||
location in memory. An **Rvalue** is an expression that creates a
|
location in memory. An **Rvalue** is an expression that creates a
|
||||||
value: in this case, the rvalue is a mutable borrow expression, which
|
value: in this case, the rvalue is a mutable borrow expression, which
|
||||||
looks like `&mut <Place>`. So we can kind of define a grammar for
|
looks like `&mut <Place>`. So we can kind of define a grammar for
|
||||||
|
|
@ -180,7 +180,7 @@ rvalues like so:
|
||||||
| move Place
|
| move Place
|
||||||
```
|
```
|
||||||
|
|
||||||
As you can see from this grammar, rvalues cannot be nested -- they can
|
As you can see from this grammar, rvalues cannot be nested – they can
|
||||||
only reference places and constants. Moreover, when you use a place,
|
only reference places and constants. Moreover, when you use a place,
|
||||||
we indicate whether we are **copying it** (which requires that the
|
we indicate whether we are **copying it** (which requires that the
|
||||||
place have a type `T` where `T: Copy`) or **moving it** (which works
|
place have a type `T` where `T: Copy`) or **moving it** (which works
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,8 @@ that appeared within the `main` function.)
|
||||||
|
|
||||||
### Implementing and registering a pass
|
### Implementing and registering a pass
|
||||||
|
|
||||||
A `MirPass` is some bit of code that processes the MIR, typically --
|
A `MirPass` is some bit of code that processes the MIR, typically –
|
||||||
but not always -- transforming it along the way somehow. For example,
|
but not always – transforming it along the way somehow. For example,
|
||||||
it might perform an optimization. The `MirPass` trait itself is found
|
it might perform an optimization. The `MirPass` trait itself is found
|
||||||
in in [the `rustc_mir::transform` module][mirtransform], and it
|
in in [the `rustc_mir::transform` module][mirtransform], and it
|
||||||
basically consists of one method, `run_pass`, that simply gets an
|
basically consists of one method, `run_pass`, that simply gets an
|
||||||
|
|
@ -110,7 +110,7 @@ came from). The MIR is therefore modified in place (which helps to
|
||||||
keep things efficient).
|
keep things efficient).
|
||||||
|
|
||||||
A good example of a basic MIR pass is [`NoLandingPads`], which walks
|
A good example of a basic MIR pass is [`NoLandingPads`], which walks
|
||||||
the MIR and removes all edges that are due to unwinding -- this is
|
the MIR and removes all edges that are due to unwinding – this is
|
||||||
used when configured with `panic=abort`, which never unwinds. As you
|
used when configured with `panic=abort`, which never unwinds. As you
|
||||||
can see from its source, a MIR pass is defined by first defining a
|
can see from its source, a MIR pass is defined by first defining a
|
||||||
dummy type, a struct with no fields, something like:
|
dummy type, a struct with no fields, something like:
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ The MIR-based region analysis consists of two major functions:
|
||||||
- `replace_regions_in_mir`, invoked first, has two jobs:
|
- `replace_regions_in_mir`, invoked first, has two jobs:
|
||||||
- First, it finds the set of regions that appear within the
|
- First, it finds the set of regions that appear within the
|
||||||
signature of the function (e.g., `'a` in `fn foo<'a>(&'a u32) {
|
signature of the function (e.g., `'a` in `fn foo<'a>(&'a u32) {
|
||||||
... }`). These are called the "universal" or "free" regions -- in
|
... }`). These are called the "universal" or "free" regions – in
|
||||||
particular, they are the regions that [appear free][fvb] in the
|
particular, they are the regions that [appear free][fvb] in the
|
||||||
function body.
|
function body.
|
||||||
- Second, it replaces all the regions from the function body with
|
- Second, it replaces all the regions from the function body with
|
||||||
fresh inference variables. This is because (presently) those
|
fresh inference variables. This is because (presently) those
|
||||||
regions are the results of lexical region inference and hence are
|
regions are the results of lexical region inference and hence are
|
||||||
not of much interest. The intention is that -- eventually -- they
|
not of much interest. The intention is that – eventually – they
|
||||||
will be "erased regions" (i.e., no information at all), since we
|
will be "erased regions" (i.e., no information at all), since we
|
||||||
won't be doing lexical region inference at all.
|
won't be doing lexical region inference at all.
|
||||||
- `compute_regions`, invoked second: this is given as argument the
|
- `compute_regions`, invoked second: this is given as argument the
|
||||||
|
|
@ -40,11 +40,11 @@ The MIR-based region analysis consists of two major functions:
|
||||||
|
|
||||||
## Universal regions
|
## Universal regions
|
||||||
|
|
||||||
*to be written* -- explain the `UniversalRegions` type
|
*to be written* – explain the `UniversalRegions` type
|
||||||
|
|
||||||
## Region variables and constraints
|
## Region variables and constraints
|
||||||
|
|
||||||
*to be written* -- describe the `RegionInferenceContext` and
|
*to be written* – describe the `RegionInferenceContext` and
|
||||||
the role of `liveness_constraints` vs other `constraints`, plus
|
the role of `liveness_constraints` vs other `constraints`, plus
|
||||||
|
|
||||||
## Closures
|
## Closures
|
||||||
|
|
@ -79,13 +79,13 @@ The kinds of region elements are as follows:
|
||||||
- Similarly, there is an element denoted `end('static)` corresponding
|
- Similarly, there is an element denoted `end('static)` corresponding
|
||||||
to the remainder of program execution after this function returns.
|
to the remainder of program execution after this function returns.
|
||||||
- There is an element `!1` for each skolemized region `!1`. This
|
- There is an element `!1` for each skolemized region `!1`. This
|
||||||
corresponds (intuitively) to some unknown set of other elements --
|
corresponds (intuitively) to some unknown set of other elements –
|
||||||
for details on skolemization, see the section
|
for details on skolemization, see the section
|
||||||
[skolemization and universes](#skol).
|
[skolemization and universes](#skol).
|
||||||
|
|
||||||
## Causal tracking
|
## Causal tracking
|
||||||
|
|
||||||
*to be written* -- describe how we can extend the values of a variable
|
*to be written* – describe how we can extend the values of a variable
|
||||||
with causal tracking etc
|
with causal tracking etc
|
||||||
|
|
||||||
<a name="skol"></a>
|
<a name="skol"></a>
|
||||||
|
|
@ -133,7 +133,7 @@ bound in the supertype and **skolemizing** them: this means that we
|
||||||
replace them with
|
replace them with
|
||||||
[universally quantified](appendix/background.html#quantified)
|
[universally quantified](appendix/background.html#quantified)
|
||||||
representatives, written like `!1`. We call these regions "skolemized
|
representatives, written like `!1`. We call these regions "skolemized
|
||||||
regions" -- they represent, basically, "some unknown region".
|
regions" – they represent, basically, "some unknown region".
|
||||||
|
|
||||||
Once we've done that replacement, we have the following relation:
|
Once we've done that replacement, we have the following relation:
|
||||||
|
|
||||||
|
|
@ -156,9 +156,9 @@ we swap the left and right here):
|
||||||
```
|
```
|
||||||
|
|
||||||
According to the basic subtyping rules for a reference, this will be
|
According to the basic subtyping rules for a reference, this will be
|
||||||
true if `'!1: 'static`. That is -- if "some unknown region `!1`" lives
|
true if `'!1: 'static`. That is – if "some unknown region `!1`" lives
|
||||||
outlives `'static`. Now, this *might* be true -- after all, `'!1`
|
outlives `'static`. Now, this *might* be true – after all, `'!1`
|
||||||
could be `'static` -- but we don't *know* that it's true. So this
|
could be `'static` – but we don't *know* that it's true. So this
|
||||||
should yield up an error (eventually).
|
should yield up an error (eventually).
|
||||||
|
|
||||||
### What is a universe
|
### What is a universe
|
||||||
|
|
@ -238,8 +238,8 @@ not U1.
|
||||||
**Giving existential variables a universe.** Now that we have this
|
**Giving existential variables a universe.** Now that we have this
|
||||||
notion of universes, we can use it to extend our type-checker and
|
notion of universes, we can use it to extend our type-checker and
|
||||||
things to prevent illegal names from leaking out. The idea is that we
|
things to prevent illegal names from leaking out. The idea is that we
|
||||||
give each inference (existential) variable -- whether it be a type or
|
give each inference (existential) variable – whether it be a type or
|
||||||
a lifetime -- a universe. That variable's value can then only
|
a lifetime – a universe. That variable's value can then only
|
||||||
reference names visible from that universe. So for example is a
|
reference names visible from that universe. So for example is a
|
||||||
lifetime variable is created in U0, then it cannot be assigned a value
|
lifetime variable is created in U0, then it cannot be assigned a value
|
||||||
of `!1` or `!2`, because those names are not visible from the universe
|
of `!1` or `!2`, because those names are not visible from the universe
|
||||||
|
|
@ -247,7 +247,7 @@ U0.
|
||||||
|
|
||||||
**Representing universes with just a counter.** You might be surprised
|
**Representing universes with just a counter.** You might be surprised
|
||||||
to see that the compiler doesn't keep track of a full tree of
|
to see that the compiler doesn't keep track of a full tree of
|
||||||
universes. Instead, it just keeps a counter -- and, to determine if
|
universes. Instead, it just keeps a counter – and, to determine if
|
||||||
one universe can see another one, it just checks if the index is
|
one universe can see another one, it just checks if the index is
|
||||||
greater. For example, U2 can see U0 because 2 >= 0. But U0 cannot see
|
greater. For example, U2 can see U0 because 2 >= 0. But U0 cannot see
|
||||||
U2, because 0 >= 2 is false.
|
U2, because 0 >= 2 is false.
|
||||||
|
|
@ -323,12 +323,12 @@ Now there are two ways that could happen. First, if `U(V1)` can see
|
||||||
the universe `x` (i.e., `x <= U(V1)`), then we can just add `skol(x)`
|
the universe `x` (i.e., `x <= U(V1)`), then we can just add `skol(x)`
|
||||||
to `value(V1)` and be done. But if not, then we have to approximate:
|
to `value(V1)` and be done. But if not, then we have to approximate:
|
||||||
we may not know what set of elements `skol(x)` represents, but we
|
we may not know what set of elements `skol(x)` represents, but we
|
||||||
should be able to compute some sort of **upper bound** B for it --
|
should be able to compute some sort of **upper bound** B for it –
|
||||||
some region B that outlives `skol(x)`. For now, we'll just use
|
some region B that outlives `skol(x)`. For now, we'll just use
|
||||||
`'static` for that (since it outlives everything) -- in the future, we
|
`'static` for that (since it outlives everything) – in the future, we
|
||||||
can sometimes be smarter here (and in fact we have code for doing this
|
can sometimes be smarter here (and in fact we have code for doing this
|
||||||
already in other contexts). Moreover, since `'static` is in the root
|
already in other contexts). Moreover, since `'static` is in the root
|
||||||
universe U0, we know that all variables can see it -- so basically if
|
universe U0, we know that all variables can see it – so basically if
|
||||||
we find that `value(V2)` contains `skol(x)` for some universe `x`
|
we find that `value(V2)` contains `skol(x)` for some universe `x`
|
||||||
that `V1` can't see, then we force `V1` to `'static`.
|
that `V1` can't see, then we force `V1` to `'static`.
|
||||||
|
|
||||||
|
|
@ -398,8 +398,8 @@ outlives relationships are satisfied. Then we would go to the "check
|
||||||
universal regions" portion of the code, which would test that no
|
universal regions" portion of the code, which would test that no
|
||||||
universal region grew too large.
|
universal region grew too large.
|
||||||
|
|
||||||
In this case, `V1` *did* grow too large -- it is not known to outlive
|
In this case, `V1` *did* grow too large – it is not known to outlive
|
||||||
`end('static)`, nor any of the CFG -- so we would report an error.
|
`end('static)`, nor any of the CFG – so we would report an error.
|
||||||
|
|
||||||
## Another example
|
## Another example
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
The MIR visitor is a convenient tool for traversing the MIR and either
|
The MIR visitor is a convenient tool for traversing the MIR and either
|
||||||
looking for things or making changes to it. The visitor traits are
|
looking for things or making changes to it. The visitor traits are
|
||||||
defined in [the `rustc::mir::visit` module][m-v] -- there are two of
|
defined in [the `rustc::mir::visit` module][m-v] – there are two of
|
||||||
them, generated via a single macro: `Visitor` (which operates on a
|
them, generated via a single macro: `Visitor` (which operates on a
|
||||||
`&Mir` and gives back shared references) and `MutVisitor` (which
|
`&Mir` and gives back shared references) and `MutVisitor` (which
|
||||||
operates on a `&mut Mir` and gives back mutable references).
|
operates on a `&mut Mir` and gives back mutable references).
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ Rust compiler is current transitioning from a traditional "pass-based"
|
||||||
setup to a "demand-driven" system. **The Compiler Query System is the
|
setup to a "demand-driven" system. **The Compiler Query System is the
|
||||||
key to our new demand-driven organization.** The idea is pretty
|
key to our new demand-driven organization.** The idea is pretty
|
||||||
simple. You have various queries that compute things about the input
|
simple. You have various queries that compute things about the input
|
||||||
-- for example, there is a query called `type_of(def_id)` that, given
|
– for example, there is a query called `type_of(def_id)` that, given
|
||||||
the def-id of some item, will compute the type of that item and return
|
the def-id of some item, will compute the type of that item and return
|
||||||
it to you.
|
it to you.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ considered an ideal setup.
|
||||||
|
|
||||||
[`src/test/run-pass`]: https://github.com/rust-lang/rust/tree/master/src/test/run-pass/
|
[`src/test/run-pass`]: https://github.com/rust-lang/rust/tree/master/src/test/run-pass/
|
||||||
|
|
||||||
For regression tests -- basically, some random snippet of code that
|
For regression tests – basically, some random snippet of code that
|
||||||
came in from the internet -- we often just name the test after the
|
came in from the internet – we often just name the test after the
|
||||||
issue. For example, `src/test/run-pass/issue-12345.rs`. If possible,
|
issue. For example, `src/test/run-pass/issue-12345.rs`. If possible,
|
||||||
though, it is better if you can put the test into a directory that
|
though, it is better if you can put the test into a directory that
|
||||||
helps identify what piece of code is being tested here (e.g.,
|
helps identify what piece of code is being tested here (e.g.,
|
||||||
|
|
@ -267,9 +267,9 @@ can also make UI tests where compilation is expected to succeed, and
|
||||||
you can even run the resulting program. Just add one of the following
|
you can even run the resulting program. Just add one of the following
|
||||||
[header commands](#header_commands):
|
[header commands](#header_commands):
|
||||||
|
|
||||||
- `// compile-pass` -- compilation should succeed but do
|
- `// compile-pass` – compilation should succeed but do
|
||||||
not run the resulting binary
|
not run the resulting binary
|
||||||
- `// run-pass` -- compilation should succeed and we should run the
|
- `// run-pass` – compilation should succeed and we should run the
|
||||||
resulting binary
|
resulting binary
|
||||||
|
|
||||||
<a name="bless"></a>
|
<a name="bless"></a>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ on [how to run tests](./tests/running.html#ui) as well as
|
||||||
The compiletest tests are located in the tree in the [`src/test`]
|
The compiletest tests are located in the tree in the [`src/test`]
|
||||||
directory. Immediately within you will see a series of subdirectories
|
directory. Immediately within you will see a series of subdirectories
|
||||||
(e.g. `ui`, `run-make`, and so forth). Each of those directories is
|
(e.g. `ui`, `run-make`, and so forth). Each of those directories is
|
||||||
called a **test suite** -- they house a group of tests that are run in
|
called a **test suite** – they house a group of tests that are run in
|
||||||
a distinct mode.
|
a distinct mode.
|
||||||
|
|
||||||
[`src/test`]: https://github.com/rust-lang/rust/tree/master/src/test
|
[`src/test`]: https://github.com/rust-lang/rust/tree/master/src/test
|
||||||
|
|
@ -24,31 +24,31 @@ Here is a brief summary of the test suites as of this writing and what
|
||||||
they mean. In some cases, the test suites are linked to parts of the manual
|
they mean. In some cases, the test suites are linked to parts of the manual
|
||||||
that give more details.
|
that give more details.
|
||||||
|
|
||||||
- [`ui`](./tests/adding.html#ui) -- tests that check the exact
|
- [`ui`](./tests/adding.html#ui) – tests that check the exact
|
||||||
stdout/stderr from compilation and/or running the test
|
stdout/stderr from compilation and/or running the test
|
||||||
- `run-pass` -- tests that are expected to compile and execute
|
- `run-pass` – tests that are expected to compile and execute
|
||||||
successfully (no panics)
|
successfully (no panics)
|
||||||
- `run-pass-valgrind` -- tests that ought to run with valgrind
|
- `run-pass-valgrind` – tests that ought to run with valgrind
|
||||||
- `run-fail` -- tests that are expected to compile but then panic
|
- `run-fail` – tests that are expected to compile but then panic
|
||||||
during execution
|
during execution
|
||||||
- `compile-fail` -- tests that are expected to fail compilation.
|
- `compile-fail` – tests that are expected to fail compilation.
|
||||||
- `parse-fail` -- tests that are expected to fail to parse
|
- `parse-fail` – tests that are expected to fail to parse
|
||||||
- `pretty` -- tests targeting the Rust "pretty printer", which
|
- `pretty` – tests targeting the Rust "pretty printer", which
|
||||||
generates valid Rust code from the AST
|
generates valid Rust code from the AST
|
||||||
- `debuginfo` -- tests that run in gdb or lldb and query the debug info
|
- `debuginfo` – tests that run in gdb or lldb and query the debug info
|
||||||
- `codegen` -- tests that compile and then test the generated LLVM
|
- `codegen` – tests that compile and then test the generated LLVM
|
||||||
code to make sure that the optimizations we want are taking effect.
|
code to make sure that the optimizations we want are taking effect.
|
||||||
- `mir-opt` -- tests that check parts of the generated MIR to make
|
- `mir-opt` – tests that check parts of the generated MIR to make
|
||||||
sure we are building things correctly or doing the optimizations we
|
sure we are building things correctly or doing the optimizations we
|
||||||
expect.
|
expect.
|
||||||
- `incremental` -- tests for incremental compilation, checking that
|
- `incremental` – tests for incremental compilation, checking that
|
||||||
when certain modifications are performed, we are able to reuse the
|
when certain modifications are performed, we are able to reuse the
|
||||||
results from previous compilations.
|
results from previous compilations.
|
||||||
- `run-make` -- tests that basically just execute a `Makefile`; the
|
- `run-make` – tests that basically just execute a `Makefile`; the
|
||||||
ultimate in flexibility but quite annoying to write.
|
ultimate in flexibility but quite annoying to write.
|
||||||
- `rustdoc` -- tests for rustdoc, making sure that the generated files
|
- `rustdoc` – tests for rustdoc, making sure that the generated files
|
||||||
contain the expected documentation.
|
contain the expected documentation.
|
||||||
- `*-fulldeps` -- same as above, but indicates that the test depends
|
- `*-fulldeps` – same as above, but indicates that the test depends
|
||||||
on things other than `libstd` (and hence those things must be built)
|
on things other than `libstd` (and hence those things must be built)
|
||||||
|
|
||||||
## Other Tests
|
## Other Tests
|
||||||
|
|
@ -56,44 +56,44 @@ that give more details.
|
||||||
The Rust build system handles running tests for various other things,
|
The Rust build system handles running tests for various other things,
|
||||||
including:
|
including:
|
||||||
|
|
||||||
- **Tidy** -- This is a custom tool used for validating source code
|
- **Tidy** – This is a custom tool used for validating source code
|
||||||
style and formatting conventions, such as rejecting long lines.
|
style and formatting conventions, such as rejecting long lines.
|
||||||
There is more information in the
|
There is more information in the
|
||||||
[section on coding conventions](./conventions.html#formatting).
|
[section on coding conventions](./conventions.html#formatting).
|
||||||
|
|
||||||
Example: `./x.py test src/tools/tidy`
|
Example: `./x.py test src/tools/tidy`
|
||||||
|
|
||||||
- **Unittests** -- The Rust standard library and many of the Rust packages
|
- **Unittests** – The Rust standard library and many of the Rust packages
|
||||||
include typical Rust `#[test]` unittests. Under the hood, `x.py` will run
|
include typical Rust `#[test]` unittests. Under the hood, `x.py` will run
|
||||||
`cargo test` on each package to run all the tests.
|
`cargo test` on each package to run all the tests.
|
||||||
|
|
||||||
Example: `./x.py test src/libstd`
|
Example: `./x.py test src/libstd`
|
||||||
|
|
||||||
- **Doctests** -- Example code embedded within Rust documentation is executed
|
- **Doctests** – Example code embedded within Rust documentation is executed
|
||||||
via `rustdoc --test`. Examples:
|
via `rustdoc --test`. Examples:
|
||||||
|
|
||||||
`./x.py test src/doc` -- Runs `rustdoc --test` for all documentation in
|
`./x.py test src/doc` – Runs `rustdoc --test` for all documentation in
|
||||||
`src/doc`.
|
`src/doc`.
|
||||||
|
|
||||||
`./x.py test --doc src/libstd` -- Runs `rustdoc --test` on the standard
|
`./x.py test --doc src/libstd` – Runs `rustdoc --test` on the standard
|
||||||
library.
|
library.
|
||||||
|
|
||||||
- **Linkchecker** -- A small tool for verifying `href` links within
|
- **Linkchecker** – A small tool for verifying `href` links within
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
Example: `./x.py test src/tools/linkchecker`
|
Example: `./x.py test src/tools/linkchecker`
|
||||||
|
|
||||||
- **Distcheck** -- This verifies that the source distribution tarball created
|
- **Distcheck** – This verifies that the source distribution tarball created
|
||||||
by the build system will unpack, build, and run all tests.
|
by the build system will unpack, build, and run all tests.
|
||||||
|
|
||||||
Example: `./x.py test distcheck`
|
Example: `./x.py test distcheck`
|
||||||
|
|
||||||
- **Tool tests** -- Packages that are included with Rust have all of their
|
- **Tool tests** – Packages that are included with Rust have all of their
|
||||||
tests run as well (typically by running `cargo test` within their
|
tests run as well (typically by running `cargo test` within their
|
||||||
directory). This includes things such as cargo, clippy, rustfmt, rls, miri,
|
directory). This includes things such as cargo, clippy, rustfmt, rls, miri,
|
||||||
bootstrap (testing the Rust build system itself), etc.
|
bootstrap (testing the Rust build system itself), etc.
|
||||||
|
|
||||||
- **Cargotest** -- This is a small tool which runs `cargo test` on a few
|
- **Cargotest** – This is a small tool which runs `cargo test` on a few
|
||||||
significant projects (such as `servo`, `ripgrep`, `tokei`, etc.) just to
|
significant projects (such as `servo`, `ripgrep`, `tokei`, etc.) just to
|
||||||
ensure there aren't any significant regressions.
|
ensure there aren't any significant regressions.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Running tests
|
# Running tests
|
||||||
|
|
||||||
You can run the tests using `x.py`. The most basic command -- which
|
You can run the tests using `x.py`. The most basic command – which
|
||||||
you will almost never want to use! -- is as follows:
|
you will almost never want to use! – is as follows:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
> ./x.py test
|
> ./x.py test
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ When a trait defines an associated type (e.g.,
|
||||||
[the `Item` type in the `IntoIterator` trait][intoiter-item]), that
|
[the `Item` type in the `IntoIterator` trait][intoiter-item]), that
|
||||||
type can be referenced by the user using an **associated type
|
type can be referenced by the user using an **associated type
|
||||||
projection** like `<Option<u32> as IntoIterator>::Item`. (Often,
|
projection** like `<Option<u32> as IntoIterator>::Item`. (Often,
|
||||||
though, people will use the shorthand syntax `T::Item` -- presently,
|
though, people will use the shorthand syntax `T::Item` – presently,
|
||||||
that syntax is expanded during
|
that syntax is expanded during
|
||||||
["type collection"](./type-checking.html) into the explicit form,
|
["type collection"](./type-checking.html) into the explicit form,
|
||||||
though that is something we may want to change in the future.)
|
though that is something we may want to change in the future.)
|
||||||
|
|
@ -24,8 +24,8 @@ though that is something we may want to change in the future.)
|
||||||
|
|
||||||
<a name="normalize"></a>
|
<a name="normalize"></a>
|
||||||
|
|
||||||
In some cases, associated type projections can be **normalized** --
|
In some cases, associated type projections can be **normalized** –
|
||||||
that is, simplified -- based on the types given in an impl. So, to
|
that is, simplified – based on the types given in an impl. So, to
|
||||||
continue with our example, the impl of `IntoIterator` for `Option<T>`
|
continue with our example, the impl of `IntoIterator` for `Option<T>`
|
||||||
declares (among other things) that `Item = T`:
|
declares (among other things) that `Item = T`:
|
||||||
|
|
||||||
|
|
@ -39,9 +39,9 @@ impl<T> IntoIterator for Option<T> {
|
||||||
This means we can normalize the projection `<Option<u32> as
|
This means we can normalize the projection `<Option<u32> as
|
||||||
IntoIterator>::Item` to just `u32`.
|
IntoIterator>::Item` to just `u32`.
|
||||||
|
|
||||||
In this case, the projection was a "monomorphic" one -- that is, it
|
In this case, the projection was a "monomorphic" one – that is, it
|
||||||
did not have any type parameters. Monomorphic projections are special
|
did not have any type parameters. Monomorphic projections are special
|
||||||
because they can **always** be fully normalized -- but often we can
|
because they can **always** be fully normalized – but often we can
|
||||||
normalize other associated type projections as well. For example,
|
normalize other associated type projections as well. For example,
|
||||||
`<Option<?T> as IntoIterator>::Item` (where `?T` is an inference
|
`<Option<?T> as IntoIterator>::Item` (where `?T` is an inference
|
||||||
variable) can be normalized to just `?T`.
|
variable) can be normalized to just `?T`.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Canonical queries
|
# Canonical queries
|
||||||
|
|
||||||
The "start" of the trait system is the **canonical query** (these are
|
The "start" of the trait system is the **canonical query** (these are
|
||||||
both queries in the more general sense of the word -- something you
|
both queries in the more general sense of the word – something you
|
||||||
would like to know the answer to -- and in the
|
would like to know the answer to – and in the
|
||||||
[rustc-specific sense](./query.html)). The idea is that the type
|
[rustc-specific sense](./query.html)). The idea is that the type
|
||||||
checker or other parts of the system, may in the course of doing their
|
checker or other parts of the system, may in the course of doing their
|
||||||
thing want to know whether some trait is implemented for some type
|
thing want to know whether some trait is implemented for some type
|
||||||
|
|
@ -35,7 +35,7 @@ solver is finding **all possible** instantiations of your query that
|
||||||
are true. In this case, if we instantiate `?U = [i32]`, then the query
|
are true. In this case, if we instantiate `?U = [i32]`, then the query
|
||||||
is true (note that a traditional Prolog interface does not, directly,
|
is true (note that a traditional Prolog interface does not, directly,
|
||||||
tell us a value for `?U`, but we can infer one by unifying the
|
tell us a value for `?U`, but we can infer one by unifying the
|
||||||
response with our original query -- Rust's solver gives back a
|
response with our original query – Rust's solver gives back a
|
||||||
substitution instead). If we were to hit `y`, the solver might then
|
substitution instead). If we were to hit `y`, the solver might then
|
||||||
give us another possible answer:
|
give us another possible answer:
|
||||||
|
|
||||||
|
|
@ -135,7 +135,7 @@ we did find. It consists of four parts:
|
||||||
[section on handling regions in traits](./traits/regions.html) for
|
[section on handling regions in traits](./traits/regions.html) for
|
||||||
more details.
|
more details.
|
||||||
- **Value:** The query result also comes with a value of type `T`. For
|
- **Value:** The query result also comes with a value of type `T`. For
|
||||||
some specialized queries -- like normalizing associated types --
|
some specialized queries – like normalizing associated types –
|
||||||
this is used to carry back an extra result, but it's often just
|
this is used to carry back an extra result, but it's often just
|
||||||
`()`.
|
`()`.
|
||||||
|
|
||||||
|
|
@ -187,8 +187,8 @@ for example:
|
||||||
Therefore, the result we get back would be as follows (I'm going to
|
Therefore, the result we get back would be as follows (I'm going to
|
||||||
ignore region constraints and the "value"):
|
ignore region constraints and the "value"):
|
||||||
|
|
||||||
- Certainty: `Ambiguous` -- we're not sure yet if this holds
|
- Certainty: `Ambiguous` – we're not sure yet if this holds
|
||||||
- Var values: `[?T = ?T, ?U = ?U]` -- we learned nothing about the values of
|
- Var values: `[?T = ?T, ?U = ?U]` – we learned nothing about the values of
|
||||||
the variables
|
the variables
|
||||||
|
|
||||||
In short, the query result says that it is too soon to say much about
|
In short, the query result says that it is too soon to say much about
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ form of `X` would be `(?0, ?1)`, where `?0` and `?1` represent these
|
||||||
**canonical placeholders**. Note that the type `Y = (?U, ?T)` also
|
**canonical placeholders**. Note that the type `Y = (?U, ?T)` also
|
||||||
canonicalizes to `(?0, ?1)`. But the type `Z = (?T, ?T)` would
|
canonicalizes to `(?0, ?1)`. But the type `Z = (?T, ?T)` would
|
||||||
canonicalize to `(?0, ?0)` (as would `(?U, ?U)`). In other words, the
|
canonicalize to `(?0, ?0)` (as would `(?U, ?U)`). In other words, the
|
||||||
exact identity of the inference variables is not important -- unless
|
exact identity of the inference variables is not important – unless
|
||||||
they are repeated.
|
they are repeated.
|
||||||
|
|
||||||
We use this to improve caching as well as to detect cycles and other
|
We use this to improve caching as well as to detect cycles and other
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ Implemented(Foo: Send) :-
|
||||||
|
|
||||||
As you can probably imagine, proving that `Option<Box<Foo>>: Send` is
|
As you can probably imagine, proving that `Option<Box<Foo>>: Send` is
|
||||||
going to wind up circularly requiring us to prove that `Foo: Send`
|
going to wind up circularly requiring us to prove that `Foo: Send`
|
||||||
again. So this would be an example where we wind up in a cycle -- but
|
again. So this would be an example where we wind up in a cycle – but
|
||||||
that's ok, we *do* consider `Foo: Send` to hold, even though it
|
that's ok, we *do* consider `Foo: Send` to hold, even though it
|
||||||
references itself.
|
references itself.
|
||||||
|
|
||||||
|
|
@ -219,4 +219,4 @@ as described in the section on [implied bounds].
|
||||||
Some topics yet to be written:
|
Some topics yet to be written:
|
||||||
|
|
||||||
- Elaborate on the proof procedure
|
- Elaborate on the proof procedure
|
||||||
- SLG solving -- introduce negative reasoning
|
- SLG solving – introduce negative reasoning
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ Trait solving is based around a few key ideas:
|
||||||
whether types are equal.
|
whether types are equal.
|
||||||
- [Region constraints](./traits/regions.html), which are accumulated
|
- [Region constraints](./traits/regions.html), which are accumulated
|
||||||
during trait solving but mostly ignored. This means that trait
|
during trait solving but mostly ignored. This means that trait
|
||||||
solving effectively ignores the precise regions involved, always --
|
solving effectively ignores the precise regions involved, always –
|
||||||
but we still remember the constraints on them so that those
|
but we still remember the constraints on them so that those
|
||||||
constraints can be checked by thet type checker.
|
constraints can be checked by thet type checker.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ created in the [`rustc_traits::lowering`][lowering] module.
|
||||||
|
|
||||||
## The `program_clauses_for` query
|
## The `program_clauses_for` query
|
||||||
|
|
||||||
The main entry point is the `program_clauses_for` [query], which --
|
The main entry point is the `program_clauses_for` [query], which –
|
||||||
given a def-id -- produces a set of Chalk program clauses. These
|
given a def-id – produces a set of Chalk program clauses. These
|
||||||
queries are tested using a
|
queries are tested using a
|
||||||
[dedicated unit-testing mechanism, described below](#unit-tests). The
|
[dedicated unit-testing mechanism, described below](#unit-tests). The
|
||||||
query is invoked on a `DefId` that identifies something like a trait,
|
query is invoked on a `DefId` that identifies something like a trait,
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,11 @@ from the Rust syntax into goals.
|
||||||
In addition, in the rules below, we sometimes do some transformations
|
In addition, in the rules below, we sometimes do some transformations
|
||||||
on the lowered where clauses, as defined here:
|
on the lowered where clauses, as defined here:
|
||||||
|
|
||||||
- `FromEnv(WC)` -- this indicates that:
|
- `FromEnv(WC)` – this indicates that:
|
||||||
- `Implemented(TraitRef)` becomes `FromEnv(TraitRef)`
|
- `Implemented(TraitRef)` becomes `FromEnv(TraitRef)`
|
||||||
- `ProjectionEq(Projection = Ty)` becomes `FromEnv(Projection = Ty)`
|
- `ProjectionEq(Projection = Ty)` becomes `FromEnv(Projection = Ty)`
|
||||||
- other where-clauses are left intact
|
- other where-clauses are left intact
|
||||||
- `WellFormed(WC)` -- this indicates that:
|
- `WellFormed(WC)` – this indicates that:
|
||||||
- `Implemented(TraitRef)` becomes `WellFormed(TraitRef)`
|
- `Implemented(TraitRef)` becomes `WellFormed(TraitRef)`
|
||||||
- `ProjectionEq(Projection = Ty)` becomes `WellFormed(Projection = Ty)`
|
- `ProjectionEq(Projection = Ty)` becomes `WellFormed(Projection = Ty)`
|
||||||
|
|
||||||
|
|
@ -121,8 +121,8 @@ trait Eq: PartialEq { ... }
|
||||||
|
|
||||||
In this case, the `PartialEq` supertrait is equivalent to a `where
|
In this case, the `PartialEq` supertrait is equivalent to a `where
|
||||||
Self: PartialEq` where clause, in our simplified model. The program
|
Self: PartialEq` where clause, in our simplified model. The program
|
||||||
clause above therefore states that if we can prove `FromEnv(T: Eq)` --
|
clause above therefore states that if we can prove `FromEnv(T: Eq)` –
|
||||||
e.g., if we are in some function with `T: Eq` in its where clauses --
|
e.g., if we are in some function with `T: Eq` in its where clauses –
|
||||||
then we also know that `FromEnv(T: PartialEq)`. Thus the set of things
|
then we also know that `FromEnv(T: PartialEq)`. Thus the set of things
|
||||||
that follow from the environment are not only the **direct where
|
that follow from the environment are not only the **direct where
|
||||||
clauses** but also things that follow from them.
|
clauses** but also things that follow from them.
|
||||||
|
|
@ -169,7 +169,7 @@ have to prove each one of those:
|
||||||
- `WellFormed(T: Foo)` -- cycle, true coinductively
|
- `WellFormed(T: Foo)` -- cycle, true coinductively
|
||||||
|
|
||||||
This `WellFormed` predicate is only used when proving that impls are
|
This `WellFormed` predicate is only used when proving that impls are
|
||||||
well-formed -- basically, for each impl of some trait ref `TraitRef`,
|
well-formed – basically, for each impl of some trait ref `TraitRef`,
|
||||||
we must show that `WellFormed(TraitRef)`. This in turn justifies the
|
we must show that `WellFormed(TraitRef)`. This in turn justifies the
|
||||||
implied bounds rules that allow us to extend the set of `FromEnv`
|
implied bounds rules that allow us to extend the set of `FromEnv`
|
||||||
items.
|
items.
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ One of the first observations is that the Rust trait system is
|
||||||
basically a kind of logic. As such, we can map our struct, trait, and
|
basically a kind of logic. As such, we can map our struct, trait, and
|
||||||
impl declarations into logical inference rules. For the most part,
|
impl declarations into logical inference rules. For the most part,
|
||||||
these are basically Horn clauses, though we'll see that to capture the
|
these are basically Horn clauses, though we'll see that to capture the
|
||||||
full richness of Rust -- and in particular to support generic
|
full richness of Rust – and in particular to support generic
|
||||||
programming -- we have to go a bit further than standard Horn clauses.
|
programming – we have to go a bit further than standard Horn clauses.
|
||||||
|
|
||||||
To see how this mapping works, let's start with an example. Imagine
|
To see how this mapping works, let's start with an example. Imagine
|
||||||
we declare a trait and a few impls, like so:
|
we declare a trait and a few impls, like so:
|
||||||
|
|
@ -38,8 +38,8 @@ Clone(Vec<?T>) :- Clone(?T).
|
||||||
// Or, put another way, B implies A.
|
// Or, put another way, B implies A.
|
||||||
```
|
```
|
||||||
|
|
||||||
In Prolog terms, we might say that `Clone(Foo)` -- where `Foo` is some
|
In Prolog terms, we might say that `Clone(Foo)` – where `Foo` is some
|
||||||
Rust type -- is a *predicate* that represents the idea that the type
|
Rust type – is a *predicate* that represents the idea that the type
|
||||||
`Foo` implements `Clone`. These rules are **program clauses**; they
|
`Foo` implements `Clone`. These rules are **program clauses**; they
|
||||||
state the conditions under which that predicate can be proven (i.e.,
|
state the conditions under which that predicate can be proven (i.e.,
|
||||||
considered true). So the first rule just says "Clone is implemented
|
considered true). So the first rule just says "Clone is implemented
|
||||||
|
|
@ -162,7 +162,7 @@ notation but a bit Rustified. Anyway, the problem is that standard
|
||||||
Horn clauses don't allow universal quantification (`forall`) or
|
Horn clauses don't allow universal quantification (`forall`) or
|
||||||
implication (`if`) in goals (though many Prolog engines do support
|
implication (`if`) in goals (though many Prolog engines do support
|
||||||
them, as an extension). For this reason, we need to accept something
|
them, as an extension). For this reason, we need to accept something
|
||||||
called "first-order hereditary harrop" (FOHH) clauses -- this long
|
called "first-order hereditary harrop" (FOHH) clauses – this long
|
||||||
name basically means "standard Horn clauses with `forall` and `if` in
|
name basically means "standard Horn clauses with `forall` and `if` in
|
||||||
the body". But it's nice to know the proper name, because there is a
|
the body". But it's nice to know the proper name, because there is a
|
||||||
lot of work describing how to efficiently handle FOHH clauses; see for
|
lot of work describing how to efficiently handle FOHH clauses; see for
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ draws heavily on the [type inference] and [trait solving].)
|
||||||
|
|
||||||
Type "collection" is the process of converting the types found in the HIR
|
Type "collection" is the process of converting the types found in the HIR
|
||||||
(`hir::Ty`), which represent the syntactic things that the user wrote, into the
|
(`hir::Ty`), which represent the syntactic things that the user wrote, into the
|
||||||
**internal representation** used by the compiler (`Ty<'tcx>`) -- we also do
|
**internal representation** used by the compiler (`Ty<'tcx>`) – we also do
|
||||||
similar conversions for where-clauses and other bits of the function signature.
|
similar conversions for where-clauses and other bits of the function signature.
|
||||||
|
|
||||||
To try and get a sense for the difference, consider this function:
|
To try and get a sense for the difference, consider this function:
|
||||||
|
|
@ -30,7 +30,7 @@ they encode the path somewhat differently. But once they are "collected" into
|
||||||
|
|
||||||
Collection is defined as a bundle of [queries] for computing information about
|
Collection is defined as a bundle of [queries] for computing information about
|
||||||
the various functions, traits, and other items in the crate being compiled.
|
the various functions, traits, and other items in the crate being compiled.
|
||||||
Note that each of these queries is concerned with *interprocedural* things --
|
Note that each of these queries is concerned with *interprocedural* things –
|
||||||
for example, for a function definition, collection will figure out the type and
|
for example, for a function definition, collection will figure out the type and
|
||||||
signature of the function, but it will not visit the *body* of the function in
|
signature of the function, but it will not visit the *body* of the function in
|
||||||
any way, nor examine type annotations on local variables (that's the job of
|
any way, nor examine type annotations on local variables (that's the job of
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ one could interpret variance and trait matching.
|
||||||
Just as with structs and enums, we can decide the subtyping
|
Just as with structs and enums, we can decide the subtyping
|
||||||
relationship between two object types `&Trait<A>` and `&Trait<B>`
|
relationship between two object types `&Trait<A>` and `&Trait<B>`
|
||||||
based on the relationship of `A` and `B`. Note that for object
|
based on the relationship of `A` and `B`. Note that for object
|
||||||
types we ignore the `Self` type parameter -- it is unknown, and
|
types we ignore the `Self` type parameter – it is unknown, and
|
||||||
the nature of dynamic dispatch ensures that we will always call a
|
the nature of dynamic dispatch ensures that we will always call a
|
||||||
function that is expected the appropriate `Self` type. However, we
|
function that is expected the appropriate `Self` type. However, we
|
||||||
must be careful with the other type parameters, or else we could
|
must be careful with the other type parameters, or else we could
|
||||||
|
|
@ -274,8 +274,8 @@ These conditions are satisfied and so we are happy.
|
||||||
|
|
||||||
### Variance and associated types
|
### Variance and associated types
|
||||||
|
|
||||||
Traits with associated types -- or at minimum projection
|
Traits with associated types – or at minimum projection
|
||||||
expressions -- must be invariant with respect to all of their
|
expressions – must be invariant with respect to all of their
|
||||||
inputs. To see why this makes sense, consider what subtyping for a
|
inputs. To see why this makes sense, consider what subtyping for a
|
||||||
trait reference means:
|
trait reference means:
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue