]> git.lizzy.rs Git - rust.git/blob - src/librustc/util/ppaux.rs
librustc: Fix errors arising from the automated `~[T]` conversion
[rust.git] / src / librustc / util / ppaux.rs
1 // Copyright 2012 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
12 use metadata::encoder;
13 use middle::ty::{ReSkolemized, ReVar};
14 use middle::ty::{BoundRegion, BrAnon, BrNamed};
15 use middle::ty::{BrFresh, ctxt};
16 use middle::ty::{mt, t, param_ty};
17 use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region,
18                  ReEmpty};
19 use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
20 use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
21 use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_self, ty_tup};
22 use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_unboxed_vec, ty_infer};
23 use middle::ty;
24 use middle::typeck;
25 use syntax::abi::AbiSet;
26 use syntax::ast_map;
27 use syntax::codemap::{Span, Pos};
28 use syntax::parse::token;
29 use syntax::print::pprust;
30 use syntax::{ast, ast_util};
31 use syntax::opt_vec;
32 use syntax::opt_vec::OptVec;
33
34 /// Produces a string suitable for debugging output.
35 pub trait Repr {
36     fn repr(&self, tcx: ctxt) -> ~str;
37 }
38
39 /// Produces a string suitable for showing to the user.
40 pub trait UserString {
41     fn user_string(&self, tcx: ctxt) -> ~str;
42 }
43
44 pub fn note_and_explain_region(cx: ctxt,
45                                prefix: &str,
46                                region: ty::Region,
47                                suffix: &str) {
48     match explain_region_and_span(cx, region) {
49       (ref str, Some(span)) => {
50         cx.sess.span_note(
51             span,
52             format!("{}{}{}", prefix, *str, suffix));
53       }
54       (ref str, None) => {
55         cx.sess.note(
56             format!("{}{}{}", prefix, *str, suffix));
57       }
58     }
59 }
60
61 /// Returns a string like "the block at 27:31" that attempts to explain a
62 /// lifetime in a way it might plausibly be understood.
63 pub fn explain_region(cx: ctxt, region: ty::Region) -> ~str {
64   let (res, _) = explain_region_and_span(cx, region);
65   return res;
66 }
67
68
69 pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
70                             -> (~str, Option<Span>) {
71     return match region {
72       ReScope(node_id) => {
73         match cx.map.find(node_id) {
74           Some(ast_map::NodeBlock(ref blk)) => {
75             explain_span(cx, "block", blk.span)
76           }
77           Some(ast_map::NodeExpr(expr)) => {
78             match expr.node {
79               ast::ExprCall(..) => explain_span(cx, "call", expr.span),
80               ast::ExprMethodCall(..) => {
81                 explain_span(cx, "method call", expr.span)
82               },
83               ast::ExprMatch(..) => explain_span(cx, "match", expr.span),
84               _ => explain_span(cx, "expression", expr.span)
85             }
86           }
87           Some(ast_map::NodeStmt(stmt)) => {
88               explain_span(cx, "statement", stmt.span)
89           }
90           Some(ast_map::NodeItem(it)) if (match it.node {
91                 ast::ItemFn(..) => true, _ => false}) => {
92               explain_span(cx, "function body", it.span)
93           }
94           Some(_) | None => {
95             // this really should not happen
96             (format!("unknown scope: {}.  Please report a bug.", node_id),
97              None)
98           }
99         }
100       }
101
102       ReFree(ref fr) => {
103         let prefix = match fr.bound_region {
104           BrAnon(idx) => format!("the anonymous lifetime \\#{} defined on",
105                                idx + 1),
106           BrFresh(_) => format!("an anonymous lifetime defined on"),
107           _ => format!("the lifetime {} as defined on",
108                     bound_region_ptr_to_str(cx, fr.bound_region))
109         };
110
111         match cx.map.find(fr.scope_id) {
112           Some(ast_map::NodeBlock(ref blk)) => {
113             let (msg, opt_span) = explain_span(cx, "block", blk.span);
114             (format!("{} {}", prefix, msg), opt_span)
115           }
116           Some(ast_map::NodeItem(it)) if match it.node {
117                 ast::ItemImpl(..) => true, _ => false} => {
118             let (msg, opt_span) = explain_span(cx, "impl", it.span);
119             (format!("{} {}", prefix, msg), opt_span)
120           }
121           Some(_) | None => {
122             // this really should not happen
123             (format!("{} node {}", prefix, fr.scope_id), None)
124           }
125         }
126       }
127
128       ReStatic => { (~"the static lifetime", None) }
129
130       ReEmpty => { (~"the empty lifetime", None) }
131
132       // I believe these cases should not occur (except when debugging,
133       // perhaps)
134       ty::ReInfer(_) | ty::ReEarlyBound(..) | ty::ReLateBound(..) => {
135         (format!("lifetime {:?}", region), None)
136       }
137     };
138
139     fn explain_span(cx: ctxt, heading: &str, span: Span)
140         -> (~str, Option<Span>)
141     {
142         let lo = cx.sess.codemap.lookup_char_pos_adj(span.lo);
143         (format!("the {} at {}:{}", heading,
144               lo.line, lo.col.to_uint()), Some(span))
145     }
146 }
147
148 pub fn bound_region_ptr_to_str(cx: ctxt, br: BoundRegion) -> ~str {
149     bound_region_to_str(cx, "&", true, br)
150 }
151
152 pub fn bound_region_to_str(cx: ctxt,
153                            prefix: &str, space: bool,
154                            br: BoundRegion) -> ~str {
155     let space_str = if space { " " } else { "" };
156
157     if cx.sess.verbose() {
158         return format!("{}{}{}", prefix, br.repr(cx), space_str);
159     }
160
161     match br {
162         BrNamed(_, ident)   => format!("{}'{}{}", prefix,
163                                        token::get_name(ident), space_str),
164         BrAnon(_)           => prefix.to_str(),
165         BrFresh(_)          => prefix.to_str(),
166     }
167 }
168
169 pub fn ReScope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str {
170     match cx.map.find(node_id) {
171       Some(ast_map::NodeBlock(ref blk)) => {
172         format!("<block at {}>",
173              cx.sess.codemap.span_to_str(blk.span))
174       }
175       Some(ast_map::NodeExpr(expr)) => {
176         match expr.node {
177           ast::ExprCall(..) => {
178             format!("<call at {}>",
179                  cx.sess.codemap.span_to_str(expr.span))
180           }
181           ast::ExprMatch(..) => {
182             format!("<match at {}>",
183                  cx.sess.codemap.span_to_str(expr.span))
184           }
185           ast::ExprAssignOp(..) |
186           ast::ExprUnary(..) |
187           ast::ExprBinary(..) |
188           ast::ExprIndex(..) => {
189             format!("<method at {}>",
190                  cx.sess.codemap.span_to_str(expr.span))
191           }
192           _ => {
193             format!("<expression at {}>",
194                  cx.sess.codemap.span_to_str(expr.span))
195           }
196         }
197       }
198       None => {
199         format!("<unknown-{}>", node_id)
200       }
201       _ => cx.sess.bug(format!("ReScope refers to {}", cx.map.node_to_str(node_id)))
202     }
203 }
204
205 // In general, if you are giving a region error message,
206 // you should use `explain_region()` or, better yet,
207 // `note_and_explain_region()`
208 pub fn region_ptr_to_str(cx: ctxt, region: Region) -> ~str {
209     region_to_str(cx, "&", true, region)
210 }
211
212 pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~str {
213     let space_str = if space { " " } else { "" };
214
215     if cx.sess.verbose() {
216         return format!("{}{}{}", prefix, region.repr(cx), space_str);
217     }
218
219     // These printouts are concise.  They do not contain all the information
220     // the user might want to diagnose an error, but there is basically no way
221     // to fit that into a short string.  Hence the recommendation to use
222     // `explain_region()` or `note_and_explain_region()`.
223     match region {
224         ty::ReScope(_) => prefix.to_str(),
225         ty::ReEarlyBound(_, _, ident) => token::get_name(ident).get().to_str(),
226         ty::ReLateBound(_, br) => bound_region_to_str(cx, prefix, space, br),
227         ty::ReFree(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
228         ty::ReInfer(ReSkolemized(_, br)) => {
229             bound_region_to_str(cx, prefix, space, br)
230         }
231         ty::ReInfer(ReVar(_)) => prefix.to_str(),
232         ty::ReStatic => format!("{}'static{}", prefix, space_str),
233         ty::ReEmpty => format!("{}'<empty>{}", prefix, space_str)
234     }
235 }
236
237 pub fn mutability_to_str(m: ast::Mutability) -> ~str {
238     match m {
239         ast::MutMutable => ~"mut ",
240         ast::MutImmutable => ~"",
241     }
242 }
243
244 pub fn mt_to_str(cx: ctxt, m: &mt) -> ~str {
245     mt_to_str_wrapped(cx, "", m, "")
246 }
247
248 pub fn mt_to_str_wrapped(cx: ctxt, before: &str, m: &mt, after: &str) -> ~str {
249     let mstr = mutability_to_str(m.mutbl);
250     return format!("{}{}{}{}", mstr, before, ty_to_str(cx, m.ty), after);
251 }
252
253 pub fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str {
254     match vs {
255       ty::vstore_fixed(n) => format!("{}", n),
256       ty::vstore_uniq => ~"~",
257       ty::vstore_slice(r) => region_ptr_to_str(cx, r)
258     }
259 }
260
261 pub fn trait_store_to_str(cx: ctxt, s: ty::TraitStore) -> ~str {
262     match s {
263       ty::UniqTraitStore => ~"~",
264       ty::RegionTraitStore(r) => region_ptr_to_str(cx, r)
265     }
266 }
267
268 pub fn vstore_ty_to_str(cx: ctxt, mt: &mt, vs: ty::vstore) -> ~str {
269     match vs {
270         ty::vstore_fixed(_) => {
271             format!("[{}, .. {}]", mt_to_str(cx, mt), vstore_to_str(cx, vs))
272         }
273         _ => {
274             format!("{}{}", vstore_to_str(cx, vs), mt_to_str_wrapped(cx, "[", mt, "]"))
275         }
276     }
277 }
278
279 pub fn vec_map_to_str<T>(ts: &[T], f: |t: &T| -> ~str) -> ~str {
280     let tstrs = ts.map(f);
281     format!("[{}]", tstrs.connect(", "))
282 }
283
284 pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
285     vec_map_to_str(ts, |t| ty_to_str(cx, *t))
286 }
287
288 pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
289     format!("fn{}{} -> {}",
290             typ.binder_id,
291             typ.inputs.repr(cx),
292             typ.output.repr(cx))
293 }
294
295 pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str {
296     trait_ref.user_string(cx)
297 }
298
299 pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
300     fn fn_input_to_str(cx: ctxt, input: ty::t) -> ~str {
301         ty_to_str(cx, input)
302     }
303     fn bare_fn_to_str(cx: ctxt,
304                       purity: ast::Purity,
305                       abis: AbiSet,
306                       ident: Option<ast::Ident>,
307                       sig: &ty::FnSig)
308                       -> ~str {
309         let mut s = if abis.is_rust() {
310             ~""
311         } else {
312             format!("extern {} ", abis.to_str())
313         };
314
315         match purity {
316             ast::ImpureFn => {}
317             _ => {
318                 s.push_str(purity.to_str());
319                 s.push_char(' ');
320             }
321         };
322
323         s.push_str("fn");
324
325         match ident {
326             Some(i) => {
327                 s.push_char(' ');
328                 s.push_str(token::get_ident(i).get());
329             }
330             _ => { }
331         }
332
333         push_sig_to_str(cx, &mut s, '(', ')', sig);
334
335         return s;
336     }
337     fn closure_to_str(cx: ctxt, cty: &ty::ClosureTy) -> ~str {
338         let is_proc =
339             (cty.sigil, cty.onceness) == (ast::OwnedSigil, ast::Once);
340         let is_borrowed_closure = cty.sigil == ast::BorrowedSigil;
341
342         let mut s = if is_proc || is_borrowed_closure {
343             ~""
344         } else {
345             cty.sigil.to_str()
346         };
347
348         match (cty.sigil, cty.region) {
349             (ast::ManagedSigil, ty::ReStatic) |
350             (ast::OwnedSigil, ty::ReStatic) => {}
351
352             (_, region) => {
353                 s.push_str(region_to_str(cx, "", true, region));
354             }
355         }
356
357         match cty.purity {
358             ast::ImpureFn => {}
359             _ => {
360                 s.push_str(cty.purity.to_str());
361                 s.push_char(' ');
362             }
363         };
364
365         if is_proc {
366             s.push_str("proc");
367         } else {
368             match cty.onceness {
369                 ast::Many => {}
370                 ast::Once => {
371                     s.push_str(cty.onceness.to_str());
372                     s.push_char(' ');
373                 }
374             };
375
376             if !is_borrowed_closure {
377                 s.push_str("fn");
378             }
379         }
380
381         if !is_borrowed_closure {
382             // Print bounds before `fn` if this is not a borrowed closure.
383             if !cty.bounds.is_empty() {
384                 s.push_str(":");
385                 s.push_str(cty.bounds.repr(cx));
386             }
387
388             push_sig_to_str(cx, &mut s, '(', ')', &cty.sig);
389         } else {
390             // Print bounds after the signature if this is a borrowed closure.
391             push_sig_to_str(cx, &mut s, '|', '|', &cty.sig);
392
393             if is_borrowed_closure {
394                 if !cty.bounds.is_empty() {
395                     s.push_str(":");
396                     s.push_str(cty.bounds.repr(cx));
397                 }
398             }
399         }
400
401         return s;
402     }
403     fn push_sig_to_str(cx: ctxt,
404                        s: &mut ~str,
405                        bra: char,
406                        ket: char,
407                        sig: &ty::FnSig) {
408         s.push_char(bra);
409         let strs = sig.inputs.map(|a| fn_input_to_str(cx, *a));
410         s.push_str(strs.connect(", "));
411         if sig.variadic {
412             s.push_str(", ...");
413         }
414         s.push_char(ket);
415
416         if ty::get(sig.output).sty != ty_nil {
417             s.push_str(" -> ");
418             if ty::type_is_bot(sig.output) {
419                 s.push_char('!');
420             } else {
421                 s.push_str(ty_to_str(cx, sig.output));
422             }
423         }
424     }
425
426     // if there is an id, print that instead of the structural type:
427     /*for def_id in ty::type_def_id(typ).iter() {
428         // note that this typedef cannot have type parameters
429         return ty::item_path_str(cx, *def_id);
430     }*/
431
432     // pretty print the structural type representation:
433     return match ty::get(typ).sty {
434       ty_nil => ~"()",
435       ty_bot => ~"!",
436       ty_bool => ~"bool",
437       ty_char => ~"char",
438       ty_int(ast::TyI) => ~"int",
439       ty_int(t) => ast_util::int_ty_to_str(t),
440       ty_uint(ast::TyU) => ~"uint",
441       ty_uint(t) => ast_util::uint_ty_to_str(t),
442       ty_float(t) => ast_util::float_ty_to_str(t),
443       ty_box(typ) => ~"@" + ty_to_str(cx, typ),
444       ty_uniq(typ) => ~"~" + ty_to_str(cx, typ),
445       ty_ptr(ref tm) => ~"*" + mt_to_str(cx, tm),
446       ty_rptr(r, ref tm) => {
447         region_ptr_to_str(cx, r) + mt_to_str(cx, tm)
448       }
449       ty_unboxed_vec(ref tm) => { format!("unboxed_vec<{}>", mt_to_str(cx, tm)) }
450       ty_tup(ref elems) => {
451         let strs = elems.map(|elem| ty_to_str(cx, *elem));
452         ~"(" + strs.connect(",") + ")"
453       }
454       ty_closure(ref f) => {
455           closure_to_str(cx, f)
456       }
457       ty_bare_fn(ref f) => {
458           bare_fn_to_str(cx, f.purity, f.abis, None, &f.sig)
459       }
460       ty_infer(infer_ty) => infer_ty.to_str(),
461       ty_err => ~"[type error]",
462       ty_param(param_ty {idx: id, def_id: did}) => {
463           let ty_param_defs = cx.ty_param_defs.borrow();
464           let param_def = ty_param_defs.get().find(&did.node);
465           let ident = match param_def {
466               Some(def) => token::get_ident(def.ident).get().to_str(),
467               // This should not happen...
468               None => format!("BUG[{:?}]", id)
469           };
470           if !cx.sess.verbose() {
471               ident
472           } else {
473             format!("{}:{:?}", ident, did)
474           }
475       }
476       ty_self(..) => ~"Self",
477       ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
478         let base = ty::item_path_str(cx, did);
479         parameterized(cx, base, &substs.regions, substs.tps, did, false)
480       }
481       ty_trait(did, ref substs, s, mutbl, ref bounds) => {
482         let base = ty::item_path_str(cx, did);
483         let ty = parameterized(cx, base, &substs.regions,
484                                substs.tps, did, true);
485         let bound_sep = if bounds.is_empty() { "" } else { ":" };
486         let bound_str = bounds.repr(cx);
487         format!("{}{}{}{}{}", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
488                            bound_sep, bound_str)
489       }
490       ty_vec(ref mt, vs) => {
491         vstore_ty_to_str(cx, mt, vs)
492       }
493       ty_str(vs) => format!("{}{}", vstore_to_str(cx, vs), "str")
494     }
495 }
496
497 pub fn parameterized(cx: ctxt,
498                      base: &str,
499                      regions: &ty::RegionSubsts,
500                      tps: &[ty::t],
501                      did: ast::DefId,
502                      is_trait: bool) -> ~str {
503
504     let mut strs = ~[];
505     match *regions {
506         ty::ErasedRegions => { }
507         ty::NonerasedRegions(ref regions) => {
508             for &r in regions.iter() {
509                 strs.push(region_to_str(cx, "", false, r))
510             }
511         }
512     }
513
514     let generics = if is_trait {
515         ty::lookup_trait_def(cx, did).generics.clone()
516     } else {
517         ty::lookup_item_type(cx, did).generics
518     };
519     let ty_params = generics.type_param_defs();
520     let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some());
521     let num_defaults = if has_defaults {
522         // We should have a borrowed version of substs instead of cloning.
523         let mut substs = ty::substs {
524             tps: tps.to_owned(),
525             regions: regions.clone(),
526             self_ty: None
527         };
528         ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| {
529             substs.tps.pop();
530             match def.default {
531                 Some(default) => ty::subst(cx, &substs, default) == actual,
532                 None => false
533             }
534         }).len()
535     } else {
536         0
537     };
538
539     for t in tps.slice_to(tps.len() - num_defaults).iter() {
540         strs.push(ty_to_str(cx, *t))
541     }
542
543     if strs.len() > 0u {
544         format!("{}<{}>", base, strs.connect(","))
545     } else {
546         format!("{}", base)
547     }
548 }
549
550 pub fn ty_to_short_str(cx: ctxt, typ: t) -> ~str {
551     let mut s = encoder::encoded_ty(cx, typ);
552     if s.len() >= 32u { s = s.slice(0u, 32u).to_owned(); }
553     return s;
554 }
555
556 impl<T:Repr> Repr for Option<T> {
557     fn repr(&self, tcx: ctxt) -> ~str {
558         match self {
559             &None => ~"None",
560             &Some(ref t) => t.repr(tcx),
561         }
562     }
563 }
564
565 impl<T:Repr,U:Repr> Repr for Result<T,U> {
566     fn repr(&self, tcx: ctxt) -> ~str {
567         match self {
568             &Ok(ref t) => t.repr(tcx),
569             &Err(ref u) => format!("Err({})", u.repr(tcx))
570         }
571     }
572 }
573
574 impl Repr for () {
575     fn repr(&self, _tcx: ctxt) -> ~str {
576         ~"()"
577     }
578 }
579
580 impl<T:Repr> Repr for @T {
581     fn repr(&self, tcx: ctxt) -> ~str {
582         (&**self).repr(tcx)
583     }
584 }
585
586 impl<T:Repr> Repr for ~T {
587     fn repr(&self, tcx: ctxt) -> ~str {
588         (&**self).repr(tcx)
589     }
590 }
591
592 fn repr_vec<T:Repr>(tcx: ctxt, v: &[T]) -> ~str {
593     vec_map_to_str(v, |t| t.repr(tcx))
594 }
595
596 impl<'a, T:Repr> Repr for &'a [T] {
597     fn repr(&self, tcx: ctxt) -> ~str {
598         repr_vec(tcx, *self)
599     }
600 }
601
602 impl<T:Repr> Repr for OptVec<T> {
603     fn repr(&self, tcx: ctxt) -> ~str {
604         match *self {
605             opt_vec::Empty => ~"[]",
606             opt_vec::Vec(ref v) => repr_vec(tcx, v.as_slice())
607         }
608     }
609 }
610
611 // This is necessary to handle types like Option<~[T]>, for which
612 // autoderef cannot convert the &[T] handler
613 impl<T:Repr> Repr for ~[T] {
614     fn repr(&self, tcx: ctxt) -> ~str {
615         repr_vec(tcx, *self)
616     }
617 }
618
619 impl Repr for ty::TypeParameterDef {
620     fn repr(&self, tcx: ctxt) -> ~str {
621         format!("TypeParameterDef({:?}, {})",
622                 self.def_id,
623                 self.bounds.repr(tcx))
624     }
625 }
626
627 impl Repr for ty::RegionParameterDef {
628     fn repr(&self, _tcx: ctxt) -> ~str {
629         format!("RegionParameterDef({}, {:?})",
630                 token::get_name(self.ident),
631                 self.def_id)
632     }
633 }
634
635 impl Repr for ty::t {
636     fn repr(&self, tcx: ctxt) -> ~str {
637         ty_to_str(tcx, *self)
638     }
639 }
640
641 impl Repr for ty::substs {
642     fn repr(&self, tcx: ctxt) -> ~str {
643         format!("substs(regions={}, self_ty={}, tps={})",
644              self.regions.repr(tcx),
645              self.self_ty.repr(tcx),
646              self.tps.repr(tcx))
647     }
648 }
649
650 impl Repr for ty::RegionSubsts {
651     fn repr(&self, tcx: ctxt) -> ~str {
652         match *self {
653             ty::ErasedRegions => ~"erased",
654             ty::NonerasedRegions(ref regions) => regions.repr(tcx)
655         }
656     }
657 }
658
659 impl Repr for ty::ParamBounds {
660     fn repr(&self, tcx: ctxt) -> ~str {
661         let mut res = ~[];
662         for b in self.builtin_bounds.iter() {
663             res.push(match b {
664                 ty::BoundStatic => ~"'static",
665                 ty::BoundSend => ~"Send",
666                 ty::BoundFreeze => ~"Freeze",
667                 ty::BoundSized => ~"Sized",
668                 ty::BoundPod => ~"Pod",
669             });
670         }
671         for t in self.trait_bounds.iter() {
672             res.push(t.repr(tcx));
673         }
674         res.connect("+")
675     }
676 }
677
678 impl Repr for ty::TraitRef {
679     fn repr(&self, tcx: ctxt) -> ~str {
680         trait_ref_to_str(tcx, self)
681     }
682 }
683
684 impl Repr for ast::Expr {
685     fn repr(&self, _tcx: ctxt) -> ~str {
686         format!("expr({}: {})", self.id, pprust::expr_to_str(self))
687     }
688 }
689
690 impl Repr for ast::Item {
691     fn repr(&self, tcx: ctxt) -> ~str {
692         format!("item({})", tcx.map.node_to_str(self.id))
693     }
694 }
695
696 impl Repr for ast::Stmt {
697     fn repr(&self, _tcx: ctxt) -> ~str {
698         format!("stmt({}: {})",
699                 ast_util::stmt_id(self),
700                 pprust::stmt_to_str(self))
701     }
702 }
703
704 impl Repr for ast::Pat {
705     fn repr(&self, _tcx: ctxt) -> ~str {
706         format!("pat({}: {})",
707              self.id,
708              pprust::pat_to_str(self))
709     }
710 }
711
712 impl Repr for ty::BoundRegion {
713     fn repr(&self, tcx: ctxt) -> ~str {
714         match *self {
715             ty::BrAnon(id) => format!("BrAnon({})", id),
716             ty::BrNamed(id, ident) => format!("BrNamed({}, {})",
717                                                id.repr(tcx),
718                                                token::get_name(ident)),
719             ty::BrFresh(id) => format!("BrFresh({})", id),
720         }
721     }
722 }
723
724 impl Repr for ty::Region {
725     fn repr(&self, tcx: ctxt) -> ~str {
726         match *self {
727             ty::ReEarlyBound(id, index, ident) => {
728                 format!("ReEarlyBound({}, {}, {})",
729                         id, index, token::get_name(ident))
730             }
731
732             ty::ReLateBound(binder_id, ref bound_region) => {
733                 format!("ReLateBound({}, {})",
734                         binder_id, bound_region.repr(tcx))
735             }
736
737             ty::ReFree(ref fr) => {
738                 format!("ReFree({}, {})",
739                         fr.scope_id,
740                         fr.bound_region.repr(tcx))
741             }
742
743             ty::ReScope(id) => {
744                 format!("ReScope({})", id)
745             }
746
747             ty::ReStatic => {
748                 format!("ReStatic")
749             }
750
751             ty::ReInfer(ReVar(ref vid)) => {
752                 format!("ReInfer({})", vid.id)
753             }
754
755             ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
756                 format!("re_skolemized({}, {})",
757                         id, bound_region.repr(tcx))
758             }
759
760             ty::ReEmpty => {
761                 format!("ReEmpty")
762             }
763         }
764     }
765 }
766
767 impl Repr for ast::DefId {
768     fn repr(&self, tcx: ctxt) -> ~str {
769         // Unfortunately, there seems to be no way to attempt to print
770         // a path for a def-id, so I'll just make a best effort for now
771         // and otherwise fallback to just printing the crate/node pair
772         if self.krate == ast::LOCAL_CRATE {
773             {
774                 match tcx.map.find(self.node) {
775                     Some(ast_map::NodeItem(..)) |
776                     Some(ast_map::NodeForeignItem(..)) |
777                     Some(ast_map::NodeMethod(..)) |
778                     Some(ast_map::NodeTraitMethod(..)) |
779                     Some(ast_map::NodeVariant(..)) |
780                     Some(ast_map::NodeStructCtor(..)) => {
781                         return format!("{:?}:{}",
782                                        *self,
783                                        ty::item_path_str(tcx, *self));
784                     }
785                     _ => {}
786                 }
787             }
788         }
789         return format!("{:?}", *self);
790     }
791 }
792
793 impl Repr for ty::ty_param_bounds_and_ty {
794     fn repr(&self, tcx: ctxt) -> ~str {
795         format!("ty_param_bounds_and_ty \\{generics: {}, ty: {}\\}",
796              self.generics.repr(tcx),
797              self.ty.repr(tcx))
798     }
799 }
800
801 impl Repr for ty::Generics {
802     fn repr(&self, tcx: ctxt) -> ~str {
803         format!("Generics(type_param_defs: {}, region_param_defs: {})",
804                 self.type_param_defs().repr(tcx),
805                 self.region_param_defs().repr(tcx))
806     }
807 }
808
809 impl Repr for ty::ItemVariances {
810     fn repr(&self, tcx: ctxt) -> ~str {
811         format!("IterVariances(self_param={}, type_params={}, region_params={})",
812                 self.self_param.repr(tcx),
813                 self.type_params.repr(tcx),
814                 self.region_params.repr(tcx))
815     }
816 }
817
818 impl Repr for ty::Variance {
819     fn repr(&self, _: ctxt) -> ~str {
820         self.to_str().to_owned()
821     }
822 }
823
824 impl Repr for ty::Method {
825     fn repr(&self, tcx: ctxt) -> ~str {
826         format!("method(ident: {}, generics: {}, fty: {}, \
827                 explicit_self: {}, vis: {}, def_id: {})",
828                 self.ident.repr(tcx),
829                 self.generics.repr(tcx),
830                 self.fty.repr(tcx),
831                 self.explicit_self.repr(tcx),
832                 self.vis.repr(tcx),
833                 self.def_id.repr(tcx))
834     }
835 }
836
837 impl Repr for ast::Ident {
838     fn repr(&self, _tcx: ctxt) -> ~str {
839         token::get_ident(*self).get().to_str()
840     }
841 }
842
843 impl Repr for ast::ExplicitSelf_ {
844     fn repr(&self, _tcx: ctxt) -> ~str {
845         format!("{:?}", *self)
846     }
847 }
848
849 impl Repr for ast::Visibility {
850     fn repr(&self, _tcx: ctxt) -> ~str {
851         format!("{:?}", *self)
852     }
853 }
854
855 impl Repr for ty::BareFnTy {
856     fn repr(&self, tcx: ctxt) -> ~str {
857         format!("BareFnTy \\{purity: {:?}, abis: {}, sig: {}\\}",
858              self.purity,
859              self.abis.to_str(),
860              self.sig.repr(tcx))
861     }
862 }
863
864 impl Repr for ty::FnSig {
865     fn repr(&self, tcx: ctxt) -> ~str {
866         fn_sig_to_str(tcx, self)
867     }
868 }
869
870 impl Repr for typeck::MethodCallee {
871     fn repr(&self, tcx: ctxt) -> ~str {
872         format!("MethodCallee \\{origin: {}, ty: {}, {}\\}",
873             self.origin.repr(tcx),
874             self.ty.repr(tcx),
875             self.substs.repr(tcx))
876     }
877 }
878
879 impl Repr for typeck::MethodOrigin {
880     fn repr(&self, tcx: ctxt) -> ~str {
881         match self {
882             &typeck::MethodStatic(def_id) => {
883                 format!("MethodStatic({})", def_id.repr(tcx))
884             }
885             &typeck::MethodParam(ref p) => {
886                 p.repr(tcx)
887             }
888             &typeck::MethodObject(ref p) => {
889                 p.repr(tcx)
890             }
891         }
892     }
893 }
894
895 impl Repr for typeck::MethodParam {
896     fn repr(&self, tcx: ctxt) -> ~str {
897         format!("MethodParam({},{:?},{:?},{:?})",
898              self.trait_id.repr(tcx),
899              self.method_num,
900              self.param_num,
901              self.bound_num)
902     }
903 }
904
905 impl Repr for typeck::MethodObject {
906     fn repr(&self, tcx: ctxt) -> ~str {
907         format!("MethodObject({},{:?},{:?})",
908              self.trait_id.repr(tcx),
909              self.method_num,
910              self.real_index)
911     }
912 }
913
914
915 impl Repr for ty::RegionVid {
916     fn repr(&self, _tcx: ctxt) -> ~str {
917         format!("{:?}", *self)
918     }
919 }
920
921 impl Repr for ty::TraitStore {
922     fn repr(&self, tcx: ctxt) -> ~str {
923         match self {
924             &ty::UniqTraitStore => ~"~Trait",
925             &ty::RegionTraitStore(r) => format!("&{} Trait", r.repr(tcx))
926         }
927     }
928 }
929
930 impl Repr for ty::vstore {
931     fn repr(&self, tcx: ctxt) -> ~str {
932         vstore_to_str(tcx, *self)
933     }
934 }
935
936 impl Repr for ty::BuiltinBound {
937     fn repr(&self, _tcx: ctxt) -> ~str {
938         format!("{:?}", *self)
939     }
940 }
941
942 impl UserString for ty::BuiltinBound {
943     fn user_string(&self, _tcx: ctxt) -> ~str {
944         match *self {
945             ty::BoundStatic => ~"'static",
946             ty::BoundSend => ~"Send",
947             ty::BoundFreeze => ~"Freeze",
948             ty::BoundSized => ~"Sized",
949             ty::BoundPod => ~"Pod",
950         }
951     }
952 }
953
954 impl Repr for ty::BuiltinBounds {
955     fn repr(&self, tcx: ctxt) -> ~str {
956         self.user_string(tcx)
957     }
958 }
959
960 impl Repr for Span {
961     fn repr(&self, tcx: ctxt) -> ~str {
962         tcx.sess.codemap.span_to_str(*self)
963     }
964 }
965
966 impl<A:UserString> UserString for @A {
967     fn user_string(&self, tcx: ctxt) -> ~str {
968         let this: &A = &**self;
969         this.user_string(tcx)
970     }
971 }
972
973 impl UserString for ty::BuiltinBounds {
974     fn user_string(&self, tcx: ctxt) -> ~str {
975         if self.is_empty() { ~"<no-bounds>" } else {
976             let mut result = ~[];
977             for bb in self.iter() {
978                 result.push(bb.user_string(tcx));
979             }
980             result.connect("+")
981         }
982     }
983 }
984
985 impl UserString for ty::TraitRef {
986     fn user_string(&self, tcx: ctxt) -> ~str {
987         let base = ty::item_path_str(tcx, self.def_id);
988         if tcx.sess.verbose() && self.substs.self_ty.is_some() {
989             let mut all_tps = self.substs.tps.clone();
990             for &t in self.substs.self_ty.iter() { all_tps.push(t); }
991             parameterized(tcx, base, &self.substs.regions,
992                           all_tps, self.def_id, true)
993         } else {
994             parameterized(tcx, base, &self.substs.regions,
995                           self.substs.tps, self.def_id, true)
996         }
997     }
998 }
999
1000 impl UserString for ty::t {
1001     fn user_string(&self, tcx: ctxt) -> ~str {
1002         ty_to_str(tcx, *self)
1003     }
1004 }
1005
1006 impl Repr for AbiSet {
1007     fn repr(&self, _tcx: ctxt) -> ~str {
1008         self.to_str()
1009     }
1010 }
1011
1012 impl UserString for AbiSet {
1013     fn user_string(&self, _tcx: ctxt) -> ~str {
1014         self.to_str()
1015     }
1016 }
1017
1018 impl Repr for ty::UpvarId {
1019     fn repr(&self, tcx: ctxt) -> ~str {
1020         format!("UpvarId({};`{}`;{})",
1021              self.var_id,
1022              ty::local_var_name_str(tcx, self.var_id),
1023              self.closure_expr_id)
1024     }
1025 }
1026
1027 impl Repr for ast::Mutability {
1028     fn repr(&self, _tcx: ctxt) -> ~str {
1029         format!("{:?}", *self)
1030     }
1031 }
1032
1033 impl Repr for ty::BorrowKind {
1034     fn repr(&self, _tcx: ctxt) -> ~str {
1035         format!("{:?}", *self)
1036     }
1037 }
1038
1039 impl Repr for ty::UpvarBorrow {
1040     fn repr(&self, tcx: ctxt) -> ~str {
1041         format!("UpvarBorrow({}, {})",
1042              self.kind.repr(tcx),
1043              self.region.repr(tcx))
1044     }
1045 }