Hard-wrapped lines that are too long.

This commit is contained in:
Alexander Regueiro 2018-02-24 01:43:53 +00:00 committed by Who? Me?!
parent 34ec755d27
commit b3d8fba198
15 changed files with 206 additions and 161 deletions

View File

@ -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

View File

@ -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)

View File

@ -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
@ -12,17 +14,17 @@ testing framework, see [`this chapter`](./tests/intro.html) for additional backg
The tests themselves are typically (but not always) organized into "suites"--for example, `run-pass`, a folder
representing tests that should succeed, `run-fail`, a folder holding tests that should compile successfully, 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 [src/tools/compiletest/src/common.rs](https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/common.rs) in the `pub struct Config` declaration. And a very good
suites are defined in [src/tools/compiletest/src/common.rs](https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/common.rs) in the `pub struct Config` declaration. And a very good
introduction to the different suites of compiler tests along with details about them can be found in [`Adding new tests`](./tests/adding.html).
## Adding a new test file
Briefly, simply create your new test in the appropriate location under [src/test](https://github.com/rust-lang/rust/tree/master/src/test). No registration of test files is necessary as
Briefly, simply create your new test in the appropriate location under [src/test](https://github.com/rust-lang/rust/tree/master/src/test). No registration of test files is necessary as
`compiletest` will scan the [src/test](https://github.com/rust-lang/rust/tree/master/src/test) subfolder recursively, and will execute any Rust source files it finds as tests.
See [`Adding new tests`](./tests/adding.html) for a complete guide on how to adding new tests.
See [`Adding new tests`](./tests/adding.html) for a complete guide on how to adding new tests.
## Header Commands
Source file annotations which appear in comments near the top of the source file *before* any test code are known as header
commands. These commands can instruct `compiletest` to ignore this test, set expectations on whether it is expected to
commands. These commands can instruct `compiletest` to ignore this test, set expectations on whether it is expected to
succeed at compiling, or what the test's return code is expected to be. Header commands (and their inline counterparts,
Error Info commands) are described more fully [here](./tests/adding.html#header-commands-configuring-rustc).
@ -96,7 +98,7 @@ As a concrete example, here is the implementation for the `parse_failure_status(
pub normalize_stderr: Vec<(String, String)>,
+ pub failure_status: i32,
}
impl TestProps {
@@ -260,6 +261,7 @@ impl TestProps {
run_pass: false,
@ -105,7 +107,7 @@ As a concrete example, here is the implementation for the `parse_failure_status(
+ failure_status: 101,
}
}
@@ -383,6 +385,10 @@ impl TestProps {
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") {
self.normalize_stderr.push(rule);
@ -115,12 +117,12 @@ As a concrete example, here is the implementation for the `parse_failure_status(
+ self.failure_status = code;
+ }
});
for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
@@ -488,6 +494,13 @@ impl Config {
self.parse_name_directive(line, "pretty-compare-only")
}
+ fn parse_failure_status(&self, line: &str) -> Option<i32> {
+ match self.parse_name_value_directive(line, "failure-status") {
+ Some(code) => code.trim().parse::<i32>().ok(),
@ -141,7 +143,7 @@ located in [src/tools/compiletest/src/runtest.rs](https://github.com/rust-lang/r
```diff
@@ -295,11 +295,14 @@ impl<'test> TestCx<'test> {
}
fn check_correct_failure_status(&self, proc_res: &ProcRes) {
- // The value the rust runtime returns on failure
- const RUST_ERR: i32 = 101;
@ -160,7 +162,7 @@ located in [src/tools/compiletest/src/runtest.rs](https://github.com/rust-lang/r
}
@@ -320,7 +323,6 @@ impl<'test> TestCx<'test> {
);
let proc_res = self.exec_compiled_test();
-
if !proc_res.status.success() {
@ -172,7 +174,7 @@ located in [src/tools/compiletest/src/runtest.rs](https://github.com/rust-lang/r
);
- panic!();
}
}
}
```
Note the use of `self.props.failure_status` to access the header command property. In tests which do not specify the failure
status header command, `self.props.failure_status` will evaluate to the default value of 101 at the time of this writing.

View File

@ -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.

View File

@ -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()`).

View File

@ -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

View File

@ -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
@ -40,7 +40,7 @@ There are two key insights here:
produced the same result as the previous time. **If it did,** we
can still mark the query as green, and hence avoid re-executing
dependent queries.
### The try-mark-green algorithm
At the core of incremental compilation is an algorithm called
@ -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">
@ -80,14 +82,14 @@ Try-mark-green works as follows:
The query DAG code is stored in
[`src/librustc/dep_graph`][dep_graph]. Construction of the DAG is done
by instrumenting the query execution.
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.

View File

@ -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.

View File

@ -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
@ -59,8 +61,8 @@ When writing a new feature, **create a subdirectory to store your
tests**. For example, if you are implementing RFC 1234 ("Widgets"),
then it might make sense to put the tests in directories like:
- `src/test/ui/rfc1234-widgets/`
- `src/test/run-pass/rfc1234-widgets/`
- `src/test/ui/rfc1234-widgets/`
- `src/test/run-pass/rfc1234-widgets/`
- etc
In other cases, there may already be a suitable directory. (The proper
@ -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

View File

@ -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`

View File

@ -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

View File

@ -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>`.

View File

@ -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?

View File

@ -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};

View File

@ -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