]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/debuginfo/type_names.rs
2d0003d93a5d25a8a63e332fc42418331e8973a8
[rustc.git] / src / librustc_trans / trans / debuginfo / type_names.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // Type Names for Debug Info.
12
13 use super::namespace::crate_root_namespace;
14
15 use trans::common::CrateContext;
16 use middle::subst::{self, Substs};
17 use middle::ty::{self, Ty, ClosureTyper};
18 use syntax::ast;
19 use syntax::parse::token;
20 use util::ppaux;
21
22
23 // Compute the name of the type as it should be stored in debuginfo. Does not do
24 // any caching, i.e. calling the function twice with the same type will also do
25 // the work twice. The `qualified` parameter only affects the first level of the
26 // type name, further levels (i.e. type parameters) are always fully qualified.
27 pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
28 t: Ty<'tcx>,
29 qualified: bool)
30 -> String {
31 let mut result = String::with_capacity(64);
32 push_debuginfo_type_name(cx, t, qualified, &mut result);
33 result
34 }
35
36 // Pushes the name of the type as it should be stored in debuginfo on the
37 // `output` String. See also compute_debuginfo_type_name().
38 pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
39 t: Ty<'tcx>,
40 qualified: bool,
41 output: &mut String) {
42 match t.sty {
43 ty::ty_bool => output.push_str("bool"),
44 ty::ty_char => output.push_str("char"),
45 ty::ty_str => output.push_str("str"),
46 ty::ty_int(ast::TyIs) => output.push_str("isize"),
47 ty::ty_int(ast::TyI8) => output.push_str("i8"),
48 ty::ty_int(ast::TyI16) => output.push_str("i16"),
49 ty::ty_int(ast::TyI32) => output.push_str("i32"),
50 ty::ty_int(ast::TyI64) => output.push_str("i64"),
51 ty::ty_uint(ast::TyUs) => output.push_str("usize"),
52 ty::ty_uint(ast::TyU8) => output.push_str("u8"),
53 ty::ty_uint(ast::TyU16) => output.push_str("u16"),
54 ty::ty_uint(ast::TyU32) => output.push_str("u32"),
55 ty::ty_uint(ast::TyU64) => output.push_str("u64"),
56 ty::ty_float(ast::TyF32) => output.push_str("f32"),
57 ty::ty_float(ast::TyF64) => output.push_str("f64"),
58 ty::ty_struct(def_id, substs) |
59 ty::ty_enum(def_id, substs) => {
60 push_item_name(cx, def_id, qualified, output);
61 push_type_params(cx, substs, output);
62 },
63 ty::ty_tup(ref component_types) => {
64 output.push('(');
65 for &component_type in component_types {
66 push_debuginfo_type_name(cx, component_type, true, output);
67 output.push_str(", ");
68 }
69 if !component_types.is_empty() {
70 output.pop();
71 output.pop();
72 }
73 output.push(')');
74 },
75 ty::ty_uniq(inner_type) => {
76 output.push_str("Box<");
77 push_debuginfo_type_name(cx, inner_type, true, output);
78 output.push('>');
79 },
80 ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
81 output.push('*');
82 match mutbl {
83 ast::MutImmutable => output.push_str("const "),
84 ast::MutMutable => output.push_str("mut "),
85 }
86
87 push_debuginfo_type_name(cx, inner_type, true, output);
88 },
89 ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
90 output.push('&');
91 if mutbl == ast::MutMutable {
92 output.push_str("mut ");
93 }
94
95 push_debuginfo_type_name(cx, inner_type, true, output);
96 },
97 ty::ty_vec(inner_type, optional_length) => {
98 output.push('[');
99 push_debuginfo_type_name(cx, inner_type, true, output);
100
101 match optional_length {
102 Some(len) => {
103 output.push_str(&format!("; {}", len));
104 }
105 None => { /* nothing to do */ }
106 };
107
108 output.push(']');
109 },
110 ty::ty_trait(ref trait_data) => {
111 let principal = ty::erase_late_bound_regions(cx.tcx(), &trait_data.principal);
112 push_item_name(cx, principal.def_id, false, output);
113 push_type_params(cx, principal.substs, output);
114 },
115 ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
116 if unsafety == ast::Unsafety::Unsafe {
117 output.push_str("unsafe ");
118 }
119
120 if abi != ::syntax::abi::Rust {
121 output.push_str("extern \"");
122 output.push_str(abi.name());
123 output.push_str("\" ");
124 }
125
126 output.push_str("fn(");
127
128 let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
129 if !sig.inputs.is_empty() {
130 for &parameter_type in &sig.inputs {
131 push_debuginfo_type_name(cx, parameter_type, true, output);
132 output.push_str(", ");
133 }
134 output.pop();
135 output.pop();
136 }
137
138 if sig.variadic {
139 if !sig.inputs.is_empty() {
140 output.push_str(", ...");
141 } else {
142 output.push_str("...");
143 }
144 }
145
146 output.push(')');
147
148 match sig.output {
149 ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {}
150 ty::FnConverging(result_type) => {
151 output.push_str(" -> ");
152 push_debuginfo_type_name(cx, result_type, true, output);
153 }
154 ty::FnDiverging => {
155 output.push_str(" -> !");
156 }
157 }
158 },
159 ty::ty_closure(..) => {
160 output.push_str("closure");
161 }
162 ty::ty_err |
163 ty::ty_infer(_) |
164 ty::ty_projection(..) |
165 ty::ty_param(_) => {
166 cx.sess().bug(&format!("debuginfo: Trying to create type name for \
167 unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t)));
168 }
169 }
170
171 fn push_item_name(cx: &CrateContext,
172 def_id: ast::DefId,
173 qualified: bool,
174 output: &mut String) {
175 ty::with_path(cx.tcx(), def_id, |path| {
176 if qualified {
177 if def_id.krate == ast::LOCAL_CRATE {
178 output.push_str(crate_root_namespace(cx));
179 output.push_str("::");
180 }
181
182 let mut path_element_count = 0;
183 for path_element in path {
184 let name = token::get_name(path_element.name());
185 output.push_str(&name);
186 output.push_str("::");
187 path_element_count += 1;
188 }
189
190 if path_element_count == 0 {
191 cx.sess().bug("debuginfo: Encountered empty item path!");
192 }
193
194 output.pop();
195 output.pop();
196 } else {
197 let name = token::get_name(path.last()
198 .expect("debuginfo: Empty item path?")
199 .name());
200 output.push_str(&name);
201 }
202 });
203 }
204
205 // Pushes the type parameters in the given `Substs` to the output string.
206 // This ignores region parameters, since they can't reliably be
207 // reconstructed for items from non-local crates. For local crates, this
208 // would be possible but with inlining and LTO we have to use the least
209 // common denominator - otherwise we would run into conflicts.
210 fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
211 substs: &subst::Substs<'tcx>,
212 output: &mut String) {
213 if substs.types.is_empty() {
214 return;
215 }
216
217 output.push('<');
218
219 for &type_parameter in substs.types.iter() {
220 push_debuginfo_type_name(cx, type_parameter, true, output);
221 output.push_str(", ");
222 }
223
224 output.pop();
225 output.pop();
226
227 output.push('>');
228 }
229 }
230