1 // Type Names for Debug Info.
3 use rustc::ty::{self, subst::SubstsRef, Ty, TyCtxt};
4 use rustc_data_structures::fx::FxHashSet;
6 use rustc_hir::def_id::DefId;
8 // Compute the name of the type as it should be stored in debuginfo. Does not do
9 // any caching, i.e., calling the function twice with the same type will also do
10 // the work twice. The `qualified` parameter only affects the first level of the
11 // type name, further levels (i.e., type parameters) are always fully qualified.
12 pub fn compute_debuginfo_type_name<'tcx>(
17 let mut result = String::with_capacity(64);
18 let mut visited = FxHashSet::default();
19 push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited);
23 // Pushes the name of the type as it should be stored in debuginfo on the
24 // `output` String. See also compute_debuginfo_type_name().
25 pub fn push_debuginfo_type_name<'tcx>(
30 visited: &mut FxHashSet<Ty<'tcx>>,
32 // When targeting MSVC, emit C++ style type names for compatibility with
33 // .natvis visualizers (and perhaps other existing native debuggers?)
34 let cpp_like_names = tcx.sess.target.target.options.is_like_msvc;
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(int_ty) => output.push_str(int_ty.name_str()),
42 ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()),
43 ty::Float(float_ty) => output.push_str(float_ty.name_str()),
44 ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
45 ty::Adt(def, substs) => {
46 push_item_name(tcx, def.did, qualified, output);
47 push_type_params(tcx, substs, output, visited);
49 ty::Tuple(component_types) => {
51 for &component_type in component_types {
52 push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
53 output.push_str(", ");
55 if !component_types.is_empty() {
61 ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
66 hir::Mutability::Not => output.push_str("const "),
67 hir::Mutability::Mut => output.push_str("mut "),
70 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
76 ty::Ref(_, inner_type, mutbl) => {
80 output.push_str(mutbl.prefix_str());
82 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
88 ty::Array(inner_type, len) => {
90 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
91 output.push_str(&format!("; {}", len.eval_usize(tcx, ty::ParamEnv::reveal_all())));
94 ty::Slice(inner_type) => {
96 output.push_str("slice<");
101 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
109 ty::Dynamic(ref trait_data, ..) => {
110 if let Some(principal) = trait_data.principal() {
112 .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &principal);
113 push_item_name(tcx, principal.def_id, false, output);
114 push_type_params(tcx, principal.substs, output, visited);
116 output.push_str("dyn '_");
119 ty::FnDef(..) | ty::FnPtr(_) => {
120 // We've encountered a weird 'recursive type'
121 // Currently, the only way to generate such a type
122 // is by using 'impl trait':
124 // fn foo() -> impl Copy { foo }
126 // There's not really a sensible name we can generate,
127 // since we don't include 'impl trait' types (e.g. ty::Opaque)
130 // Since we need to generate *something*, we just
131 // use a dummy string that should make it clear
132 // that something unusual is going on
133 if !visited.insert(t) {
134 output.push_str("<recursive_type>");
138 let sig = t.fn_sig(tcx);
139 output.push_str(sig.unsafety().prefix_str());
142 if abi != rustc_target::spec::abi::Abi::Rust {
143 output.push_str("extern \"");
144 output.push_str(abi.name());
145 output.push_str("\" ");
148 output.push_str("fn(");
150 let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
151 if !sig.inputs().is_empty() {
152 for ¶meter_type in sig.inputs() {
153 push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
154 output.push_str(", ");
161 if !sig.inputs().is_empty() {
162 output.push_str(", ...");
164 output.push_str("...");
170 if !sig.output().is_unit() {
171 output.push_str(" -> ");
172 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
175 // We only keep the type in 'visited'
176 // for the duration of the body of this method.
177 // It's fine for a particular function type
178 // to show up multiple times in one overall type
179 // (e.g. MyType<fn() -> u8, fn() -> u8>
181 // We only care about avoiding recursing
182 // directly back to the type we're currently
186 ty::Closure(def_id, ..) => {
187 output.push_str(&format!(
189 tcx.def_key(def_id).disambiguated_data.disambiguator
192 ty::Generator(def_id, ..) => {
193 output.push_str(&format!(
195 tcx.def_key(def_id).disambiguated_data.disambiguator
200 | ty::Placeholder(..)
201 | ty::UnnormalizedProjection(..)
205 | ty::GeneratorWitness(..)
208 "debuginfo: Trying to create type name for \
209 unexpected type: {:?}",
215 fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
217 output.push_str(&tcx.crate_name(def_id.krate).as_str());
218 for path_element in tcx.def_path(def_id).data {
219 output.push_str("::");
220 output.push_str(&path_element.data.as_symbol().as_str());
223 output.push_str(&tcx.item_name(def_id).as_str());
227 // Pushes the type parameters in the given `InternalSubsts` to the output string.
228 // This ignores region parameters, since they can't reliably be
229 // reconstructed for items from non-local crates. For local crates, this
230 // would be possible but with inlining and LTO we have to use the least
231 // common denominator - otherwise we would run into conflicts.
232 fn push_type_params<'tcx>(
234 substs: SubstsRef<'tcx>,
236 visited: &mut FxHashSet<Ty<'tcx>>,
238 if substs.types().next().is_none() {
244 for type_parameter in substs.types() {
245 push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
246 output.push_str(", ");