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.
|
// loop, so we need to account for that.
|
||||||
direct = !direct;
|
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)
|
&& (destination.label == label || direct)
|
||||||
{
|
{
|
||||||
if let Some((reason_span, message)) =
|
if let Some((reason_span, message)) =
|
||||||
|
@ -594,25 +594,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span,
|
span,
|
||||||
format!("this loop is expected to be of type `{expected}`"),
|
format!("this loop is expected to be of type `{expected}`"),
|
||||||
);
|
);
|
||||||
|
break 'outer;
|
||||||
} else {
|
} else {
|
||||||
// Locate all other `break` statements within the same `loop` that might
|
// Locate all other `break` statements within the same `loop` that might
|
||||||
// have affected inference.
|
// have affected inference.
|
||||||
struct FindBreaks<'tcx> {
|
struct FindBreaks<'tcx> {
|
||||||
label: Option<rustc_ast::Label>,
|
label: Option<rustc_ast::Label>,
|
||||||
uses: Vec<&'tcx hir::Expr<'tcx>>,
|
uses: Vec<&'tcx hir::Expr<'tcx>>,
|
||||||
|
nest_depth: usize,
|
||||||
}
|
}
|
||||||
impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
|
impl<'tcx> Visitor<'tcx> for FindBreaks<'tcx> {
|
||||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'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
|
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);
|
self.uses.push(ex);
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_expr(self, ex);
|
hir::intravisit::walk_expr(self, ex);
|
||||||
|
self.nest_depth = nest_depth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut expr_finder = FindBreaks { label, uses: vec![] };
|
let mut expr_finder = FindBreaks { label, uses: vec![], nest_depth: 0 };
|
||||||
expr_finder.visit_expr(parent);
|
expr_finder.visit_block(block);
|
||||||
|
let mut exit = false;
|
||||||
for ex in expr_finder.uses {
|
for ex in expr_finder.uses {
|
||||||
let hir::ExprKind::Break(_, val) = ex.kind else {
|
let hir::ExprKind::Break(_, val) = ex.kind else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -631,10 +645,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ex.span,
|
ex.span,
|
||||||
format!("expected because of this `break`"),
|
format!("expected because of this `break`"),
|
||||||
);
|
);
|
||||||
|
exit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if exit {
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break 'outer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
break; //~ ERROR mismatched types
|
break; //~ ERROR mismatched types
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = 'a: loop {
|
let _ = 'a: loop {
|
||||||
loop {
|
loop {
|
||||||
break; // This doesn't affect the expected break type of the 'a 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
|
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
|
loop { // point at the return type
|
||||||
break 2; //~ ERROR mismatched types
|
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
|
error[E0425]: cannot find value `LOOP` in this scope
|
||||||
--> $DIR/loop-break-value.rs:95:15
|
--> $DIR/loop-break-value.rs:95:15
|
||||||
|
|
|
|
||||||
|
@ -164,12 +182,19 @@ LL | break "asdf";
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/loop-break-value.rs:21:31
|
--> $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";
|
LL | break 'outer_loop "nope";
|
||||||
| ^^^^^^ expected `i32`, found `&str`
|
| ^^^^^^ expected `i32`, found `&str`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/loop-break-value.rs:73:26
|
--> $DIR/loop-break-value.rs:73:26
|
||||||
|
|
|
|
||||||
|
LL | break;
|
||||||
|
| ----- expected because of this `break`
|
||||||
LL | break 'c 123;
|
LL | break 'c 123;
|
||||||
| ^^^ expected `()`, found integer
|
| ^^^ expected `()`, found integer
|
||||||
|
|
||||||
|
@ -218,7 +243,7 @@ LL | break;
|
||||||
| help: give it a value of the expected type: `break value`
|
| help: give it a value of the expected type: `break value`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/loop-break-value.rs:119:9
|
--> $DIR/loop-break-value.rs:120:9
|
||||||
|
|
|
|
||||||
LL | break 'a 1;
|
LL | break 'a 1;
|
||||||
| ---------- expected because of this `break`
|
| ---------- expected because of this `break`
|
||||||
|
@ -230,7 +255,58 @@ LL | break 'a;
|
||||||
| help: give it a value of the expected type: `break 'a value`
|
| help: give it a value of the expected type: `break 'a value`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
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() {
|
LL | fn main() {
|
||||||
| - expected `()` because of this return type
|
| - expected `()` because of this return type
|
||||||
|
@ -240,7 +316,7 @@ LL | loop { // point at the return type
|
||||||
LL | break 2;
|
LL | break 2;
|
||||||
| ^ expected `()`, found integer
|
| ^ 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.
|
Some errors have detailed explanations: E0308, E0425, E0571.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue