Skip to content

Commit ad3389a

Browse files
authored
Rollup merge of #84516 - torhovland:issue-84114, r=estebank
Add suggestion to "use break" when attempting to implicit-break a loop Fixes #84114
2 parents ae316d6 + 3b50461 commit ad3389a

File tree

4 files changed

+121
-5
lines changed

4 files changed

+121
-5
lines changed

compiler/rustc_typeck/src/check/coercion.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14941494
if let (Some((expr, _)), Some((fn_decl, _, _))) =
14951495
(expression, fcx.get_node_fn_decl(parent_item))
14961496
{
1497-
fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found, parent_id);
1497+
fcx.suggest_missing_break_or_return_expr(
1498+
&mut err, expr, fn_decl, expected, found, id, parent_id,
1499+
);
14981500
}
14991501

15001502
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {

compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs

+40-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
88
use rustc_hir as hir;
99
use rustc_hir::def::{CtorOf, DefKind};
1010
use rustc_hir::lang_items::LangItem;
11-
use rustc_hir::{ExprKind, ItemKind, Node};
11+
use rustc_hir::{Expr, ExprKind, ItemKind, Node, Stmt, StmtKind};
1212
use rustc_infer::infer;
1313
use rustc_middle::lint::in_external_macro;
1414
use rustc_middle::ty::{self, Binder, Ty};
@@ -55,7 +55,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5555
pointing_at_return_type =
5656
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
5757
let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
58-
self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found, fn_id);
58+
self.suggest_missing_break_or_return_expr(
59+
err, expr, &fn_decl, expected, found, blk_id, fn_id,
60+
);
5961
}
6062
pointing_at_return_type
6163
}
@@ -472,22 +474,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
472474
}
473475
}
474476

475-
pub(in super::super) fn suggest_missing_return_expr(
477+
pub(in super::super) fn suggest_missing_break_or_return_expr(
476478
&self,
477479
err: &mut DiagnosticBuilder<'_>,
478480
expr: &'tcx hir::Expr<'tcx>,
479481
fn_decl: &hir::FnDecl<'_>,
480482
expected: Ty<'tcx>,
481483
found: Ty<'tcx>,
482484
id: hir::HirId,
485+
fn_id: hir::HirId,
483486
) {
484487
if !expected.is_unit() {
485488
return;
486489
}
487490
let found = self.resolve_vars_with_obligations(found);
491+
492+
let in_loop = self.is_loop(id)
493+
|| self.tcx.hir().parent_iter(id).any(|(parent_id, _)| self.is_loop(parent_id));
494+
495+
let in_local_statement = self.is_local_statement(id)
496+
|| self
497+
.tcx
498+
.hir()
499+
.parent_iter(id)
500+
.any(|(parent_id, _)| self.is_local_statement(parent_id));
501+
502+
if in_loop && in_local_statement {
503+
err.multipart_suggestion(
504+
"you might have meant to break the loop with this value",
505+
vec![
506+
(expr.span.shrink_to_lo(), "break ".to_string()),
507+
(expr.span.shrink_to_hi(), ";".to_string()),
508+
],
509+
Applicability::MaybeIncorrect,
510+
);
511+
return;
512+
}
513+
488514
if let hir::FnRetTy::Return(ty) = fn_decl.output {
489515
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
490-
let bound_vars = self.tcx.late_bound_vars(id);
516+
let bound_vars = self.tcx.late_bound_vars(fn_id);
491517
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
492518
let ty = self.normalize_associated_types_in(expr.span, ty);
493519
if self.can_coerce(found, ty) {
@@ -514,4 +540,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
514540
self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
515541
}
516542
}
543+
544+
fn is_loop(&self, id: hir::HirId) -> bool {
545+
let node = self.tcx.hir().get(id);
546+
matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. }))
547+
}
548+
549+
fn is_local_statement(&self, id: hir::HirId) -> bool {
550+
let node = self.tcx.hir().get(id);
551+
matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. }))
552+
}
517553
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
fn main() {
2+
let a: i8 = loop {
3+
1 //~ ERROR mismatched types
4+
};
5+
6+
let b: i8 = loop {
7+
break 1;
8+
};
9+
}
10+
11+
fn foo() -> i8 {
12+
let a: i8 = loop {
13+
1 //~ ERROR mismatched types
14+
};
15+
16+
let b: i8 = loop {
17+
break 1;
18+
};
19+
20+
loop {
21+
1 //~ ERROR mismatched types
22+
}
23+
24+
loop {
25+
return 1;
26+
}
27+
28+
loop {
29+
1 //~ ERROR mismatched types
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/loop-no-implicit-break.rs:3:9
3+
|
4+
LL | 1
5+
| ^ expected `()`, found integer
6+
|
7+
help: you might have meant to break the loop with this value
8+
|
9+
LL | break 1;
10+
| ^^^^^ ^
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/loop-no-implicit-break.rs:13:9
14+
|
15+
LL | 1
16+
| ^ expected `()`, found integer
17+
|
18+
help: you might have meant to break the loop with this value
19+
|
20+
LL | break 1;
21+
| ^^^^^ ^
22+
23+
error[E0308]: mismatched types
24+
--> $DIR/loop-no-implicit-break.rs:21:9
25+
|
26+
LL | 1
27+
| ^ expected `()`, found integer
28+
|
29+
help: you might have meant to return this value
30+
|
31+
LL | return 1;
32+
| ^^^^^^ ^
33+
34+
error[E0308]: mismatched types
35+
--> $DIR/loop-no-implicit-break.rs:29:9
36+
|
37+
LL | 1
38+
| ^ expected `()`, found integer
39+
|
40+
help: you might have meant to return this value
41+
|
42+
LL | return 1;
43+
| ^^^^^^ ^
44+
45+
error: aborting due to 4 previous errors
46+
47+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)