diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 13cc607135a02..92096958f2b6f 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 e6feafea12284..9e6f277ef7700 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>, ) -> 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 0000000000000..12daad5a60947 --- /dev/null +++ b/tests/ui/async-await/async-closures/type-name.rs @@ -0,0 +1,18 @@ +//@ run-pass +//@ edition: 2024 + +fn once 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}}"); +}