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

Divergence

A diverging expression is an expression that never completes normal execution.

#![allow(unused)]
fn main() {
fn diverges() -> ! {
    panic!("This function never returns!");
}

fn example() {
    let x: i32 = diverges(); // This line never completes.
    println!("This is never printed: {x}");
}
}

See the following rules for specific expression divergence behavior:

Note

The panic! macro and related panic-generating macros like unreachable! also have the type ! and are diverging.

Any expression of type ! is a diverging expression. However, diverging expressions are not limited to type !; expressions of other types may also diverge (e.g., Some(loop {}) has type Option<!>).

Note

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

#![allow(unused)]
fn main() {
enum Empty {}
fn make_never() -> ! {loop{}}
fn make_empty() -> Empty {loop{}}

fn diverging() -> ! {
    // This has a type of `!`.
    // So, the entire function is considered diverging.
    make_never();
    // OK: The type of the body is `!` which matches the return type.
}
fn not_diverging() -> ! {
    // This type is uninhabited.
    // However, the entire function is not considered diverging.
    make_empty();
    // ERROR: The type of the body is `()` but expected type `!`.
}
}

Note

Divergence can propagate to the surrounding block. See expr.block.diverging.

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),
};
}