Skip to content

Commit 58d73b1

Browse files
Fix consider borrowing for else-if
1 parent 6de3a73 commit 58d73b1

13 files changed

+218
-0
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27132713
));
27142714
}
27152715

2716+
// Don't try to suggest ref/deref on an `if` expression, because:
2717+
// - The `if` could be part of a desugared `if else` statement,
2718+
// which would create impossible suggestions such as `if ... { ... } else &if { ... } else { ... }`.
2719+
// - In general the suggestions it creates such as `&if ... { ... } else { ... }` are kind of ugly.
2720+
// We try to generate a suggestion such as `if ... { &... } else { &... }` instead.
2721+
if let hir::ExprKind::If(_c, then, els) = expr.kind {
2722+
// If there is no `else`, the return type of this `if` will be (), so suggesting to change the `then` block is useless
2723+
let Some(els) = els else {
2724+
return None;
2725+
};
2726+
let (mut then_suggs, help, app, verbose, mutref) =
2727+
self.suggest_deref_or_ref(then, checked_ty, expected)?;
2728+
let (else_suggs, ..) =
2729+
self.suggest_deref_or_ref(els, checked_ty, expected)?;
2730+
then_suggs.extend(else_suggs);
2731+
return Some((then_suggs, help, app, verbose, mutref));
2732+
}
2733+
2734+
// Don't try to suggest ref/deref on a `block` expression, because it is ugly.
2735+
// It creates suggestions such as `&{ ... }`.
2736+
// Instead suggest `{ ...; &... }` ref/deref on the final expression
2737+
if let hir::ExprKind::Block(block, _) = expr.kind {
2738+
// If the block expression does not have a final expression the type will be `()`,
2739+
// in which case there are no good ref/deref suggestions to be made.
2740+
let Some(expr) = block.expr else {
2741+
return None;
2742+
};
2743+
return self.suggest_deref_or_ref(expr, checked_ty, expected);
2744+
}
2745+
27162746
if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
27172747
return Some((
27182748
sugg,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
let x = if true {
3+
&true
4+
} else if false { //~ ERROR `if` and `else` have incompatible types [E0308]
5+
true //~ HELP consider borrowing here
6+
} else {
7+
true
8+
};
9+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/consider-borrowing-141810-1.rs:4:12
3+
|
4+
LL | let x = if true {
5+
| ______________-
6+
LL | | &true
7+
| | ----- expected because of this
8+
LL | | } else if false {
9+
| | ____________^
10+
LL | || true
11+
LL | || } else {
12+
LL | || true
13+
LL | || };
14+
| || ^
15+
| ||_____|
16+
| |_____`if` and `else` have incompatible types
17+
| expected `&bool`, found `bool`
18+
|
19+
help: consider borrowing here
20+
|
21+
LL ~ &true
22+
LL | } else {
23+
LL ~ &true
24+
|
25+
26+
error: aborting due to 1 previous error
27+
28+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
let x = if true {
3+
&()
4+
} else if false { //~ ERROR `if` and `else` have incompatible types [E0308]
5+
} else {
6+
};
7+
8+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/consider-borrowing-141810-2.rs:4:12
3+
|
4+
LL | let x = if true {
5+
| ______________-
6+
LL | | &()
7+
| | --- expected because of this
8+
LL | | } else if false {
9+
| | ____________^
10+
LL | || } else {
11+
LL | || };
12+
| || ^
13+
| ||_____|
14+
| |_____`if` and `else` have incompatible types
15+
| expected `&()`, found `()`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
expect_ref_bool({
3+
true
4+
//~^ ERROR mismatched types
5+
//~| HELP consider borrowing here
6+
})
7+
}
8+
9+
fn expect_ref_bool(b: &bool) {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/consider-borrowing-141810-3.rs:3:9
3+
|
4+
LL | true
5+
| ^^^^ expected `&bool`, found `bool`
6+
|
7+
help: consider borrowing here
8+
|
9+
LL | &true
10+
| +
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {
2+
let x = if true {
3+
&true
4+
} else if false { //~ ERROR `if` and `else` have incompatible types [E0308]
5+
{
6+
true //~ HELP consider borrowing here
7+
}
8+
} else {
9+
true
10+
};
11+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/consider-borrowing-141810-4.rs:4:12
3+
|
4+
LL | let x = if true {
5+
| ______________-
6+
LL | | &true
7+
| | ----- expected because of this
8+
LL | | } else if false {
9+
| | ____________^
10+
LL | || {
11+
LL | || true
12+
... ||
13+
LL | || true
14+
LL | || };
15+
| || ^
16+
| ||_____|
17+
| |_____`if` and `else` have incompatible types
18+
| expected `&bool`, found `bool`
19+
|
20+
help: consider borrowing here
21+
|
22+
LL ~ &true
23+
LL | }
24+
LL | } else {
25+
LL ~ &true
26+
|
27+
28+
error: aborting due to 1 previous error
29+
30+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let x = if true {
3+
&()
4+
} else if false { //~ ERROR `if` and `else` have incompatible types [E0308]
5+
6+
};
7+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/consider-borrowing-141810-5.rs:4:12
3+
|
4+
LL | let x = if true {
5+
| ______________-
6+
LL | | &()
7+
| | --- expected because of this
8+
LL | | } else if false {
9+
| | ____________^
10+
LL | ||
11+
LL | || };
12+
| || ^
13+
| ||_____|
14+
| |_____`if` and `else` have incompatible types
15+
| expected `&()`, found `()`
16+
|
17+
= note: `if` expressions without `else` evaluate to `()`
18+
= note: consider adding an `else` block that evaluates to the expected type
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
let x = if true {
3+
&()
4+
} else if false { //~ ERROR `if` and `else` have incompatible types [E0308]
5+
{
6+
7+
}
8+
};
9+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/consider-borrowing-141810-6.rs:4:12
3+
|
4+
LL | let x = if true {
5+
| ______________-
6+
LL | | &()
7+
| | --- expected because of this
8+
LL | | } else if false {
9+
| | ____________^
10+
... ||
11+
LL | || };
12+
| || ^
13+
| ||_____|
14+
| |_____`if` and `else` have incompatible types
15+
| expected `&()`, found `()`
16+
|
17+
= note: `if` expressions without `else` evaluate to `()`
18+
= note: consider adding an `else` block that evaluates to the expected type
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)