Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
Expand Down
22 changes: 15 additions & 7 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1170,23 +1170,31 @@ 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
.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![
Expand Down
8 changes: 2 additions & 6 deletions tests/ui/block-result/block-must-not-have-result-while.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Loading