Skip to content

Commit 1451099

Browse files
Rollup merge of #157033 - anoshyn:issue-116572-irrefutable-while-let-note, r=Nadrieril
Note irrefutable while let in loop type errors When a while-let loop is used where a non-unit value is expected, rustc already notes that while loops evaluate to unit. For simple irrefutable while-let patterns, add an extra note explaining that the pattern always matches and the loop condition never fails. Covers binding, wildcard, and tuples made from those patterns. Fixes #116572. Tested with: ```./x test tests/ui/coercion/coerce-loop-issue-122561.rs --bless```
2 parents 6717454 + 57393b7 commit 1451099

3 files changed

Lines changed: 97 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_if_let_expr(block)
1899+
{
1900+
err.span_label(
1901+
pat.span,
1902+
"this pattern always matches, consider using `loop` instead",
1903+
);
1904+
}
18971905
}
18981906

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

2137+
fn irrefutable_if_let_expr<'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: 52 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,52 @@ 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+
| ^ - this pattern always matches, consider using `loop` instead
178+
| _____|
179+
| |
180+
LL | |
181+
LL | | if x {
182+
LL | | return true;
183+
LL | | }
184+
LL | | }
185+
| |_____^ expected `bool`, found `()`
186+
|
187+
= note: `while` loops evaluate to unit type `()`
188+
help: consider returning a value here
189+
|
190+
LL ~ }
191+
LL + /* `bool` value */
192+
|
193+
194+
error[E0308]: mismatched types
195+
--> $DIR/coerce-loop-issue-122561.rs:82:5
196+
|
197+
LL | fn while_let_tuple() -> bool {
198+
| ---- expected `bool` because of return type
199+
LL | while let (x, _) = (false, true) {
200+
| ^ ------ this pattern always matches, consider using `loop` instead
201+
| _____|
202+
| |
203+
LL | |
204+
LL | | if x {
205+
LL | | return true;
206+
LL | | }
207+
LL | | }
208+
| |_____^ expected `bool`, found `()`
209+
|
210+
= note: `while` loops evaluate to unit type `()`
211+
help: consider returning a value here
212+
|
213+
LL ~ }
214+
LL + /* `bool` value */
215+
|
216+
217+
error[E0308]: mismatched types
218+
--> $DIR/coerce-loop-issue-122561.rs:91:5
219+
|
174220
LL | fn while_never_type() -> ! {
175221
| - expected `!` because of return type
176222
LL | / while true {
@@ -188,7 +234,7 @@ LL + /* `loop {}` or `panic!("...")` */
188234
|
189235

190236
error[E0308]: mismatched types
191-
--> $DIR/coerce-loop-issue-122561.rs:87:5
237+
--> $DIR/coerce-loop-issue-122561.rs:105:5
192238
|
193239
LL | / for i in 0.. {
194240
LL | |
@@ -203,7 +249,7 @@ LL + /* `i32` value */
203249
|
204250

205251
error[E0308]: mismatched types
206-
--> $DIR/coerce-loop-issue-122561.rs:94:9
252+
--> $DIR/coerce-loop-issue-122561.rs:112:9
207253
|
208254
LL | / for i in 0..5 {
209255
LL | |
@@ -218,7 +264,7 @@ LL + /* `usize` value */
218264
|
219265

220266
error[E0308]: mismatched types
221-
--> $DIR/coerce-loop-issue-122561.rs:100:9
267+
--> $DIR/coerce-loop-issue-122561.rs:118:9
222268
|
223269
LL | / while false {
224270
LL | |
@@ -233,7 +279,7 @@ LL + /* `usize` value */
233279
|
234280

235281
error[E0308]: mismatched types
236-
--> $DIR/coerce-loop-issue-122561.rs:106:23
282+
--> $DIR/coerce-loop-issue-122561.rs:124:23
237283
|
238284
LL | let _ = |a: &[(); for x in 0..2 {}]| {};
239285
| ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
@@ -244,6 +290,6 @@ help: consider returning a value here
244290
LL | let _ = |a: &[(); for x in 0..2 {} /* `usize` value */]| {};
245291
| +++++++++++++++++++
246292

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

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

0 commit comments

Comments
 (0)