Skip to content

Commit a9d8264

Browse files
committed
Address some review comments
1 parent 2403b18 commit a9d8264

File tree

6 files changed

+89
-53
lines changed

6 files changed

+89
-53
lines changed

src/divergence.md

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,32 @@ Divergence is the state where a particular section of code could never be encoun
66

77
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!())`).
88

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.diverging-expressions.place-expressions]
27-
A place expression of the type [`!`](./types/never.md) is considering _diverging_ only if it is read from.
28-
299
r[divergence.fallback]
3010
## Fallback
3111
If a type to be inferred is only unified with diverging expressions, then that type will be inferred to be `!`.
3212

33-
The following fails to compile because `!` does not implement `Debug`:
34-
```rust,compile_fail,E0277
35-
fn foo() -> i32 { 22 }
36-
match foo() {
37-
4 => Default::default(),
38-
_ => return,
39-
};
40-
```
13+
> [!EXAMPLE]
14+
> ```rust,compile_fail,E0277
15+
> fn foo() -> i32 { 22 }
16+
> match foo() {
17+
> // ERROR: The trait bound `!: Default` is not satisfied.
18+
> 4 => Default::default(),
19+
> _ => return,
20+
> };
21+
> ```
4122
4223
> [!EDITION-2024]
4324
> Before the 2024 edition, the type was inferred to instead be `()`.
4425
45-
Importantly, type unification may happen *structurally*, so the fallback `!` may be part of a larger type. The following compiles:
46-
```rust
47-
fn foo() -> i32 { 22 }
48-
// This has the type `Option<!>`, not `!`
49-
match foo() {
50-
4 => Default::default(),
51-
_ => Some(return),
52-
};
53-
```
26+
> [!NOTE]
27+
> Importantly, type unification may happen *structurally*, so the fallback `!` may be part of a larger type. The > following compiles:
28+
> ```rust
29+
> fn foo() -> i32 { 22 }
30+
> // This has the type `Option<!>`, not `!`
31+
> match foo() {
32+
> 4 => Default::default(),
33+
> _ => Some(return),
34+
> };
35+
> ```
5436
5537
<!-- TODO: This last point should likely should be moved to a more general "type inference" section discussing generalization + unification. -->

src/expressions/block-expr.md

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ r[expr.block.result]
4444
Then the final operand is executed, if given.
4545

4646
r[expr.block.type]
47-
Typically, the type of a block is the type of the final operand, or `()` if the final operand is omitted.
47+
Except in the case of divergence (see below), the type of a block is the type of the final operand, or `()` if the final operand is omitted.
4848

4949
```rust
5050
# fn fn_call() {}
@@ -64,7 +64,46 @@ assert_eq!(5, five);
6464
> As a control flow expression, if a block expression is the outer expression of an expression statement, the expected type is `()` unless it is followed immediately by a semicolon.
6565
6666
r[expr.block.type.diverging]
67-
A block is itself considered to be [diverging](../divergence.md) if all reachable control flow paths contain a [diverging expression](../divergence.md#r-divergence.diverging-expressions).
67+
A block is itself considered to be [diverging](../divergence.md) if all reachable control flow paths contain a [diverging expression](../divergence.md#r-divergence.diverging-expressions), unless that expression is a place expression that is not read from.
68+
69+
```rust
70+
# #![ feature(never_type) ]
71+
# fn make<T>() -> T { loop {} }
72+
let no_control_flow: ! = {
73+
// There are no conditional statements, so this entire block is diverging.
74+
loop {}
75+
};
76+
77+
let control_flow_diverging: ! = {
78+
// All paths are diverging, so this entire block is diverging.
79+
if true {
80+
loop {}
81+
} else {
82+
loop {}
83+
}
84+
};
85+
86+
let control_flow_not_diverging: () = {
87+
// Some paths are not diverging, so this entire block is not diverging.
88+
if true {
89+
()
90+
} else {
91+
loop {}
92+
}
93+
};
94+
95+
struct Foo {
96+
x: !,
97+
}
98+
99+
let foo = Foo { x: make() };
100+
let diverging_place_not_read: () = {
101+
let _: () = {
102+
// Asssignment to `_` means the place is not read
103+
let _ = foo.x;
104+
};
105+
};
106+
```
68107

69108
r[expr.block.value]
70109
Blocks are always [value expressions] and evaluate the last operand in value expression context.

src/expressions/if-expr.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,25 @@ let y = if 12 * 15 > 150 {
7373
assert_eq!(y, "Bigger");
7474
```
7575

76+
r[expr.if.diverging]
77+
An `if` expression diverges if either the condition expression diverges or if all arms diverge.
78+
79+
```rust
80+
# #![ feature(never_type) ]
81+
// Diverges because the condition expression diverges
82+
let x: ! = if { loop {}; true } {
83+
()
84+
} else {
85+
()
86+
};
87+
88+
let x: ! = if true {
89+
loop {}
90+
} else {
91+
loop {}
92+
};
93+
```
94+
7695
r[expr.if.let]
7796
## `if let` patterns
7897

src/expressions/loop-expr.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ for x in 1..100 {
292292
assert_eq!(last, 12);
293293
```
294294

295+
Thus, the `break` expression itself is diverging and has a type of [`!`](../types/never.md).
296+
295297
r[expr.loop.break.label]
296298
A `break` expression is normally associated with the innermost `loop`, `for` or `while` loop enclosing the `break` expression,
297299
but a [label](#loop-labels) can be used to specify which enclosing loop is affected.
@@ -308,9 +310,6 @@ Example:
308310
r[expr.loop.break.value]
309311
A `break` expression is only permitted in the body of a loop, and has one of the forms `break`, `break 'label` or ([see below](#break-and-loop-values)) `break EXPR` or `break 'label EXPR`.
310312

311-
r[expr.loop.break.type]
312-
A `break` expression itself has a type of [`!`](../types/never.md).
313-
314313
r[expr.loop.block-labels]
315314
## Labelled block expressions
316315

@@ -358,6 +357,8 @@ ContinueExpression -> `continue` LIFETIME_OR_LABEL?
358357
r[expr.loop.continue.intro]
359358
When `continue` is encountered, the current iteration of the associated loop body is immediately terminated, returning control to the loop *head*.
360359

360+
Thus, the `continue` expression itself has a type of [`!`](../types/never.md).
361+
361362
r[expr.loop.continue.while]
362363
In the case of a `while` loop, the head is the conditional operands controlling the loop.
363364

@@ -370,9 +371,6 @@ Like `break`, `continue` is normally associated with the innermost enclosing loo
370371
r[expr.loop.continue.in-loop-only]
371372
A `continue` expression is only permitted in the body of a loop.
372373

373-
r[expr.loop.continue.type]
374-
A `continue` expression itself has a type of [`!`](../types/never.md).
375-
376374
r[expr.loop.break-value]
377375
## `break` and loop values
378376

src/expressions/match-expr.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,21 @@ Every binding of the same name must have the same type, and have the same bindin
9999
r[expr.match.type]
100100
The type of the overall `match` expression is the [least upper bound](../type-coercions.md#r-coerce.least-upper-bound) of the individual match arms.
101101

102-
r[expr.match.type.diverging.empty]
102+
r[expr.match.empty]
103103
If there are no match arms, then the `match` expression is diverging and the type is [`!`](../types/never.md).
104104

105-
r[expr.match.type.diverging.conditional]
105+
r[expr.match.conditional]
106106
If either the scrutinee expression or all of the match arms diverge, then the entire `match` expression also diverges.
107107

108108
> [!NOTE]
109-
> If even the entire `match` expression diverges, its type may not be [`!`](../types/never.md).
109+
> Even if the entire `match` expression diverges, its type may not be [`!`](../types/never.md).
110110
>
111111
>```rust,compile_fail,E0004
112112
> let a = match true {
113113
> true => Some(panic!()),
114114
> false => None,
115115
> };
116-
> // Fails to compile because `a` has the type `Option<!>`
117-
> // (or, `Option<()>` in edition 2021 and below)
116+
> // Fails to compile because `a` has the type `Option<!>`.
118117
> match a {}
119118
>```
120119

src/expressions/return-expr.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Return expressions are denoted with the keyword `return`.
1212
r[expr.return.behavior]
1313
Evaluating a `return` expression moves its argument into the designated output location for the current function call, destroys the current function activation frame, and transfers control to the caller frame.
1414

15+
Thus, a `return` expression itself has a type of [`!`](../types/never.md).
16+
1517
An example of a `return` expression:
1618

1719
```rust
@@ -22,6 +24,3 @@ fn max(a: i32, b: i32) -> i32 {
2224
return b;
2325
}
2426
```
25-
26-
r[expr.return.type]
27-
A `return` expression itself has a type of [`!`](../types/never.md).

0 commit comments

Comments
 (0)