Skip to content

Commit

Permalink
Rollup merge of #76099 - camelid:patch-8, r=jyn514
Browse files Browse the repository at this point in the history
Add info about `!` and `impl Trait`

Fixes #76094.

@rustbot modify labels: T-doc C-enhancement
  • Loading branch information
tmandry committed Sep 2, 2020
2 parents 7c1c7de + 55637f5 commit 34c8b7a
Showing 1 changed file with 38 additions and 5 deletions.
43 changes: 38 additions & 5 deletions library/std/src/primitive_docs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#[doc(primitive = "bool")]
#[doc(alias = "true")]
#[doc(alias = "false")]
//
/// The boolean type.
///
/// The `bool` represents a value, which could only be either `true` or `false`. If you cast
Expand All @@ -12,8 +11,8 @@
/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
/// which allow us to perform boolean operations using `&`, `|` and `!`.
///
/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing,
/// checks whether an expression returns `true`.
/// `if` always demands a `bool` value. [`assert!`], which is an important macro in testing,
/// checks whether an expression returns `true` and panics if it isn't.
///
/// ```
/// let bool_val = true & false | false;
Expand Down Expand Up @@ -194,14 +193,48 @@ mod prim_bool {}
/// # `!` and traits
///
/// 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:
///
/// ```
/// #![feature(never_type)]
/// # use std::fmt;
/// # trait Debug {
/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
/// # }
/// impl Debug for ! {
/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down

0 comments on commit 34c8b7a

Please sign in to comment.