use rustc_data_structures::intern::Interned; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use rustc_middle::ty::{ self, print::{PrettyPrinter, Print, PrintError, Printer}, GenericArg, GenericArgKind, Ty, TyCtxt, }; use std::fmt::Write; struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, path: String, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { Ok(()) } fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { match *ty.kind() { // Types without identity. ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Array(_, _) | ty::Slice(_) | ty::RawPtr(_) | ty::Ref(_, _, _) | ty::FnPtr(_) | ty::Never | ty::Tuple(_) | ty::Dynamic(_, _, _) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { write!(self, "_")?; Ok(()) } // Types with identity (print the module path). ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args) | ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) | ty::Coroutine(def_id, args, _) => self.print_def_path(def_id, args), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"), ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"), ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"), } } fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { self.pretty_print_const(ct, false) } fn print_dyn_existential( &mut self, predicates: &'tcx ty::List>, ) -> Result<(), PrintError> { self.pretty_print_dyn_existential(predicates) } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.path.push_str(self.tcx.crate_name(cnum).as_str()); Ok(()) } fn path_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { self.pretty_path_qualified(self_ty, trait_ref) } fn path_append_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { self.pretty_path_append_impl( |cx| { print_prefix(cx)?; cx.path.push_str("::"); Ok(()) }, self_ty, trait_ref, ) } fn path_append( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError> { print_prefix(self)?; write!(self.path, "::{}", disambiguated_data.data).unwrap(); Ok(()) } fn path_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, args: &[GenericArg<'tcx>], ) -> Result<(), PrintError> { print_prefix(self)?; let args = args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_))); if args.clone().next().is_some() { self.generic_delimiters(|cx| cx.comma_sep(args)) } else { Ok(()) } } } impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { fn should_print_region(&self, _region: ty::Region<'_>) -> bool { false } fn comma_sep(&mut self, mut elems: impl Iterator) -> Result<(), PrintError> where T: Print<'tcx, Self>, { if let Some(first) = elems.next() { first.print(self)?; for elem in elems { self.path.push_str(", "); elem.print(self)?; } } Ok(()) } fn generic_delimiters( &mut self, f: impl FnOnce(&mut Self) -> Result<(), PrintError>, ) -> Result<(), PrintError> { write!(self, "<")?; f(self)?; write!(self, ">")?; Ok(()) } fn should_print_verbose(&self) -> bool { // `std::any::type_name` should never print verbose type names false } } impl Write for AbsolutePathPrinter<'_> { fn write_str(&mut self, s: &str) -> std::fmt::Result { self.path.push_str(s); Ok(()) } } pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String { let mut printer = AbsolutePathPrinter { tcx, path: String::new() }; printer.print_type(ty).unwrap(); printer.path }