Don't suggest breaking with value from for or while loops

This commit is contained in:
Alan Egerton
2026-01-09 12:04:23 +00:00
parent 7c7cf45dcf
commit 5674be29fa
3 changed files with 96 additions and 7 deletions
@@ -10,8 +10,8 @@
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
WherePredicateKind, expr_needs_parens, is_range_literal,
GenericBound, HirId, LoopSource, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind,
TyKind, WherePredicateKind, expr_needs_parens, is_range_literal,
};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_hir_analysis::suggest_impl_trait;
@@ -1170,15 +1170,23 @@ pub(in super::super) fn suggest_missing_break_or_return_expr(
}
let found = self.resolve_vars_if_possible(found);
let in_loop = self.is_loop(id)
|| self
.tcx
let innermost_loop = if self.is_loop(id) {
Some(self.tcx.hir_node(id))
} else {
self.tcx
.hir_parent_iter(id)
.take_while(|(_, node)| {
// look at parents until we find the first body owner
node.body_id().is_none()
})
.any(|(parent_id, _)| self.is_loop(parent_id));
.find_map(|(parent_id, node)| self.is_loop(parent_id).then_some(node))
};
let can_break_with_value = innermost_loop.is_some_and(|node| {
matches!(
node,
Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. })
)
});
let in_local_statement = self.is_local_statement(id)
|| self
@@ -1186,7 +1194,7 @@ pub(in super::super) fn suggest_missing_break_or_return_expr(
.hir_parent_iter(id)
.any(|(parent_id, _)| self.is_local_statement(parent_id));
if in_loop && in_local_statement {
if can_break_with_value && in_local_statement {
err.multipart_suggestion(
"you might have meant to break the loop with this value",
vec![
@@ -0,0 +1,39 @@
//! Don't suggest breaking with value from `for` or `while` loops
//!
//! Regression test for https://github.com/rust-lang/rust/issues/150850
fn returns_i32() -> i32 { 0 }
fn suggest_breaking_from_loop() {
let _ = loop {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
//~| SUGGESTION break
};
}
fn dont_suggest_breaking_from_for() {
let _ = for _ in 0.. {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
};
}
fn dont_suggest_breaking_from_while() {
let cond = true;
let _ = while cond {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
};
}
fn dont_suggest_breaking_from_for_nested_in_loop() {
let _ = loop {
for _ in 0.. {
returns_i32() //~ ERROR mismatched types
//~^ SUGGESTION ;
}
};
}
fn main() {}
@@ -0,0 +1,42 @@
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:9:9
|
LL | returns_i32()
| ^^^^^^^^^^^^^ expected `()`, found `i32`
|
help: consider using a semicolon here
|
LL | returns_i32();
| +
help: you might have meant to break the loop with this value
|
LL | break returns_i32();
| +++++ +
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:17:9
|
LL | returns_i32()
| ^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| expected `()`, found `i32`
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:25:9
|
LL | returns_i32()
| ^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| expected `()`, found `i32`
error[E0308]: mismatched types
--> $DIR/dont-suggest-break-from-unbreakable-loops.rs:33:13
|
LL | returns_i32()
| ^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| expected `()`, found `i32`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.