Point at previous breaks that have the expected type
This commit is contained in:
parent
af68593179
commit
f6d4950fee
@ -530,7 +530,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
|||||||
|
|
||||||
// When encountering a type error on the value of a `break`, try to point at the reason for the
|
// When encountering a type error on the value of a `break`, try to point at the reason for the
|
||||||
// expected type.
|
// expected type.
|
||||||
fn annotate_loop_expected_due_to_inference(
|
pub fn annotate_loop_expected_due_to_inference(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
@ -540,11 +540,13 @@ fn annotate_loop_expected_due_to_inference(
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut parent_id = self.tcx.hir().parent_id(expr.hir_id);
|
let mut parent_id = self.tcx.hir().parent_id(expr.hir_id);
|
||||||
|
let mut parent;
|
||||||
loop {
|
loop {
|
||||||
// Climb the HIR tree to see if the current `Expr` is part of a `break;` statement.
|
// Climb the HIR tree to see if the current `Expr` is part of a `break;` statement.
|
||||||
let Some(hir::Node::Expr(parent)) = self.tcx.hir().find(parent_id) else {
|
let Some(hir::Node::Expr(p)) = self.tcx.hir().find(parent_id) else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
parent = p;
|
||||||
parent_id = self.tcx.hir().parent_id(parent.hir_id);
|
parent_id = self.tcx.hir().parent_id(parent.hir_id);
|
||||||
let hir::ExprKind::Break(destination, _) = parent.kind else {
|
let hir::ExprKind::Break(destination, _) = parent.kind else {
|
||||||
continue;
|
continue;
|
||||||
@ -582,6 +584,45 @@ fn annotate_loop_expected_due_to_inference(
|
|||||||
span,
|
span,
|
||||||
format!("this loop is expected to be of type `{expected}`"),
|
format!("this loop is expected to be of type `{expected}`"),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// Locate all other `break` statements within the same `loop` that might
|
||||||
|
// have affected inference.
|
||||||
|
struct FindBreaks<'tcx> {
|
||||||
|
destination: hir::Destination,
|
||||||
|
uses: Vec<&'tcx hir::Expr<'tcx>>,
|
||||||
|
}
|
||||||
|
impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
|
||||||
|
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
||||||
|
if let hir::ExprKind::Break(destination, _) = ex.kind
|
||||||
|
&& self.destination.label == destination.label
|
||||||
|
{
|
||||||
|
self.uses.push(ex);
|
||||||
|
}
|
||||||
|
hir::intravisit::walk_expr(self, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut expr_finder = FindBreaks { destination, uses: vec![] };
|
||||||
|
expr_finder.visit_expr(parent);
|
||||||
|
for ex in expr_finder.uses {
|
||||||
|
let hir::ExprKind::Break(_, val) = ex.kind else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let ty = match val {
|
||||||
|
Some(val) => {
|
||||||
|
match self.typeck_results.borrow().expr_ty_adjusted_opt(val) {
|
||||||
|
None => continue,
|
||||||
|
Some(ty) => ty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => self.tcx.types.unit,
|
||||||
|
};
|
||||||
|
if self.can_eq(self.param_env, ty, expected) {
|
||||||
|
err.span_label(
|
||||||
|
ex.span,
|
||||||
|
format!("expected because of this `break`"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,9 @@ LL | let val: ! = loop { break break; };
|
|||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/loop-break-value.rs:11:19
|
--> $DIR/loop-break-value.rs:11:19
|
||||||
|
|
|
|
||||||
|
LL | break "asdf";
|
||||||
|
| ------------ expected because of this `break`
|
||||||
|
LL | } else {
|
||||||
LL | break 123;
|
LL | break 123;
|
||||||
| ^^^ expected `&str`, found integer
|
| ^^^ expected `&str`, found integer
|
||||||
|
|
||||||
@ -176,7 +179,11 @@ error[E0308]: mismatched types
|
|||||||
--> $DIR/loop-break-value.rs:80:15
|
--> $DIR/loop-break-value.rs:80:15
|
||||||
|
|
|
|
||||||
LL | break (break, break);
|
LL | break (break, break);
|
||||||
| ^^^^^^^^^^^^^^ expected `()`, found `(!, !)`
|
| ^-----^^-----^
|
||||||
|
| || |
|
||||||
|
| || expected because of this `break`
|
||||||
|
| |expected because of this `break`
|
||||||
|
| expected `()`, found `(!, !)`
|
||||||
|
|
|
|
||||||
= note: expected unit type `()`
|
= note: expected unit type `()`
|
||||||
found tuple `(!, !)`
|
found tuple `(!, !)`
|
||||||
@ -184,6 +191,8 @@ LL | break (break, break);
|
|||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/loop-break-value.rs:85:15
|
--> $DIR/loop-break-value.rs:85:15
|
||||||
|
|
|
|
||||||
|
LL | break;
|
||||||
|
| ----- expected because of this `break`
|
||||||
LL | break 2;
|
LL | break 2;
|
||||||
| ^ expected `()`, found integer
|
| ^ expected `()`, found integer
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user