about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-08-19 19:21:39 +0000
committerMichael Goulet <michael@errs.io>2025-08-19 19:21:55 +0000
commitab6f4d62c0aab0f64b663bb572de8a896411b46a (patch)
treec81ad263775b6025d4eb2adb9527960eb791dd1b
parent239e8b1b47b34120287ec36b33228c1e177f0c38 (diff)
downloadrust-ab6f4d62c0aab0f64b663bb572de8a896411b46a.tar.gz
rust-ab6f4d62c0aab0f64b663bb572de8a896411b46a.zip
Pretty print the name of an future from calling async closure
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs31
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs16
-rw-r--r--tests/ui/async-await/async-closures/type-name.rs18
3 files changed, 61 insertions, 4 deletions
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 13cc607135a..92096958f2b 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -1,7 +1,7 @@
 use std::fmt::Write;
 
 use rustc_data_structures::intern::Interned;
-use rustc_hir::def_id::CrateNum;
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::DisambiguatedDefPathData;
 use rustc_middle::bug;
 use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer};
@@ -132,6 +132,35 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
             Ok(())
         }
     }
+
+    fn print_coroutine_with_kind(
+        &mut self,
+        def_id: DefId,
+        parent_args: &'tcx [GenericArg<'tcx>],
+        kind: Ty<'tcx>,
+    ) -> Result<(), PrintError> {
+        self.print_def_path(def_id, parent_args)?;
+
+        let ty::Coroutine(_, args) = self.tcx.type_of(def_id).instantiate_identity().kind() else {
+            // Could be `ty::Error`.
+            return Ok(());
+        };
+
+        let default_kind = args.as_coroutine().kind_ty();
+
+        match kind.to_opt_closure_kind() {
+            _ if kind == default_kind => {
+                // No need to mark the closure if it's the deduced coroutine kind.
+            }
+            Some(ty::ClosureKind::Fn) | None => {
+                // Should never happen. Just don't mark anything rather than panicking.
+            }
+            Some(ty::ClosureKind::FnMut) => self.path.push_str("::{{call_mut}}"),
+            Some(ty::ClosureKind::FnOnce) => self.path.push_str("::{{call_once}}"),
+        }
+
+        Ok(())
+    }
 }
 
 impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index e6feafea122..9e6f277ef77 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -124,6 +124,15 @@ pub trait Printer<'tcx>: Sized {
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError>;
 
+    fn print_coroutine_with_kind(
+        &mut self,
+        def_id: DefId,
+        parent_args: &'tcx [GenericArg<'tcx>],
+        kind: Ty<'tcx>,
+    ) -> Result<(), PrintError> {
+        self.print_path_with_generic_args(|p| p.print_def_path(def_id, parent_args), &[kind.into()])
+    }
+
     // Defaults (should not be overridden):
 
     #[instrument(skip(self), level = "debug")]
@@ -162,9 +171,10 @@ pub trait Printer<'tcx>: Sized {
                             )) = self.tcx().coroutine_kind(def_id)
                                 && args.len() > parent_args.len()
                             {
-                                return self.print_path_with_generic_args(
-                                    |p| p.print_def_path(def_id, parent_args),
-                                    &args[..parent_args.len() + 1][..1],
+                                return self.print_coroutine_with_kind(
+                                    def_id,
+                                    parent_args,
+                                    args[parent_args.len()].expect_ty(),
                                 );
                             } else {
                                 // Closures' own generics are only captures, don't print them.
diff --git a/tests/ui/async-await/async-closures/type-name.rs b/tests/ui/async-await/async-closures/type-name.rs
new file mode 100644
index 00000000000..12daad5a609
--- /dev/null
+++ b/tests/ui/async-await/async-closures/type-name.rs
@@ -0,0 +1,18 @@
+//@ run-pass
+//@ edition: 2024
+
+fn once<F: FnOnce() -> T, T>(f: F) -> T {
+    f()
+}
+
+fn main() {
+    let closure = async || {};
+
+    // Name of future when called normally.
+    let name = std::any::type_name_of_val(&closure());
+    assert_eq!(name, "type_name::main::{{closure}}::{{closure}}");
+
+    // Name of future when closure is called via its FnOnce shim.
+    let name = std::any::type_name_of_val(&once(closure));
+    assert_eq!(name, "type_name::main::{{closure}}::{{closure}}::{{call_once}}");
+}