]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_ssa/debuginfo/type_names.rs
166a74fe48795adcfc7582fc060111570f228024
[rust.git] / src / librustc_codegen_ssa / debuginfo / type_names.rs
1 // Type Names for Debug Info.
2
3 use rustc::hir::{self, def_id::DefId};
4 use rustc::ty::{self, Ty, TyCtxt, subst::SubstsRef};
5 use rustc_data_structures::fx::FxHashSet;
6
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>(
12     tcx: TyCtxt<'tcx>,
13     t: Ty<'tcx>,
14     qualified: bool,
15 ) -> String {
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);
19     result
20 }
21
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>(
25     tcx: TyCtxt<'tcx>,
26     t: Ty<'tcx>,
27     qualified: bool,
28     output: &mut String,
29     visited: &mut FxHashSet<Ty<'tcx>>,
30 ) {
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;
34
35     match t.kind {
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);
47         },
48         ty::Tuple(component_types) => {
49             output.push('(');
50             for &component_type in component_types {
51                 push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
52                 output.push_str(", ");
53             }
54             if !component_types.is_empty() {
55                 output.pop();
56                 output.pop();
57             }
58             output.push(')');
59         },
60         ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
61             if !cpp_like_names {
62                 output.push('*');
63             }
64             match mutbl {
65                 hir::MutImmutable => output.push_str("const "),
66                 hir::MutMutable => output.push_str("mut "),
67             }
68
69             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
70
71             if cpp_like_names {
72                 output.push('*');
73             }
74         },
75         ty::Ref(_, inner_type, mutbl) => {
76             if !cpp_like_names {
77                 output.push('&');
78             }
79             if mutbl == hir::MutMutable {
80                 output.push_str("mut ");
81             }
82
83             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
84
85             if cpp_like_names {
86                 output.push('*');
87             }
88         },
89         ty::Array(inner_type, len) => {
90             output.push('[');
91             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
92             output.push_str(&format!("; {}", len.eval_usize(tcx, ty::ParamEnv::reveal_all())));
93             output.push(']');
94         },
95         ty::Slice(inner_type) => {
96             if cpp_like_names {
97                 output.push_str("slice<");
98             } else {
99                 output.push('[');
100             }
101
102             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
103
104             if cpp_like_names {
105                 output.push('>');
106             } else {
107                 output.push(']');
108             }
109         },
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(),
114                     &principal,
115                 );
116                 push_item_name(tcx, principal.def_id, false, output);
117                 push_type_params(tcx, principal.substs, output, visited);
118             } else {
119                 output.push_str("dyn '_");
120             }
121         },
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':
126             //
127             // fn foo() -> impl Copy { foo }
128             //
129             // There's not really a sensible name we can generate,
130             // since we don't include 'impl trait' types (e.g. ty::Opaque)
131             // in the output
132             //
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>");
138                 return;
139             }
140
141
142             let sig = t.fn_sig(tcx);
143             if sig.unsafety() == hir::Unsafety::Unsafe {
144                 output.push_str("unsafe ");
145             }
146
147             let abi = sig.abi();
148             if abi != rustc_target::spec::abi::Abi::Rust {
149                 output.push_str("extern \"");
150                 output.push_str(abi.name());
151                 output.push_str("\" ");
152             }
153
154             output.push_str("fn(");
155
156             let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
157             if !sig.inputs().is_empty() {
158                 for &parameter_type in sig.inputs() {
159                     push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
160                     output.push_str(", ");
161                 }
162                 output.pop();
163                 output.pop();
164             }
165
166             if sig.c_variadic {
167                 if !sig.inputs().is_empty() {
168                     output.push_str(", ...");
169                 } else {
170                     output.push_str("...");
171                 }
172             }
173
174             output.push(')');
175
176             if !sig.output().is_unit() {
177                 output.push_str(" -> ");
178                 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
179             }
180
181
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>
187             //
188             // We only care about avoiding recursing
189             // directly back to the type we're currently
190             // processing
191             visited.remove(t);
192         },
193         ty::Closure(def_id, ..) => {
194             output.push_str(&format!(
195                 "closure-{}",
196                 tcx.def_key(def_id).disambiguated_data.disambiguator
197             ));
198         }
199         ty::Generator(def_id, ..) => {
200             output.push_str(&format!(
201                 "generator-{}",
202                 tcx.def_key(def_id).disambiguated_data.disambiguator
203             ));
204         }
205         ty::Error |
206         ty::Infer(_) |
207         ty::Placeholder(..) |
208         ty::UnnormalizedProjection(..) |
209         ty::Projection(..) |
210         ty::Bound(..) |
211         ty::Opaque(..) |
212         ty::GeneratorWitness(..) |
213         ty::Param(_) => {
214             bug!("debuginfo: Trying to create type name for \
215                   unexpected type: {:?}", t);
216         }
217     }
218
219     fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
220         if qualified {
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());
225             }
226         } else {
227             output.push_str(&tcx.item_name(def_id).as_str());
228         }
229     }
230
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>(
237         tcx: TyCtxt<'tcx>,
238         substs: SubstsRef<'tcx>,
239         output: &mut String,
240         visited: &mut FxHashSet<Ty<'tcx>>,
241     ) {
242         if substs.types().next().is_none() {
243             return;
244         }
245
246         output.push('<');
247
248         for type_parameter in substs.types() {
249             push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
250             output.push_str(", ");
251         }
252
253         output.pop();
254         output.pop();
255
256         output.push('>');
257     }
258 }