1 // Type Names for Debug Info.
3 use rustc::hir::{self, def_id::DefId};
4 use rustc::ty::{self, Ty, TyCtxt, subst::SubstsRef};
5 use rustc_data_structures::fx::FxHashSet;
7 // Compute the name of the type as it should be stored in debuginfo. Does not do
8 // any caching, i.e., calling the function twice with the same type will also do
9 // the work twice. The `qualified` parameter only affects the first level of the
10 // type name, further levels (i.e., type parameters) are always fully qualified.
11 pub fn compute_debuginfo_type_name<'tcx>(
16 let mut result = String::with_capacity(64);
17 let mut visited = FxHashSet::default();
18 push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited);
22 // Pushes the name of the type as it should be stored in debuginfo on the
23 // `output` String. See also compute_debuginfo_type_name().
24 pub fn push_debuginfo_type_name<'tcx>(
29 visited: &mut FxHashSet<Ty<'tcx>>,
31 // When targeting MSVC, emit C++ style type names for compatibility with
32 // .natvis visualizers (and perhaps other existing native debuggers?)
33 let cpp_like_names = tcx.sess.target.target.options.is_like_msvc;
36 ty::Bool => output.push_str("bool"),
37 ty::Char => output.push_str("char"),
38 ty::Str => output.push_str("str"),
39 ty::Never => output.push_str("!"),
40 ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()),
41 ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
42 ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()),
43 ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
44 ty::Adt(def, substs) => {
45 push_item_name(tcx, def.did, qualified, output);
46 push_type_params(tcx, substs, output, visited);
48 ty::Tuple(component_types) => {
50 for &component_type in component_types {
51 push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
52 output.push_str(", ");
54 if !component_types.is_empty() {
60 ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
65 hir::MutImmutable => output.push_str("const "),
66 hir::MutMutable => output.push_str("mut "),
69 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
75 ty::Ref(_, inner_type, mutbl) => {
79 if mutbl == hir::MutMutable {
80 output.push_str("mut ");
83 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
89 ty::Array(inner_type, len) => {
91 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
92 output.push_str(&format!("; {}", len.eval_usize(tcx, ty::ParamEnv::reveal_all())));
95 ty::Slice(inner_type) => {
97 output.push_str("slice<");
102 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
110 ty::Dynamic(ref trait_data, ..) => {
111 if let Some(principal) = trait_data.principal() {
112 let principal = tcx.normalize_erasing_late_bound_regions(
113 ty::ParamEnv::reveal_all(),
116 push_item_name(tcx, principal.def_id, false, output);
117 push_type_params(tcx, principal.substs, output, visited);
119 output.push_str("dyn '_");
122 ty::FnDef(..) | ty::FnPtr(_) => {
123 // We've encountered a weird 'recursive type'
124 // Currently, the only way to generate such a type
125 // is by using 'impl trait':
127 // fn foo() -> impl Copy { foo }
129 // There's not really a sensible name we can generate,
130 // since we don't include 'impl trait' types (e.g. ty::Opaque)
133 // Since we need to generate *something*, we just
134 // use a dummy string that should make it clear
135 // that something unusual is going on
136 if !visited.insert(t) {
137 output.push_str("<recursive_type>");
142 let sig = t.fn_sig(tcx);
143 if sig.unsafety() == hir::Unsafety::Unsafe {
144 output.push_str("unsafe ");
148 if abi != rustc_target::spec::abi::Abi::Rust {
149 output.push_str("extern \"");
150 output.push_str(abi.name());
151 output.push_str("\" ");
154 output.push_str("fn(");
156 let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
157 if !sig.inputs().is_empty() {
158 for ¶meter_type in sig.inputs() {
159 push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
160 output.push_str(", ");
167 if !sig.inputs().is_empty() {
168 output.push_str(", ...");
170 output.push_str("...");
176 if !sig.output().is_unit() {
177 output.push_str(" -> ");
178 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
182 // We only keep the type in 'visited'
183 // for the duration of the body of this method.
184 // It's fine for a particular function type
185 // to show up multiple times in one overall type
186 // (e.g. MyType<fn() -> u8, fn() -> u8>
188 // We only care about avoiding recursing
189 // directly back to the type we're currently
193 ty::Closure(def_id, ..) => {
194 output.push_str(&format!(
196 tcx.def_key(def_id).disambiguated_data.disambiguator
199 ty::Generator(def_id, ..) => {
200 output.push_str(&format!(
202 tcx.def_key(def_id).disambiguated_data.disambiguator
207 ty::Placeholder(..) |
208 ty::UnnormalizedProjection(..) |
212 ty::GeneratorWitness(..) |
214 bug!("debuginfo: Trying to create type name for \
215 unexpected type: {:?}", t);
219 fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
221 output.push_str(&tcx.crate_name(def_id.krate).as_str());
222 for path_element in tcx.def_path(def_id).data {
223 output.push_str("::");
224 output.push_str(&path_element.data.as_symbol().as_str());
227 output.push_str(&tcx.item_name(def_id).as_str());
231 // Pushes the type parameters in the given `InternalSubsts` to the output string.
232 // This ignores region parameters, since they can't reliably be
233 // reconstructed for items from non-local crates. For local crates, this
234 // would be possible but with inlining and LTO we have to use the least
235 // common denominator - otherwise we would run into conflicts.
236 fn push_type_params<'tcx>(
238 substs: SubstsRef<'tcx>,
240 visited: &mut FxHashSet<Ty<'tcx>>,
242 if substs.types().next().is_none() {
248 for type_parameter in substs.types() {
249 push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
250 output.push_str(", ");