Skip to content

Commit 12ea0f6

Browse files
authored
Rollup merge of rust-lang#82364 - osa1:issue82361, r=estebank
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 rust-lang#82361 --- r? ````@estebank````
2 parents 20928e0 + fa74d48 commit 12ea0f6

File tree

5 files changed

+128
-4
lines changed

5 files changed

+128
-4
lines changed

compiler/rustc_hir/src/hir.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,14 @@ impl Expr<'_> {
15771577
expr
15781578
}
15791579

1580+
pub fn peel_blocks(&self) -> &Self {
1581+
let mut expr = self;
1582+
while let ExprKind::Block(Block { expr: Some(inner), .. }, _) = &expr.kind {
1583+
expr = inner;
1584+
}
1585+
expr
1586+
}
1587+
15801588
pub fn can_have_side_effects(&self) -> bool {
15811589
match self.peel_drop_temps().kind {
15821590
ExprKind::Path(_) | ExprKind::Lit(_) => false,

compiler/rustc_typeck/src/check/demand.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -616,10 +616,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
616616
}
617617
_ if sp == expr.span && !is_macro => {
618618
if let Some(steps) = self.deref_steps(checked_ty, expected) {
619+
let expr = expr.peel_blocks();
620+
619621
if steps == 1 {
620-
// For a suggestion to make sense, the type would need to be `Copy`.
621-
if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp) {
622-
if let Ok(code) = sm.span_to_snippet(sp) {
622+
if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind {
623+
// If the expression has `&`, removing it would fix the error
624+
let prefix_span = expr.span.with_hi(inner.span.lo());
625+
let message = match mutbl {
626+
hir::Mutability::Not => "consider removing the `&`",
627+
hir::Mutability::Mut => "consider removing the `&mut`",
628+
};
629+
let suggestion = String::new();
630+
return Some((
631+
prefix_span,
632+
message,
633+
suggestion,
634+
Applicability::MachineApplicable,
635+
));
636+
} else if self.infcx.type_is_copy_modulo_regions(
637+
self.param_env,
638+
expected,
639+
sp,
640+
) {
641+
// For this suggestion to make sense, the type would need to be `Copy`.
642+
if let Ok(code) = sm.span_to_snippet(expr.span) {
623643
let message = if checked_ty.is_region_ptr() {
624644
"consider dereferencing the borrow"
625645
} else {
@@ -631,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
631651
format!("*{}", code)
632652
};
633653
return Some((
634-
sp,
654+
expr.span,
635655
message,
636656
suggestion,
637657
Applicability::MachineApplicable,
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-rustfix
2+
3+
fn main() {
4+
let a: usize = 123;
5+
let b: &usize = &a;
6+
7+
if true {
8+
a
9+
} else {
10+
*b //~ ERROR `if` and `else` have incompatible types [E0308]
11+
};
12+
13+
if true {
14+
1
15+
} else {
16+
1 //~ ERROR `if` and `else` have incompatible types [E0308]
17+
};
18+
19+
if true {
20+
1
21+
} else {
22+
1 //~ ERROR `if` and `else` have incompatible types [E0308]
23+
};
24+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-rustfix
2+
3+
fn main() {
4+
let a: usize = 123;
5+
let b: &usize = &a;
6+
7+
if true {
8+
a
9+
} else {
10+
b //~ ERROR `if` and `else` have incompatible types [E0308]
11+
};
12+
13+
if true {
14+
1
15+
} else {
16+
&1 //~ ERROR `if` and `else` have incompatible types [E0308]
17+
};
18+
19+
if true {
20+
1
21+
} else {
22+
&mut 1 //~ ERROR `if` and `else` have incompatible types [E0308]
23+
};
24+
}
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/issue-82361.rs:10:9
3+
|
4+
LL | / if true {
5+
LL | | a
6+
| | - expected because of this
7+
LL | | } else {
8+
LL | | b
9+
| | ^
10+
| | |
11+
| | expected `usize`, found `&usize`
12+
| | help: consider dereferencing the borrow: `*b`
13+
LL | | };
14+
| |_____- `if` and `else` have incompatible types
15+
16+
error[E0308]: `if` and `else` have incompatible types
17+
--> $DIR/issue-82361.rs:16:9
18+
|
19+
LL | / if true {
20+
LL | | 1
21+
| | - expected because of this
22+
LL | | } else {
23+
LL | | &1
24+
| | -^
25+
| | |
26+
| | expected integer, found `&{integer}`
27+
| | help: consider removing the `&`
28+
LL | | };
29+
| |_____- `if` and `else` have incompatible types
30+
31+
error[E0308]: `if` and `else` have incompatible types
32+
--> $DIR/issue-82361.rs:22:9
33+
|
34+
LL | / if true {
35+
LL | | 1
36+
| | - expected because of this
37+
LL | | } else {
38+
LL | | &mut 1
39+
| | -----^
40+
| | |
41+
| | expected integer, found `&mut {integer}`
42+
| | help: consider removing the `&mut`
43+
LL | | };
44+
| |_____- `if` and `else` have incompatible types
45+
46+
error: aborting due to 3 previous errors
47+
48+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)