diff --git a/ci/check_line_lengths.sh b/ci/check_line_lengths.sh index 27711806..b32906da 100755 --- a/ci/check_line_lengths.sh +++ b/ci/check_line_lengths.sh @@ -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 diff --git a/src/SUMMARY.md b/src/SUMMARY.md index da84350e..3460d949 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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) diff --git a/src/compiletest.md b/src/compiletest.md index f07d3065..0cfc6b39 100644 --- a/src/compiletest.md +++ b/src/compiletest.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 @@ -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 { + match self.parse_name_value_directive(line, "failure-status") { + Some(code) => code.trim().parse::().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. diff --git a/src/high-level-overview.md b/src/high-level-overview.md index 49365671..04113654 100644 --- a/src/high-level-overview.md +++ b/src/high-level-overview.md @@ -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. diff --git a/src/hir.md b/src/hir.md index 41ed0ab2..f66468ff 100644 --- a/src/hir.md +++ b/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()`). diff --git a/src/how-to-build-and-run.md b/src/how-to-build-and-run.md index 7b6088c7..6e292934 100644 --- a/src/how-to-build-and-run.md +++ b/src/how-to-build-and-run.md @@ -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 diff --git a/src/incremental-compilation.md b/src/incremental-compilation.md index 6f5b48cc..a209207f 100644 --- a/src/incremental-compilation.md +++ b/src/incremental-compilation.md @@ -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. @@ -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. diff --git a/src/query.md b/src/query.md index 33d2b3ba..500b9dec 100644 --- a/src/query.md +++ b/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. diff --git a/src/tests/adding.md b/src/tests/adding.md index 276189f5..f777a458 100644 --- a/src/tests/adding.md +++ b/src/tests/adding.md @@ -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 diff --git a/src/tests/intro.md b/src/tests/intro.md index eb7294c8..e8cf34af 100644 --- a/src/tests/intro.md +++ b/src/tests/intro.md @@ -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` diff --git a/src/tests/running.md b/src/tests/running.md index 98d59067..6bac0121 100644 --- a/src/tests/running.md +++ b/src/tests/running.md @@ -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 diff --git a/src/trait-hrtb.md b/src/trait-hrtb.md index 8c3a6f4e..d677db2c 100644 --- a/src/trait-hrtb.md +++ b/src/trait-hrtb.md @@ -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>`. diff --git a/src/trait-resolution.md b/src/trait-resolution.md index d6edcf68..7494d969 100644 --- a/src/trait-resolution.md +++ b/src/trait-resolution.md @@ -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? diff --git a/src/ty.md b/src/ty.md index 26b8c1ca..1fd86a6b 100644 --- a/src/ty.md +++ b/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` - 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` 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}; diff --git a/src/type-inference.md b/src/type-inference.md index c7a9c2b6..45f9df18 100644 --- a/src/type-inference.md +++ b/src/type-inference.md @@ -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