Skip to content

Commit 34c8b7a

Browse files
authored
Rollup merge of #76099 - camelid:patch-8, r=jyn514
Add info about `!` and `impl Trait` Fixes #76094. @rustbot modify labels: T-doc C-enhancement
2 parents 7c1c7de + 55637f5 commit 34c8b7a

File tree

1 file changed

+38
-5
lines changed

1 file changed

+38
-5
lines changed

library/std/src/primitive_docs.rs

+38-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#[doc(primitive = "bool")]
22
#[doc(alias = "true")]
33
#[doc(alias = "false")]
4-
//
54
/// The boolean type.
65
///
76
/// The `bool` represents a value, which could only be either `true` or `false`. If you cast
@@ -12,8 +11,8 @@
1211
/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
1312
/// which allow us to perform boolean operations using `&`, `|` and `!`.
1413
///
15-
/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing,
16-
/// checks whether an expression returns `true`.
14+
/// `if` always demands a `bool` value. [`assert!`], which is an important macro in testing,
15+
/// checks whether an expression returns `true` and panics if it isn't.
1716
///
1817
/// ```
1918
/// let bool_val = true & false | false;
@@ -194,14 +193,48 @@ mod prim_bool {}
194193
/// # `!` and traits
195194
///
196195
/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
197-
/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`]
196+
/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!`
197+
/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other
198+
/// words, they can't return `!` from every code path. As an example, this code doesn't compile:
199+
///
200+
/// ```compile_fail
201+
/// use core::ops::Add;
202+
///
203+
/// fn foo() -> impl Add<u32> {
204+
/// unimplemented!()
205+
/// }
206+
/// ```
207+
///
208+
/// But this code does:
209+
///
210+
/// ```
211+
/// use core::ops::Add;
212+
///
213+
/// fn foo() -> impl Add<u32> {
214+
/// if true {
215+
/// unimplemented!()
216+
/// } else {
217+
/// 0
218+
/// }
219+
/// }
220+
/// ```
221+
///
222+
/// The reason is that, in the first example, there are many possible types that `!` could coerce
223+
/// to, because many types implement `Add<u32>`. However, in the second example,
224+
/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type
225+
/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375]
226+
/// for more information on this quirk of `!`.
227+
///
228+
/// [#36375]: https://github.com/rust-lang/rust/issues/36375
229+
///
230+
/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`]
198231
/// for example:
199232
///
200233
/// ```
201234
/// #![feature(never_type)]
202235
/// # use std::fmt;
203236
/// # trait Debug {
204-
/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
237+
/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
205238
/// # }
206239
/// impl Debug for ! {
207240
/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {

0 commit comments

Comments
 (0)