Skip to content

Commit 92130a3

Browse files
committed
Add core::convert::absurd
1 parent ceab612 commit 92130a3

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

compiler/rustc_hir/src/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ language_item_table! {
317317
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
318318
TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;
319319

320+
Absurd, sym::absurd, absurd, Target::Fn, GenericRequirement::Exact(1);
321+
320322
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
321323

322324
ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ symbols! {
354354
abi_vectorcall,
355355
abi_x86_interrupt,
356356
abort,
357+
absurd,
357358
add,
358359
add_assign,
359360
add_with_overflow,

library/core/src/convert/mod.rs

+60
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,66 @@ pub const fn identity<T>(x: T) -> T {
105105
x
106106
}
107107

108+
/// Converts [`!`] (the never type) to any type.
109+
///
110+
/// This is possible because `!` is uninhabited (has no values), so this function can't actually
111+
/// be ever called at runtime.
112+
///
113+
/// Even though `!` can be coerced to any type implicitly anyway (and indeed this function
114+
/// implemented by just "returning" the argument), this is still useful, as this prevents the
115+
/// fallback from happening during typechecking.
116+
///
117+
/// For example, this snippet type checks:
118+
///
119+
/// ```rust
120+
/// let x: Result<_, ()> = Err(());
121+
/// let y = match x {
122+
/// Ok(v) => v,
123+
/// Err(()) => return,
124+
/// };
125+
/// ```
126+
///
127+
/// This is a bit unexpected, because the type of `y` is seemingly unbound (indeed, it can be any
128+
/// type). However, the `match` unifies type of `v` with type of `return` (which is `!`), so `y`
129+
/// becomes `!` (or `()`, because of backwards compatibility shenanigans).
130+
///
131+
/// This can be avoided by adding `absurd`;
132+
///
133+
/// ```compile_fail,E0282
134+
/// use core::convert::absurd;
135+
///
136+
/// let x: Result<_, ()> = Err(());
137+
/// let y = match x { //~ error[E0282]: type annotations needed
138+
/// Ok(v) => v,
139+
///
140+
/// // the call to `absurd` *is* unreachable, but it's still important for type check reasons
141+
/// #[allow(unreachable_code)]
142+
/// Err(()) => absurd(return),
143+
/// };
144+
/// ```
145+
///
146+
/// This might be handy when writing macros.
147+
///
148+
/// `absurd` can also be passed to higher order functions, just like any other function:
149+
///
150+
/// ```
151+
/// #![feature(never_type)]
152+
/// use core::convert::absurd;
153+
///
154+
/// let x: Result<_, !> = Ok(1);
155+
/// let x: u32 = x.unwrap_or_else(absurd);
156+
/// ```
157+
///
158+
/// [`!`]: ../../primitive.never.html
159+
#[inline(always)]
160+
#[lang = "absurd"]
161+
#[unstable(feature = "convert_absurd", issue = "none")]
162+
#[rustc_const_unstable(feature = "convert_absurd", issue = "none")]
163+
#[cfg(not(bootstrap))]
164+
pub const fn absurd<T>(x: !) -> T {
165+
x
166+
}
167+
108168
/// Used to do a cheap reference-to-reference conversion.
109169
///
110170
/// This trait is similar to [`AsMut`] which is used for converting between mutable references.

0 commit comments

Comments
 (0)