Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file can be // run-rustfix, right?


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`.