Handle all arbitrary loop
nesting in break
type errors
This commit is contained in:
parent
58adfd84e2
commit
3747ef5d6f
3 changed files with 137 additions and 8 deletions
|
@ -583,7 +583,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// loop, so we need to account for that.
|
||||
direct = !direct;
|
||||
}
|
||||
if let hir::ExprKind::Loop(_, label, _, span) = parent.kind
|
||||
if let hir::ExprKind::Loop(block, label, _, span) = parent.kind
|
||||
&& (destination.label == label || direct)
|
||||
{
|
||||
if let Some((reason_span, message)) =
|
||||
|
@ -594,25 +594,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span,
|
||||
format!("this loop is expected to be of type `{expected}`"),
|
||||
);
|
||||
break 'outer;
|
||||
} else {
|
||||
// Locate all other `break` statements within the same `loop` that might
|
||||
// have affected inference.
|
||||
struct FindBreaks<'tcx> {
|
||||
label: Option<rustc_ast::Label>,
|
||||
uses: Vec<&'tcx hir::Expr<'tcx>>,
|
||||
nest_depth: usize,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
||||
let nest_depth = self.nest_depth;
|
||||
if let hir::ExprKind::Loop(_, label, _, _) = ex.kind {
|
||||
if label == self.label {
|
||||
// Account for `'a: loop { 'a: loop {...} }`.
|
||||
return;
|
||||
}
|
||||
self.nest_depth += 1;
|
||||
}
|
||||
if let hir::ExprKind::Break(destination, _) = ex.kind
|
||||
&& self.label == destination.label
|
||||
&& (self.label == destination.label
|
||||
// Account for `loop { 'a: loop { loop { break; } } }`.
|
||||
|| destination.label.is_none() && self.nest_depth == 0)
|
||||
{
|
||||
self.uses.push(ex);
|
||||
}
|
||||
hir::intravisit::walk_expr(self, ex);
|
||||
self.nest_depth = nest_depth;
|
||||
}
|
||||
}
|
||||
let mut expr_finder = FindBreaks { label, uses: vec![] };
|
||||
expr_finder.visit_expr(parent);
|
||||
let mut expr_finder = FindBreaks { label, uses: vec![], nest_depth: 0 };
|
||||
expr_finder.visit_block(block);
|
||||
let mut exit = false;
|
||||
for ex in expr_finder.uses {
|
||||
let hir::ExprKind::Break(_, val) = ex.kind else {
|
||||
continue;
|
||||
|
@ -631,10 +645,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ex.span,
|
||||
format!("expected because of this `break`"),
|
||||
);
|
||||
exit = true;
|
||||
}
|
||||
}
|
||||
if exit {
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ fn main() {
|
|||
}
|
||||
break; //~ ERROR mismatched types
|
||||
};
|
||||
|
||||
let _ = 'a: loop {
|
||||
loop {
|
||||
break; // This doesn't affect the expected break type of the 'a loop
|
||||
|
@ -119,6 +120,41 @@ fn main() {
|
|||
break 'a; //~ ERROR mismatched types
|
||||
};
|
||||
|
||||
loop {
|
||||
break;
|
||||
let _ = loop {
|
||||
break 2;
|
||||
loop {
|
||||
break;
|
||||
}
|
||||
};
|
||||
break 2; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
'a: loop {
|
||||
break;
|
||||
let _ = 'a: loop {
|
||||
//~^ WARNING label name `'a` shadows a label name that is already in scope
|
||||
break 2;
|
||||
loop {
|
||||
break 'a; //~ ERROR mismatched types
|
||||
}
|
||||
};
|
||||
break 2; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
'a: loop {
|
||||
break;
|
||||
let _ = 'a: loop {
|
||||
//~^ WARNING label name `'a` shadows a label name that is already in scope
|
||||
break 'a 2;
|
||||
loop {
|
||||
break 'a; //~ ERROR mismatched types
|
||||
}
|
||||
};
|
||||
break 2; //~ ERROR mismatched types
|
||||
};
|
||||
|
||||
loop { // point at the return type
|
||||
break 2; //~ ERROR mismatched types
|
||||
}
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
warning: label name `'a` shadows a label name that is already in scope
|
||||
--> $DIR/loop-break-value.rs:136:17
|
||||
|
|
||||
LL | 'a: loop {
|
||||
| -- first declared here
|
||||
LL | break;
|
||||
LL | let _ = 'a: loop {
|
||||
| ^^ label `'a` already in scope
|
||||
|
||||
warning: label name `'a` shadows a label name that is already in scope
|
||||
--> $DIR/loop-break-value.rs:148:17
|
||||
|
|
||||
LL | 'a: loop {
|
||||
| -- first declared here
|
||||
LL | break;
|
||||
LL | let _ = 'a: loop {
|
||||
| ^^ label `'a` already in scope
|
||||
|
||||
error[E0425]: cannot find value `LOOP` in this scope
|
||||
--> $DIR/loop-break-value.rs:95:15
|
||||
|
|
||||
|
@ -164,12 +182,19 @@ LL | break "asdf";
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:21:31
|
||||
|
|
||||
LL | let _: i32 = 'outer_loop: loop {
|
||||
| - ---- this loop is expected to be of type `i32`
|
||||
| |
|
||||
| expected because of this assignment
|
||||
LL | loop {
|
||||
LL | break 'outer_loop "nope";
|
||||
| ^^^^^^ expected `i32`, found `&str`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:73:26
|
||||
|
|
||||
LL | break;
|
||||
| ----- expected because of this `break`
|
||||
LL | break 'c 123;
|
||||
| ^^^ expected `()`, found integer
|
||||
|
||||
|
@ -218,7 +243,7 @@ LL | break;
|
|||
| help: give it a value of the expected type: `break value`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:119:9
|
||||
--> $DIR/loop-break-value.rs:120:9
|
||||
|
|
||||
LL | break 'a 1;
|
||||
| ---------- expected because of this `break`
|
||||
|
@ -230,7 +255,58 @@ LL | break 'a;
|
|||
| help: give it a value of the expected type: `break 'a value`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:123:15
|
||||
--> $DIR/loop-break-value.rs:131:15
|
||||
|
|
||||
LL | break;
|
||||
| ----- expected because of this `break`
|
||||
...
|
||||
LL | break 2;
|
||||
| ^ expected `()`, found integer
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:140:17
|
||||
|
|
||||
LL | break 2;
|
||||
| ------- expected because of this `break`
|
||||
LL | loop {
|
||||
LL | break 'a;
|
||||
| ^^^^^^^^
|
||||
| |
|
||||
| expected integer, found `()`
|
||||
| help: give it a value of the expected type: `break 'a value`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:143:15
|
||||
|
|
||||
LL | break;
|
||||
| ----- expected because of this `break`
|
||||
...
|
||||
LL | break 2;
|
||||
| ^ expected `()`, found integer
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:152:17
|
||||
|
|
||||
LL | break 'a 2;
|
||||
| ---------- expected because of this `break`
|
||||
LL | loop {
|
||||
LL | break 'a;
|
||||
| ^^^^^^^^
|
||||
| |
|
||||
| expected integer, found `()`
|
||||
| help: give it a value of the expected type: `break 'a value`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:155:15
|
||||
|
|
||||
LL | break;
|
||||
| ----- expected because of this `break`
|
||||
...
|
||||
LL | break 2;
|
||||
| ^ expected `()`, found integer
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:159:15
|
||||
|
|
||||
LL | fn main() {
|
||||
| - expected `()` because of this return type
|
||||
|
@ -240,7 +316,7 @@ LL | loop { // point at the return type
|
|||
LL | break 2;
|
||||
| ^ expected `()`, found integer
|
||||
|
||||
error: aborting due to 20 previous errors; 1 warning emitted
|
||||
error: aborting due to 25 previous errors; 3 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0308, E0425, E0571.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
|
Loading…
Add table
Reference in a new issue