Advanced Type Features

The Never Type !

The never type—written !—is Rust's built-in empty (uninhabited) type representing computations that never return control to their caller. While the unit type () has exactly 1 possible value (()), the never type ! has 0 possible values: no instance of ! can ever exist at runtime.

Cardinality Comparison: (), !, and bool

Type Cardinalities (Number of Valid Runtime Inhabitants):

  `!` / `enum Infallible {}`  --->  0 inhabitants (computation diverges; never produces a value)
  `()` / `struct Unit;`       --->  1 inhabitant  (computation finishes with trivial `()` value)
  `bool`                      --->  2 inhabitants (`false`, `true`)
Type Inhabitants Size in Memory (size_of) Meaning as a Function Return Type (fn f() -> T)
! 0 0 bytes f() never returns normally (loops forever, panics, or exits the process)
std::convert::Infallible 0 0 bytes Empty enum Infallible {} used in generic type positions like Result<T, Infallible>
() 1 (()) 0 bytes f() returns normally with no meaningful payload

Diverging Functions (fn() -> !)

A function with return type -> ! is called a diverging function. The compiler verifies that every control-flow path through a diverging function either panics, calls another diverging function (such as std::process::exit or std::hint::unreachable_unchecked), or runs an infinite loop {} without a break:

// ❌ does not compile
fn invalid_diverging(flag: bool) -> ! {
    if flag {
        panic!("diverged via panic");
    }
    // Error: if `flag` is false, control reaches the end of the function,
    // producing `()` instead of diverging (`!`)!
}

fn main() {}
error[E0308]: mismatched types
 --> src/main.rs:2:37
  |
2 | fn invalid_diverging(flag: bool) -> ! {
  |    -----------------                ^ expected `!`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression

Elimination of Impossible Enum Branches (Result<T, Infallible>)

When an enum variant holds ! or an uninhabited enum like std::convert::Infallible (such as Result<u32, Infallible> returned by <u32 as TryFrom<u16>>::try_from), the Err variant has 0 inhabitants (1 * 0 = 0), so the compiler knows Err is unreachable and eliminates the discriminant tag entirely:

use std::convert::Infallible;

fn always_succeeds(x: u16) -> Result<u64, Infallible> {
    Ok(u64::from(x) * 10)
}

fn main() {
    println!("size of u64:                    {} bytes", size_of::<u64>());
    println!("size of Result<u64, Infallible>: {} bytes", size_of::<Result<u64, Infallible>>());

    // `let Ok(val) = ...` is an irrefutable pattern when the `Err` type is uninhabited!
    let Ok(val) = always_succeeds(42);
    println!("unwrapped irrefutably: {}", val);
}
size of u64:                    8 bytes
size of Result<u64, Infallible>: 8 bytes
unwrapped irrefutably: 420

Rust 2024 Edition Change: Never-Type Fallback to !

When a diverging expression appears in an unconstrained generic return position (such as panic!() inside a closure passed to a generic function fn call<R>(f: impl FnOnce() -> R) -> R), older Rust editions fell back to inferring R = (). Starting in the Rust 2024 edition, unconstrained never-type fallback resolves directly to R = !, and ! implements core traits (Debug, Display, Clone, Default, Error, PartialEq, Ord, Hash) in the standard library.