mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-19 11:12:43 +00:00
Auto merge of #116080 - estebank:issue-115905-2, r=compiler-errors
Point at more causes of expectation of break value when possible Follow up to #116071. r? `@compiler-errors` Disregard the first commit, which is in the other PR.
This commit is contained in:
commit
c614c17626
@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// When encountering a type error on the value of a `break`, try to point at the reason for the
|
||||
// expected type.
|
||||
fn annotate_loop_expected_due_to_inference(
|
||||
pub fn annotate_loop_expected_due_to_inference(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'_>,
|
||||
@ -540,16 +540,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return;
|
||||
};
|
||||
let mut parent_id = self.tcx.hir().parent_id(expr.hir_id);
|
||||
loop {
|
||||
let mut parent;
|
||||
'outer: loop {
|
||||
// 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::Stmt(hir::Stmt { kind: hir::StmtKind::Semi(&ref p), .. })
|
||||
| hir::Node::Expr(&ref p),
|
||||
) = self.tcx.hir().find(parent_id)
|
||||
else {
|
||||
break;
|
||||
};
|
||||
parent_id = self.tcx.hir().parent_id(parent.hir_id);
|
||||
parent = p;
|
||||
parent_id = self.tcx.hir().parent_id(parent_id);
|
||||
let hir::ExprKind::Break(destination, _) = parent.kind else {
|
||||
continue;
|
||||
};
|
||||
let mut parent_id = parent.hir_id;
|
||||
let mut parent_id = parent_id;
|
||||
let mut direct = false;
|
||||
loop {
|
||||
// Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to.
|
||||
let parent = match self.tcx.hir().find(parent_id) {
|
||||
@ -565,14 +572,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
parent_id = self.tcx.hir().parent_id(*hir_id);
|
||||
parent
|
||||
}
|
||||
Some(hir::Node::Block(hir::Block { .. })) => {
|
||||
Some(hir::Node::Block(_)) => {
|
||||
parent_id = self.tcx.hir().parent_id(parent_id);
|
||||
parent
|
||||
}
|
||||
_ => break,
|
||||
};
|
||||
if let hir::ExprKind::Loop(_, label, _, span) = parent.kind
|
||||
&& destination.label == label
|
||||
if let hir::ExprKind::Loop(..) = parent.kind {
|
||||
// When you have `'a: loop { break; }`, the `break` corresponds to the labeled
|
||||
// loop, so we need to account for that.
|
||||
direct = !direct;
|
||||
}
|
||||
if let hir::ExprKind::Loop(block, label, _, span) = parent.kind
|
||||
&& (destination.label == label || direct)
|
||||
{
|
||||
if let Some((reason_span, message)) =
|
||||
self.maybe_get_coercion_reason(parent_id, parent.span)
|
||||
@ -582,8 +594,64 @@ 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
|
||||
// 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![], 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;
|
||||
};
|
||||
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`"),
|
||||
);
|
||||
exit = true;
|
||||
}
|
||||
}
|
||||
if exit {
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,10 @@ use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
||||
use rustc_middle::ty::error::TypeError::FieldMisMatch;
|
||||
use rustc_middle::ty::error::{
|
||||
ExpectedFound,
|
||||
TypeError::{FieldMisMatch, Sorts},
|
||||
};
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
@ -664,15 +667,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.suggest_mismatched_types_on_tail(
|
||||
&mut err, expr, ty, e_ty, target_id,
|
||||
);
|
||||
let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
|
||||
self.annotate_loop_expected_due_to_inference(&mut err, expr, error);
|
||||
if let Some(val) = ty_kind_suggestion(ty) {
|
||||
let label = destination
|
||||
.label
|
||||
.map(|l| format!(" {}", l.ident))
|
||||
.unwrap_or_else(String::new);
|
||||
err.span_suggestion(
|
||||
expr.span,
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
"give it a value of the expected type",
|
||||
format!("break{label} {val}"),
|
||||
format!(" {val}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
@ -717,7 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// ... except when we try to 'break rust;'.
|
||||
// ICE this expression in particular (see #43162).
|
||||
if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
|
||||
if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust {
|
||||
if let [segment] = path.segments && segment.ident.name == sym::rust {
|
||||
fatally_break_rust(self.tcx);
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let expr = expr.peel_drop_temps();
|
||||
self.suggest_missing_semicolon(err, expr, expected, false);
|
||||
let mut pointing_at_return_type = false;
|
||||
if let hir::ExprKind::Break(..) = expr.kind {
|
||||
// `break` type mismatches provide better context for tail `loop` expressions.
|
||||
return false;
|
||||
}
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
||||
pointing_at_return_type = self.suggest_missing_return_type(
|
||||
err,
|
||||
|
@ -12,10 +12,12 @@ error[E0308]: mismatched types
|
||||
--> $DIR/issue-27042.rs:6:16
|
||||
|
|
||||
LL | loop { break };
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected `i32`, found `()`
|
||||
| help: give it a value of the expected type: `break 42`
|
||||
| ^^^^^ expected `i32`, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | loop { break 42 };
|
||||
| ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-27042.rs:8:9
|
||||
|
@ -95,6 +95,66 @@ fn main() {
|
||||
break LOOP;
|
||||
//~^ ERROR cannot find value `LOOP` in this scope
|
||||
}
|
||||
|
||||
let _ = 'a: loop {
|
||||
loop {
|
||||
break; // This doesn't affect the expected break type of the 'a loop
|
||||
loop {
|
||||
loop {
|
||||
break 'a 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break; //~ ERROR mismatched types
|
||||
};
|
||||
|
||||
let _ = 'a: loop {
|
||||
loop {
|
||||
break; // This doesn't affect the expected break type of the 'a loop
|
||||
loop {
|
||||
loop {
|
||||
break 'a 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
||||
@ -134,7 +152,10 @@ error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:4:31
|
||||
|
|
||||
LL | let val: ! = loop { break break; };
|
||||
| ^^^^^ expected `!`, found `()`
|
||||
| --- ---- ^^^^^ expected `!`, found `()`
|
||||
| | |
|
||||
| | this loop is expected to be of type `!`
|
||||
| expected because of this assignment
|
||||
|
|
||||
= note: expected type `!`
|
||||
found unit type `()`
|
||||
@ -142,6 +163,9 @@ LL | let val: ! = loop { break break; };
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:11:19
|
||||
|
|
||||
LL | break "asdf";
|
||||
| ------------ expected because of this `break`
|
||||
LL | } else {
|
||||
LL | break 123;
|
||||
| ^^^ expected `&str`, found integer
|
||||
|
||||
@ -169,6 +193,8 @@ LL | break 'outer_loop "nope";
|
||||
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
|
||||
|
||||
@ -176,7 +202,11 @@ error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:80:15
|
||||
|
|
||||
LL | break (break, break);
|
||||
| ^^^^^^^^^^^^^^ expected `()`, found `(!, !)`
|
||||
| ^-----^^-----^
|
||||
| || |
|
||||
| || expected because of this `break`
|
||||
| |expected because of this `break`
|
||||
| expected `()`, found `(!, !)`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found tuple `(!, !)`
|
||||
@ -184,20 +214,109 @@ LL | break (break, break);
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:85:15
|
||||
|
|
||||
LL | break;
|
||||
| ----- expected because of this `break`
|
||||
LL | break 2;
|
||||
| ^ expected `()`, found integer
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:90:9
|
||||
|
|
||||
LL | break 2;
|
||||
| ------- expected because of this `break`
|
||||
LL | break;
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected integer, found `()`
|
||||
| help: give it a value of the expected type: `break value`
|
||||
| ^^^^^ expected integer, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | break value;
|
||||
| +++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:99:15
|
||||
--> $DIR/loop-break-value.rs:108:9
|
||||
|
|
||||
LL | break 'a 1;
|
||||
| ---------- expected because of this `break`
|
||||
...
|
||||
LL | break;
|
||||
| ^^^^^ expected integer, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | break value;
|
||||
| +++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-break-value.rs:120:9
|
||||
|
|
||||
LL | break 'a 1;
|
||||
| ---------- expected because of this `break`
|
||||
...
|
||||
LL | break 'a;
|
||||
| ^^^^^^^^ expected integer, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | break 'a value;
|
||||
| +++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $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
|
||||
|
|
||||
LL | 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
|
||||
|
|
||||
LL | 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
|
||||
@ -207,7 +326,7 @@ LL | loop { // point at the return type
|
||||
LL | break 2;
|
||||
| ^ expected `()`, found integer
|
||||
|
||||
error: aborting due to 18 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`.
|
||||
|
@ -2,28 +2,34 @@ error[E0308]: mismatched types
|
||||
--> $DIR/loop-labeled-break-value.rs:3:29
|
||||
|
|
||||
LL | let _: i32 = loop { break };
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected `i32`, found `()`
|
||||
| help: give it a value of the expected type: `break 42`
|
||||
| ^^^^^ expected `i32`, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | let _: i32 = loop { break 42 };
|
||||
| ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-labeled-break-value.rs:6:37
|
||||
|
|
||||
LL | let _: i32 = 'inner: loop { break 'inner };
|
||||
| ^^^^^^^^^^^^
|
||||
| |
|
||||
| expected `i32`, found `()`
|
||||
| help: give it a value of the expected type: `break 'inner 42`
|
||||
| ^^^^^^^^^^^^ expected `i32`, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | let _: i32 = 'inner: loop { break 'inner 42 };
|
||||
| ++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/loop-labeled-break-value.rs:9:45
|
||||
|
|
||||
LL | let _: i32 = 'inner2: loop { loop { break 'inner2 } };
|
||||
| ^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected `i32`, found `()`
|
||||
| help: give it a value of the expected type: `break 'inner2 42`
|
||||
| ^^^^^^^^^^^^^ expected `i32`, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | let _: i32 = 'inner2: loop { loop { break 'inner2 42 } };
|
||||
| ++
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -2,10 +2,12 @@ error[E0308]: mismatched types
|
||||
--> $DIR/loop-properly-diverging-2.rs:2:23
|
||||
|
|
||||
LL | let x: i32 = loop { break };
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected `i32`, found `()`
|
||||
| help: give it a value of the expected type: `break 42`
|
||||
| ^^^^^ expected `i32`, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | let x: i32 = loop { break 42 };
|
||||
| ++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -33,10 +33,12 @@ error[E0308]: mismatched types
|
||||
--> $DIR/issue-52443.rs:4:17
|
||||
|
|
||||
LL | [(); loop { break }];
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected `usize`, found `()`
|
||||
| help: give it a value of the expected type: `break 42`
|
||||
| ^^^^^ expected `usize`, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | [(); loop { break 42 }];
|
||||
| ++
|
||||
|
||||
error[E0015]: cannot convert `RangeFrom<usize>` into an iterator in constants
|
||||
--> $DIR/issue-52443.rs:9:21
|
||||
|
@ -2,13 +2,16 @@ error[E0308]: mismatched types
|
||||
--> $DIR/type-error-break-tail.rs:3:20
|
||||
|
|
||||
LL | fn loop_ending() -> i32 {
|
||||
| --- expected `i32` because of return type
|
||||
| --- expected `i32` because of this return type
|
||||
LL | loop {
|
||||
| ---- this loop is expected to be of type `i32`
|
||||
LL | if false { break; }
|
||||
| ^^^^^
|
||||
| |
|
||||
| expected `i32`, found `()`
|
||||
| help: give it a value of the expected type: `break 42`
|
||||
| ^^^^^ expected `i32`, found `()`
|
||||
|
|
||||
help: give it a value of the expected type
|
||||
|
|
||||
LL | if false { break 42; }
|
||||
| ++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user