about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamelid <37223377+camelid@users.noreply.github.com>2020-08-29 19:53:06 -0700
committerCamelid <camelidcamel@gmail.com>2020-08-29 19:59:22 -0700
commit4aae7814075ffe94486e2cc04ff5d08351eb8fd3 (patch)
treeb27a359f976e77e061b043179d68c3ad3ff3d75c
parent62850d882b1f546783d064ca3b51d1f85b92eeb7 (diff)
downloadrust-4aae7814075ffe94486e2cc04ff5d08351eb8fd3.tar.gz
rust-4aae7814075ffe94486e2cc04ff5d08351eb8fd3.zip
Add info about `!` and `impl Trait`
-rw-r--r--library/std/src/primitive_docs.rs37
1 files changed, 35 insertions, 2 deletions
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 2339ca527bd..d88a9cbd0ac 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -194,14 +194,47 @@ 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` cannot have
+/// divergence, i.e., returning `!`, as their only possible code path. As an example, this code
+/// doesn't compile:
+///
+/// ```compile_fail
+/// use core::ops::Add;
+///
+/// fn foo() -> impl Add<u32> {
+///     unimplemented!()
+/// }
+/// ```
+///
+/// While 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 for `!` to coerce
+/// to, because the function's return value is polymorphic. However, in the second example, the
+/// other branch returns `0` which has a concrete type that `!` can be coerced to. 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 {