1 //! Allows for producing a unique string key for a mono item.
2 //! These keys are used by the handwritten auto-tests, so they need to be
3 //! predictable and human-readable.
5 //! Note: A lot of this could looks very similar to what's already in `ty::print`.
6 //! FIXME(eddyb) implement a custom `PrettyPrinter` for this.
9 use rustc::ty::subst::SubstsRef;
10 use rustc::ty::{self, Const, Instance, Ty, TyCtxt};
12 use rustc_hir::def_id::DefId;
16 /// Same as `unique_type_name()` but with the result pushed onto the given
17 /// `output` parameter.
18 pub struct DefPathBasedNames<'tcx> {
20 omit_disambiguators: bool,
21 omit_local_crate_name: bool,
24 impl DefPathBasedNames<'tcx> {
25 pub fn new(tcx: TyCtxt<'tcx>, omit_disambiguators: bool, omit_local_crate_name: bool) -> Self {
26 DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name }
29 // Pushes the type name of the specified type to the provided string.
30 // If `debug` is true, printing normally unprintable types is allowed
31 // (e.g. `ty::GeneratorWitness`). This parameter should only be set when
32 // this method is being used for logging purposes (e.g. with `debug!` or `info!`)
33 // When being used for codegen purposes, `debug` should be set to `false`
34 // in order to catch unexpected types that should never end up in a type name.
35 pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
37 ty::Bool => output.push_str("bool"),
38 ty::Char => output.push_str("char"),
39 ty::Str => output.push_str("str"),
40 ty::Never => output.push_str("!"),
41 ty::Int(ty) => output.push_str(ty.name_str()),
42 ty::Uint(ty) => output.push_str(ty.name_str()),
43 ty::Float(ty) => output.push_str(ty.name_str()),
44 ty::Adt(adt_def, substs) => {
45 self.push_def_path(adt_def.did, output);
46 self.push_generic_params(substs, iter::empty(), output, debug);
48 ty::Tuple(component_types) => {
50 for &component_type in component_types {
51 self.push_type_name(component_type.expect_ty(), output, debug);
52 output.push_str(", ");
54 if !component_types.is_empty() {
60 ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
63 hir::Mutability::Not => output.push_str("const "),
64 hir::Mutability::Mut => output.push_str("mut "),
67 self.push_type_name(inner_type, output, debug);
69 ty::Ref(_, inner_type, mutbl) => {
71 output.push_str(mutbl.prefix_str());
73 self.push_type_name(inner_type, output, debug);
75 ty::Array(inner_type, len) => {
77 self.push_type_name(inner_type, output, debug);
78 let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all());
79 write!(output, "; {}", len).unwrap();
82 ty::Slice(inner_type) => {
84 self.push_type_name(inner_type, output, debug);
87 ty::Dynamic(ref trait_data, ..) => {
88 if let Some(principal) = trait_data.principal() {
89 self.push_def_path(principal.def_id(), output);
90 self.push_generic_params(
91 principal.skip_binder().substs,
92 trait_data.projection_bounds(),
97 output.push_str("dyn '_");
100 ty::Foreign(did) => self.push_def_path(did, output),
101 ty::FnDef(..) | ty::FnPtr(_) => {
102 let sig = t.fn_sig(self.tcx);
103 output.push_str(sig.unsafety().prefix_str());
106 if abi != ::rustc_target::spec::abi::Abi::Rust {
107 output.push_str("extern \"");
108 output.push_str(abi.name());
109 output.push_str("\" ");
112 output.push_str("fn(");
115 self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
117 if !sig.inputs().is_empty() {
118 for ¶meter_type in sig.inputs() {
119 self.push_type_name(parameter_type, output, debug);
120 output.push_str(", ");
127 if !sig.inputs().is_empty() {
128 output.push_str(", ...");
130 output.push_str("...");
136 if !sig.output().is_unit() {
137 output.push_str(" -> ");
138 self.push_type_name(sig.output(), output, debug);
141 ty::Generator(def_id, substs, _) | ty::Closure(def_id, substs) => {
142 self.push_def_path(def_id, output);
143 let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
144 let substs = substs.truncate_to(self.tcx, generics);
145 self.push_generic_params(substs, iter::empty(), output, debug);
150 | ty::Placeholder(..)
151 | ty::UnnormalizedProjection(..)
154 | ty::GeneratorWitness(_)
155 | ty::Opaque(..) => {
157 output.push_str(&format!("`{:?}`", t));
160 "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
168 // Pushes the the name of the specified const to the provided string.
169 // If `debug` is true, the unprintable types of constants will be printed with `fmt::Debug`
170 // (see `push_type_name` for more details).
171 pub fn push_const_name(&self, ct: &Const<'tcx>, output: &mut String, debug: bool) {
172 write!(output, "{}", ct).unwrap();
173 output.push_str(": ");
174 self.push_type_name(ct.ty, output, debug);
177 pub fn push_def_path(&self, def_id: DefId, output: &mut String) {
178 let def_path = self.tcx.def_path(def_id);
181 if !(self.omit_local_crate_name && def_id.is_local()) {
182 output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
183 output.push_str("::");
186 // foo::bar::ItemName::
187 for part in self.tcx.def_path(def_id).data {
188 if self.omit_disambiguators {
189 write!(output, "{}::", part.data.as_symbol()).unwrap();
191 write!(output, "{}[{}]::", part.data.as_symbol(), part.disambiguator).unwrap();
200 fn push_generic_params<I>(
202 substs: SubstsRef<'tcx>,
207 I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>,
209 let mut projections = projections.peekable();
210 if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
216 for type_parameter in substs.types() {
217 self.push_type_name(type_parameter, output, debug);
218 output.push_str(", ");
221 for projection in projections {
222 let projection = projection.skip_binder();
223 let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
224 output.push_str(name);
225 output.push_str("=");
226 self.push_type_name(projection.ty, output, debug);
227 output.push_str(", ");
230 for const_parameter in substs.consts() {
231 self.push_const_name(const_parameter, output, debug);
232 output.push_str(", ");
241 pub fn push_instance_as_string(
243 instance: Instance<'tcx>,
247 self.push_def_path(instance.def_id(), output);
248 self.push_generic_params(instance.substs, iter::empty(), output, debug);