1
Fork 0

Auto merge of #96094 - Elliot-Roberts:fix_doctests, r=compiler-errors

Begin fixing all the broken doctests in `compiler/`

Begins to fix #95994.
All of them pass now but 24 of them I've marked with `ignore HELP (<explanation>)` (asking for help) as I'm unsure how to get them to work / if we should leave them as they are.
There are also a few that I marked `ignore` that could maybe be made to work but seem less important.
Each `ignore` has a rough "reason" for ignoring after it parentheses, with

- `(pseudo-rust)` meaning "mostly rust-like but contains foreign syntax"
- `(illustrative)` a somewhat catchall for either a fragment of rust that doesn't stand on its own (like a lone type), or abbreviated rust with ellipses and undeclared types that would get too cluttered if made compile-worthy.
- `(not-rust)` stuff that isn't rust but benefits from the syntax highlighting, like MIR.
- `(internal)` uses `rustc_*` code which would be difficult to make work with the testing setup.

Those reason notes are a bit inconsistently applied and messy though. If that's important I can go through them again and try a more principled approach. When I run `rg '```ignore \(' .` on the repo, there look to be lots of different conventions other people have used for this sort of thing. I could try unifying them all if that would be helpful.

I'm not sure if there was a better existing way to do this but I wrote my own script to help me run all the doctests and wade through the output. If that would be useful to anyone else, I put it here: https://github.com/Elliot-Roberts/rust_doctest_fixing_tool
This commit is contained in:
bors 2022-05-07 06:30:29 +00:00
commit 574830f573
116 changed files with 668 additions and 609 deletions

View file

@ -42,15 +42,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// We tweak the handling of parameters of unsized type slightly to avoid the need to create a
/// local variable of unsized type. For example, consider this program:
///
/// ```rust
/// fn foo(p: dyn Debug) { ... }
/// ```
/// #![feature(unsized_locals, unsized_fn_params)]
/// # use core::fmt::Debug;
/// fn foo(p: dyn Debug) { dbg!(p); }
///
/// fn bar(box_p: Box<dyn Debug>) { foo(*p); }
/// fn bar(box_p: Box<dyn Debug>) { foo(*box_p); }
/// ```
///
/// Ordinarily, for sized types, we would compile the call `foo(*p)` like so:
///
/// ```rust
/// ```ignore (illustrative)
/// let tmp0 = *box_p; // tmp0 would be the operand returned by this function call
/// foo(tmp0)
/// ```
@ -60,7 +62,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// that we create *stores the entire box*, and the parameter to the call itself will be
/// `*tmp0`:
///
/// ```rust
/// ```ignore (illustrative)
/// let tmp0 = box_p; call foo(*tmp0)
/// ```
///

View file

@ -37,7 +37,7 @@ crate enum PlaceBase {
///
/// Consider the following example
/// ```rust
/// let t = (10, (10, (10, 10)));
/// let t = (((10, 10), 10), 10);
///
/// let c = || {
/// println!("{}", t.0.0.0);
@ -45,7 +45,7 @@ crate enum PlaceBase {
/// ```
/// Here the THIR expression for `t.0.0.0` will be something like
///
/// ```
/// ```ignore (illustrative)
/// * Field(0)
/// * Field(0)
/// * Field(0)

View file

@ -1032,11 +1032,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// exhaustive match, consider:
///
/// ```
/// # fn foo(x: (bool, bool)) {
/// match x {
/// (true, true) => (),
/// (_, false) => (),
/// (false, true) => (),
/// }
/// # }
/// ```
///
/// For this match, we check if `x.0` matches `true` (for the first
@ -1157,7 +1159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
///
/// For example, if we have something like this:
///
/// ```rust
/// ```ignore (illustrative)
/// ...
/// Some(x) if cond1 => ...
/// Some(x) => ...
@ -1481,11 +1483,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// ```
/// # let (x, y, z) = (true, true, true);
/// match (x, y, z) {
/// (true, _, true) => true, // (0)
/// (_, true, _) => true, // (1)
/// (false, false, _) => false, // (2)
/// (true, _, false) => false, // (3)
/// (true , _ , true ) => true, // (0)
/// (_ , true , _ ) => true, // (1)
/// (false, false, _ ) => false, // (2)
/// (true , _ , false) => false, // (3)
/// }
/// # ;
/// ```
///
/// In that case, after we test on `x`, there are 2 overlapping candidate
@ -1502,14 +1505,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// with precisely the reachable arms being reachable - but that problem
/// is trivially NP-complete:
///
/// ```rust
/// match (var0, var1, var2, var3, ...) {
/// (true, _, _, false, true, ...) => false,
/// (_, true, true, false, _, ...) => false,
/// (false, _, false, false, _, ...) => false,
/// ...
/// _ => true
/// }
/// ```ignore (illustrative)
/// match (var0, var1, var2, var3, ...) {
/// (true , _ , _ , false, true, ...) => false,
/// (_ , true, true , false, _ , ...) => false,
/// (false, _ , false, false, _ , ...) => false,
/// ...
/// _ => true
/// }
/// ```
///
/// Here the last arm is reachable only if there is an assignment to
@ -1520,7 +1523,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// our simplistic treatment of constants and guards would make it occur
/// in very common situations - for example [#29740]:
///
/// ```rust
/// ```ignore (illustrative)
/// match x {
/// "foo" if foo_guard => ...,
/// "bar" if bar_guard => ...,

View file

@ -803,16 +803,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// scope (which can be larger or smaller).
///
/// Consider:
///
/// let x = foo(bar(X, Y));
///
/// ```ignore (illustrative)
/// let x = foo(bar(X, Y));
/// ```
/// We wish to pop the storage for X and Y after `bar()` is
/// called, not after the whole `let` is completed.
///
/// As another example, if the second argument diverges:
///
/// foo(Box::new(2), panic!())
///
/// ```ignore (illustrative)
/// foo(Box::new(2), panic!())
/// ```
/// We would allocate the box but then free it on the unwinding
/// path; we would also emit a free on the 'success' path from
/// panic, but that will turn out to be removed as dead-code.
@ -944,7 +944,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
///
/// Example: when compiling the call to `foo` here:
///
/// ```rust
/// ```ignore (illustrative)
/// foo(bar(), ...)
/// ```
///
@ -955,7 +955,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// dropped). However, if no unwind occurs, then `_X` will be
/// unconditionally consumed by the `call`:
///
/// ```
/// ```ignore (illustrative)
/// bb {
/// ...
/// _R = CALL(foo, _X, ...)

View file

@ -13,7 +13,7 @@
//! Instead of listing all those constructors (which is intractable), we group those value
//! constructors together as much as possible. Example:
//!
//! ```
//! ```compile_fail,E0004
//! match (0, false) {
//! (0 ..=100, true) => {} // `p_1`
//! (50..=150, false) => {} // `p_2`
@ -344,13 +344,13 @@ enum IntBorder {
/// straddles the boundary of one of the inputs.
///
/// The following input:
/// ```
/// ```text
/// |-------------------------| // `self`
/// |------| |----------| |----|
/// |-------| |-------|
/// ```
/// would be iterated over as follows:
/// ```
/// ```text
/// ||---|--||-|---|---|---|--|
/// ```
#[derive(Debug, Clone)]
@ -492,14 +492,17 @@ impl Slice {
///
/// Let's look at an example, where we are trying to split the last pattern:
/// ```
/// # fn foo(x: &[bool]) {
/// match x {
/// [true, true, ..] => {}
/// [.., false, false] => {}
/// [..] => {}
/// }
/// # }
/// ```
/// Here are the results of specialization for the first few lengths:
/// ```
/// # fn foo(x: &[bool]) { match x {
/// // length 0
/// [] => {}
/// // length 1
@ -520,6 +523,8 @@ impl Slice {
/// [true, true, _, _, _ ] => {}
/// [_, _, _, false, false] => {}
/// [_, _, _, _, _ ] => {}
/// # _ => {}
/// # }}
/// ```
///
/// If we went above length 5, we would simply be inserting more columns full of wildcards in the
@ -1128,7 +1133,8 @@ impl<'tcx> SplitWildcard<'tcx> {
/// In the following example `Fields::wildcards` returns `[_, _, _, _]`. Then in
/// `extract_pattern_arguments` we fill some of the entries, and the result is
/// `[Some(0), _, _, _]`.
/// ```rust
/// ```compile_fail,E0004
/// # fn foo() -> [Option<u8>; 4] { [None; 4] }
/// let x: [Option<u8>; 4] = foo();
/// match x {
/// [Some(0), ..] => {}

View file

@ -35,23 +35,27 @@
//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it
//! is useful w.r.t. the patterns above it:
//! ```rust
//! # fn foo(x: Option<i32>) {
//! match x {
//! Some(_) => ...,
//! None => ..., // reachable: `None` is matched by this but not the branch above
//! Some(0) => ..., // unreachable: all the values this matches are already matched by
//! // `Some(_)` above
//! Some(_) => {},
//! None => {}, // reachable: `None` is matched by this but not the branch above
//! Some(0) => {}, // unreachable: all the values this matches are already matched by
//! // `Some(_)` above
//! }
//! # }
//! ```
//!
//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_`
//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness`
//! are used to tell the user which values are missing.
//! ```rust
//! ```compile_fail,E0004
//! # fn foo(x: Option<i32>) {
//! match x {
//! Some(0) => ...,
//! None => ...,
//! Some(0) => {},
//! None => {},
//! // not exhaustive: `_` is useful because it matches `Some(1)`
//! }
//! # }
//! ```
//!
//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes
@ -120,12 +124,15 @@
//! say from knowing only the first constructor of our candidate value.
//!
//! Let's take the following example:
//! ```
//! ```compile_fail,E0004
//! # enum Enum { Variant1(()), Variant2(Option<bool>, u32)}
//! # fn foo(x: Enum) {
//! match x {
//! Enum::Variant1(_) => {} // `p1`
//! Enum::Variant2(None, 0) => {} // `p2`
//! Enum::Variant2(Some(_), 0) => {} // `q`
//! }
//! # }
//! ```
//!
//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`.
@ -133,11 +140,13 @@
//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple
//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match:
//!
//! ```
//! ```compile_fail,E0004
//! # fn foo(x: (Option<bool>, u32)) {
//! match x {
//! (None, 0) => {} // `p2'`
//! (Some(_), 0) => {} // `q'`
//! }
//! # }
//! ```
//!
//! This motivates a new step in computing usefulness, that we call _specialization_.
@ -150,7 +159,7 @@
//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`.
//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's
//! happening:
//! ```
//! ```ignore (illustrative)
//! [Enum::Variant1(_)]
//! [Enum::Variant2(None, 0)]
//! [Enum::Variant2(Some(_), 0)]
@ -234,7 +243,7 @@
//! - We return the concatenation of all the witnesses found, if any.
//!
//! Example:
//! ```
//! ```ignore (illustrative)
//! [Some(true)] // p_1
//! [None] // p_2
//! [Some(_)] // q
@ -659,13 +668,15 @@ enum ArmType {
///
/// For example, if we are constructing a witness for the match against
///
/// ```
/// ```compile_fail,E0004
/// # #![feature(type_ascription)]
/// struct Pair(Option<(u32, u32)>, bool);
///
/// # fn foo(p: Pair) {
/// match (p: Pair) {
/// Pair(None, _) => {}
/// Pair(_, false) => {}
/// }
/// # }
/// ```
///
/// We'll perform the following steps: