|
| 1 | +r[divergence] |
| 2 | +# Divergence |
| 3 | + |
| 4 | +r[divergence.intro] |
| 5 | +Divergence is the state where a particular section of code could never be encountered at runtime. Importantly, while there are certain language constructs that immediately produce a _diverging expression_ of the type [`!`](./types/never.md), divergence can also propogate to the surrounding block. |
| 6 | + |
| 7 | +Any expression of type [`!`](./types/never.md) is a _diverging expression_, but there are also diverging expressions which are not of type `!` (e.g. `Some(panic!())`). |
| 8 | + |
| 9 | +r[divergence.diverging-expressions] |
| 10 | +## Producing diverging expressions |
| 11 | + |
| 12 | +r[divergence.diverging-expressions.unconditional] |
| 13 | +The following language constructs unconditonally produce a _diverging expression_ of the type [`!`](./types/never.md): |
| 14 | + |
| 15 | +* [A call to a function returning `!`.](./types/never.md#r-type.never.constraint) |
| 16 | +* [A `loop` expression with no corresponding break.](./expressions/loop-expr.md#r-expr.loop.infinite.diverging) |
| 17 | +* [A `break` expression](./expressions/loop-expr.md#r-expr.loop.break.type) |
| 18 | +* [A `continue` expression](./expressions/loop-expr.md#r-expr.loop.continue.type) |
| 19 | +* [A `return` expression](./expressions/return-expr.md#r-expr.return.type) |
| 20 | +* [A `match` expression with no arms](./expressions/match-expr.md#r-expr.match.type.diverging.empty) |
| 21 | +* [A `block` expression that it itself is diverging.](../expressions/block-expr.md#r-expr.block.type.diverging) |
| 22 | + |
| 23 | +r[divergence.diverging-expressions.conditional] |
| 24 | +In a control flow expression, if all arms diverge, then the entire expression also diverges. |
| 25 | + |
| 26 | +r[divergence.fallback] |
| 27 | +## Fallback |
| 28 | +If a type to be inferred is only unified with diverging expressions, then that type will be inferred to be `!`. |
| 29 | + |
| 30 | +The following fails to compile because `!` does not implement `Debug`: |
| 31 | +```rust,compile_fail,E0277 |
| 32 | +fn foo() -> i32 { 22 } |
| 33 | +match foo() { |
| 34 | + 4 => Default::default(), |
| 35 | + _ => return, |
| 36 | +}; |
| 37 | +``` |
| 38 | + |
| 39 | +> [!EDITION-2024] |
| 40 | +> Before the 2024 edition, the type was inferred to instead be `()`. |
| 41 | +
|
| 42 | +Importantly, type unification may happen *structurally*, so the fallback `!` may be part of a larger type. The following compiles: |
| 43 | +```rust |
| 44 | +fn foo() -> i32 { 22 } |
| 45 | +// This has the type `Option<!>`, not `!` |
| 46 | +match foo() { |
| 47 | + 4 => Default::default(), |
| 48 | + _ => Some(return), |
| 49 | +}; |
| 50 | +``` |
| 51 | + |
| 52 | +<!-- TODO: This last point should likely should be moved to a more general "type inference" section discussing generalization + unification. --> |
0 commit comments