Skip to content

Commit b746484

Browse files
authored
Merge pull request #2 from nagisa/loop-break-pr
Refine rough edges wrt coercion
2 parents 32bdf90 + e9495fb commit b746484

File tree

1 file changed

+53
-32
lines changed

1 file changed

+53
-32
lines changed

text/0000-loop-break-value.md

+53-32
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,15 @@ Four forms of `break` will be supported:
8484
3. `break EXPR;`
8585
4. `break 'label EXPR;`
8686

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.
8889

8990
### Result type of loop
9091

9192
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:
9596

9697
```rust
9798
fn f() {
@@ -109,20 +110,30 @@ fn g() -> () {
109110
fn h() -> ! {
110111
loop {
111112
do_something();
112-
// this loop is not allowed to break due to inferred `!` type
113+
// this loop must diverge for the function to typecheck
113114
}
114115
}
115116
```
116117

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.
126137

127138
Examples of errors:
128139

@@ -148,24 +159,6 @@ fn z() -> ! {
148159
}
149160
```
150161

151-
Examples involving `!`:
152-
153-
```rust
154-
fn f() -> () {
155-
// ! coerces to ()
156-
loop {}
157-
}
158-
fn g() -> u32 {
159-
// ! coerces to u32
160-
loop {}
161-
}
162-
fn z() -> ! {
163-
loop {
164-
break panic!();
165-
}
166-
}
167-
```
168-
169162
Example showing the equivalence of `break;` and `break ();`:
170163

171164
```rust
@@ -180,6 +173,34 @@ fn y() -> () {
180173
}
181174
```
182175

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+
break 42;
188+
// ...
189+
break panic!();
190+
}: u32;
191+
192+
// break EXPRs are not of the same type, but both coerce to `&[u8]`.
193+
let x = [0; 32];
194+
let y = [0; 48];
195+
loop {
196+
// ...
197+
break &x;
198+
// ...
199+
break &y;
200+
}: &[u8];
201+
```
202+
203+
183204
### Result value
184205

185206
A loop only yields a value if broken via some form of `break ...;` statement,

0 commit comments

Comments
 (0)