From 4aae7814075ffe94486e2cc04ff5d08351eb8fd3 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 19:53:06 -0700 Subject: [PATCH] Add info about `!` and `impl Trait` --- library/std/src/primitive_docs.rs | 37 +++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 2339ca527bd83..d88a9cbd0acff 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 { +/// unimplemented!() +/// } +/// ``` +/// +/// While this code does: +/// +/// ``` +/// use core::ops::Add; +/// +/// fn foo() -> impl Add { +/// 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 {