]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print/obsolete.rs
Rollup merge of #61698 - davidtwco:ice-const-generic-length, r=varkor
[rust.git] / src / librustc / ty / print / obsolete.rs
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.
4 //!
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.
7
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};
13 use std::fmt::Write;
14 use std::iter;
15 use syntax::ast;
16
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,
23 }
24
25 impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
26     pub fn new(
27         tcx: TyCtxt<'a, 'tcx, 'tcx>,
28         omit_disambiguators: bool,
29         omit_local_crate_name: bool,
30     ) -> Self {
31         DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name }
32     }
33
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) {
41         match t.sty {
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);
63             }
64             ty::Tuple(component_types) => {
65                 output.push('(');
66                 for &component_type in component_types {
67                     self.push_type_name(component_type.expect_ty(), output, debug);
68                     output.push_str(", ");
69                 }
70                 if !component_types.is_empty() {
71                     output.pop();
72                     output.pop();
73                 }
74                 output.push(')');
75             }
76             ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
77                 output.push('*');
78                 match mutbl {
79                     hir::MutImmutable => output.push_str("const "),
80                     hir::MutMutable => output.push_str("mut "),
81                 }
82
83                 self.push_type_name(inner_type, output, debug);
84             }
85             ty::Ref(_, inner_type, mutbl) => {
86                 output.push('&');
87                 if mutbl == hir::MutMutable {
88                     output.push_str("mut ");
89                 }
90
91                 self.push_type_name(inner_type, output, debug);
92             }
93             ty::Array(inner_type, len) => {
94                 output.push('[');
95                 self.push_type_name(inner_type, output, debug);
96                 write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
97                 output.push(']');
98             }
99             ty::Slice(inner_type) => {
100                 output.push('[');
101                 self.push_type_name(inner_type, output, debug);
102                 output.push(']');
103             }
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(),
110                         output,
111                         debug,
112                     );
113                 } else {
114                     output.push_str("dyn '_");
115                 }
116             }
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 ");
122                 }
123
124                 let abi = sig.abi();
125                 if abi != ::rustc_target::spec::abi::Abi::Rust {
126                     output.push_str("extern \"");
127                     output.push_str(abi.name());
128                     output.push_str("\" ");
129                 }
130
131                 output.push_str("fn(");
132
133                 let sig =
134                     self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
135
136                 if !sig.inputs().is_empty() {
137                     for &parameter_type in sig.inputs() {
138                         self.push_type_name(parameter_type, output, debug);
139                         output.push_str(", ");
140                     }
141                     output.pop();
142                     output.pop();
143                 }
144
145                 if sig.c_variadic {
146                     if !sig.inputs().is_empty() {
147                         output.push_str(", ...");
148                     } else {
149                         output.push_str("...");
150                     }
151                 }
152
153                 output.push(')');
154
155                 if !sig.output().is_unit() {
156                     output.push_str(" -> ");
157                     self.push_type_name(sig.output(), output, debug);
158                 }
159             }
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);
166             }
167             ty::Error
168             | ty::Bound(..)
169             | ty::Infer(_)
170             | ty::Placeholder(..)
171             | ty::UnnormalizedProjection(..)
172             | ty::Projection(..)
173             | ty::Param(_)
174             | ty::GeneratorWitness(_)
175             | ty::Opaque(..) => {
176                 if debug {
177                     output.push_str(&format!("`{:?}`", t));
178                 } else {
179                     bug!(
180                         "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
181                         t,
182                     );
183                 }
184             }
185         }
186     }
187
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) {
192         match c.val {
193             ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef(..) => {
194                 // FIXME(const_generics): we could probably do a better job here.
195                 write!(output, "{:?}", c).unwrap()
196             }
197             _ => {
198                 if debug {
199                     write!(output, "{:?}", c).unwrap()
200                 } else {
201                     bug!(
202                         "DefPathBasedNames: trying to create const name for unexpected const: {:?}",
203                         c,
204                     );
205                 }
206             }
207         }
208         output.push_str(": ");
209         self.push_type_name(c.ty, output, debug);
210     }
211
212     pub fn push_def_path(&self, def_id: DefId, output: &mut String) {
213         let def_path = self.tcx.def_path(def_id);
214
215         // some_crate::
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("::");
219         }
220
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();
225             } else {
226                 write!(output, "{}[{}]::", part.data.as_interned_str(), part.disambiguator)
227                     .unwrap();
228             }
229         }
230
231         // remove final "::"
232         output.pop();
233         output.pop();
234     }
235
236     fn push_generic_params<I>(
237         &self,
238         substs: SubstsRef<'tcx>,
239         projections: I,
240         output: &mut String,
241         debug: bool,
242     ) where
243         I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>,
244     {
245         let mut projections = projections.peekable();
246         if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
247             return;
248         }
249
250         output.push('<');
251
252         for type_parameter in substs.types() {
253             self.push_type_name(type_parameter, output, debug);
254             output.push_str(", ");
255         }
256
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(", ");
264         }
265
266         for const_parameter in substs.consts() {
267             self.push_const_name(const_parameter, output, debug);
268             output.push_str(", ");
269         }
270
271         output.pop();
272         output.pop();
273
274         output.push('>');
275     }
276
277     pub fn push_instance_as_string(
278         &self,
279         instance: Instance<'tcx>,
280         output: &mut String,
281         debug: bool,
282     ) {
283         self.push_def_path(instance.def_id(), output);
284         self.push_generic_params(instance.substs, iter::empty(), output, debug);
285     }
286 }