Skip to content

rewrite never type documentation#158370

Draft
WaffleLapkin wants to merge 2 commits into
rust-lang:mainfrom
WaffleLapkin:never-scratch-docs
Draft

rewrite never type documentation#158370
WaffleLapkin wants to merge 2 commits into
rust-lang:mainfrom
WaffleLapkin:never-scratch-docs

Conversation

@WaffleLapkin

@WaffleLapkin WaffleLapkin commented Jun 24, 2026

Copy link
Copy Markdown
Member

With the never type stabilization approaching, I think the documentation could be improved a lot over the status quo ^^'

I intend to merge this after #155499. Split it off into a separate PR for ease of reviewing.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 24, 2026
@WaffleLapkin WaffleLapkin added the F-never_type `#![feature(never_type)]` label Jun 24, 2026
@WaffleLapkin WaffleLapkin added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 24, 2026

@kpreid kpreid left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I saw some typos, so here’s a batch of copyediting suggestions (also some for jargon clarification). Feel free to ignore these if not useful.

View changes since this review

Comment thread library/core/src/primitive_docs.rs Outdated
Comment thread library/core/src/primitive_docs.rs Outdated
Comment thread library/core/src/primitive_docs.rs Outdated
/// // `x` has type `u32`
/// Some(x) => x,
/// // `return` has type `!`, which is then coerced to `u32`,
/// // allowing the `match` to typecheck

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// // allowing the `match` to typecheck
/// // allowing the `match` to pass type checking.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hm, I prefer "to typecheck", do you think this is too jargony?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ehhhh vague hand gestures only kind of. As a general matter of how I see people failing to understanding things, I think that programming jargon often has what I call a “noun pileup” problem: squeezing all the meaning into a single noun phrase (or verb, in this case) that lacks any structure to indicate what its parts are referring to if you don’t already know. This suggestion was an attempt, not to fix a definite problem, but to improve the average.

In particular, it add an indication (“pass”) that “type checking” is something done to the match, whereas “typecheck” as a verb whose subject is match could point towards more incorrect theories such as “the match is (at run time) checking that the type of the arm matches the type that is needed”. Does that disagree with how Rust works in general? Yes. But the people who need this documentation won’t necessarily know that, so adding more clues towards the right reading helps learning go more smoothly.

But, just like I said for the rest of these, feel free to disregard this suggestion. It’s a guess at what will be more clear.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If I can throw my two cents in, I think "pass type checking" reads smoother, something about "...allowing the match to typecheck." just feels clunky.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

To me, "typecheck" is an action done by the compiler, not the code itself. So I suggest "pass typechecking".

Comment thread library/core/src/primitive_docs.rs Outdated
Comment thread library/core/src/primitive_docs.rs Outdated
@traviscross traviscross self-assigned this Jun 25, 2026
@traviscross traviscross added T-lang Relevant to the language team T-lang-docs Relevant to the lang-docs team. labels Jun 25, 2026
Co-authored-by: Kevin Reid <kpreid@switchb.org>

@mkrasnitski mkrasnitski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Due to the slightly messy diff, I ended up splitting my review up into many small comments, so apologies for the large number of them. Most are copy-edits, with a couple small content changes here and there. Feel free to use them or not as you see fit.

View changes since this review

Comment on lines +67 to +68
/// `!` is the canonical uninhabited type. `!` represents the type of diverging computations --
/// computations which never resolve to any value.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// `!` is the canonical uninhabited type. `!` represents the type of diverging computations --
/// computations which never resolve to any value.
/// `!` represents the type of diverging computations -- computations which never resolve to any
/// value. It the canonical uninhabited type.

Comment on lines +70 to +71
/// A different way to look at it is that since `!` is uninhabited, since it has no values, it is a
/// marker for unreachable code.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// A different way to look at it is that since `!` is uninhabited, since it has no values, it is a
/// marker for unreachable code.
/// Another perspective is that since `!` has no values (since it is uninhabited), it is a marker
/// for unreachable code.

Comment on lines +73 to +75
/// For example, the [`exit`] function is defined as returning `!`, to signify that it doesn't
/// return normally and exits the process instead. Thus, any code following a call to [`exit`] is
/// unreachable. ([`panic!`] works the same way.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// For example, the [`exit`] function is defined as returning `!`, to signify that it doesn't
/// return normally and exits the process instead. Thus, any code following a call to [`exit`] is
/// unreachable. ([`panic!`] works the same way.)
/// For example, the [`exit`] function is defined as returning `!`, to signify that it exits the
/// process instead of returning normally. Thus, any code following a call to [`exit`] is
/// unreachable. The [`panic!`] macro works the same way.

Comment on lines +77 to +78
/// Similarly, [`return`], [`break`], [`continue`], [`become`], and infinite [`loop`] expressions
/// all have type `!`, as the code following them is unreachable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should become be included here if it is still unstable?

/// Both match arms must produce values of type [`u32`], but since `break` never produces a value
/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
/// behavior of the `!` type - expressions with type `!` will coerce into any other type.
/// The `let` is pointless, but shows that `return` has type `!`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// The `let` is pointless, but shows that `return` has type `!`.
/// The `let` binding above is pointless, but shows that `return` expressions have type `!`.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
/// // we can dereference `self` (which has type `&!`),
/// // and then coerce to `fmt::Result`

Moved the sentence below into the example as a comment.

Comment on lines +244 to +247
/// Since `!` has no values, it has no default value either. There is no meaningful implementation
/// for `default`. Since it would have to return `!`, it would also need to diverge. While one
/// *could* implement it using `panic!` or an infinite loop, or something alike, that would not be
/// useful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Since `!` has no values, it has no default value either. There is no meaningful implementation
/// for `default`. Since it would have to return `!`, it would also need to diverge. While one
/// *could* implement it using `panic!` or an infinite loop, or something alike, that would not be
/// useful.
/// Since `!` has no values, it has no default value either. There is no meaningful implementation
/// for `default`, since it would have to return `!` -- in other words it would need to diverge.
/// While one *could* write an implementation using `panic!` or an infinite loop, or something
/// alike, that would not be useful.

Comment on lines +283 to +285
/// This is because `impl Trait` is not a specific type in and of itself, but instead a marker that
/// the return type of the function is hidden and the only thing that can be assumed by the caller
/// is that whatever the type is, it implements `Trait`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// This is because `impl Trait` is not a specific type in and of itself, but instead a marker that
/// the return type of the function is hidden and the only thing that can be assumed by the caller
/// is that whatever the type is, it implements `Trait`.
/// Here, never-to-any coercion fails because `impl Trait` is not itself a concrete type, but rather
/// a way to tell the compiler that a function's return type is hidden, and the only thing which can
/// be assumed about this type is that it implements `Trait`.

Comment on lines +287 to +288
/// In case of using `todo!()` the hidden return type is inferred to be `!`, which may not
/// implement the trait.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// In case of using `todo!()` the hidden return type is inferred to be `!`, which may not
/// implement the trait.
/// The compiler then attempts to choose such a concrete type, but is unable to do so. In this case,
/// we abandon the coercion and fall back to just the never type itself, which will fail to compile
/// if `!` does not implement `Trait`.

I think fallback should be explicitly mentioned here.

Comment on lines +192 to +193
/// // Enum with no variants is an example of an uninhabited type
/// enum Void {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// // Enum with no variants is an example of an uninhabited type
/// enum Void {}
/// // An enum with no variants is an example of an uninhabited type
/// enum Void {}

Probably this should be moved up above the definition of Onomatopoeias

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

F-never_type `#![feature(never_type)]` S-blocked Status: Blocked on something else such as an RFC or other implementation work. T-lang Relevant to the language team T-lang-docs Relevant to the lang-docs team. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants