Rollup merge of #150872 - issue-150850, r=dianne

Fix some loop block coercion diagnostics

Fixes rust-lang/rust#150850
This commit is contained in:
Matthias Krüger 2026-01-10 08:33:58 +01:00 committed by GitHub
commit 86806ab019
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 102 additions and 18 deletions

View file

@ -54,7 +54,7 @@ use rustc_middle::ty::adjustment::{
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span};
use rustc_span::{BytePos, DUMMY_SP, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
use rustc_trait_selection::solve::{Certainty, Goal, NoSolution};
@ -1828,10 +1828,9 @@ impl<'tcx> CoerceMany<'tcx> {
// If the block is from an external macro or try (`?`) desugaring, then
// do not suggest adding a semicolon, because there's nowhere to put it.
// See issues #81943 and #87051.
&& matches!(
cond_expr.span.desugaring_kind(),
None | Some(DesugaringKind::WhileLoop)
)
// Similarly, if the block is from a loop desugaring, then also do not
// suggest adding a semicolon. See issue #150850.
&& cond_expr.span.desugaring_kind().is_none()
&& !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map())
&& !matches!(
cond_expr.kind,

View file

@ -10,8 +10,8 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.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![

View file

@ -9,12 +9,8 @@ LL | while true {
error[E0308]: mismatched types
--> $DIR/block-must-not-have-result-while.rs:5:9
|
LL | / while true {
LL | | true
| | ^^^^ expected `()`, found `bool`
LL | |
LL | | }
| |_____- expected this to be `()`
LL | true
| ^^^^ expected `()`, found `bool`
error: aborting due to 1 previous error; 1 warning emitted

View file

@ -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() {}

View file

@ -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`.