]> git.lizzy.rs Git - rust.git/blob - src/librustc/util/ppaux.rs
2e11a3741369e0454ecbd427f0a5be0f8f9904f7
[rust.git] / src / librustc / util / ppaux.rs
1 use crate::hir;
2 use crate::hir::def::Namespace;
3 use crate::ty::subst::{Kind, UnpackedKind};
4 use crate::ty::{self, ParamConst, Ty};
5 use crate::ty::print::{FmtPrinter, PrettyPrinter, PrintCx, Print};
6 use crate::mir::interpret::ConstValue;
7
8 use std::fmt;
9 use std::iter;
10
11 use rustc_target::spec::abi::Abi;
12
13 macro_rules! define_print {
14     ([$($target:ty),+] $vars:tt $def:tt) => {
15         $(define_print!($target, $vars $def);)+
16     };
17
18     ($target:ty, ($self:ident, $cx:ident) { display $disp:block }) => {
19         impl<P: PrettyPrinter> Print<'tcx, P> for $target {
20             type Output = P;
21             type Error = fmt::Error;
22             fn print(&$self, $cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
23                 #[allow(unused_mut)]
24                 let mut $cx = $cx;
25                 define_scoped_cx!($cx);
26                 let _: () = $disp;
27                 #[allow(unreachable_code)]
28                 Ok($cx.printer)
29             }
30         }
31
32         impl fmt::Display for $target {
33             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34                 PrintCx::with_tls_tcx(FmtPrinter::new(f, Namespace::TypeNS), |cx| {
35                     cx.tcx.lift(self).expect("could not lift for printing").print(cx)?;
36                     Ok(())
37                 })
38             }
39         }
40     };
41 }
42
43 macro_rules! nest {
44     ($closure:expr) => {
45         scoped_cx!() = scoped_cx!().nest($closure)?
46     }
47 }
48 macro_rules! print_inner {
49     (write ($($data:expr),+)) => {
50         write!(scoped_cx!().printer, $($data),+)?
51     };
52     ($kind:ident ($data:expr)) => {
53         nest!(|cx| $data.$kind(cx))
54     };
55 }
56 macro_rules! p {
57     ($($kind:ident $data:tt),+) => {
58         {
59             $(print_inner!($kind $data));+
60         }
61     };
62 }
63 macro_rules! define_scoped_cx {
64     ($cx:ident) => {
65         #[allow(unused_macros)]
66         macro_rules! scoped_cx {
67             () => ($cx)
68         }
69     };
70 }
71
72 define_print! {
73     &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, (self, cx) {
74         display {
75             // Generate the main trait ref, including associated types.
76             let mut first = true;
77
78             if let Some(principal) = self.principal() {
79                 let mut resugared_principal = false;
80
81                 // Special-case `Fn(...) -> ...` and resugar it.
82                 let fn_trait_kind = cx.tcx.lang_items().fn_trait_kind(principal.def_id);
83                 if !cx.tcx.sess.verbose() && fn_trait_kind.is_some() {
84                     if let ty::Tuple(ref args) = principal.substs.type_at(0).sty {
85                         let mut projections = self.projection_bounds();
86                         if let (Some(proj), None) = (projections.next(), projections.next()) {
87                             nest!(|cx| cx.print_def_path(principal.def_id, None, iter::empty()));
88                             nest!(|cx| cx.pretty_fn_sig(args, false, proj.ty));
89                             resugared_principal = true;
90                         }
91                     }
92                 }
93
94                 if !resugared_principal {
95                     // Use a type that can't appear in defaults of type parameters.
96                     let dummy_self = cx.tcx.mk_infer(ty::FreshTy(0));
97                     let principal = principal.with_self_ty(cx.tcx, dummy_self);
98                     nest!(|cx| cx.print_def_path(
99                         principal.def_id,
100                         Some(principal.substs),
101                         self.projection_bounds(),
102                     ));
103                 }
104                 first = false;
105             }
106
107             // Builtin bounds.
108             // FIXME(eddyb) avoid printing twice (needed to ensure
109             // that the auto traits are sorted *and* printed via cx).
110             let mut auto_traits: Vec<_> = self.auto_traits().map(|did| {
111                 (cx.tcx.def_path_str(did), did)
112             }).collect();
113
114             // The auto traits come ordered by `DefPathHash`. While
115             // `DefPathHash` is *stable* in the sense that it depends on
116             // neither the host nor the phase of the moon, it depends
117             // "pseudorandomly" on the compiler version and the target.
118             //
119             // To avoid that causing instabilities in compiletest
120             // output, sort the auto-traits alphabetically.
121             auto_traits.sort();
122
123             for (_, def_id) in auto_traits {
124                 if !first {
125                     p!(write(" + "));
126                 }
127                 first = false;
128
129                 nest!(|cx| cx.print_def_path(def_id, None, iter::empty()));
130             }
131         }
132     }
133 }
134
135 define_print! {
136     &'tcx ty::List<Ty<'tcx>>, (self, cx) {
137         display {
138             p!(write("{{"));
139             let mut tys = self.iter();
140             if let Some(&ty) = tys.next() {
141                 p!(print(ty));
142                 for &ty in tys {
143                     p!(write(", "), print(ty));
144                 }
145             }
146             p!(write("}}"))
147         }
148     }
149 }
150
151 define_print! {
152     ty::TypeAndMut<'tcx>, (self, cx) {
153         display {
154             p!(
155                    write("{}", if self.mutbl == hir::MutMutable { "mut " } else { "" }),
156                    print(self.ty))
157         }
158     }
159 }
160
161 define_print! {
162     ty::ExistentialTraitRef<'tcx>, (self, cx) {
163         display {
164             let dummy_self = cx.tcx.mk_infer(ty::FreshTy(0));
165
166             let trait_ref = *ty::Binder::bind(*self)
167                 .with_self_ty(cx.tcx, dummy_self)
168                 .skip_binder();
169             p!(print(trait_ref))
170         }
171     }
172 }
173
174 define_print! {
175     ty::RegionKind, (self, cx) {
176         display {
177             return cx.print_region(self);
178         }
179     }
180 }
181
182 define_print! {
183     ty::FnSig<'tcx>, (self, cx) {
184         display {
185             if self.unsafety == hir::Unsafety::Unsafe {
186                 p!(write("unsafe "));
187             }
188
189             if self.abi != Abi::Rust {
190                 p!(write("extern {} ", self.abi));
191             }
192
193             p!(write("fn"));
194             nest!(|cx| cx.pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
195         }
196     }
197 }
198
199 define_print! {
200     ty::InferTy, (self, cx) {
201         display {
202             if cx.tcx.sess.verbose() {
203                 p!(write("{:?}", self));
204                 return Ok(cx.printer);
205             }
206             match *self {
207                 ty::TyVar(_) => p!(write("_")),
208                 ty::IntVar(_) => p!(write("{}", "{integer}")),
209                 ty::FloatVar(_) => p!(write("{}", "{float}")),
210                 ty::FreshTy(v) => p!(write("FreshTy({})", v)),
211                 ty::FreshIntTy(v) => p!(write("FreshIntTy({})", v)),
212                 ty::FreshFloatTy(v) => p!(write("FreshFloatTy({})", v))
213             }
214         }
215     }
216 }
217
218 // The generic impl doesn't work yet because projections are not
219 // normalized under HRTB.
220 /*impl<T> fmt::Display for ty::Binder<T>
221     where T: fmt::Display + for<'a> ty::Lift<'a>,
222           for<'a> <T as ty::Lift<'a>>::Lifted: fmt::Display + TypeFoldable<'a>
223 {
224     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225         PrintCx::with_tls_tcx(|cx| cx.pretty_in_binder(cx.tcx.lift(self)
226             .expect("could not lift for printing")))
227     }
228 }*/
229
230 define_print! {
231     [
232         ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
233         ty::Binder<ty::TraitRef<'tcx>>,
234         ty::Binder<ty::FnSig<'tcx>>,
235         ty::Binder<ty::TraitPredicate<'tcx>>,
236         ty::Binder<ty::SubtypePredicate<'tcx>>,
237         ty::Binder<ty::ProjectionPredicate<'tcx>>,
238         ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
239         ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>
240     ]
241     (self, cx) {
242         display {
243             nest!(|cx| cx.pretty_in_binder(self))
244         }
245     }
246 }
247
248 define_print! {
249     ty::TraitRef<'tcx>, (self, cx) {
250         display {
251             nest!(|cx| cx.print_def_path(self.def_id, Some(self.substs), iter::empty()));
252         }
253     }
254 }
255
256 define_print! {
257     Ty<'tcx>, (self, cx) {
258         display {
259             return cx.print_type(self);
260         }
261     }
262 }
263
264 define_print! {
265     ConstValue<'tcx>, (self, cx) {
266         display {
267             match self {
268                 ConstValue::Infer(..) => p!(write("_")),
269                 ConstValue::Param(ParamConst { name, .. }) => p!(write("{}", name)),
270                 _ => p!(write("{:?}", self)),
271             }
272         }
273     }
274 }
275
276 define_print! {
277     ty::Const<'tcx>, (self, cx) {
278         display {
279             p!(write("{} : {}", self.val, self.ty))
280         }
281     }
282 }
283
284 define_print! {
285     ty::LazyConst<'tcx>, (self, cx) {
286         display {
287             match self {
288                 // FIXME(const_generics) this should print at least the type.
289                 ty::LazyConst::Unevaluated(..) => p!(write("_ : _")),
290                 ty::LazyConst::Evaluated(c) => p!(write("{}", c)),
291             }
292         }
293     }
294 }
295
296 define_print! {
297     ty::ParamTy, (self, cx) {
298         display {
299             p!(write("{}", self.name))
300         }
301     }
302 }
303
304 define_print! {
305     ty::ParamConst, (self, cx) {
306         display {
307             p!(write("{}", self.name))
308         }
309     }
310 }
311
312 // Similar problem to `Binder<T>`, can't define a generic impl.
313 define_print! {
314     [
315         ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
316         ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
317     ]
318     (self, cx) {
319         display {
320             p!(print(self.0), write(" : "), print(self.1))
321         }
322     }
323 }
324
325 define_print! {
326     ty::SubtypePredicate<'tcx>, (self, cx) {
327         display {
328             p!(print(self.a), write(" <: "), print(self.b))
329         }
330     }
331 }
332
333 define_print! {
334     ty::TraitPredicate<'tcx>, (self, cx) {
335         display {
336             p!(print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref))
337         }
338     }
339 }
340
341 define_print! {
342     ty::ProjectionPredicate<'tcx>, (self, cx) {
343         display {
344             p!(print(self.projection_ty), write(" == "), print(self.ty))
345         }
346     }
347 }
348
349 define_print! {
350     ty::ProjectionTy<'tcx>, (self, cx) {
351         display {
352             nest!(|cx| cx.print_def_path(self.item_def_id, Some(self.substs), iter::empty()));
353         }
354     }
355 }
356
357 define_print! {
358     ty::ClosureKind, (self, cx) {
359         display {
360             match *self {
361                 ty::ClosureKind::Fn => p!(write("Fn")),
362                 ty::ClosureKind::FnMut => p!(write("FnMut")),
363                 ty::ClosureKind::FnOnce => p!(write("FnOnce")),
364             }
365         }
366     }
367 }
368
369 define_print! {
370     ty::Predicate<'tcx>, (self, cx) {
371         display {
372             match *self {
373                 ty::Predicate::Trait(ref data) => p!(print(data)),
374                 ty::Predicate::Subtype(ref predicate) => p!(print(predicate)),
375                 ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)),
376                 ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)),
377                 ty::Predicate::Projection(ref predicate) => p!(print(predicate)),
378                 ty::Predicate::WellFormed(ty) => p!(print(ty), write(" well-formed")),
379                 ty::Predicate::ObjectSafe(trait_def_id) => {
380                     p!(write("the trait `"));
381                     nest!(|cx| cx.print_def_path(trait_def_id, None, iter::empty()));
382                     p!(write("` is object-safe"))
383                 }
384                 ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => {
385                     p!(write("the closure `"));
386                     nest!(|cx| cx.print_value_path(closure_def_id, None));
387                     p!(write("` implements the trait `{}`", kind))
388                 }
389                 ty::Predicate::ConstEvaluatable(def_id, substs) => {
390                     p!(write("the constant `"));
391                     nest!(|cx| cx.print_value_path(def_id, Some(substs)));
392                     p!(write("` can be evaluated"))
393                 }
394             }
395         }
396     }
397 }
398
399 define_print! {
400     Kind<'tcx>, (self, cx) {
401         display {
402             match self.unpack() {
403                 UnpackedKind::Lifetime(lt) => p!(print(lt)),
404                 UnpackedKind::Type(ty) => p!(print(ty)),
405                 UnpackedKind::Const(ct) => p!(print(ct)),
406             }
407         }
408     }
409 }