Skip to content

Commit 3cb68f8

Browse files
committed
Point at previous breaks that have the expected type
1 parent d3dea30 commit 3cb68f8

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

compiler/rustc_hir_typeck/src/demand.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
530530

531531
// When encountering a type error on the value of a `break`, try to point at the reason for the
532532
// expected type.
533-
fn annotate_loop_expected_due_to_inference(
533+
pub fn annotate_loop_expected_due_to_inference(
534534
&self,
535535
err: &mut Diagnostic,
536536
expr: &hir::Expr<'_>,
@@ -540,11 +540,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
540540
return;
541541
};
542542
let mut parent_id = self.tcx.hir().parent_id(expr.hir_id);
543+
let mut parent;
543544
loop {
544545
// Climb the HIR tree to see if the current `Expr` is part of a `break;` statement.
545-
let Some(hir::Node::Expr(parent)) = self.tcx.hir().find(parent_id) else {
546+
let Some(hir::Node::Expr(p)) = self.tcx.hir().find(parent_id) else {
546547
break;
547548
};
549+
parent = p;
548550
parent_id = self.tcx.hir().parent_id(parent.hir_id);
549551
let hir::ExprKind::Break(destination, _) = parent.kind else {
550552
continue;
@@ -582,6 +584,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
582584
span,
583585
format!("this loop is expected to be of type `{expected}`"),
584586
);
587+
} else {
588+
// Locate all the usages of the relevant binding.
589+
struct FindBreaks<'tcx> {
590+
destination: hir::Destination,
591+
uses: Vec<&'tcx hir::Expr<'tcx>>,
592+
}
593+
impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
594+
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
595+
if let hir::ExprKind::Break(destination, _) = ex.kind
596+
&& self.destination.label == destination.label
597+
{
598+
self.uses.push(ex);
599+
}
600+
hir::intravisit::walk_expr(self, ex);
601+
}
602+
}
603+
let mut expr_finder = FindBreaks { destination, uses: vec![] };
604+
expr_finder.visit_expr(parent);
605+
for ex in expr_finder.uses {
606+
info!(?ex);
607+
let hir::ExprKind::Break(_, val) = ex.kind else {
608+
continue;
609+
};
610+
let ty = match val {
611+
Some(val) => {
612+
match self.typeck_results.borrow().expr_ty_adjusted_opt(val) {
613+
None => continue,
614+
Some(ty) => ty,
615+
}
616+
}
617+
None => self.tcx.types.unit,
618+
};
619+
if self.can_eq(self.param_env, ty, expected) {
620+
err.span_label(
621+
ex.span,
622+
format!("expected because of this `break`"),
623+
);
624+
}
625+
}
585626
}
586627
break;
587628
}

tests/ui/loops/loop-break-value.stderr

+10-1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ LL | let val: ! = loop { break break; };
142142
error[E0308]: mismatched types
143143
--> $DIR/loop-break-value.rs:11:19
144144
|
145+
LL | break "asdf";
146+
| ------------ expected because of this `break`
147+
LL | } else {
145148
LL | break 123;
146149
| ^^^ expected `&str`, found integer
147150

@@ -176,14 +179,20 @@ error[E0308]: mismatched types
176179
--> $DIR/loop-break-value.rs:80:15
177180
|
178181
LL | break (break, break);
179-
| ^^^^^^^^^^^^^^ expected `()`, found `(!, !)`
182+
| ^-----^^-----^
183+
| || |
184+
| || expected because of this `break`
185+
| |expected because of this `break`
186+
| expected `()`, found `(!, !)`
180187
|
181188
= note: expected unit type `()`
182189
found tuple `(!, !)`
183190

184191
error[E0308]: mismatched types
185192
--> $DIR/loop-break-value.rs:85:15
186193
|
194+
LL | break;
195+
| ----- expected because of this `break`
187196
LL | break 2;
188197
| ^ expected `()`, found integer
189198

0 commit comments

Comments
 (0)