Rollup merge of #76099 - camelid:patch-8, r=jyn514

Add info about `!` and `impl Trait`

Fixes #76094.

@rustbot modify labels: T-doc C-enhancement
This commit is contained in:
Tyler Mandry 2020-09-01 18:24:29 -07:00 committed by GitHub
commit 34c8b7a92c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,7 +1,6 @@
#[doc(primitive = "bool")] #[doc(primitive = "bool")]
#[doc(alias = "true")] #[doc(alias = "true")]
#[doc(alias = "false")] #[doc(alias = "false")]
//
/// The boolean type. /// The boolean type.
/// ///
/// The `bool` represents a value, which could only be either `true` or `false`. If you cast /// The `bool` represents a value, which could only be either `true` or `false`. If you cast
@ -12,8 +11,8 @@
/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., /// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
/// which allow us to perform boolean operations using `&`, `|` and `!`. /// which allow us to perform boolean operations using `&`, `|` and `!`.
/// ///
/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing, /// `if` always demands a `bool` value. [`assert!`], which is an important macro in testing,
/// checks whether an expression returns `true`. /// checks whether an expression returns `true` and panics if it isn't.
/// ///
/// ``` /// ```
/// let bool_val = true & false | false; /// let bool_val = true & false | false;
@ -194,14 +193,48 @@ mod prim_bool {}
/// # `!` and traits /// # `!` and traits
/// ///
/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`] /// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!`
/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other
/// words, they can't return `!` from every code path. As an example, this code doesn't compile:
///
/// ```compile_fail
/// use core::ops::Add;
///
/// fn foo() -> impl Add<u32> {
/// unimplemented!()
/// }
/// ```
///
/// But this code does:
///
/// ```
/// use core::ops::Add;
///
/// fn foo() -> impl Add<u32> {
/// if true {
/// unimplemented!()
/// } else {
/// 0
/// }
/// }
/// ```
///
/// The reason is that, in the first example, there are many possible types that `!` could coerce
/// to, because many types implement `Add<u32>`. However, in the second example,
/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type
/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375]
/// for more information on this quirk of `!`.
///
/// [#36375]: https://github.com/rust-lang/rust/issues/36375
///
/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`]
/// for example: /// for example:
/// ///
/// ``` /// ```
/// #![feature(never_type)] /// #![feature(never_type)]
/// # use std::fmt; /// # use std::fmt;
/// # trait Debug { /// # trait Debug {
/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; /// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
/// # } /// # }
/// impl Debug for ! { /// impl Debug for ! {
/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {