diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 35170fa7c1d02..658e20bcaa9db 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 use crate::def::{DefKind, Namespace, Res};
 use crate::def_id::DefId;
 crate use crate::hir_id::HirId;
@@ -1274,7 +1275,7 @@ impl Body<'hir> {
 }
 
 /// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum GeneratorKind {
     /// An explicit `async` block or the body of an async function.
     Async(AsyncGeneratorKind),
@@ -1292,12 +1293,21 @@ impl fmt::Display for GeneratorKind {
     }
 }
 
+impl GeneratorKind {
+    pub fn descr(&self) -> &'static str {
+        match self {
+            GeneratorKind::Async(ask) => ask.descr(),
+            GeneratorKind::Gen => "generator",
+        }
+    }
+}
+
 /// In the case of a generator created as part of an async construct,
 /// which kind of async construct caused it to be created?
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum AsyncGeneratorKind {
     /// An explicit `async` block written by the user.
     Block,
@@ -1319,6 +1329,16 @@ impl fmt::Display for AsyncGeneratorKind {
     }
 }
 
+impl AsyncGeneratorKind {
+    pub fn descr(&self) -> &'static str {
+        match self {
+            AsyncGeneratorKind::Block => "`async` block",
+            AsyncGeneratorKind::Closure => "`async` closure body",
+            AsyncGeneratorKind::Fn => "`async fn` body",
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum BodyOwnerKind {
     /// Functions and methods.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index c39daea0811e0..893fe343fdd19 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1509,7 +1509,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                if let Some((kind, def_id)) = TyCategory::from_ty(t) {
+                if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
                     let span = self.tcx.def_span(def_id);
                     // Avoid cluttering the output when the "found" and error span overlap:
                     //
@@ -1582,11 +1582,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
         if let Some((expected, found)) = expected_found {
             let expected_label = match exp_found {
-                Mismatch::Variable(ef) => ef.expected.prefix_string(),
+                Mismatch::Variable(ef) => ef.expected.prefix_string(self.tcx),
                 Mismatch::Fixed(s) => s.into(),
             };
             let found_label = match exp_found {
-                Mismatch::Variable(ef) => ef.found.prefix_string(),
+                Mismatch::Variable(ef) => ef.found.prefix_string(self.tcx),
                 Mismatch::Fixed(s) => s.into(),
             };
             let exp_found = match exp_found {
@@ -2436,7 +2436,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
 pub enum TyCategory {
     Closure,
     Opaque,
-    Generator,
+    Generator(hir::GeneratorKind),
     Foreign,
 }
 
@@ -2445,16 +2445,18 @@ impl TyCategory {
         match self {
             Self::Closure => "closure",
             Self::Opaque => "opaque type",
-            Self::Generator => "generator",
+            Self::Generator(gk) => gk.descr(),
             Self::Foreign => "foreign type",
         }
     }
 
-    pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
+    pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
             ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
-            ty::Generator(def_id, ..) => Some((Self::Generator, def_id)),
+            ty::Generator(def_id, ..) => {
+                Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
+            }
             ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
             _ => None,
         }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index bd43d3c01e218..e7de11fffdea0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -383,7 +383,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 InferenceDiagnosticsData {
                     name: s,
                     span: None,
-                    kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() },
+                    kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
                     parent: None,
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index c211f07bed8c2..5625264911aac 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -264,7 +264,7 @@ impl<'tcx> ty::TyS<'tcx> {
                 }
             }
             ty::Closure(..) => "closure".into(),
-            ty::Generator(..) => "generator".into(),
+            ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
             ty::GeneratorWitness(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
@@ -282,7 +282,7 @@ impl<'tcx> ty::TyS<'tcx> {
         }
     }
 
-    pub fn prefix_string(&self) -> Cow<'static, str> {
+    pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
         match *self.kind() {
             ty::Infer(_)
             | ty::Error(_)
@@ -308,7 +308,7 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
-            ty::Generator(..) => "generator".into(),
+            ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
             ty::GeneratorWitness(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index a42a05c5f0284..7b00a828a974f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1366,8 +1366,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                     Some(t) => Some(t),
                     None => {
                         let ty = parent_trait_ref.skip_binder().self_ty();
-                        let span =
-                            TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
+                        let span = TyCategory::from_ty(self.tcx, ty)
+                            .map(|(_, def_id)| self.tcx.def_span(def_id));
                         Some((ty.to_string(), span))
                     }
                 }
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index d49c7cae8222b..09a15df97a2d1 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -390,7 +390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             "no {} named `{}` found for {} `{}` in the current scope",
                             item_kind,
                             item_name,
-                            actual.prefix_string(),
+                            actual.prefix_string(self.tcx),
                             ty_str,
                         );
                         if let Mode::MethodCall = mode {
@@ -728,7 +728,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .map(|(_, path)| path)
                             .collect::<Vec<_>>()
                             .join("\n");
-                        let actual_prefix = actual.prefix_string();
+                        let actual_prefix = actual.prefix_string(self.tcx);
                         err.set_primary_message(&format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
diff --git a/src/test/ui/async-await/generator-desc.rs b/src/test/ui/async-await/generator-desc.rs
new file mode 100644
index 0000000000000..5008120166711
--- /dev/null
+++ b/src/test/ui/async-await/generator-desc.rs
@@ -0,0 +1,16 @@
+// edition:2018
+#![feature(async_closure)]
+use std::future::Future;
+
+async fn one() {}
+async fn two() {}
+
+fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
+fn main() {
+    fun(async {}, async {});
+    //~^ ERROR mismatched types
+    fun(one(), two());
+    //~^ ERROR mismatched types
+    fun((async || {})(), (async || {})());
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr
new file mode 100644
index 0000000000000..b85926c7a03c0
--- /dev/null
+++ b/src/test/ui/async-await/generator-desc.stderr
@@ -0,0 +1,49 @@
+error[E0308]: mismatched types
+  --> $DIR/generator-desc.rs:10:25
+   |
+LL |     fun(async {}, async {});
+   |               --        ^^ expected `async` block, found a different `async` block
+   |               |
+   |               the expected `async` block
+   |
+   = note: expected `async` block `[static generator@$DIR/generator-desc.rs:10:15: 10:17]`
+              found `async` block `[static generator@$DIR/generator-desc.rs:10:25: 10:27]`
+
+error[E0308]: mismatched types
+  --> $DIR/generator-desc.rs:12:16
+   |
+LL | async fn one() {}
+   |                - the `Output` of this `async fn`'s expected opaque type
+LL | async fn two() {}
+   |                - the `Output` of this `async fn`'s found opaque type
+...
+LL |     fun(one(), two());
+   |                ^^^^^ expected opaque type, found a different 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
+   = note: distinct uses of `impl Trait` result in different opaque types
+
+error[E0308]: mismatched types
+  --> $DIR/generator-desc.rs:14:26
+   |
+LL |     fun((async || {})(), (async || {})());
+   |                   --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+   |                   |
+   |                   the expected `async` closure body
+   | 
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
+   |                                           -------------------------------
+   |                                           |
+   |                                           the expected opaque type
+   |                                           the found opaque type
+   |
+   = note: expected opaque type `impl Future` (`async` closure body)
+              found opaque type `impl Future` (`async` closure body)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.