Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Work in progress

Divergence

If an expression diverges, then nothing after that expression will execute. Importantly, while there are certain language constructs that immediately produce a diverging expression of the type !, divergence can also propogate to the surrounding block — where divergence indicates that the block itself will never finish executing.

Any expression of type ! is a diverging expression, but there are also diverging expressions which are not of type ! (e.g. Some(loop {}) produces a type of Option<!>).

Note

Though ! is considered an uninhabited type, a type being uninhabited is not sufficient for it to diverge.

#![allow(unused)]
fn main() {
#![ feature(never_type) ]
fn make<T>() -> T { loop {} }
enum Empty {}
fn diverging() -> ! {
    // This has a type of `!`.
    // So, the entire function is considered diverging
    make::<!>();
}
fn not_diverging() -> ! {
    // This type is uninhabited.
    // However, the entire function is not considered diverging
    make::<Empty>();
}
}

Fallback

If a type to be inferred is only unified with diverging expressions, then that type will be inferred to be !.

Example

#![allow(unused)]
fn main() {
fn foo() -> i32 { 22 }
match foo() {
    // ERROR: The trait bound `!: Default` is not satisfied.
    4 => Default::default(),
    _ => return,
};
}

2024 Edition differences

Before the 2024 edition, the type was inferred to instead be ().

Note

Importantly, type unification may happen structurally, so the fallback ! may be part of a larger type. The > following compiles:

#![allow(unused)]
fn main() {
fn foo() -> i32 { 22 }
// This has the type `Option<!>`, not `!`
match foo() {
    4 => Default::default(),
    _ => Some(return),
};
}