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.
8 use rustc::hir::def_id::DefId;
9 use rustc::mir::interpret::ConstValue;
10 use rustc::ty::subst::SubstsRef;
11 use rustc::ty::{self, ClosureSubsts, Const, GeneratorSubsts, Instance, Ty, TyCtxt};
12 use rustc::{bug, hir};
17 /// Same as `unique_type_name()` but with the result pushed onto the given
18 /// `output` parameter.
19 pub struct DefPathBasedNames<'a, 'tcx: 'a> {
20 tcx: TyCtxt<'a, 'tcx, 'tcx>,
21 omit_disambiguators: bool,
22 omit_local_crate_name: bool,
25 impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
27 tcx: TyCtxt<'a, 'tcx, 'tcx>,
28 omit_disambiguators: bool,
29 omit_local_crate_name: bool,
31 DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name }
34 // Pushes the type name of the specified type to the provided string.
35 // If `debug` is true, printing normally unprintable types is allowed
36 // (e.g. `ty::GeneratorWitness`). This parameter should only be set when
37 // this method is being used for logging purposes (e.g. with `debug!` or `info!`)
38 // When being used for codegen purposes, `debug` should be set to `false`
39 // in order to catch unexpected types that should never end up in a type name.
40 pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
42 ty::Bool => output.push_str("bool"),
43 ty::Char => output.push_str("char"),
44 ty::Str => output.push_str("str"),
45 ty::Never => output.push_str("!"),
46 ty::Int(ast::IntTy::Isize) => output.push_str("isize"),
47 ty::Int(ast::IntTy::I8) => output.push_str("i8"),
48 ty::Int(ast::IntTy::I16) => output.push_str("i16"),
49 ty::Int(ast::IntTy::I32) => output.push_str("i32"),
50 ty::Int(ast::IntTy::I64) => output.push_str("i64"),
51 ty::Int(ast::IntTy::I128) => output.push_str("i128"),
52 ty::Uint(ast::UintTy::Usize) => output.push_str("usize"),
53 ty::Uint(ast::UintTy::U8) => output.push_str("u8"),
54 ty::Uint(ast::UintTy::U16) => output.push_str("u16"),
55 ty::Uint(ast::UintTy::U32) => output.push_str("u32"),
56 ty::Uint(ast::UintTy::U64) => output.push_str("u64"),
57 ty::Uint(ast::UintTy::U128) => output.push_str("u128"),
58 ty::Float(ast::FloatTy::F32) => output.push_str("f32"),
59 ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
60 ty::Adt(adt_def, substs) => {
61 self.push_def_path(adt_def.did, output);
62 self.push_generic_params(substs, iter::empty(), output, debug);
64 ty::Tuple(component_types) => {
66 for &component_type in component_types {
67 self.push_type_name(component_type.expect_ty(), output, debug);
68 output.push_str(", ");
70 if !component_types.is_empty() {
76 ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
79 hir::MutImmutable => output.push_str("const "),
80 hir::MutMutable => output.push_str("mut "),
83 self.push_type_name(inner_type, output, debug);
85 ty::Ref(_, inner_type, mutbl) => {
87 if mutbl == hir::MutMutable {
88 output.push_str("mut ");
91 self.push_type_name(inner_type, output, debug);
93 ty::Array(inner_type, len) => {
95 self.push_type_name(inner_type, output, debug);
96 write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
99 ty::Slice(inner_type) => {
101 self.push_type_name(inner_type, output, debug);
104 ty::Dynamic(ref trait_data, ..) => {
105 if let Some(principal) = trait_data.principal() {
106 self.push_def_path(principal.def_id(), output);
107 self.push_generic_params(
108 principal.skip_binder().substs,
109 trait_data.projection_bounds(),
114 output.push_str("dyn '_");
117 ty::Foreign(did) => self.push_def_path(did, output),
118 ty::FnDef(..) | ty::FnPtr(_) => {
119 let sig = t.fn_sig(self.tcx);
120 if sig.unsafety() == hir::Unsafety::Unsafe {
121 output.push_str("unsafe ");
125 if abi != ::rustc_target::spec::abi::Abi::Rust {
126 output.push_str("extern \"");
127 output.push_str(abi.name());
128 output.push_str("\" ");
131 output.push_str("fn(");
134 self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
136 if !sig.inputs().is_empty() {
137 for ¶meter_type in sig.inputs() {
138 self.push_type_name(parameter_type, output, debug);
139 output.push_str(", ");
146 if !sig.inputs().is_empty() {
147 output.push_str(", ...");
149 output.push_str("...");
155 if !sig.output().is_unit() {
156 output.push_str(" -> ");
157 self.push_type_name(sig.output(), output, debug);
160 ty::Generator(def_id, GeneratorSubsts { ref substs }, _)
161 | ty::Closure(def_id, ClosureSubsts { ref substs }) => {
162 self.push_def_path(def_id, output);
163 let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
164 let substs = substs.truncate_to(self.tcx, generics);
165 self.push_generic_params(substs, iter::empty(), output, debug);
170 | ty::Placeholder(..)
171 | ty::UnnormalizedProjection(..)
174 | ty::GeneratorWitness(_)
175 | ty::Opaque(..) => {
177 output.push_str(&format!("`{:?}`", t));
180 "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
188 // Pushes the the name of the specified const to the provided string.
189 // If `debug` is true, usually-unprintable consts (such as `Infer`) will be printed,
190 // as well as the unprintable types of constants (see `push_type_name` for more details).
191 pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
193 ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef(..) => {
194 // FIXME(const_generics): we could probably do a better job here.
195 write!(output, "{:?}", c).unwrap()
199 write!(output, "{:?}", c).unwrap()
202 "DefPathBasedNames: trying to create const name for unexpected const: {:?}",
208 output.push_str(": ");
209 self.push_type_name(c.ty, output, debug);
212 pub fn push_def_path(&self, def_id: DefId, output: &mut String) {
213 let def_path = self.tcx.def_path(def_id);
216 if !(self.omit_local_crate_name && def_id.is_local()) {
217 output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
218 output.push_str("::");
221 // foo::bar::ItemName::
222 for part in self.tcx.def_path(def_id).data {
223 if self.omit_disambiguators {
224 write!(output, "{}::", part.data.as_interned_str()).unwrap();
226 write!(output, "{}[{}]::", part.data.as_interned_str(), part.disambiguator)
236 fn push_generic_params<I>(
238 substs: SubstsRef<'tcx>,
243 I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>,
245 let mut projections = projections.peekable();
246 if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
252 for type_parameter in substs.types() {
253 self.push_type_name(type_parameter, output, debug);
254 output.push_str(", ");
257 for projection in projections {
258 let projection = projection.skip_binder();
259 let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
260 output.push_str(name);
261 output.push_str("=");
262 self.push_type_name(projection.ty, output, debug);
263 output.push_str(", ");
266 for const_parameter in substs.consts() {
267 self.push_const_name(const_parameter, output, debug);
268 output.push_str(", ");
277 pub fn push_instance_as_string(
279 instance: Instance<'tcx>,
283 self.push_def_path(instance.def_id(), output);
284 self.push_generic_params(instance.substs, iter::empty(), output, debug);