From 052084af13cc2b6b80a2db25ec8ed22812a0269b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 31 Jul 2021 12:20:00 -0700
Subject: [PATCH] Tweak opaque type mismatch error

---
 .../src/infer/error_reporting/mod.rs          | 68 ++++++++++++-------
 .../dont-suggest-missing-await.stderr         |  9 +--
 src/test/ui/async-await/generator-desc.stderr | 17 +++--
 src/test/ui/async-await/issue-61076.rs        |  3 +-
 src/test/ui/async-await/issue-61076.stderr    | 19 +++---
 .../suggest-missing-await-closure.stderr      |  9 +--
 .../async-await/suggest-missing-await.stderr  | 18 ++---
 src/test/ui/suggestions/issue-81839.stderr    |  9 ++-
 .../match-prev-arm-needing-semi.rs            |  9 ++-
 .../match-prev-arm-needing-semi.stderr        | 35 +++++-----
 10 files changed, 114 insertions(+), 82 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index f885c0a4b87bd..cdc9a21253145 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -71,7 +71,7 @@ use rustc_middle::ty::{
     subst::{GenericArgKind, Subst, SubstsRef},
     Region, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::ControlFlow;
 use std::{cmp, fmt, iter};
@@ -1485,31 +1485,49 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     let count = values.len();
                     let kind = key.descr();
                     let mut returned_async_output_error = false;
-                    for sp in values {
-                        err.span_label(
-                            *sp,
-                            format!(
-                                "{}{}{} {}{}",
-                                if sp.is_desugaring(DesugaringKind::Async)
-                                    && !returned_async_output_error
-                                {
-                                    "checked the `Output` of this `async fn`, "
-                                } else if count == 1 {
-                                    "the "
-                                } else {
-                                    ""
-                                },
-                                if count > 1 { "one of the " } else { "" },
-                                target,
-                                kind,
-                                pluralize!(count),
-                            ),
-                        );
-                        if sp.is_desugaring(DesugaringKind::Async)
-                            && returned_async_output_error == false
-                        {
-                            err.note("while checking the return type of the `async fn`");
+                    for &sp in values {
+                        if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
+                            if &[sp] != err.span.primary_spans() {
+                                let mut span: MultiSpan = sp.into();
+                                span.push_span_label(
+                                    sp,
+                                    format!(
+                                        "checked the `Output` of this `async fn`, {}{} {}{}",
+                                        if count > 1 { "one of the " } else { "" },
+                                        target,
+                                        kind,
+                                        pluralize!(count),
+                                    ),
+                                );
+                                err.span_note(
+                                    span,
+                                    "while checking the return type of the `async fn`",
+                                );
+                            } else {
+                                err.span_label(
+                                    sp,
+                                    format!(
+                                        "checked the `Output` of this `async fn`, {}{} {}{}",
+                                        if count > 1 { "one of the " } else { "" },
+                                        target,
+                                        kind,
+                                        pluralize!(count),
+                                    ),
+                                );
+                                err.note("while checking the return type of the `async fn`");
+                            }
                             returned_async_output_error = true;
+                        } else {
+                            err.span_label(
+                                sp,
+                                format!(
+                                    "{}{} {}{}",
+                                    if count == 1 { "the " } else { "one of the " },
+                                    target,
+                                    kind,
+                                    pluralize!(count),
+                                ),
+                            );
                         }
                     }
                 }
diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr
index 654a3bcc92dd8..4dc5cafb98614 100644
--- a/src/test/ui/async-await/dont-suggest-missing-await.stderr
+++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr
@@ -1,13 +1,14 @@
 error[E0308]: mismatched types
   --> $DIR/dont-suggest-missing-await.rs:14:18
    |
-LL | async fn make_u32() -> u32 {
-   |                        --- checked the `Output` of this `async fn`, found opaque type
-...
 LL |         take_u32(x)
    |                  ^ expected `u32`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/dont-suggest-missing-await.rs:7:24
+   |
+LL | async fn make_u32() -> u32 {
+   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr
index 04f191cc5e8cb..a7aedbb2b322f 100644
--- a/src/test/ui/async-await/generator-desc.stderr
+++ b/src/test/ui/async-await/generator-desc.stderr
@@ -12,16 +12,19 @@ LL |     fun(async {}, async {});
 error[E0308]: mismatched types
   --> $DIR/generator-desc.rs:12:16
    |
-LL | async fn one() {}
-   |                - checked the `Output` of this `async fn`, expected opaque type
-LL | async fn two() {}
-   |                - checked the `Output` of this `async fn`, found opaque type
-...
 LL |     fun(one(), two());
    |                ^^^^^ expected opaque type, found a different opaque type
    |
-   = note: while checking the return type of the `async fn`
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/generator-desc.rs:5:16
+   |
+LL | async fn one() {}
+   |                ^ checked the `Output` of this `async fn`, expected opaque type
+note: while checking the return type of the `async fn`
+  --> $DIR/generator-desc.rs:6:16
+   |
+LL | async fn two() {}
+   |                ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
               found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
    = help: consider `await`ing on both `Future`s
diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs
index 9fe3313ee6cc6..220f0774e2d54 100644
--- a/src/test/ui/async-await/issue-61076.rs
+++ b/src/test/ui/async-await/issue-61076.rs
@@ -57,6 +57,8 @@ async fn struct_() -> Struct {
 
 async fn tuple() -> Tuple {
     //~^ 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
     Tuple(1i32)
 }
 
@@ -92,7 +94,6 @@ async fn match_() {
         Tuple(_) => {} //~ ERROR mismatched types
         //~^ NOTE expected opaque type, found struct `Tuple`
         //~| NOTE expected opaque type `impl Future`
-        //~| NOTE while checking the return type of the `async fn`
     }
 }
 
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
index ba97e135790c1..9fb2d5bc6cb42 100644
--- a/src/test/ui/async-await/issue-61076.stderr
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -16,7 +16,7 @@ LL |     foo().await?;
    |          ^^^^^^
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/issue-61076.rs:65:5
+  --> $DIR/issue-61076.rs:67:5
    |
 LL |     t?;
    |     ^^ the `?` operator cannot be applied to type `T`
@@ -33,7 +33,7 @@ LL |     t.await?;
    |      ^^^^^^
 
 error[E0609]: no field `0` on type `impl Future`
-  --> $DIR/issue-61076.rs:76:26
+  --> $DIR/issue-61076.rs:78:26
    |
 LL |     let _: i32 = tuple().0;
    |                          ^ field not available in `impl Future`, but it is available in its `Output`
@@ -44,7 +44,7 @@ LL |     let _: i32 = tuple().await.0;
    |                         ^^^^^^
 
 error[E0609]: no field `a` on type `impl Future`
-  --> $DIR/issue-61076.rs:80:28
+  --> $DIR/issue-61076.rs:82:28
    |
 LL |     let _: i32 = struct_().a;
    |                            ^ field not available in `impl Future`, but it is available in its `Output`
@@ -55,7 +55,7 @@ LL |     let _: i32 = struct_().await.a;
    |                           ^^^^^^
 
 error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope
-  --> $DIR/issue-61076.rs:84:15
+  --> $DIR/issue-61076.rs:86:15
    |
 LL |     struct_().method();
    |               ^^^^^^ method not found in `impl Future`
@@ -66,15 +66,16 @@ LL |     struct_().await.method();
    |               ^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/issue-61076.rs:92:9
+  --> $DIR/issue-61076.rs:94:9
    |
-LL | async fn tuple() -> Tuple {
-   |                     ----- checked the `Output` of this `async fn`, expected opaque type
-...
 LL |         Tuple(_) => {}
    |         ^^^^^^^^ expected opaque type, found struct `Tuple`
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-61076.rs:58:21
+   |
+LL | async fn tuple() -> Tuple {
+   |                     ^^^^^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future`
                    found struct `Tuple`
 help: consider `await`ing on the `Future`
diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr
index 483e52536a1b4..9d742049046b2 100644
--- a/src/test/ui/async-await/suggest-missing-await-closure.stderr
+++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr
@@ -1,13 +1,14 @@
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await-closure.rs:16:18
    |
-LL | async fn make_u32() -> u32 {
-   |                        --- checked the `Output` of this `async fn`, found opaque type
-...
 LL |         take_u32(x)
    |                  ^ expected `u32`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/suggest-missing-await-closure.rs:8:24
+   |
+LL | async fn make_u32() -> u32 {
+   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr
index 14b5ee95ee8ba..890f66c58d0f8 100644
--- a/src/test/ui/async-await/suggest-missing-await.stderr
+++ b/src/test/ui/async-await/suggest-missing-await.stderr
@@ -1,13 +1,14 @@
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:12:14
    |
-LL | async fn make_u32() -> u32 {
-   |                        --- checked the `Output` of this `async fn`, found opaque type
-...
 LL |     take_u32(x)
    |              ^ expected `u32`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/suggest-missing-await.rs:5:24
+   |
+LL | async fn make_u32() -> u32 {
+   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
@@ -18,13 +19,14 @@ LL |     take_u32(x.await)
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:22:5
    |
-LL | async fn dummy() {}
-   |                  - checked the `Output` of this `async fn`, found opaque type
-...
 LL |     dummy()
    |     ^^^^^^^ expected `()`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/suggest-missing-await.rs:18:18
+   |
+LL | async fn dummy() {}
+   |                  ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future`
 help: consider `await`ing on the `Future`
diff --git a/src/test/ui/suggestions/issue-81839.stderr b/src/test/ui/suggestions/issue-81839.stderr
index f907658708730..1e0aa9ce40d18 100644
--- a/src/test/ui/suggestions/issue-81839.stderr
+++ b/src/test/ui/suggestions/issue-81839.stderr
@@ -13,13 +13,12 @@ LL | |         _ => cx.answer_str("hi"),
    | |              ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
 LL | |     }
    | |_____- `match` arms have incompatible types
-   | 
-  ::: $DIR/auxiliary/issue-81839.rs:6:49
    |
-LL |       pub async fn answer_str(&self, _s: &str) -> Test {
-   |                                                   ---- checked the `Output` of this `async fn`, found opaque type
+note: while checking the return type of the `async fn`
+  --> $DIR/auxiliary/issue-81839.rs:6:49
    |
-   = note: while checking the return type of the `async fn`
+LL |     pub async fn answer_str(&self, _s: &str) -> Test {
+   |                                                 ^^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `()`
            found opaque type `impl Future`
 
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
index 3b2cff3140d63..990a4469764f0 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
@@ -14,8 +14,14 @@ fn extra_semicolon() {
 }
 
 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
 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 _ = match true { //~ NOTE `match` arms have incompatible types
@@ -26,7 +32,6 @@ async fn async_extra_semicolon_same() {
         false => async_dummy(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected `()`, found opaque type
         //~| NOTE expected type `()`
-        //~| NOTE while checking the return type of the `async fn`
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -40,7 +45,6 @@ async fn async_extra_semicolon_different() {
         false => async_dummy2(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected `()`, found opaque type
         //~| NOTE expected type `()`
-        //~| NOTE while checking the return type of the `async fn`
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -53,7 +57,6 @@ async fn async_different_futures() {
         //~^ NOTE expected opaque type, found a different opaque type
         //~| NOTE expected type `impl Future`
         //~| NOTE distinct uses of `impl Trait` result in different opaque types
-        //~| NOTE while checking the return type of the `async fn`
     };
 }
 
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
index e31ea9679b51d..9e64b539f0fdc 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
@@ -1,9 +1,6 @@
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:26:18
+  --> $DIR/match-prev-arm-needing-semi.rs:32:18
    |
-LL |   async fn async_dummy() {}
-   |                          - checked the `Output` of this `async fn`, found opaque type
-...
 LL |       let _ = match true {
    |  _____________-
 LL | |         true => {
@@ -18,7 +15,11 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/match-prev-arm-needing-semi.rs:16:24
+   |
+LL | async fn async_dummy() {}
+   |                        ^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `()`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
@@ -31,11 +32,8 @@ LL |             async_dummy()
    |                         --
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:40:18
+  --> $DIR/match-prev-arm-needing-semi.rs:45:18
    |
-LL |   async fn async_dummy2() {}
-   |                           - checked the `Output` of this `async fn`, found opaque type
-...
 LL |       let _ = match true {
    |  _____________-
 LL | |         true => {
@@ -50,7 +48,11 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/match-prev-arm-needing-semi.rs:19:25
+   |
+LL | async fn async_dummy2() {}
+   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `()`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
@@ -66,11 +68,8 @@ LL |         false => Box::new(async_dummy2()),
    |
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:52:18
+  --> $DIR/match-prev-arm-needing-semi.rs:56:18
    |
-LL |   async fn async_dummy2() {}
-   |                           - checked the `Output` of this `async fn`, found opaque type
-...
 LL |       let _ = match true {
    |  _____________-
 LL | |         true => async_dummy(),
@@ -83,9 +82,13 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/match-prev-arm-needing-semi.rs:19:25
+   |
+LL | async fn async_dummy2() {}
+   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
-           found opaque type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:17:25>)
+           found opaque type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:19:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |