You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/rust-2024/never-type-fallback.md
+13-28
Original file line number
Diff line number
Diff line change
@@ -4,12 +4,11 @@
4
4
5
5
## Summary
6
6
7
-
- Never type (`!`) to any type coercions fallback to never type (`!`)
7
+
- Never type (`!`) to any type coercions fallback to never type (`!`).
8
8
9
9
## Details
10
10
11
-
When the compiler sees a value of type ! in a [coercion site],
12
-
it implicitly inserts a coercion to allow the type checker to infer any type:
11
+
When the compiler sees a value of type ! in a [coercion site], it implicitly inserts a coercion to allow the type checker to infer any type:
13
12
14
13
```rust,ignore (has placeholders)
15
14
// this
@@ -33,8 +32,7 @@ This can lead to compilation errors if the type cannot be inferred:
33
32
{ absurd(panic!()) }; // error: can't infer the type of `absurd`
34
33
```
35
34
36
-
To prevent such errors, the compiler remembers where it inserted absurd calls,
37
-
and if it can’t infer the type, it uses the fallback type instead:
35
+
To prevent such errors, the compiler remembers where it inserted absurd calls, and if it can’t infer the type, it uses the fallback type instead:
38
36
39
37
```rust,ignore (has placeholders, uses code from previous example)
40
38
type Fallback = /* An arbitrarily selected type! */;
@@ -43,29 +41,21 @@ type Fallback = /* An arbitrarily selected type! */;
43
41
44
42
This is what is known as “never type fallback”.
45
43
46
-
Historically, the fallback type was `()`, causing confusing behavior where `!` spontaneously coerced to `()`,
47
-
even when it would not infer `()` without the fallback.
44
+
Historically, the fallback type was `()`, causing confusing behavior where `!` spontaneously coerced to `()`, even when it would not infer `()` without the fallback.
48
45
49
-
In the 2024 edition (and possibly in all editions on a later date) the fallback is now `!`.
50
-
This makes it work more intuitively, now when you pass `!` and there is no reason to coerce it to
51
-
something else, it is kept as `!`.
46
+
In the 2024 edition (and possibly in all editions on a later date) the fallback is now `!`. This makes it work more intuitively, now when you pass `!` and there is no reason to coerce it to something else, it is kept as `!`.
52
47
53
-
In some cases your code might depend on the fallback being `()`, so this can cause compilation
54
-
errors or changes in behavior.
48
+
In some cases your code might depend on the fallback being `()`, so this can cause compilation errors or changes in behavior.
There is no automatic fix, but there is automatic detection of code which will be broken by the
61
-
edition change. While still on a previous edition you should see warnings if your code will be
62
-
broken.
54
+
There is no automatic fix, but there is automatic detection of code which will be broken by the edition change. While still on a previous edition you should see warnings if your code will be broken.
63
55
64
-
In either case the fix is to specify the type explicitly, so the fallback is not used.
65
-
The complication is that it might not be trivial to see which type needs to be specified.
56
+
In either case the fix is to specify the type explicitly, so the fallback is not used. The complication is that it might not be trivial to see which type needs to be specified.
66
57
67
-
One of the most common patterns which are broken by this change is using `f()?;` where `f` is
68
-
generic over the ok-part of the return type:
58
+
One of the most common patterns which are broken by this change is using `f()?;` where `f` is generic over the ok-part of the return type:
69
59
70
60
```rust,ignore (can't compile outside of a result-returning function)
You might think that in this example type `T` can't be inferred, however due to the current
79
-
desugaring of `?` operator it used to be inferred to `()`, but it will be inferred to `!` now.
68
+
You might think that in this example type `T` can't be inferred, however due to the current desugaring of `?` operator it used to be inferred to `()`, but it will be inferred to `!` now.
80
69
81
70
To fix the issue you need to specify the `T` type explicitly:
Previously `!` from the `panic!` coerced to `()` which implements `Unit`.
103
-
However now the `!` is kept as `!` so this code fails because `!` does not implement `Unit`.
104
-
To fix this you can specify return type of the closure:
91
+
Previously `!` from the `panic!` coerced to `()` which implements `Unit`. However now the `!` is kept as `!` so this code fails because `!` does not implement `Unit`. To fix this you can specify return type of the closure:
105
92
106
93
```rust,ignore (uses function from the previous example)
107
94
run(|| -> () { panic!() });
108
95
```
109
96
110
-
A similar case to the `f()?` can be seen when using a `!`-typed expression in a branch and a
111
-
function with unconstrained return in the other:
97
+
A similar case to the `f()?` can be seen when using a `!`-typed expression in a branch and a function with unconstrained return in the other:
112
98
113
99
```rust,edition2015
114
100
if true {
@@ -118,8 +104,7 @@ if true {
118
104
};
119
105
```
120
106
121
-
Previously `()` was inferred as the return type of `Default::default()` because `!` from `return` got spuriously coerced to `()`.
122
-
Now, `!` will be inferred instead causing this code to not compile, because `!` does not implement `Default`.
107
+
Previously `()` was inferred as the return type of `Default::default()` because `!` from `return` got spuriously coerced to `()`. Now, `!` will be inferred instead causing this code to not compile, because `!` does not implement `Default`.
123
108
124
109
Again, this can be fixed by specifying the type explicitly:
0 commit comments