about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWaffle Lapkin <waffle.lapkin@gmail.com>2024-04-26 20:48:15 +0200
committerWaffle Lapkin <waffle.lapkin@gmail.com>2024-04-26 20:49:34 +0200
commit23b67de1513f412d0df37ece3bd90a3fd653c444 (patch)
treed2a4cd62c68014e3cb4df05176d0344cdf8f1caa
parent6a9758d4f38d4763bd437c48fa7e5246cecf8d04 (diff)
downloadrust-23b67de1513f412d0df37ece3bd90a3fd653c444.tar.gz
rust-23b67de1513f412d0df37ece3bd90a3fd653c444.zip
Document never type fallback in `!`'s docs
-rw-r--r--library/core/src/primitive_docs.rs41
1 files changed, 41 insertions, 0 deletions
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index bda1ee6f457..99b132fe399 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -268,6 +268,47 @@ mod prim_bool {}
 /// [`Debug`]: fmt::Debug
 /// [`default()`]: Default::default
 ///
+/// # Never type fallback
+///
+/// When the compiler sees a value of type `!` it implicitly inserts a coercion (if possible),
+/// to allow type check to infer any type:
+///
+/// ```rust,ignore (illustrative-and-has-placeholders)
+/// // this
+/// let x: u8 = panic!();
+///
+/// // is (essentially) turned by the compiler into
+/// let x: u8 = absurd(panic!());
+///
+/// // where absurd is a function with the following signature
+/// // (it's sound, because `!` always marks unreachable code):
+/// fn absurd<T>(_: !) -> T { ... }
+// FIXME: use `core::convert::absurd` here instead, once it's merged
+/// ```
+///
+/// While it's convenient to be able to use non-diverging code in one of the branches (like
+/// `if a { b } else { return }`) this could lead to compilation errors:
+///
+/// ```compile_fail
+/// // this
+/// { panic!() };
+///
+/// // gets turned into this
+/// { absurd(panic!()) }; // error: can't infer the type of `absurd`
+/// ```
+///
+/// To prevent such errors, compiler remembers where it inserted `absurd` calls, and if it can't
+/// infer their type, it sets the type to the fallback type. `{ absurd::<Fallback>(panic!()) };`.
+/// This is what is known as "never type fallback".
+///
+/// Historically fallback was [`()`], causing confusing behavior where `!` spontaneously coerced
+/// to `()`, even though `()` was never mentioned (because of the fallback). There are plans to
+/// change it in 2024 edition (and possibly in all editions on a later date), see
+/// [Tracking Issue for making `!` fall back to `!`][fallback-ti].
+///
+/// [`()`]: prim@unit
+/// [fallback-ti]: https://github.com/rust-lang/rust/issues/123748
+///
 #[unstable(feature = "never_type", issue = "35121")]
 mod prim_never {}