Skip to content

Commit d36b7f0

Browse files
committed
Add an explanation about never type fallback
1 parent 3490ee7 commit d36b7f0

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -4249,13 +4249,46 @@ declare_lint! {
42494249
/// The `never_type_fallback_flowing_into_unsafe` lint detects cases where never type fallback
42504250
/// affects unsafe function calls.
42514251
///
4252+
/// ### Never type fallback
4253+
///
4254+
/// When the compiler sees a value of type [`!`] it implicitly inserts a coercion (if possible),
4255+
/// to allow type check to infer any type:
4256+
///
4257+
/// ```ignore (illustrative-and-has-placeholders)
4258+
/// // this
4259+
/// let x: u8 = panic!();
4260+
///
4261+
/// // is (essentially) turned by the compiler into
4262+
/// let x: u8 = absurd(panic!());
4263+
///
4264+
/// // where absurd is a function with the following signature
4265+
/// // (it's sound, because `!` always marks unreachable code):
4266+
/// fn absurd<T>(_: !) -> T { ... }
4267+
// FIXME: use `core::convert::absurd` here instead, once it's merged
4268+
/// ```
4269+
///
4270+
/// While it's convenient to be able to use non-diverging code in one of the branches (like
4271+
/// `if a { b } else { return }`) this could lead to compilation errors:
4272+
///
4273+
/// ```compile_fail
4274+
/// // this
4275+
/// { panic!() };
4276+
///
4277+
/// // gets turned into this
4278+
/// { absurd(panic!()) }; // error: can't infer the type of `absurd`
4279+
/// ```
4280+
///
4281+
/// To prevent such errors, compiler remembers where it inserted `absurd` calls, and if it
4282+
/// can't infer their type, it sets the type to fallback. `{ absurd::<Fallback>(panic!()) };`.
4283+
/// This is what is known as "never type fallback".
4284+
///
42524285
/// ### Example
42534286
///
42544287
/// ```rust,compile_fail
42554288
/// #![deny(never_type_fallback_flowing_into_unsafe)]
42564289
/// fn main() {
42574290
/// if true {
4258-
/// // return has type `!` (never) which, is some cases, causes never type fallback
4291+
/// // return has type `!` which, is some cases, causes never type fallback
42594292
/// return
42604293
/// } else {
42614294
/// // `zeroed` is an unsafe function, which returns an unbounded type
@@ -4270,7 +4303,7 @@ declare_lint! {
42704303
///
42714304
/// ### Explanation
42724305
///
4273-
/// Due to historic reasons never type fallback were `()`, meaning that `!` got spontaneously
4306+
/// Due to historic reasons never type fallback was `()`, meaning that `!` got spontaneously
42744307
/// coerced to `()`. There are plans to change that, but they may make the code such as above
42754308
/// unsound. Instead of depending on the fallback, you should specify the type explicitly:
42764309
/// ```
@@ -4283,6 +4316,9 @@ declare_lint! {
42834316
/// ```
42844317
///
42854318
/// See [Tracking Issue for making `!` fall back to `!`](https://github.com/rust-lang/rust/issues/123748).
4319+
///
4320+
/// [`!`]: https://doc.rust-lang.org/core/primitive.never.html
4321+
/// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html
42864322
pub NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
42874323
Warn,
42884324
"never type fallback affecting unsafe function calls"

0 commit comments

Comments
 (0)