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:
commit
574830f573
116 changed files with 668 additions and 609 deletions
|
@ -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)
|
||||
/// ```
|
||||
///
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 => ...,
|
||||
|
|
|
@ -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, ...)
|
||||
|
|
|
@ -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), ..] => {}
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue