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: text/0000-loop-break-value.md
+53-32
Original file line number
Diff line number
Diff line change
@@ -84,14 +84,15 @@ Four forms of `break` will be supported:
84
84
3.`break EXPR;`
85
85
4.`break 'label EXPR;`
86
86
87
-
where `'label` is the name of a loop and `EXPR` is an expression.
87
+
where `'label` is the name of a loop and `EXPR` is an expression. `break` and `break 'label` become
88
+
equivalent to `break ()` and `break 'label ()` respectively.
88
89
89
90
### Result type of loop
90
91
91
92
Currently the result type of a 'loop' without 'break' is `!` (never returns),
92
-
which may be coerced to any type), and the result type of a 'loop' with 'break'
93
-
is `()`. This is important since a loop may appear as
94
-
the last expression of a function:
93
+
which may be coerced to any type. The result type of a 'loop' with a 'break'
94
+
is `()`. This is important since a loop may appear as the last expression of
95
+
a function:
95
96
96
97
```rust
97
98
fnf() {
@@ -109,20 +110,30 @@ fn g() -> () {
109
110
fnh() ->! {
110
111
loop {
111
112
do_something();
112
-
// this loop is not allowed to break due to inferred `!` type
113
+
// this loop must diverge for the function to typecheck
113
114
}
114
115
}
115
116
```
116
117
117
-
This proposal changes the result type of 'loop' to `T`, where:
118
-
119
-
* if a loop is "broken" via `break;` or `break 'label;`, the loop's result type must be `()`
120
-
* if a loop is "broken" via `break EXPR;` or `break 'label EXPR;`, `EXPR` must evaluate to type `T`
121
-
* as a special case, if a loop is "broken" via `break EXPR;` or `break 'label EXPR;` where `EXPR` evaluates to type `!` (does not return), this does not place a constraint on the type of the loop
122
-
* if external constaint on the loop's result type exist (e.g. `let x: S = loop { ... };`), then `T` must be coercible to this type
123
-
124
-
It is an error if these types do not agree or if the compiler's type deduction
125
-
rules do not yield a concrete type.
118
+
This proposal allows 'loop' expression to be of any type `T`, following the same typing and
119
+
inference rules that are applicable to other expressions in the language. Type of `EXPR` in every
120
+
`break EXPR` and `break 'label EXPR` must be coercible to the type of the loop the `EXPR` appears
121
+
in.
122
+
123
+
<!-- [ASIDE] The above paragraph captures pretty much every important typesystem interaction:
124
+
* `!` coerces to any type, so `break (expr: !)` works regardless of the loop type;
125
+
* It also does not preclude having `loop { break (expr: !) }: !`
126
+
* It, works well for `T = !`, because nothing in this paragraph demands to have breaks, only
127
+
sets requirements type coercibility;
128
+
* Similarly it works well for `T = ()` with all break forms because of `break` ≡ `break ()`.
129
+
* Finally the `loop { ... }: S` also works fine, because it requires every EXPR to coerce to
130
+
S, which is consistent with the behaviour of `if` bodies, `match` bodies etc.
131
+
* It also retains the `break`-less loop may be of type `!` property, because there’s no EXPRs
132
+
that have to coerce to `!`, whereas if it contains some `break`, then () cannot coerce to !.
133
+
-->
134
+
135
+
It is an error if these types do not agree or if the compiler's type deduction rules do not yield a
136
+
concrete type.
126
137
127
138
Examples of errors:
128
139
@@ -148,24 +159,6 @@ fn z() -> ! {
148
159
}
149
160
```
150
161
151
-
Examples involving `!`:
152
-
153
-
```rust
154
-
fnf() -> () {
155
-
// ! coerces to ()
156
-
loop {}
157
-
}
158
-
fng() ->u32 {
159
-
// ! coerces to u32
160
-
loop {}
161
-
}
162
-
fnz() ->! {
163
-
loop {
164
-
breakpanic!();
165
-
}
166
-
}
167
-
```
168
-
169
162
Example showing the equivalence of `break;` and `break ();`:
170
163
171
164
```rust
@@ -180,6 +173,34 @@ fn y() -> () {
180
173
}
181
174
```
182
175
176
+
Coercion examples:
177
+
178
+
```rust
179
+
// ! coerces to any type
180
+
loop {}: ();
181
+
loop {}:u32;
182
+
loop {
183
+
break (loop {}:!);
184
+
}:u32;
185
+
loop {
186
+
// ...
187
+
break42;
188
+
// ...
189
+
breakpanic!();
190
+
}:u32;
191
+
192
+
// break EXPRs are not of the same type, but both coerce to `&[u8]`.
193
+
letx= [0; 32];
194
+
lety= [0; 48];
195
+
loop {
196
+
// ...
197
+
break&x;
198
+
// ...
199
+
break&y;
200
+
}:&[u8];
201
+
```
202
+
203
+
183
204
### Result value
184
205
185
206
A loop only yields a value if broken via some form of `break ...;` statement,
0 commit comments