Skip to content

Commit 542dcbf

Browse files
authored
Rollup merge of #141812 - JonathanBrouwer:fix-else-if-help, r=jdonszelmann
Fix "consider borrowing" for else-if Fixes #141810 When trying to suggest a borrow on a `if` or `block` expression, instead we now recurse into the `if` or `block`. The comments in the code should explain the goal of the new code. r? ``@jdonszelmann``
2 parents ac49339 + b1a1df2 commit 542dcbf

9 files changed

+143
-0
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,31 @@ 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 not very helpful.
2720+
// We try to generate a suggestion such as `if ... { &... } else { &... }` instead.
2721+
if let hir::ExprKind::If(_c, then, els) = expr.kind {
2722+
// The `then` of a `Expr::If` always contains a block, and that block may have a final expression that we can borrow
2723+
// If the block does not have a final expression, it will return () and we do not make a suggestion to borrow that.
2724+
let ExprKind::Block(then, _) = then.kind else { return None };
2725+
let Some(then) = then.expr else { return None };
2726+
let (mut suggs, help, app, verbose, mutref) =
2727+
self.suggest_deref_or_ref(then, checked_ty, expected)?;
2728+
2729+
// If there is no `else`, the return type of this `if` will be (), so suggesting to change the `then` block is useless
2730+
let els_expr = match els?.kind {
2731+
ExprKind::Block(block, _) => block.expr?,
2732+
_ => els?,
2733+
};
2734+
let (else_suggs, ..) =
2735+
self.suggest_deref_or_ref(els_expr, checked_ty, expected)?;
2736+
suggs.extend(else_suggs);
2737+
2738+
return Some((suggs, help, app, verbose, mutref));
2739+
}
2740+
27162741
if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
27172742
return Some((
27182743
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: 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-3.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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn baz(x: &String) {}
2+
3+
fn bar() {
4+
baz({
5+
String::from("hi") //~ ERROR mismatched types
6+
});
7+
}
8+
9+
fn main() {
10+
bar();
11+
}
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-4.rs:5:9
3+
|
4+
LL | String::from("hi")
5+
| ^^^^^^^^^^^^^^^^^^ expected `&String`, found `String`
6+
|
7+
help: consider borrowing here
8+
|
9+
LL | &String::from("hi")
10+
| +
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)