Skip to content

Commit

Permalink
Rollup merge of #99974 - TaKO8Ki:suggest-removing-semicolon-and-boxin…
Browse files Browse the repository at this point in the history
…g-the-expressions, r=compiler-errors

Suggest removing a semicolon and boxing the expressions for if-else

`InferCtxt::suggest_remove_semi_or_return_binding` was not working well, so I fixed it and added a ui test.
  • Loading branch information
Dylan-DPC authored Jul 31, 2022
2 parents 8b2637f + f6908be commit 990bce4
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 6 deletions.
16 changes: 10 additions & 6 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
opt_suggest_box_span,
}) => {
let then_span = self.find_block_span_from_hir_id(then_id);
let else_span = self.find_block_span_from_hir_id(then_id);
let else_span = self.find_block_span_from_hir_id(else_id);
err.span_label(then_span, "expected because of this");
if let Some(sp) = outer_span {
err.span_label(sp, "`if` and `else` have incompatible types");
Expand Down Expand Up @@ -760,11 +760,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
second_ty: Ty<'tcx>,
second_span: Span,
) {
let remove_semicolon =
[(first_id, second_ty), (second_id, first_ty)].into_iter().find_map(|(id, ty)| {
let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None };
self.could_remove_semicolon(blk, ty)
});
let remove_semicolon = [
(first_id, self.resolve_vars_if_possible(second_ty)),
(second_id, self.resolve_vars_if_possible(first_ty)),
]
.into_iter()
.find_map(|(id, ty)| {
let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None };
self.could_remove_semicolon(blk, ty)
});
match remove_semicolon {
Some((sp, StatementAsExpression::NeedsBoxing)) => {
err.multipart_suggestion(
Expand Down
70 changes: 70 additions & 0 deletions src/test/ui/suggestions/if-then-neeing-semi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// edition:2018

fn dummy() -> i32 {
42
}

fn extra_semicolon() {
let _ = if true {
//~^ NOTE `if` and `else` have incompatible types
dummy(); //~ NOTE expected because of this
//~^ HELP consider removing this semicolon
} else {
dummy() //~ ERROR `if` and `else` have incompatible types
//~^ NOTE expected `()`, found `i32`
};
}

async fn async_dummy() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE while checking the return type of the `async fn`
//~| NOTE in this expansion of desugaring of `async` block or function
//~| NOTE checked the `Output` of this `async fn`, expected opaque type
//~| NOTE while checking the return type of the `async fn`
//~| NOTE in this expansion of desugaring of `async` block or function
async fn async_dummy2() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE while checking the return type of the `async fn`
//~| NOTE in this expansion of desugaring of `async` block or function
//~| NOTE while checking the return type of the `async fn`
//~| NOTE in this expansion of desugaring of `async` block or function

async fn async_extra_semicolon_same() {
let _ = if true {
//~^ NOTE `if` and `else` have incompatible types
async_dummy(); //~ NOTE expected because of this
//~^ HELP consider removing this semicolon
} else {
async_dummy() //~ ERROR `if` and `else` have incompatible types
//~^ NOTE expected `()`, found opaque type
//~| NOTE expected unit type `()`
//~| HELP consider `await`ing on the `Future`
};
}

async fn async_extra_semicolon_different() {
let _ = if true {
//~^ NOTE `if` and `else` have incompatible types
async_dummy(); //~ NOTE expected because of this
//~^ HELP consider removing this semicolon
} else {
async_dummy2() //~ ERROR `if` and `else` have incompatible types
//~^ NOTE expected `()`, found opaque type
//~| NOTE expected unit type `()`
//~| HELP consider `await`ing on the `Future`
};
}

async fn async_different_futures() {
let _ = if true {
//~^ NOTE `if` and `else` have incompatible types
async_dummy() //~ NOTE expected because of this
//~| HELP consider `await`ing on both `Future`s
} else {
async_dummy2() //~ ERROR `if` and `else` have incompatible types
//~^ NOTE expected opaque type, found a different opaque type
//~| NOTE expected opaque type `impl Future<Output = ()>`
//~| NOTE distinct uses of `impl Trait` result in different opaque types
};
}

fn main() {}
130 changes: 130 additions & 0 deletions src/test/ui/suggestions/if-then-neeing-semi.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-then-neeing-semi.rs:37:9
|
LL | let _ = if true {
| _____________-
LL | |
LL | | async_dummy();
| | -------------- expected because of this
LL | |
LL | | } else {
LL | | async_dummy()
| | ^^^^^^^^^^^^^ expected `()`, found opaque type
... |
LL | |
LL | | };
| |_____- `if` and `else` have incompatible types
|
note: while checking the return type of the `async fn`
--> $DIR/if-then-neeing-semi.rs:18:24
|
LL | async fn async_dummy() {}
| ^ checked the `Output` of this `async fn`, found opaque type
= note: expected unit type `()`
found opaque type `impl Future<Output = ()>`
help: consider `await`ing on the `Future`
|
LL | async_dummy().await
| ++++++
help: consider removing this semicolon
|
LL - async_dummy();
LL + async_dummy()
|

error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-then-neeing-semi.rs:50:9
|
LL | let _ = if true {
| _____________-
LL | |
LL | | async_dummy();
| | -------------- expected because of this
LL | |
LL | | } else {
LL | | async_dummy2()
| | ^^^^^^^^^^^^^^ expected `()`, found opaque type
... |
LL | |
LL | | };
| |_____- `if` and `else` have incompatible types
|
note: while checking the return type of the `async fn`
--> $DIR/if-then-neeing-semi.rs:24:25
|
LL | async fn async_dummy2() {}
| ^ checked the `Output` of this `async fn`, found opaque type
= note: expected unit type `()`
found opaque type `impl Future<Output = ()>`
help: consider `await`ing on the `Future`
|
LL | async_dummy2().await
| ++++++
help: consider removing this semicolon and boxing the expressions
|
LL ~ Box::new(async_dummy())
LL |
LL | } else {
LL ~ Box::new(async_dummy2())
|

error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-then-neeing-semi.rs:63:9
|
LL | let _ = if true {
| _____________-
LL | |
LL | | async_dummy()
| | ------------- expected because of this
LL | |
LL | | } else {
LL | | async_dummy2()
| | ^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
... |
LL | |
LL | | };
| |_____- `if` and `else` have incompatible types
|
note: while checking the return type of the `async fn`
--> $DIR/if-then-neeing-semi.rs:18:24
|
LL | async fn async_dummy() {}
| ^ checked the `Output` of this `async fn`, expected opaque type
note: while checking the return type of the `async fn`
--> $DIR/if-then-neeing-semi.rs:24:25
|
LL | async fn async_dummy2() {}
| ^ checked the `Output` of this `async fn`, found opaque type
= note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/if-then-neeing-semi.rs:18:24>)
found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/if-then-neeing-semi.rs:24:25>)
= note: distinct uses of `impl Trait` result in different opaque types
help: consider `await`ing on both `Future`s
|
LL ~ async_dummy().await
LL |
LL | } else {
LL ~ async_dummy2().await
|

error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-then-neeing-semi.rs:13:9
|
LL | let _ = if true {
| _____________-
LL | |
LL | | dummy();
| | --------
| | | |
| | | help: consider removing this semicolon
| | expected because of this
LL | |
LL | | } else {
LL | | dummy()
| | ^^^^^^^ expected `()`, found `i32`
LL | |
LL | | };
| |_____- `if` and `else` have incompatible types

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 990bce4

Please sign in to comment.