]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print/obsolete.rs
Rollup merge of #63285 - Mark-Simulacrum:rm-await-origin, r=Centril
[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<'tcx> {
20     tcx: TyCtxt<'tcx>,
21     omit_disambiguators: bool,
22     omit_local_crate_name: bool,
23 }
24
25 impl DefPathBasedNames<'tcx> {
26     pub fn new(tcx: TyCtxt<'tcx>, omit_disambiguators: bool, omit_local_crate_name: bool) -> Self {
27         DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name }
28     }
29
30     // Pushes the type name of the specified type to the provided string.
31     // If `debug` is true, printing normally unprintable types is allowed
32     // (e.g. `ty::GeneratorWitness`). This parameter should only be set when
33     // this method is being used for logging purposes (e.g. with `debug!` or `info!`)
34     // When being used for codegen purposes, `debug` should be set to `false`
35     // in order to catch unexpected types that should never end up in a type name.
36     pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
37         match t.sty {
38             ty::Bool => output.push_str("bool"),
39             ty::Char => output.push_str("char"),
40             ty::Str => output.push_str("str"),
41             ty::Never => output.push_str("!"),
42             ty::Int(ast::IntTy::Isize) => output.push_str("isize"),
43             ty::Int(ast::IntTy::I8) => output.push_str("i8"),
44             ty::Int(ast::IntTy::I16) => output.push_str("i16"),
45             ty::Int(ast::IntTy::I32) => output.push_str("i32"),
46             ty::Int(ast::IntTy::I64) => output.push_str("i64"),
47             ty::Int(ast::IntTy::I128) => output.push_str("i128"),
48             ty::Uint(ast::UintTy::Usize) => output.push_str("usize"),
49             ty::Uint(ast::UintTy::U8) => output.push_str("u8"),
50             ty::Uint(ast::UintTy::U16) => output.push_str("u16"),
51             ty::Uint(ast::UintTy::U32) => output.push_str("u32"),
52             ty::Uint(ast::UintTy::U64) => output.push_str("u64"),
53             ty::Uint(ast::UintTy::U128) => output.push_str("u128"),
54             ty::Float(ast::FloatTy::F32) => output.push_str("f32"),
55             ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
56             ty::Adt(adt_def, substs) => {
57                 self.push_def_path(adt_def.did, output);
58                 self.push_generic_params(substs, iter::empty(), output, debug);
59             }
60             ty::Tuple(component_types) => {
61                 output.push('(');
62                 for &component_type in component_types {
63                     self.push_type_name(component_type.expect_ty(), output, debug);
64                     output.push_str(", ");
65                 }
66                 if !component_types.is_empty() {
67                     output.pop();
68                     output.pop();
69                 }
70                 output.push(')');
71             }
72             ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
73                 output.push('*');
74                 match mutbl {
75                     hir::MutImmutable => output.push_str("const "),
76                     hir::MutMutable => output.push_str("mut "),
77                 }
78
79                 self.push_type_name(inner_type, output, debug);
80             }
81             ty::Ref(_, inner_type, mutbl) => {
82                 output.push('&');
83                 if mutbl == hir::MutMutable {
84                     output.push_str("mut ");
85                 }
86
87                 self.push_type_name(inner_type, output, debug);
88             }
89             ty::Array(inner_type, len) => {
90                 output.push('[');
91                 self.push_type_name(inner_type, output, debug);
92                 let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all());
93                 write!(output, "; {}", len).unwrap();
94                 output.push(']');
95             }
96             ty::Slice(inner_type) => {
97                 output.push('[');
98                 self.push_type_name(inner_type, output, debug);
99                 output.push(']');
100             }
101             ty::Dynamic(ref trait_data, ..) => {
102                 if let Some(principal) = trait_data.principal() {
103                     self.push_def_path(principal.def_id(), output);
104                     self.push_generic_params(
105                         principal.skip_binder().substs,
106                         trait_data.projection_bounds(),
107                         output,
108                         debug,
109                     );
110                 } else {
111                     output.push_str("dyn '_");
112                 }
113             }
114             ty::Foreign(did) => self.push_def_path(did, output),
115             ty::FnDef(..) | ty::FnPtr(_) => {
116                 let sig = t.fn_sig(self.tcx);
117                 if sig.unsafety() == hir::Unsafety::Unsafe {
118                     output.push_str("unsafe ");
119                 }
120
121                 let abi = sig.abi();
122                 if abi != ::rustc_target::spec::abi::Abi::Rust {
123                     output.push_str("extern \"");
124                     output.push_str(abi.name());
125                     output.push_str("\" ");
126                 }
127
128                 output.push_str("fn(");
129
130                 let sig =
131                     self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
132
133                 if !sig.inputs().is_empty() {
134                     for &parameter_type in sig.inputs() {
135                         self.push_type_name(parameter_type, output, debug);
136                         output.push_str(", ");
137                     }
138                     output.pop();
139                     output.pop();
140                 }
141
142                 if sig.c_variadic {
143                     if !sig.inputs().is_empty() {
144                         output.push_str(", ...");
145                     } else {
146                         output.push_str("...");
147                     }
148                 }
149
150                 output.push(')');
151
152                 if !sig.output().is_unit() {
153                     output.push_str(" -> ");
154                     self.push_type_name(sig.output(), output, debug);
155                 }
156             }
157             ty::Generator(def_id, GeneratorSubsts { ref substs }, _)
158             | ty::Closure(def_id, ClosureSubsts { ref substs }) => {
159                 self.push_def_path(def_id, output);
160                 let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
161                 let substs = substs.truncate_to(self.tcx, generics);
162                 self.push_generic_params(substs, iter::empty(), output, debug);
163             }
164             ty::Error
165             | ty::Bound(..)
166             | ty::Infer(_)
167             | ty::Placeholder(..)
168             | ty::UnnormalizedProjection(..)
169             | ty::Projection(..)
170             | ty::Param(_)
171             | ty::GeneratorWitness(_)
172             | ty::Opaque(..) => {
173                 if debug {
174                     output.push_str(&format!("`{:?}`", t));
175                 } else {
176                     bug!(
177                         "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
178                         t,
179                     );
180                 }
181             }
182         }
183     }
184
185     // Pushes the the name of the specified const to the provided string.
186     // If `debug` is true, usually-unprintable consts (such as `Infer`) will be printed,
187     // as well as the unprintable types of constants (see `push_type_name` for more details).
188     pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
189         match c.val {
190             ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef { .. } => {
191                 // FIXME(const_generics): we could probably do a better job here.
192                 write!(output, "{:?}", c).unwrap()
193             }
194             _ => {
195                 if debug {
196                     write!(output, "{:?}", c).unwrap()
197                 } else {
198                     bug!(
199                         "DefPathBasedNames: trying to create const name for unexpected const: {:?}",
200                         c,
201                     );
202                 }
203             }
204         }
205         output.push_str(": ");
206         self.push_type_name(c.ty, output, debug);
207     }
208
209     pub fn push_def_path(&self, def_id: DefId, output: &mut String) {
210         let def_path = self.tcx.def_path(def_id);
211
212         // some_crate::
213         if !(self.omit_local_crate_name && def_id.is_local()) {
214             output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
215             output.push_str("::");
216         }
217
218         // foo::bar::ItemName::
219         for part in self.tcx.def_path(def_id).data {
220             if self.omit_disambiguators {
221                 write!(output, "{}::", part.data.as_interned_str()).unwrap();
222             } else {
223                 write!(output, "{}[{}]::", part.data.as_interned_str(), part.disambiguator)
224                     .unwrap();
225             }
226         }
227
228         // remove final "::"
229         output.pop();
230         output.pop();
231     }
232
233     fn push_generic_params<I>(
234         &self,
235         substs: SubstsRef<'tcx>,
236         projections: I,
237         output: &mut String,
238         debug: bool,
239     ) where
240         I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>,
241     {
242         let mut projections = projections.peekable();
243         if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
244             return;
245         }
246
247         output.push('<');
248
249         for type_parameter in substs.types() {
250             self.push_type_name(type_parameter, output, debug);
251             output.push_str(", ");
252         }
253
254         for projection in projections {
255             let projection = projection.skip_binder();
256             let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
257             output.push_str(name);
258             output.push_str("=");
259             self.push_type_name(projection.ty, output, debug);
260             output.push_str(", ");
261         }
262
263         for const_parameter in substs.consts() {
264             self.push_const_name(const_parameter, output, debug);
265             output.push_str(", ");
266         }
267
268         output.pop();
269         output.pop();
270
271         output.push('>');
272     }
273
274     pub fn push_instance_as_string(
275         &self,
276         instance: Instance<'tcx>,
277         output: &mut String,
278         debug: bool,
279     ) {
280         self.push_def_path(instance.def_id(), output);
281         self.push_generic_params(instance.substs, iter::empty(), output, debug);
282     }
283 }