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, Printer}, subst::{GenericArg, GenericArgKind}, Ty, TyCtxt, }; use std::fmt::Write; struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, path: String, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { type Error = std::fmt::Error; type Path = Self; type Region = Self; type Type = Self; type DynExistential = Self; type Const = Self; fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn print_region(self, _region: ty::Region<'_>) -> Result { Ok(self) } fn print_type(mut self, ty: Ty<'tcx>) -> Result { 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(self) } // Types with identity (print the module path). ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs) | ty::FnDef(def_id, substs) | ty::Alias(_, ty::AliasTy { def_id, substs, .. }) | ty::Closure(def_id, substs) | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), } } fn print_const(self, ct: ty::Const<'tcx>) -> Result { self.pretty_print_const(ct, false) } fn print_dyn_existential( self, predicates: &'tcx ty::List>, ) -> Result { self.pretty_print_dyn_existential(predicates) } fn path_crate(mut self, cnum: CrateNum) -> Result { self.path.push_str(self.tcx.crate_name(cnum).as_str()); Ok(self) } fn path_qualified( self, self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result { self.pretty_path_qualified(self_ty, trait_ref) } fn path_append_impl( self, print_prefix: impl FnOnce(Self) -> Result, _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result { self.pretty_path_append_impl( |mut cx| { cx = print_prefix(cx)?; cx.path.push_str("::"); Ok(cx) }, self_ty, trait_ref, ) } fn path_append( mut self, print_prefix: impl FnOnce(Self) -> Result, disambiguated_data: &DisambiguatedDefPathData, ) -> Result { self = print_prefix(self)?; write!(self.path, "::{}", disambiguated_data.data).unwrap(); Ok(self) } fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result, args: &[GenericArg<'tcx>], ) -> Result { self = 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(self) } } } 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 where T: Print<'tcx, Self, Output = Self, Error = Self::Error>, { if let Some(first) = elems.next() { self = first.print(self)?; for elem in elems { self.path.push_str(", "); self = elem.print(self)?; } } Ok(self) } fn generic_delimiters( mut self, f: impl FnOnce(Self) -> Result, ) -> Result { write!(self, "<")?; self = f(self)?; write!(self, ">")?; Ok(self) } 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 { AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path }