Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add info about ! and impl Trait #76099

Merged
merged 13 commits into from
Sep 2, 2020
37 changes: 35 additions & 2 deletions library/std/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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` 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 for `!` to coerce
/// to, because the function's return value is polymorphic. However, in the second example, the
camelid marked this conversation as resolved.
Show resolved Hide resolved
/// other branch returns `0` which has a concrete type that `!` can be coerced to. See issue
camelid marked this conversation as resolved.
Show resolved Hide resolved
/// [#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`]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most -> all? Not sure if that's true but it seems like it should be.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I thought too; I would think you would be able to impl any trait for ! since it can never :) exist. The body of it could just be panic!("This shouldn't happen!").

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or even simpler, *self, yeah.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean because it can be coerced to any concrete type, so it can just return itself?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> impl Trait is not allowed in trait methods. So any trait it implemented would require returning some concrete type. Since ! can be coerced to any type, it would be coerced to the required type.

/// 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;
/// # }
Comment on lines 236 to 238
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is Debug defined here instead of imported?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to delete this redefinition and import it instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it's because of the orphan rule or something, so I had to revert my change :(

/// impl Debug for ! {
/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down