Hard-wrapped lines that are too long.
This commit is contained in:
parent
34ec755d27
commit
b3d8fba198
|
|
@ -14,7 +14,7 @@ for file in "$@" ; do
|
|||
(( inside_block = !$inside_block ))
|
||||
continue
|
||||
fi
|
||||
if ! (( $inside_block )) && ! [[ "$line" =~ " | "|"://"|\[\^[^\ ]+\]: ]] && (( "${#line}" > $MAX_LINE_LENGTH )) ; then
|
||||
if ! (( $inside_block )) && ! [[ "$line" =~ " | "|"-|-"|"://"|\[\^[^\ ]+\]: ]] && (( "${#line}" > $MAX_LINE_LENGTH )) ; then
|
||||
(( bad_lines++ ))
|
||||
echo -e "\t$line_no : $line"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
- [The compiler testing framework](./tests/intro.md)
|
||||
- [Running tests](./tests/running.md)
|
||||
- [Adding new tests](./tests/adding.md)
|
||||
- [Using `compiletest` + commands to control test execution](./compiletest.md)
|
||||
- [Using `compiletest` + commands to control test
|
||||
execution](./compiletest.md)
|
||||
- [Walkthrough: a typical contribution](./walkthrough.md)
|
||||
- [High-level overview of the compiler source](./high-level-overview.md)
|
||||
- [The Rustc Driver](./rustc-driver.md)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
# `compiletest`
|
||||
## Introduction
|
||||
`compiletest` is the main test harness of the Rust test suite. It allows test authors to organize large numbers of tests (the
|
||||
Rust compiler has many thousands), efficient test execution (parallel execution is supported), and allows the test author to
|
||||
configure behavior and expected results of both individual and groups of tests.
|
||||
`compiletest` is the main test harness of the Rust test suite. It allows
|
||||
test authors to organize large numbers of tests (the Rust compiler has many
|
||||
thousands), efficient test execution (parallel execution is supported), and
|
||||
allows the test author to configure behavior and expected results of both
|
||||
individual and groups of tests.
|
||||
|
||||
`compiletest` tests may check test code for success, for failure or in some cases, even failure to compile. Tests are
|
||||
typically organized as a Rust source file with annotations in comments before and/or within the test code, which serve to
|
||||
|
|
|
|||
|
|
@ -94,20 +94,21 @@ order to compile a Rust crate, these are the general steps that we
|
|||
take:
|
||||
|
||||
1. **Parsing input**
|
||||
- this processes the `.rs` files and produces the AST ("abstract syntax tree")
|
||||
- this processes the `.rs` files and produces the AST
|
||||
("abstract syntax tree")
|
||||
- the AST is defined in `syntax/ast.rs`. It is intended to match the lexical
|
||||
syntax of the Rust language quite closely.
|
||||
2. **Name resolution, macro expansion, and configuration**
|
||||
- once parsing is complete, we process the AST recursively, resolving paths
|
||||
and expanding macros. This same process also processes `#[cfg]` nodes, and hence
|
||||
may strip things out of the AST as well.
|
||||
- once parsing is complete, we process the AST recursively, resolving
|
||||
paths and expanding macros. This same process also processes `#[cfg]`
|
||||
nodes, and hence may strip things out of the AST as well.
|
||||
3. **Lowering to HIR**
|
||||
- Once name resolution completes, we convert the AST into the HIR,
|
||||
or "high-level IR". The HIR is defined in `src/librustc/hir/`; that module also includes
|
||||
the lowering code.
|
||||
- The HIR is a lightly desugared variant of the AST. It is more processed than the
|
||||
AST and more suitable for the analyses that follow. It is **not** required to match
|
||||
the syntax of the Rust language.
|
||||
or "high-level IR". The HIR is defined in `src/librustc/hir/`;
|
||||
that module also includes the lowering code.
|
||||
- The HIR is a lightly desugared variant of the AST. It is more processed
|
||||
than the AST and more suitable for the analyses that follow.
|
||||
It is **not** required to match the syntax of the Rust language.
|
||||
- As a simple example, in the **AST**, we preserve the parentheses
|
||||
that the user wrote, so `((1 + 2) + 3)` and `1 + 2 + 3` parse
|
||||
into distinct trees, even though they are equivalent. In the
|
||||
|
|
@ -125,13 +126,13 @@ take:
|
|||
the types of expressions, the way to resolve methods, and so forth.
|
||||
- After type-checking, we can do other analyses, such as privacy checking.
|
||||
4. **Lowering to MIR and post-processing**
|
||||
- Once type-checking is done, we can lower the HIR into MIR ("middle IR"), which
|
||||
is a **very** desugared version of Rust, well suited to the borrowck but also
|
||||
certain high-level optimizations.
|
||||
- Once type-checking is done, we can lower the HIR into MIR ("middle IR"),
|
||||
which is a **very** desugared version of Rust, well suited to borrowck
|
||||
but also to certain high-level optimizations.
|
||||
5. **Translation to LLVM and LLVM optimizations**
|
||||
- From MIR, we can produce LLVM IR.
|
||||
- LLVM then runs its various optimizations, which produces a number of `.o` files
|
||||
(one for each "codegen unit").
|
||||
- LLVM then runs its various optimizations, which produces a number of
|
||||
`.o` files (one for each "codegen unit").
|
||||
6. **Linking**
|
||||
- Finally, those `.o` files are linked together.
|
||||
|
||||
|
|
|
|||
38
src/hir.md
38
src/hir.md
|
|
@ -63,23 +63,25 @@ carry around references into the HIR, but rather to carry around
|
|||
*identifier numbers* (or just "ids"). Right now, you will find four
|
||||
sorts of identifiers in active use:
|
||||
|
||||
- `DefId` – primarily names "definitions" or top-level items.
|
||||
- You can think of a `DefId` as shorthand for a very explicit and complete
|
||||
path, like `std::collections::HashMap`. However, these paths are able to
|
||||
name things that are not nameable in normal Rust (e.g. `impl`s), and they
|
||||
also include extra information about the crate (such as its version number,
|
||||
since two versions of the same crate can co-exist).
|
||||
- A `DefId` really consists of two parts, a `CrateNum` (which identifies the
|
||||
crate) and a `DefIndex` (which indexes into a list of items that is
|
||||
maintained per crate).
|
||||
- `HirId` – combines the index of a particular item with an offset within
|
||||
that item.
|
||||
- The key point of an `HirId` is that it is *relative* to some item (which is
|
||||
named via a `DefId`).
|
||||
- `BodyId` – an absolute identifier that refers to a specific body (definition
|
||||
of a function or constant) in the crate. It is currently effectively a
|
||||
"newtype'd" `NodeId`.
|
||||
- `NodeId` – an absolute ID that identifies a single node in the HIR tree.
|
||||
- `DefId`, which primarily names "definitions" or top-level items.
|
||||
- You can think of a `DefId` as being shorthand for a very explicit
|
||||
and complete path, like `std::collections::HashMap`. However,
|
||||
these paths are able to name things that are not nameable in
|
||||
normal Rust (e.g. impls), and they also include extra information
|
||||
about the crate (such as its version number, as two versions of
|
||||
the same crate can co-exist).
|
||||
- A `DefId` really consists of two parts, a `CrateNum` (which
|
||||
identifies the crate) and a `DefIndex` (which indixes into a list
|
||||
of items that is maintained per crate).
|
||||
- `HirId`, which combines the index of a particular item with an
|
||||
offset within that item.
|
||||
- the key point of a `HirId` is that it is *relative* to some item
|
||||
(which is named via a `DefId`).
|
||||
- `BodyId`, this is an absolute identifier that refers to a specific
|
||||
body (definition of a function or constant) in the crate. It is currently
|
||||
effectively a "newtype'd" `NodeId`.
|
||||
- `NodeId`, which is an absolute id that identifies a single node in the HIR
|
||||
tree.
|
||||
- While these are still in common use, **they are being slowly phased out**.
|
||||
- Since they are absolute within the crate, adding a new node anywhere in the
|
||||
tree causes the `NodeId`s of all subsequent code in the crate to change.
|
||||
|
|
@ -119,5 +121,5 @@ of a function/closure or the definition of a constant. Bodies are
|
|||
associated with an **owner**, which is typically some kind of item
|
||||
(e.g. an `fn()` or `const`), but could also be a closure expression
|
||||
(e.g. `|x, y| x + y`). You can use the HIR map to find the body
|
||||
associated with a given `DefId` (`maybe_body_owned_by()`) or to find
|
||||
associated with a given def-id (`maybe_body_owned_by()`) or to find
|
||||
the owner of a body (`body_owner_def_id()`).
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
The compiler is built using a tool called `x.py`. You will need to
|
||||
have Python installed to run it. But before we get to that, if you're going to
|
||||
be hacking on rustc, you'll want to tweak the configuration of the compiler. The default
|
||||
configuration is oriented towards running the compiler as a user, not a developer.
|
||||
be hacking on rustc, you'll want to tweak the configuration of the compiler.
|
||||
The default configuration is oriented towards running the compiler as a user,
|
||||
not a developer.
|
||||
|
||||
### Create a config.toml
|
||||
|
||||
|
|
@ -84,15 +85,16 @@ What this command will do is the following:
|
|||
- Using this stage 1 compiler, it will build the standard library.
|
||||
(this is what the `src/libstd`) means.
|
||||
|
||||
This is just a subset of the full rustc build. The **full** rustc build (what you
|
||||
get if you just say `./x.py build`) has quite a few more steps:
|
||||
This is just a subset of the full rustc build. The **full** rustc build
|
||||
(what you get if you just say `./x.py build`) has quite a few more steps:
|
||||
|
||||
- Build stage1 rustc with stage0 compiler
|
||||
- Build libstd with stage1 compiler (up to here is the same)
|
||||
- Build rustc from `src` again, this time with the stage1 compiler (this part is new)
|
||||
- The resulting compiler here is called the "stage2" compiler
|
||||
- Build libstd with stage2 compiler
|
||||
- Build librustdoc and a bunch of other things
|
||||
- Build stage1 rustc with stage0 compiler.
|
||||
- Build libstd with stage1 compiler (up to here is the same).
|
||||
- Build rustc from `src` again, this time with the stage1 compiler
|
||||
(this part is new).
|
||||
- The resulting compiler here is called the "stage2" compiler.
|
||||
- Build libstd with stage2 compiler.
|
||||
- Build librustdoc and a bunch of other things.
|
||||
|
||||
### Creating a rustup toolchain
|
||||
|
||||
|
|
@ -126,12 +128,16 @@ LLVM version: 4.0
|
|||
|
||||
### Other x.py commands
|
||||
|
||||
Here are a few other useful x.py commands. We'll cover some of them in detail in other sections:
|
||||
Here are a few other useful x.py commands. We'll cover some of them in detail
|
||||
in other sections:
|
||||
|
||||
- Building things:
|
||||
- `./x.py clean` – clean up the build directory (`rm -rf build` works too, but then you have to rebuild LLVM)
|
||||
- `./x.py build --stage 1` – builds everything using the stage 1 compiler, not just up to libstd
|
||||
- `./x.py clean` – clean up the build directory (`rm -rf build` works too,
|
||||
but then you have to rebuild LLVM)
|
||||
- `./x.py build --stage 1` – builds everything using the stage 1 compiler,
|
||||
not just up to libstd
|
||||
- `./x.py build` – builds the stage2 compiler
|
||||
- Running tests (see the [section on running tests](./tests/running.html) for more details):
|
||||
- Running tests (see the [section on running tests](./tests/running.html) for
|
||||
more details):
|
||||
- `./x.py test --stage 1 src/libstd` – runs the `#[test]` tests from libstd
|
||||
- `./x.py test --stage 1 src/test/run-pass` – runs the `run-pass` test suite
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
The incremental compilation scheme is, in essence, a surprisingly
|
||||
simple extension to the overall query system. We'll start by describing
|
||||
a slightly simplified variant of the real thing – the "basic algorithm" – and then describe
|
||||
some possible improvements.
|
||||
a slightly simplified variant of the real thing – the "basic algorithm" –
|
||||
and then describe some possible improvements.
|
||||
|
||||
## The basic algorithm
|
||||
|
||||
|
|
@ -66,13 +66,15 @@ Try-mark-green works as follows:
|
|||
- For each query R in `reads(Q)`, we recursively demand the color
|
||||
of R using try-mark-green.
|
||||
- Note: it is important that we visit each node in `reads(Q)` in same order
|
||||
as they occurred in the original compilation. See [the section on the query DAG below](#dag).
|
||||
- If **any** of the nodes in `reads(Q)` wind up colored **red**, then Q is dirty.
|
||||
- We re-execute Q and compare the hash of its result to the hash of the result
|
||||
from the previous compilation.
|
||||
as they occurred in the original compilation. See [the section on the
|
||||
query DAG below](#dag).
|
||||
- If **any** of the nodes in `reads(Q)` wind up colored **red**, then Q is
|
||||
dirty.
|
||||
- We re-execute Q and compare the hash of its result to the hash of the
|
||||
result from the previous compilation.
|
||||
- If the hash has not changed, we can mark Q as **green** and return.
|
||||
- Otherwise, **all** of the nodes in `reads(Q)` must be **green**. In that case,
|
||||
we can color Q as **green** and return.
|
||||
- Otherwise, **all** of the nodes in `reads(Q)` must be **green**. In that
|
||||
case, we can color Q as **green** and return.
|
||||
|
||||
<a name="dag">
|
||||
|
||||
|
|
@ -85,9 +87,9 @@ by instrumenting the query execution.
|
|||
One key point is that the query DAG also tracks ordering; that is, for
|
||||
each query Q, we not only track the queries that Q reads, we track the
|
||||
**order** in which they were read. This allows try-mark-green to walk
|
||||
those queries back in the same order. This is important because once a subquery comes back as red,
|
||||
we can no longer be sure that Q will continue along the same path as before.
|
||||
That is, imagine a query like this:
|
||||
those queries back in the same order. This is important because once a
|
||||
subquery comes back as red, we can no longer be sure that Q will continue
|
||||
along the same path as before. That is, imagine a query like this:
|
||||
|
||||
```rust,ignore
|
||||
fn main_query(tcx) {
|
||||
|
|
@ -105,9 +107,10 @@ query `main_query` executes will be `subquery2`, and `subquery3` will
|
|||
not be executed at all.
|
||||
|
||||
But now imagine that in the **next** compilation, the input has
|
||||
changed such that `subquery1` returns **false**. In this case, `subquery2` would never
|
||||
execute. If try-mark-green were to visit `reads(main_query)` out of order,
|
||||
however, it might visit `subquery2` before `subquery1`, and hence execute it.
|
||||
changed such that `subquery1` returns **false**. In this case, `subquery2`
|
||||
would never execute. If try-mark-green were to visit `reads(main_query)` out
|
||||
of order, however, it might visit `subquery2` before `subquery1`, and hence
|
||||
execute it.
|
||||
This can lead to ICEs and other problems in the compiler.
|
||||
|
||||
[dep_graph]: https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph
|
||||
|
|
@ -124,8 +127,8 @@ we **also** save the results.
|
|||
|
||||
This is why the incremental algorithm separates computing the
|
||||
**color** of a node, which often does not require its value, from
|
||||
computing the **result** of a node. Computing the result is done via a simple algorithm
|
||||
like so:
|
||||
computing the **result** of a node. Computing the result is done via a simple
|
||||
algorithm like so:
|
||||
|
||||
- Check if a saved result for Q is available. If so, compute the color of Q.
|
||||
If Q is green, deserialize and return the saved result.
|
||||
|
|
|
|||
12
src/query.md
12
src/query.md
|
|
@ -74,10 +74,12 @@ match queries::type_of::try_get(tcx, DUMMY_SP, self.did) {
|
|||
}
|
||||
```
|
||||
|
||||
So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that
|
||||
you must ensure that a compiler error message is reported. You can do that in two ways:
|
||||
So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This
|
||||
means that you must ensure that a compiler error message is reported. You can
|
||||
do that in two ways:
|
||||
|
||||
The simplest is to invoke `err.emit()`. This will emit the cycle error to the user.
|
||||
The simplest is to invoke `err.emit()`. This will emit the cycle error to the
|
||||
user.
|
||||
|
||||
However, often cycles happen because of an illegal program, and you
|
||||
know at that point that an error either already has been reported or
|
||||
|
|
@ -192,8 +194,8 @@ fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. }
|
|||
|
||||
N.B. Most of the `rustc_*` crates only provide **local
|
||||
providers**. Almost all **extern providers** wind up going through the
|
||||
[`rustc_metadata` crate][rustc_metadata], which loads the information from the crate
|
||||
metadata. But in some cases there are crates that provide queries for
|
||||
[`rustc_metadata` crate][rustc_metadata], which loads the information from the
|
||||
crate metadata. But in some cases there are crates that provide queries for
|
||||
*both* local and external crates, in which case they define both a
|
||||
`provide` and a `provide_extern` function that `rustc_driver` can
|
||||
invoke.
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ structure:
|
|||
- They always begin with the [copyright notice](./conventions.html#copyright);
|
||||
- then they should have some kind of
|
||||
[comment explaining what the test is about](#explanatory_comment);
|
||||
- next, they can have one or more [header commands](#header_commands), which are special
|
||||
comments that the test interpreter knows how to interpret.
|
||||
- next, they can have one or more [header commands](#header_commands), which
|
||||
are special comments that the test interpreter knows how to interpret.
|
||||
- finally, they have the Rust source. This may have various [error
|
||||
annotations](#error_annotations) which indicate expected compilation errors or
|
||||
warnings.
|
||||
|
|
@ -28,10 +28,12 @@ rough heuristics:
|
|||
|
||||
- Some tests have specialized needs:
|
||||
- need to run gdb or lldb? use the `debuginfo` test suite
|
||||
- need to inspect LLVM IR or MIR IR? use the `codegen` or `mir-opt` test suites
|
||||
- need to inspect LLVM IR or MIR IR? use the `codegen` or `mir-opt` test
|
||||
suites
|
||||
- need to run rustdoc? Prefer a `rustdoc` test
|
||||
- need to inspect the resulting binary in some way? Then use `run-make`
|
||||
- For most other things, [a `ui` (or `ui-fulldeps`) test](#ui) is to be preferred:
|
||||
- For most other things, [a `ui` (or `ui-fulldeps`) test](#ui) is to be
|
||||
preferred:
|
||||
- `ui` tests subsume both run-pass, compile-fail, and parse-fail tests
|
||||
- in the case of warnings or errors, `ui` tests capture the full output,
|
||||
which makes it easier to review but also helps prevent "hidden" regressions
|
||||
|
|
@ -118,16 +120,22 @@ fn main() {
|
|||
These are used to ignore the test in some situations, which means the test won't
|
||||
be compiled or run.
|
||||
|
||||
* `ignore-X` where `X` is a target detail or stage will ignore the test accordingly (see below)
|
||||
* `ignore-pretty` will not compile the pretty-printed test (this is done to test the pretty-printer, but might not always work)
|
||||
* `ignore-X` where `X` is a target detail or stage will ignore the
|
||||
test accordingly (see below)
|
||||
* `ignore-pretty` will not compile the pretty-printed test (this is
|
||||
done to test the pretty-printer, but might not always work)
|
||||
* `ignore-test` always ignores the test
|
||||
* `ignore-lldb` and `ignore-gdb` will skip a debuginfo test on that debugger.
|
||||
* `ignore-lldb` and `ignore-gdb` will skip a debuginfo test on that
|
||||
debugger.
|
||||
|
||||
Some examples of `X` in `ignore-X`:
|
||||
|
||||
* Architecture: `aarch64`, `arm`, `asmjs`, `mips`, `wasm32`, `x86_64`, `x86`, ...
|
||||
* OS: `android`, `emscripten`, `freebsd`, `ios`, `linux`, `macos`, `windows`, ...
|
||||
* Environment (fourth word of the target triple): `gnu`, `msvc`, `musl`.
|
||||
* Architecture: `aarch64`, `arm`, `asmjs`, `mips`, `wasm32`, `x86_64`,
|
||||
`x86`, ...
|
||||
* OS: `android`, `emscripten`, `freebsd`, `ios`, `linux`, `macos`,
|
||||
`windows`, ...
|
||||
* Environment (fourth word of the target triple): `gnu`, `msvc`,
|
||||
`musl`.
|
||||
* Pointer width: `32bit`, `64bit`.
|
||||
* Stage: `stage0`, `stage1`, `stage2`.
|
||||
|
||||
|
|
@ -140,17 +148,20 @@ source.
|
|||
|
||||
* `min-{gdb,lldb}-version`
|
||||
* `min-llvm-version`
|
||||
* `must-compile-successfully` for UI tests, indicates that the test is supposed
|
||||
to compile, as opposed to the default where the test is supposed to error out.
|
||||
* `must-compile-successfully` for UI tests, indicates that the test is
|
||||
supposed to compile, as opposed to the default where the test is
|
||||
supposed to error out.
|
||||
* `compile-flags` passes extra command-line args to the compiler,
|
||||
e.g. `compile-flags -g` which forces debuginfo to be enabled.
|
||||
* `should-fail` indicates that the test should fail; used for "meta testing",
|
||||
where we test the compiletest program itself to check that it will generate
|
||||
errors in appropriate scenarios. This header is ignored for pretty-printer tests.
|
||||
* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X.
|
||||
Such tests are supposed to ensure that the compiler errors when usage of a gated
|
||||
feature is attempted without the proper `#![feature(X)]` tag.
|
||||
Each unstable lang feature is required to have a gate test.
|
||||
* `should-fail` indicates that the test should fail; used for "meta
|
||||
testing", where we test the compiletest program itself to check that
|
||||
it will generate errors in appropriate scenarios. This header is
|
||||
ignored for pretty-printer tests.
|
||||
* `gate-test-X` where `X` is a feature marks the test as "gate test"
|
||||
for feature X. Such tests are supposed to ensure that the compiler
|
||||
errors when usage of a gated feature is attempted without the proper
|
||||
`#![feature(X)]` tag. Each unstable lang feature is required to
|
||||
have a gate test.
|
||||
|
||||
[`header.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/header.rs
|
||||
|
||||
|
|
@ -245,8 +256,10 @@ 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
|
||||
[header commands](#header_commands):
|
||||
|
||||
- `// must-compile-successfully` -- compilation should succeed but do not run the resulting binary
|
||||
- `// run-pass` -- compilation should succeed and we should run the resulting binary
|
||||
- `// must-compile-successfully` -- compilation should succeed but do
|
||||
not run the resulting binary
|
||||
- `// run-pass` -- compilation should succeed and we should run the
|
||||
resulting binary
|
||||
|
||||
### Editing and updating the reference files
|
||||
|
||||
|
|
@ -293,7 +306,8 @@ The corresponding reference file will use the normalized output to test both
|
|||
...
|
||||
```
|
||||
|
||||
Please see [`ui/transmute/main.rs`][mrs] and [`main.stderr`][] for a concrete usage example.
|
||||
Please see [`ui/transmute/main.rs`][mrs] and [`main.stderr`][] for a
|
||||
concrete usage example.
|
||||
|
||||
[mrs]: https://github.com/rust-lang/rust/blob/master/src/test/ui/transmute/main.rs
|
||||
[`main.stderr`]: https://github.com/rust-lang/rust/blob/master/src/test/ui/transmute/main.stderr
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# The compiler testing framework
|
||||
|
||||
The Rust project runs a wide variety of different tests, orchestrated by the
|
||||
build system (`x.py test`). The main test harness for testing the compiler
|
||||
itself is a tool called compiletest (sources in the
|
||||
[`src/tools/compiletest`]). This section gives a brief overview of how the
|
||||
testing framework is setup, and then gets into some of the details on [how to
|
||||
run tests](./tests/running.html#ui) as well as [how to add new
|
||||
tests](./tests/adding.html).
|
||||
The Rust project runs a wide variety of different tests, orchestrated
|
||||
by the build system (`x.py test`). The main test harness for testing
|
||||
the compiler itself is a tool called compiletest (sources in the
|
||||
[`src/tools/compiletest`]). This section gives a brief overview of how
|
||||
the testing framework is setup, and then gets into some of the details
|
||||
on [how to run tests](./tests/running.html#ui) as well as
|
||||
[how to add new tests](./tests/adding.html).
|
||||
|
||||
[`src/tools/compiletest`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest
|
||||
|
||||
|
|
@ -24,11 +24,13 @@ 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
|
||||
that give more details.
|
||||
|
||||
- [`ui`](./tests/adding.html#ui) -- tests that check the exact stdout/stderr from compilation
|
||||
and/or running the test
|
||||
- `run-pass` -- tests that are expected to compile and execute successfully (no panics)
|
||||
- [`ui`](./tests/adding.html#ui) -- tests that check the exact
|
||||
stdout/stderr from compilation and/or running the test
|
||||
- `run-pass` -- tests that are expected to compile and execute
|
||||
successfully (no panics)
|
||||
- `run-pass-valgrind` -- tests that ought to run with valgrind
|
||||
- `run-fail` -- tests that are expected to compile but then panic during execution
|
||||
- `run-fail` -- tests that are expected to compile but then panic
|
||||
during execution
|
||||
- `compile-fail` -- tests that are expected to fail compilation.
|
||||
- `parse-fail` -- tests that are expected to fail to parse
|
||||
- `pretty` -- tests targeting the Rust "pretty printer", which
|
||||
|
|
@ -44,19 +46,20 @@ that give more details.
|
|||
results from previous compilations.
|
||||
- `run-make` -- tests that basically just execute a `Makefile`; the
|
||||
ultimate in flexibility but quite annoying to write.
|
||||
- `rustdoc` -- tests for rustdoc, making sure that the generated files contain
|
||||
the expected documentation.
|
||||
- `*-fulldeps` -- same as above, but indicates that the test depends on things other
|
||||
than `libstd` (and hence those things must be built)
|
||||
- `rustdoc` -- tests for rustdoc, making sure that the generated files
|
||||
contain the expected documentation.
|
||||
- `*-fulldeps` -- same as above, but indicates that the test depends
|
||||
on things other than `libstd` (and hence those things must be built)
|
||||
|
||||
## Other Tests
|
||||
|
||||
The Rust build system handles running tests for various other things,
|
||||
including:
|
||||
|
||||
- **Tidy** -- This is a custom tool used for validating source code style and
|
||||
formatting conventions, such as rejecting long lines. There is more
|
||||
information in the [section on coding conventions](./conventions.html#formatting).
|
||||
- **Tidy** -- This is a custom tool used for validating source code
|
||||
style and formatting conventions, such as rejecting long lines.
|
||||
There is more information in the
|
||||
[section on coding conventions](./conventions.html#formatting).
|
||||
|
||||
Example: `./x.py test src/tools/tidy`
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@ generally working correctly would be the following:
|
|||
./x.py test --stage 1 src/test/{ui,compile-fail,run-pass}
|
||||
```
|
||||
|
||||
This will run the `ui`, `compile-fail`, and `run-pass` test suites, and
|
||||
only with the stage 1 build. Of course, the choice of test suites is somewhat
|
||||
arbitrary, and may not suit the task you are doing. For example, if you are hacking
|
||||
on debuginfo, you may be better off with the debuginfo test suite:
|
||||
This will run the `ui`, `compile-fail`, and `run-pass` test suites,
|
||||
and only with the stage 1 build. Of course, the choice of test suites
|
||||
is somewhat arbitrary, and may not suit the task you are doing. For
|
||||
example, if you are hacking on debuginfo, you may be better off with
|
||||
the debuginfo test suite:
|
||||
|
||||
```bash
|
||||
./x.py test --stage 1 src/test/debuginfo
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ impl<'a> Foo<&'a isize> for AnyInt { }
|
|||
|
||||
And the question is, does `AnyInt : for<'a> Foo<&'a isize>`? We want the
|
||||
answer to be yes. The algorithm for figuring it out is closely related
|
||||
to the subtyping for higher-ranked types (which is described in [here][hrsubtype]
|
||||
to the subtyping for higher-ranked types (which is described [here][hrsubtype]
|
||||
and also in a [paper by SPJ]. If you wish to understand higher-ranked
|
||||
subtyping, we recommend you read the paper). There are a few parts:
|
||||
|
||||
|
|
@ -83,7 +83,8 @@ skolemized to `'0` and the impl trait reference is instantiated to
|
|||
like `'static == '0`. This means that the taint set for `'0` is `{'0,
|
||||
'static}`, which fails the leak check.
|
||||
|
||||
**TODO**: This is because `'static` is not a region variable but is in the taint set, right?
|
||||
**TODO**: This is because `'static` is not a region variable but is in the
|
||||
taint set, right?
|
||||
|
||||
## Higher-ranked trait obligations
|
||||
|
||||
|
|
@ -122,4 +123,5 @@ from. (This is done in `higher_ranked::plug_leaks`). We know that the
|
|||
leak check passed, so this taint set consists solely of the skolemized
|
||||
region itself plus various intermediate region variables. We then walk
|
||||
the trait-reference and convert every region in that taint set back to
|
||||
a late-bound region, so in this case we'd wind up with `Baz: for<'a> Bar<&'a isize>`.
|
||||
a late-bound region, so in this case we'd wind up with
|
||||
`Baz: for<'a> Bar<&'a isize>`.
|
||||
|
|
|
|||
|
|
@ -58,20 +58,20 @@ will then be generated in the output binary.
|
|||
|
||||
Trait resolution consists of three major parts:
|
||||
|
||||
- **Selection** is deciding how to resolve a specific obligation. For
|
||||
- **Selection**: Deciding how to resolve a specific obligation. For
|
||||
example, selection might decide that a specific obligation can be
|
||||
resolved by employing an impl which matches the `Self` type, or by
|
||||
using a parameter bound (e.g. `T: Trait`). In the case of an impl, selecting one
|
||||
resolved by employing an impl which matches the `Self` type, or by using a
|
||||
parameter bound (e.g. `T: Trait`). In the case of an impl, selecting one
|
||||
obligation can create *nested obligations* because of where clauses
|
||||
on the impl itself. It may also require evaluating those nested
|
||||
obligations to resolve ambiguities.
|
||||
|
||||
- **Fulfillment** is keeping track of which obligations
|
||||
are completely fulfilled. Basically, it is a worklist of obligations
|
||||
- **Fulfillment**: The fulfillment code is what tracks that obligations
|
||||
are completely fulfilled. Basically it is a worklist of obligations
|
||||
to be selected: once selection is successful, the obligation is
|
||||
removed from the worklist and any nested obligations are enqueued.
|
||||
|
||||
- **Coherence** checks are intended to ensure that there
|
||||
- **Coherence**: The coherence checks are intended to ensure that there
|
||||
are never overlapping impls, where two impls could be used with
|
||||
equal precedence.
|
||||
|
||||
|
|
@ -174,8 +174,12 @@ select this impl, which will cause the type of `$Y` to be unified to
|
|||
`usize`. (Note that while assembling candidates, we do the initial
|
||||
unifications in a transaction, so that they don't affect one another.)
|
||||
|
||||
**TODO**: The example says we can "select" the impl, but this section is talking specifically about candidate assembly. Does this mean we can sometimes skip confirmation? Or is this poor wording?
|
||||
**TODO**: Is the unification of `$Y` part of trait resolution or type inference? Or is this not the same type of "inference variable" as in type inference?
|
||||
**TODO**: The example says we can "select" the impl, but this section is
|
||||
talking specifically about candidate assembly. Does this mean we can sometimes
|
||||
skip confirmation? Or is this poor wording?
|
||||
**TODO**: Is the unification of `$Y` part of trait resolution or type
|
||||
inference? Or is this not the same type of "inference variable" as in type
|
||||
inference?
|
||||
|
||||
#### Winnowing: Resolving ambiguities
|
||||
|
||||
|
|
@ -282,10 +286,10 @@ to a particular impl.
|
|||
One interesting twist has to do with nested obligations. In general, in trans,
|
||||
we only need to do a "shallow" selection for an obligation. That is, we wish to
|
||||
identify which impl applies, but we do not (yet) need to decide how to select
|
||||
any nested obligations. Nonetheless, we *do* currently do a complete
|
||||
resolution, and that is because it can sometimes inform the results of type
|
||||
inference. That is, we do not have the full substitutions for the type
|
||||
variables of the impl available to us, so we must run trait selection to figure
|
||||
any nested obligations. Nonetheless, we *do* currently do a complete resolution,
|
||||
and that is because it can sometimes inform the results of type inference.
|
||||
That is, we do not have the full substitutions in terms of the type variables
|
||||
of the impl available to us, so we must run trait selection to figure
|
||||
everything out.
|
||||
|
||||
**TODO**: is this still talking about trans?
|
||||
|
|
|
|||
17
src/ty.md
17
src/ty.md
|
|
@ -56,8 +56,8 @@ fn not_in_inference<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
|
|||
}
|
||||
```
|
||||
|
||||
In contrast, if we want to code that can be usable during type inference, then you
|
||||
need to declare a distinct `'gcx` and `'tcx` lifetime parameter:
|
||||
In contrast, if we want to code that can be usable during type inference, then
|
||||
you need to declare a distinct `'gcx` and `'tcx` lifetime parameter:
|
||||
|
||||
```rust
|
||||
fn maybe_in_inference<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) {
|
||||
|
|
@ -141,19 +141,22 @@ In addition to types, there are a number of other arena-allocated data
|
|||
structures that you can allocate, and which are found in this
|
||||
module. Here are a few examples:
|
||||
|
||||
- `Substs`, allocated with `mk_substs` – this will intern a slice of types, often used to
|
||||
specify the values to be substituted for generics (e.g. `HashMap<i32, u32>`
|
||||
would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`).
|
||||
- `Substs`, allocated with `mk_substs` – this will intern a slice of types,
|
||||
often used to specify the values to be substituted for generics
|
||||
(e.g. `HashMap<i32, u32>` would be represented as a slice
|
||||
`&'tcx [tcx.types.i32, tcx.types.u32]`).
|
||||
- `TraitRef`, typically passed by value – a **trait reference**
|
||||
consists of a reference to a trait along with its various type
|
||||
parameters (including `Self`), like `i32: Display` (here, the def-id
|
||||
would reference the `Display` trait, and the substs would contain
|
||||
`i32`).
|
||||
- `Predicate` defines something the trait system has to prove (see `traits` module).
|
||||
- `Predicate` defines something the trait system has to prove (see `traits`
|
||||
module).
|
||||
|
||||
### Import conventions
|
||||
|
||||
Although there is no hard and fast rule, the `ty` module tends to be used like so:
|
||||
Although there is no hard and fast rule, the `ty` module tends to be used like
|
||||
so:
|
||||
|
||||
```rust
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
|
|
|
|||
|
|
@ -59,13 +59,14 @@ inference works, or perhaps this blog post on
|
|||
|
||||
[Unification in the Chalk project]: http://smallcultfollowing.com/babysteps/blog/2017/03/25/unification-in-chalk-part-1/
|
||||
|
||||
All said, the inference context stores four kinds of inference variables as of
|
||||
writing:
|
||||
All told, the inference context stores four kinds of inference variables as of
|
||||
this writing:
|
||||
|
||||
- Type variables, which come in three varieties:
|
||||
- General type variables (the most common). These can be unified with any type.
|
||||
- Integral type variables, which can only be unified with an integral type, and
|
||||
arise from an integer literal expression like `22`.
|
||||
- General type variables (the most common). These can be unified with any
|
||||
type.
|
||||
- Integral type variables, which can only be unified with an integral type,
|
||||
and arise from an integer literal expression like `22`.
|
||||
- Float type variables, which can only be unified with a float type, and
|
||||
arise from a float literal expression like `22.0`.
|
||||
- Region variables, which represent lifetimes, and arise all over the place.
|
||||
|
|
@ -177,7 +178,7 @@ form of an "outlives" constraint:
|
|||
|
||||
'a: 'b
|
||||
|
||||
Actually, the code tends to view them as a subregion relation, but it's the same
|
||||
Actually the code tends to view them as a subregion relation, but it's the same
|
||||
idea:
|
||||
|
||||
'b <= 'a
|
||||
|
|
@ -185,8 +186,8 @@ idea:
|
|||
(There are various other kinds of constriants, such as "verifys"; see
|
||||
the `region_constraints` module for details.)
|
||||
|
||||
There is one case where we do some amount of eager unification. If you have an equality constraint
|
||||
between two regions
|
||||
There is one case where we do some amount of eager unification. If you have an
|
||||
equality constraint between two regions
|
||||
|
||||
'a = 'b
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue