Skip to content

Commit d2bb772

Browse files
committed
Note irrefutable while let in loop type errors
1 parent 281c97c commit d2bb772

3 files changed

Lines changed: 101 additions & 7 deletions

File tree

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1881,7 +1881,7 @@ impl<'tcx> CoerceMany<'tcx> {
18811881

18821882
if let Some(expr) = expression {
18831883
if let hir::ExprKind::Loop(
1884-
_,
1884+
block,
18851885
_,
18861886
loop_src @ (hir::LoopSource::While | hir::LoopSource::ForLoop),
18871887
_,
@@ -1894,6 +1894,14 @@ impl<'tcx> CoerceMany<'tcx> {
18941894
};
18951895

18961896
err.note(format!("{loop_type} evaluate to unit type `()`"));
1897+
if loop_src == hir::LoopSource::While
1898+
&& let Some(pat) = irrefutable_while_let_pattern(block)
1899+
{
1900+
err.span_note(
1901+
pat.span,
1902+
"this pattern always matches, so the loop condition never fails",
1903+
);
1904+
}
18971905
}
18981906

18991907
fcx.emit_coerce_suggestions(
@@ -2126,6 +2134,24 @@ impl<'tcx> CoerceMany<'tcx> {
21262134
}
21272135
}
21282136

2137+
fn irrefutable_while_let_pattern<'hir>(block: &hir::Block<'hir>) -> Option<&'hir hir::Pat<'hir>> {
2138+
let hir::ExprKind::If(cond, _, _) = block.expr?.kind else {
2139+
return None;
2140+
};
2141+
let hir::ExprKind::Let(let_expr) = cond.kind else {
2142+
return None;
2143+
};
2144+
simple_irrefutable_pattern(let_expr.pat).then_some(let_expr.pat)
2145+
}
2146+
2147+
fn simple_irrefutable_pattern(pat: &hir::Pat<'_>) -> bool {
2148+
match pat.kind {
2149+
hir::PatKind::Wild | hir::PatKind::Binding(_, _, _, None) => true,
2150+
hir::PatKind::Tuple(pats, _) => pats.iter().all(simple_irrefutable_pattern),
2151+
_ => false,
2152+
}
2153+
}
2154+
21292155
/// Recursively visit goals to decide whether an unsizing is possible.
21302156
/// `Break`s when it isn't, and an error should be raised.
21312157
/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item.

tests/ui/coercion/coerce-loop-issue-122561.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,24 @@ fn while_zero_times() -> bool {
6969
}
7070
}
7171

72+
fn while_let_binding() -> bool {
73+
while let x = false {
74+
//~^ ERROR mismatched types
75+
if x {
76+
return true;
77+
}
78+
}
79+
}
80+
81+
fn while_let_tuple() -> bool {
82+
while let (x, _) = (false, true) {
83+
//~^ ERROR mismatched types
84+
if x {
85+
return true;
86+
}
87+
}
88+
}
89+
7290
fn while_never_type() -> ! {
7391
while true {
7492
//~^ ERROR mismatched types

tests/ui/coercion/coerce-loop-issue-122561.stderr

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | while true {
77
= note: `#[warn(while_true)]` on by default
88

99
warning: denote infinite loops with `loop { ... }`
10-
--> $DIR/coerce-loop-issue-122561.rs:73:5
10+
--> $DIR/coerce-loop-issue-122561.rs:91:5
1111
|
1212
LL | while true {
1313
| ^^^^^^^^^^ help: use `loop`
@@ -171,6 +171,56 @@ LL + /* `bool` value */
171171
error[E0308]: mismatched types
172172
--> $DIR/coerce-loop-issue-122561.rs:73:5
173173
|
174+
LL | fn while_let_binding() -> bool {
175+
| ---- expected `bool` because of return type
176+
LL | / while let x = false {
177+
LL | |
178+
LL | | if x {
179+
LL | | return true;
180+
LL | | }
181+
LL | | }
182+
| |_____^ expected `bool`, found `()`
183+
|
184+
= note: `while` loops evaluate to unit type `()`
185+
note: this pattern always matches, so the loop condition never fails
186+
--> $DIR/coerce-loop-issue-122561.rs:73:15
187+
|
188+
LL | while let x = false {
189+
| ^
190+
help: consider returning a value here
191+
|
192+
LL ~ }
193+
LL + /* `bool` value */
194+
|
195+
196+
error[E0308]: mismatched types
197+
--> $DIR/coerce-loop-issue-122561.rs:82:5
198+
|
199+
LL | fn while_let_tuple() -> bool {
200+
| ---- expected `bool` because of return type
201+
LL | / while let (x, _) = (false, true) {
202+
LL | |
203+
LL | | if x {
204+
LL | | return true;
205+
LL | | }
206+
LL | | }
207+
| |_____^ expected `bool`, found `()`
208+
|
209+
= note: `while` loops evaluate to unit type `()`
210+
note: this pattern always matches, so the loop condition never fails
211+
--> $DIR/coerce-loop-issue-122561.rs:82:15
212+
|
213+
LL | while let (x, _) = (false, true) {
214+
| ^^^^^^
215+
help: consider returning a value here
216+
|
217+
LL ~ }
218+
LL + /* `bool` value */
219+
|
220+
221+
error[E0308]: mismatched types
222+
--> $DIR/coerce-loop-issue-122561.rs:91:5
223+
|
174224
LL | fn while_never_type() -> ! {
175225
| - expected `!` because of return type
176226
LL | / while true {
@@ -188,7 +238,7 @@ LL + /* `loop {}` or `panic!("...")` */
188238
|
189239

190240
error[E0308]: mismatched types
191-
--> $DIR/coerce-loop-issue-122561.rs:87:5
241+
--> $DIR/coerce-loop-issue-122561.rs:105:5
192242
|
193243
LL | / for i in 0.. {
194244
LL | |
@@ -203,7 +253,7 @@ LL + /* `i32` value */
203253
|
204254

205255
error[E0308]: mismatched types
206-
--> $DIR/coerce-loop-issue-122561.rs:94:9
256+
--> $DIR/coerce-loop-issue-122561.rs:112:9
207257
|
208258
LL | / for i in 0..5 {
209259
LL | |
@@ -218,7 +268,7 @@ LL + /* `usize` value */
218268
|
219269

220270
error[E0308]: mismatched types
221-
--> $DIR/coerce-loop-issue-122561.rs:100:9
271+
--> $DIR/coerce-loop-issue-122561.rs:118:9
222272
|
223273
LL | / while false {
224274
LL | |
@@ -233,7 +283,7 @@ LL + /* `usize` value */
233283
|
234284

235285
error[E0308]: mismatched types
236-
--> $DIR/coerce-loop-issue-122561.rs:106:23
286+
--> $DIR/coerce-loop-issue-122561.rs:124:23
237287
|
238288
LL | let _ = |a: &[(); for x in 0..2 {}]| {};
239289
| ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
@@ -244,6 +294,6 @@ help: consider returning a value here
244294
LL | let _ = |a: &[(); for x in 0..2 {} /* `usize` value */]| {};
245295
| +++++++++++++++++++
246296

247-
error: aborting due to 14 previous errors; 2 warnings emitted
297+
error: aborting due to 16 previous errors; 2 warnings emitted
248298

249299
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)