about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-07-31 17:36:44 +0530
committerGitHub <noreply@github.com>2022-07-31 17:36:44 +0530
commit990bce4da0a02a15a11abb22b00aacc5d329ce42 (patch)
treede2f60a8feb60d9b1a34b944b6fb872c6cead674
parent8b2637fd3ba839a614d578da9cad3c5897ca5aff (diff)
parentf6908be329d2be65b4de0f36393b98757c13ecad (diff)
downloadrust-990bce4da0a02a15a11abb22b00aacc5d329ce42.tar.gz
rust-990bce4da0a02a15a11abb22b00aacc5d329ce42.zip
Rollup merge of #99974 - TaKO8Ki:suggest-removing-semicolon-and-boxing-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.
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs16
-rw-r--r--src/test/ui/suggestions/if-then-neeing-semi.rs70
-rw-r--r--src/test/ui/suggestions/if-then-neeing-semi.stderr130
3 files changed, 210 insertions, 6 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 39faed0bf36..20864c657ff 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -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");
@@ -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(
diff --git a/src/test/ui/suggestions/if-then-neeing-semi.rs b/src/test/ui/suggestions/if-then-neeing-semi.rs
new file mode 100644
index 00000000000..b487f013d27
--- /dev/null
+++ b/src/test/ui/suggestions/if-then-neeing-semi.rs
@@ -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() {}
diff --git a/src/test/ui/suggestions/if-then-neeing-semi.stderr b/src/test/ui/suggestions/if-then-neeing-semi.stderr
new file mode 100644
index 00000000000..d7c5818abbd
--- /dev/null
+++ b/src/test/ui/suggestions/if-then-neeing-semi.stderr
@@ -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`.