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 01/13] 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 { From fd985e29dd97f053f31a2e282fb59363f6b6db3f Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:35:58 -0700 Subject: [PATCH 02/13] cannot have divergence -> cannot diverge --- library/std/src/primitive_docs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index d88a9cbd0acff..a577a0a51c990 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -194,9 +194,9 @@ mod prim_bool {} /// # `!` and traits /// /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// 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: +/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` cannot diverge, +/// i.e., returning `!`, as their only possible code path. As an example, this code doesn't +/// compile: /// /// ```compile_fail /// use core::ops::Add; From 0d9a2abe698e84c8b3c473659db321606d7d5c02 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:41:36 -0700 Subject: [PATCH 03/13] It's only an issue without an `impl Trait for !` --- library/std/src/primitive_docs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index a577a0a51c990..df64287bc7de8 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -194,9 +194,9 @@ mod prim_bool {} /// # `!` and traits /// /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` cannot diverge, -/// i.e., returning `!`, as their only possible code path. As an example, this code doesn't -/// compile: +/// 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; @@ -206,7 +206,7 @@ mod prim_bool {} /// } /// ``` /// -/// While this code does: +/// But this code does: /// /// ``` /// use core::ops::Add; From 26eab6a0d51b9a023471210e35fdec969c662363 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:48:53 -0700 Subject: [PATCH 04/13] Specify `0` of type `u32` --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index df64287bc7de8..710d91b6ee7db 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,8 +222,8 @@ mod prim_bool {} /// /// 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 `!`. +/// other branch returns a `0` of type `u32`, which is 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 /// From 80dcad9e5b060ba6f9e06499c799423037ce7733 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:52:09 -0700 Subject: [PATCH 05/13] Be more specific about polymorphic return types I no longer say "polymorphic" since it's a bit ambiguous here. --- library/std/src/primitive_docs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 710d91b6ee7db..fc5036a189357 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -220,10 +220,10 @@ mod prim_bool {} /// } /// ``` /// -/// 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 a `0` of type `u32`, which is a concrete type that `!` can be coerced to. -/// See issue [#36375] for more information on this quirk of `!`. +/// The reason is that, in the first example, there are many possible types that `!` could coerce +/// to, because the function can return one of many concrete types. However, in the second example, +/// the other branch returns a `0` of type `u32`, which is 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 /// From bd3196282ba61ba284f4e176db3537f61b11892c Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:53:40 -0700 Subject: [PATCH 06/13] other branch -> `else` branch --- library/std/src/primitive_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index fc5036a189357..dfc026fb84f6e 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,7 +222,7 @@ mod prim_bool {} /// /// The reason is that, in the first example, there are many possible types that `!` could coerce /// to, because the function can return one of many concrete types. However, in the second example, -/// the other branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced +/// the `else` branch returns a `0` of type `u32`, which is 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 From 7e2548fe69ff5ec4e5e06c8c28351cbf2ebf7eee Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sun, 30 Aug 2020 11:39:45 -0700 Subject: [PATCH 07/13] Import `Debug` instead of redefining it --- library/std/src/primitive_docs.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index dfc026fb84f6e..0a0aa6785ed1d 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -232,10 +232,7 @@ mod prim_bool {} /// /// ``` /// #![feature(never_type)] -/// # use std::fmt; -/// # trait Debug { -/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; -/// # } +/// # use std::fmt::{self, Debug}; /// impl Debug for ! { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// *self From 37ea97cc10212711411e6dbb6b260e668b7ac2b5 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sun, 30 Aug 2020 11:43:16 -0700 Subject: [PATCH 08/13] Explain why the `0` is a `u32` --- library/std/src/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 0a0aa6785ed1d..79621d46f0e62 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,8 +222,9 @@ mod prim_bool {} /// /// The reason is that, in the first example, there are many possible types that `!` could coerce /// to, because the function can return one of many concrete types. However, in the second example, -/// the `else` branch returns a `0` of type `u32`, which is a concrete type that `!` can be coerced -/// to. See issue [#36375] for more information on this quirk of `!`. +/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type +/// `u32`, which is 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 /// From e13a70122d380579840cec13d151870495f776ac Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 31 Aug 2020 16:32:56 -0700 Subject: [PATCH 09/13] Redefine `Debug` instead of importing it This reverts commit 7e2548fe69ff5ec4e5e06c8c28351cbf2ebf7eee. Now I know why it was redefined: it seems like it's potentially because of the orphan rule. Here are the error messages: error[E0119]: conflicting implementations of trait `std::fmt::Debug` for type `!`: --> src/primitive_docs.rs:236:1 | 6 | impl Debug for ! { | ^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - impl std::fmt::Debug for !; error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> src/primitive_docs.rs:236:1 | 6 | impl Debug for ! { | ^^^^^^^^^^^^^^^- | | | | | `!` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead --- library/std/src/primitive_docs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 79621d46f0e62..4525d8a543a66 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -233,7 +233,10 @@ mod prim_bool {} /// /// ``` /// #![feature(never_type)] -/// # use std::fmt::{self, Debug}; +/// # use std::fmt; +/// # trait Debug { +/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; +/// # } /// impl Debug for ! { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// *self From cdd6f110125971a0d7ab1457c0ea7eb30304d5f3 Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 31 Aug 2020 16:35:00 -0700 Subject: [PATCH 10/13] Remove empty comment --- library/std/src/primitive_docs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 4525d8a543a66..cba39c3eb141e 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -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 From c4c058c7167c44eacbc2f7734619c26d68eb1426 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 31 Aug 2020 19:30:03 -0700 Subject: [PATCH 11/13] Improve wording Co-authored-by: Joshua Nelson --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index cba39c3eb141e..2ca86a42bffaf 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -220,9 +220,9 @@ mod prim_bool {} /// ``` /// /// The reason is that, in the first example, there are many possible types that `!` could coerce -/// to, because the function can return one of many concrete types. However, in the second example, +/// to, because many types implement `Add`. However, in the second example, /// the `else` branch returns a `0`, which the compiler infers from the return type to be of type -/// `u32`, which is a concrete type that `!` can be coerced to. See issue [#36375] for more +/// `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 From 913354b8463a82497ebe586cfb9f5a4a218767ad Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 31 Aug 2020 19:41:27 -0700 Subject: [PATCH 12/13] Improve `assert!` section in `bool` docs --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 2ca86a42bffaf..682ca3068ee29 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -11,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; From 55637f566993e2f8659aa09288bfc00b9965c524 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 31 Aug 2020 19:44:21 -0700 Subject: [PATCH 13/13] Break line at 100 characters --- library/std/src/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 682ca3068ee29..d00824cfb3e98 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -222,8 +222,8 @@ mod prim_bool {} /// The reason is that, in the first example, there are many possible types that `!` could coerce /// to, because many types implement `Add`. 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 `!`. +/// `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 ///