Improve error msgs when found type is deref of expected
This improves help messages in two cases:
- When expected type is `T` and found type is `&T`, we now look through blocks
and suggest dereferencing the expression of the block, rather than the whole
block.
- In the above case, if the expression is an `&`, we not suggest removing the
`&` instead of adding `*`.
Both of these are demonstrated in the regression test. Before this patch the
first error in the test would be:
error[E0308]: `if` and `else` have incompatible types
--> test.rs:8:9
|
5 | / if true {
6 | | a
| | - expected because of this
7 | | } else {
8 | | b
| | ^ expected `usize`, found `&usize`
9 | | };
| |_____- `if` and `else` have incompatible types
|
help: consider dereferencing the borrow
|
7 | } else *{
8 | b
9 | };
|
Now:
error[E0308]: `if` and `else` have incompatible types
--> test.rs:8:9
|
5 | / if true {
6 | | a
| | - expected because of this
7 | | } else {
8 | | b
| | ^
| | |
| | expected `usize`, found `&usize`
| | help: consider dereferencing the borrow: `*b`
9 | | };
| |_____- `if` and `else` have incompatible types
The second error:
error[E0308]: `if` and `else` have incompatible types
--> test.rs:14:9
|
11 | / if true {
12 | | 1
| | - expected because of this
13 | | } else {
14 | | &1
| | ^^ expected integer, found `&{integer}`
15 | | };
| |_____- `if` and `else` have incompatible types
|
help: consider dereferencing the borrow
|
13 | } else *{
14 | &1
15 | };
|
now:
error[E0308]: `if` and `else` have incompatible types
--> test.rs:14:9
|
11 | / if true {
12 | | 1
| | - expected because of this
13 | | } else {
14 | | &1
| | ^-
| | ||
| | |help: consider removing the `&`: `1`
| | expected integer, found `&{integer}`
15 | | };
| |_____- `if` and `else` have incompatible types
Fixes #82361
This commit is contained in:
@@ -1577,6 +1577,14 @@ impl Expr<'_> {
|
|||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn peel_blocks(&self) -> &Self {
|
||||||
|
let mut expr = self;
|
||||||
|
while let ExprKind::Block(Block { expr: Some(inner), .. }, _) = &expr.kind {
|
||||||
|
expr = inner;
|
||||||
|
}
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
|
||||||
pub fn can_have_side_effects(&self) -> bool {
|
pub fn can_have_side_effects(&self) -> bool {
|
||||||
match self.peel_drop_temps().kind {
|
match self.peel_drop_temps().kind {
|
||||||
ExprKind::Path(_) | ExprKind::Lit(_) => false,
|
ExprKind::Path(_) | ExprKind::Lit(_) => false,
|
||||||
|
|||||||
@@ -616,10 +616,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
_ if sp == expr.span && !is_macro => {
|
_ if sp == expr.span && !is_macro => {
|
||||||
if let Some(steps) = self.deref_steps(checked_ty, expected) {
|
if let Some(steps) = self.deref_steps(checked_ty, expected) {
|
||||||
|
let expr = expr.peel_blocks();
|
||||||
|
|
||||||
if steps == 1 {
|
if steps == 1 {
|
||||||
// For a suggestion to make sense, the type would need to be `Copy`.
|
if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind {
|
||||||
if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp) {
|
// If the expression has `&`, removing it would fix the error
|
||||||
if let Ok(code) = sm.span_to_snippet(sp) {
|
let prefix_span = expr.span.with_hi(inner.span.lo());
|
||||||
|
let message = match mutbl {
|
||||||
|
hir::Mutability::Not => "consider removing the `&`",
|
||||||
|
hir::Mutability::Mut => "consider removing the `&mut`",
|
||||||
|
};
|
||||||
|
let suggestion = String::new();
|
||||||
|
return Some((
|
||||||
|
prefix_span,
|
||||||
|
message,
|
||||||
|
suggestion,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
));
|
||||||
|
} else if self.infcx.type_is_copy_modulo_regions(
|
||||||
|
self.param_env,
|
||||||
|
expected,
|
||||||
|
sp,
|
||||||
|
) {
|
||||||
|
// For this suggestion to make sense, the type would need to be `Copy`.
|
||||||
|
if let Ok(code) = sm.span_to_snippet(expr.span) {
|
||||||
let message = if checked_ty.is_region_ptr() {
|
let message = if checked_ty.is_region_ptr() {
|
||||||
"consider dereferencing the borrow"
|
"consider dereferencing the borrow"
|
||||||
} else {
|
} else {
|
||||||
@@ -631,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
format!("*{}", code)
|
format!("*{}", code)
|
||||||
};
|
};
|
||||||
return Some((
|
return Some((
|
||||||
sp,
|
expr.span,
|
||||||
message,
|
message,
|
||||||
suggestion,
|
suggestion,
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
|
|||||||
24
src/test/ui/suggestions/issue-82361.fixed
Normal file
24
src/test/ui/suggestions/issue-82361.fixed
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a: usize = 123;
|
||||||
|
let b: &usize = &a;
|
||||||
|
|
||||||
|
if true {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
*b //~ ERROR `if` and `else` have incompatible types [E0308]
|
||||||
|
};
|
||||||
|
|
||||||
|
if true {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
1 //~ ERROR `if` and `else` have incompatible types [E0308]
|
||||||
|
};
|
||||||
|
|
||||||
|
if true {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
1 //~ ERROR `if` and `else` have incompatible types [E0308]
|
||||||
|
};
|
||||||
|
}
|
||||||
24
src/test/ui/suggestions/issue-82361.rs
Normal file
24
src/test/ui/suggestions/issue-82361.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a: usize = 123;
|
||||||
|
let b: &usize = &a;
|
||||||
|
|
||||||
|
if true {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b //~ ERROR `if` and `else` have incompatible types [E0308]
|
||||||
|
};
|
||||||
|
|
||||||
|
if true {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
&1 //~ ERROR `if` and `else` have incompatible types [E0308]
|
||||||
|
};
|
||||||
|
|
||||||
|
if true {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
&mut 1 //~ ERROR `if` and `else` have incompatible types [E0308]
|
||||||
|
};
|
||||||
|
}
|
||||||
48
src/test/ui/suggestions/issue-82361.stderr
Normal file
48
src/test/ui/suggestions/issue-82361.stderr
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
|
--> $DIR/issue-82361.rs:10:9
|
||||||
|
|
|
||||||
|
LL | / if true {
|
||||||
|
LL | | a
|
||||||
|
| | - expected because of this
|
||||||
|
LL | | } else {
|
||||||
|
LL | | b
|
||||||
|
| | ^
|
||||||
|
| | |
|
||||||
|
| | expected `usize`, found `&usize`
|
||||||
|
| | help: consider dereferencing the borrow: `*b`
|
||||||
|
LL | | };
|
||||||
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
||||||
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
|
--> $DIR/issue-82361.rs:16:9
|
||||||
|
|
|
||||||
|
LL | / if true {
|
||||||
|
LL | | 1
|
||||||
|
| | - expected because of this
|
||||||
|
LL | | } else {
|
||||||
|
LL | | &1
|
||||||
|
| | -^
|
||||||
|
| | |
|
||||||
|
| | expected integer, found `&{integer}`
|
||||||
|
| | help: consider removing the `&`
|
||||||
|
LL | | };
|
||||||
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
||||||
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
|
--> $DIR/issue-82361.rs:22:9
|
||||||
|
|
|
||||||
|
LL | / if true {
|
||||||
|
LL | | 1
|
||||||
|
| | - expected because of this
|
||||||
|
LL | | } else {
|
||||||
|
LL | | &mut 1
|
||||||
|
| | -----^
|
||||||
|
| | |
|
||||||
|
| | expected integer, found `&mut {integer}`
|
||||||
|
| | help: consider removing the `&mut`
|
||||||
|
LL | | };
|
||||||
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
Reference in New Issue
Block a user