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.
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.
12 use metadata::encoder;
13 use middle::ty::{ReSkolemized, ReVar};
14 use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
15 use middle::ty::{br_fresh, ctxt, field};
16 use middle::ty::{mt, t, param_ty};
17 use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region,
19 use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum};
20 use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure};
21 use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
22 use middle::ty::{ty_ptr, ty_rptr, ty_self, ty_tup, ty_type, ty_uniq};
23 use middle::ty::{ty_trait, ty_int};
24 use middle::ty::{ty_uint, ty_unboxed_vec, ty_infer};
27 use syntax::abi::AbiSet;
29 use syntax::codemap::span;
30 use syntax::parse::token;
31 use syntax::print::pprust;
32 use syntax::{ast, ast_util};
34 use syntax::opt_vec::OptVec;
36 /// Produces a string suitable for debugging output.
38 fn repr(&self, tcx: ctxt) -> ~str;
41 /// Produces a string suitable for showing to the user.
42 pub trait UserString {
43 fn user_string(&self, tcx: ctxt) -> ~str;
46 pub fn note_and_explain_region(cx: ctxt,
50 match explain_region_and_span(cx, region) {
51 (ref str, Some(span)) => {
54 fmt!("%s%s%s", prefix, (*str), suffix));
58 fmt!("%s%s%s", prefix, (*str), suffix));
63 /// Returns a string like "the block at 27:31" that attempts to explain a
64 /// lifetime in a way it might plausibly be understood.
65 pub fn explain_region(cx: ctxt, region: ty::Region) -> ~str {
66 let (res, _) = explain_region_and_span(cx, region);
71 pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
72 -> (~str, Option<span>) {
74 re_scope(node_id) => {
75 match cx.items.find(&node_id) {
76 Some(&ast_map::node_block(ref blk)) => {
77 explain_span(cx, "block", blk.span)
79 Some(&ast_map::node_callee_scope(expr)) => {
80 explain_span(cx, "callee", expr.span)
82 Some(&ast_map::node_expr(expr)) => {
84 ast::expr_call(*) => explain_span(cx, "call", expr.span),
85 ast::expr_method_call(*) => {
86 explain_span(cx, "method call", expr.span)
88 ast::expr_match(*) => explain_span(cx, "match", expr.span),
89 _ => explain_span(cx, "expression", expr.span)
92 Some(&ast_map::node_stmt(stmt)) => {
93 explain_span(cx, "statement", stmt.span)
95 Some(&ast_map::node_item(it, _)) if (match it.node {
96 ast::item_fn(*) => true, _ => false}) => {
97 explain_span(cx, "function body", it.span)
100 // this really should not happen
101 (fmt!("unknown scope: %d. Please report a bug.", node_id),
108 let prefix = match fr.bound_region {
109 br_anon(idx) => fmt!("the anonymous lifetime #%u defined on",
111 br_fresh(_) => fmt!("an anonymous lifetime defined on"),
112 _ => fmt!("the lifetime %s as defined on",
113 bound_region_ptr_to_str(cx, fr.bound_region))
116 match cx.items.find(&fr.scope_id) {
117 Some(&ast_map::node_block(ref blk)) => {
118 let (msg, opt_span) = explain_span(cx, "block", blk.span);
119 (fmt!("%s %s", prefix, msg), opt_span)
122 // this really should not happen
123 (fmt!("%s node %d", prefix, fr.scope_id), None)
128 re_static => { (~"the static lifetime", None) }
130 re_empty => { (~"the empty lifetime", None) }
132 // I believe these cases should not occur (except when debugging,
134 re_infer(_) | re_bound(_) => {
135 (fmt!("lifetime %?", region), None)
139 fn explain_span(cx: ctxt, heading: &str, span: span)
140 -> (~str, Option<span>)
142 let lo = cx.sess.codemap.lookup_char_pos_adj(span.lo);
143 (fmt!("the %s at %u:%u", heading,
144 lo.line, lo.col.to_uint()), Some(span))
148 pub fn bound_region_ptr_to_str(cx: ctxt, br: bound_region) -> ~str {
149 bound_region_to_str(cx, "&", true, br)
152 pub fn bound_region_to_str(cx: ctxt,
153 prefix: &str, space: bool,
154 br: bound_region) -> ~str {
155 let space_str = if space { " " } else { "" };
157 if cx.sess.verbose() { return fmt!("%s%?%s", prefix, br, space_str); }
160 br_named(id) => fmt!("%s'%s%s", prefix, cx.sess.str_of(id), space_str),
161 br_self => fmt!("%s'self%s", prefix, space_str),
162 br_anon(_) => prefix.to_str(),
163 br_fresh(_) => prefix.to_str(),
164 br_cap_avoid(_, br) => bound_region_to_str(cx, prefix, space, *br)
168 pub fn re_scope_id_to_str(cx: ctxt, node_id: ast::NodeId) -> ~str {
169 match cx.items.find(&node_id) {
170 Some(&ast_map::node_block(ref blk)) => {
171 fmt!("<block at %s>",
172 cx.sess.codemap.span_to_str(blk.span))
174 Some(&ast_map::node_expr(expr)) => {
176 ast::expr_call(*) => {
178 cx.sess.codemap.span_to_str(expr.span))
180 ast::expr_match(*) => {
181 fmt!("<match at %s>",
182 cx.sess.codemap.span_to_str(expr.span))
184 ast::expr_assign_op(*) |
186 ast::expr_binary(*) |
187 ast::expr_index(*) => {
188 fmt!("<method at %s>",
189 cx.sess.codemap.span_to_str(expr.span))
192 fmt!("<expression at %s>",
193 cx.sess.codemap.span_to_str(expr.span))
198 fmt!("<unknown-%d>", node_id)
201 fmt!("re_scope refers to %s",
202 ast_map::node_id_to_str(cx.items, node_id,
203 token::get_ident_interner()))) }
207 // In general, if you are giving a region error message,
208 // you should use `explain_region()` or, better yet,
209 // `note_and_explain_region()`
210 pub fn region_ptr_to_str(cx: ctxt, region: Region) -> ~str {
211 region_to_str(cx, "&", true, region)
214 pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~str {
215 let space_str = if space { " " } else { "" };
217 if cx.sess.verbose() {
218 return fmt!("%s%?%s", prefix, region, space_str);
221 // These printouts are concise. They do not contain all the information
222 // the user might want to diagnose an error, but there is basically no way
223 // to fit that into a short string. Hence the recommendation to use
224 // `explain_region()` or `note_and_explain_region()`.
226 re_scope(_) => prefix.to_str(),
227 re_bound(br) => bound_region_to_str(cx, prefix, space, br),
228 re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
229 re_infer(ReSkolemized(_, br)) => {
230 bound_region_to_str(cx, prefix, space, br)
232 re_infer(ReVar(_)) => prefix.to_str(),
233 re_static => fmt!("%s'static%s", prefix, space_str),
234 re_empty => fmt!("%s'<empty>%s", prefix, space_str)
238 fn mutability_to_str(m: ast::mutability) -> ~str {
240 ast::m_mutbl => ~"mut ",
242 ast::m_const => ~"const "
246 pub fn mt_to_str(cx: ctxt, m: &mt) -> ~str {
247 mt_to_str_wrapped(cx, "", m, "")
250 pub fn mt_to_str_wrapped(cx: ctxt, before: &str, m: &mt, after: &str) -> ~str {
251 let mstr = mutability_to_str(m.mutbl);
252 return fmt!("%s%s%s%s", mstr, before, ty_to_str(cx, m.ty), after);
255 pub fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str {
257 ty::vstore_fixed(n) => fmt!("%u", n),
258 ty::vstore_uniq => ~"~",
259 ty::vstore_box => ~"@",
260 ty::vstore_slice(r) => region_ptr_to_str(cx, r)
264 pub fn trait_store_to_str(cx: ctxt, s: ty::TraitStore) -> ~str {
266 ty::UniqTraitStore => ~"~",
267 ty::BoxTraitStore => ~"@",
268 ty::RegionTraitStore(r) => region_ptr_to_str(cx, r)
272 pub fn vstore_ty_to_str(cx: ctxt, mt: &mt, vs: ty::vstore) -> ~str {
274 ty::vstore_fixed(_) => {
275 fmt!("[%s, .. %s]", mt_to_str(cx, mt), vstore_to_str(cx, vs))
278 fmt!("%s%s", vstore_to_str(cx, vs), mt_to_str_wrapped(cx, "[", mt, "]"))
283 pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
284 let tstrs = ts.map(|t| ty_to_str(cx, *t));
285 fmt!("(%s)", tstrs.connect(", "))
288 pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
290 tys_to_str(cx, typ.inputs.map(|a| *a)),
291 ty_to_str(cx, typ.output))
294 pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str {
295 trait_ref.user_string(cx)
298 pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
299 fn fn_input_to_str(cx: ctxt, input: ty::t) -> ~str {
302 fn bare_fn_to_str(cx: ctxt,
305 ident: Option<ast::ident>,
308 let mut s = ~"extern ";
310 s.push_str(abis.to_str());
316 s.push_str(purity.to_str());
326 s.push_str(cx.sess.str_of(i));
331 push_sig_to_str(cx, &mut s, sig);
335 fn closure_to_str(cx: ctxt, cty: &ty::ClosureTy) -> ~str
337 let mut s = cty.sigil.to_str();
339 match (cty.sigil, cty.region) {
340 (ast::ManagedSigil, ty::re_static) |
341 (ast::OwnedSigil, ty::re_static) => {}
344 s.push_str(region_to_str(cx, "", true, region));
351 s.push_str(cty.purity.to_str());
359 s.push_str(cty.onceness.to_str());
366 if !cty.bounds.is_empty() {
369 s.push_str(cty.bounds.repr(cx));
371 push_sig_to_str(cx, &mut s, &cty.sig);
375 fn push_sig_to_str(cx: ctxt, s: &mut ~str, sig: &ty::FnSig) {
377 let strs = sig.inputs.map(|a| fn_input_to_str(cx, *a));
378 s.push_str(strs.connect(", "));
380 if ty::get(sig.output).sty != ty_nil {
382 if ty::type_is_bot(sig.output) {
385 s.push_str(ty_to_str(cx, sig.output));
389 fn method_to_str(cx: ctxt, m: ty::Method) -> ~str {
396 fn field_to_str(cx: ctxt, f: field) -> ~str {
397 return fmt!("%s: %s", cx.sess.str_of(f.ident), mt_to_str(cx, &f.mt));
400 // if there is an id, print that instead of the structural type:
401 /*for def_id in ty::type_def_id(typ).iter() {
402 // note that this typedef cannot have type parameters
403 return ast_map::path_to_str(ty::item_path(cx, *def_id),
407 // pretty print the structural type representation:
408 return match ty::get(typ).sty {
412 ty_int(ast::ty_i) => ~"int",
413 ty_int(ast::ty_char) => ~"char",
414 ty_int(t) => ast_util::int_ty_to_str(t),
415 ty_uint(ast::ty_u) => ~"uint",
416 ty_uint(t) => ast_util::uint_ty_to_str(t),
417 ty_float(ast::ty_f) => ~"float",
418 ty_float(t) => ast_util::float_ty_to_str(t),
419 ty_box(ref tm) => ~"@" + mt_to_str(cx, tm),
420 ty_uniq(ref tm) => ~"~" + mt_to_str(cx, tm),
421 ty_ptr(ref tm) => ~"*" + mt_to_str(cx, tm),
422 ty_rptr(r, ref tm) => {
423 region_ptr_to_str(cx, r) + mt_to_str(cx, tm)
425 ty_unboxed_vec(ref tm) => { fmt!("unboxed_vec<%s>", mt_to_str(cx, tm)) }
427 ty_tup(ref elems) => {
428 let strs = elems.map(|elem| ty_to_str(cx, *elem));
429 ~"(" + strs.connect(",") + ")"
431 ty_closure(ref f) => {
432 closure_to_str(cx, f)
434 ty_bare_fn(ref f) => {
435 bare_fn_to_str(cx, f.purity, f.abis, None, &f.sig)
437 ty_infer(infer_ty) => infer_ty.to_str(),
438 ty_err => ~"[type error]",
439 ty_param(param_ty {idx: id, def_id: did}) => {
440 let param_def = cx.ty_param_defs.find(&did.node);
441 let ident = match param_def {
443 cx.sess.str_of(def.ident).to_owned()
446 // This should not happen...
450 if !cx.sess.verbose() { ident } else { fmt!("%s:%?", ident, did) }
452 ty_self(*) => ~"Self",
453 ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
454 let path = ty::item_path(cx, did);
455 let base = ast_map::path_to_str(path, cx.sess.intr());
456 parameterized(cx, base, &substs.regions, substs.tps)
458 ty_trait(did, ref substs, s, mutbl, ref bounds) => {
459 let path = ty::item_path(cx, did);
460 let base = ast_map::path_to_str(path, cx.sess.intr());
461 let ty = parameterized(cx, base, &substs.regions, substs.tps);
462 let bound_sep = if bounds.is_empty() { "" } else { ":" };
463 let bound_str = bounds.repr(cx);
464 fmt!("%s%s%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
465 bound_sep, bound_str)
467 ty_evec(ref mt, vs) => {
468 vstore_ty_to_str(cx, mt, vs)
470 ty_estr(vs) => fmt!("%s%s", vstore_to_str(cx, vs), "str"),
471 ty_opaque_box => ~"@?",
472 ty_opaque_closure_ptr(ast::BorrowedSigil) => ~"&closure",
473 ty_opaque_closure_ptr(ast::ManagedSigil) => ~"@closure",
474 ty_opaque_closure_ptr(ast::OwnedSigil) => ~"~closure",
478 pub fn parameterized(cx: ctxt,
480 regions: &ty::RegionSubsts,
481 tps: &[ty::t]) -> ~str {
485 ty::ErasedRegions => { }
486 ty::NonerasedRegions(ref regions) => {
487 for &r in regions.iter() {
488 strs.push(region_to_str(cx, "", false, r))
493 for t in tps.iter() {
494 strs.push(ty_to_str(cx, *t))
498 fmt!("%s<%s>", base, strs.connect(","))
504 pub fn ty_to_short_str(cx: ctxt, typ: t) -> ~str {
505 let mut s = encoder::encoded_ty(cx, typ);
506 if s.len() >= 32u { s = s.slice(0u, 32u).to_owned(); }
510 impl<T:Repr> Repr for Option<T> {
511 fn repr(&self, tcx: ctxt) -> ~str {
514 &Some(ref t) => fmt!("Some(%s)", t.repr(tcx))
519 impl<T:Repr> Repr for @T {
520 fn repr(&self, tcx: ctxt) -> ~str {
525 impl<T:Repr> Repr for ~T {
526 fn repr(&self, tcx: ctxt) -> ~str {
531 fn repr_vec<T:Repr>(tcx: ctxt, v: &[T]) -> ~str {
532 fmt!("[%s]", v.map(|t| t.repr(tcx)).connect(","))
535 impl<'self, T:Repr> Repr for &'self [T] {
536 fn repr(&self, tcx: ctxt) -> ~str {
541 impl<T:Repr> Repr for OptVec<T> {
542 fn repr(&self, tcx: ctxt) -> ~str {
544 opt_vec::Empty => ~"[]",
545 opt_vec::Vec(ref v) => repr_vec(tcx, *v)
550 // This is necessary to handle types like Option<~[T]>, for which
551 // autoderef cannot convert the &[T] handler
552 impl<T:Repr> Repr for ~[T] {
553 fn repr(&self, tcx: ctxt) -> ~str {
558 impl Repr for ty::TypeParameterDef {
559 fn repr(&self, tcx: ctxt) -> ~str {
560 fmt!("TypeParameterDef {%?, bounds: %s}",
561 self.def_id, self.bounds.repr(tcx))
565 impl Repr for ty::t {
566 fn repr(&self, tcx: ctxt) -> ~str {
567 ty_to_str(tcx, *self)
571 impl Repr for ty::substs {
572 fn repr(&self, tcx: ctxt) -> ~str {
573 fmt!("substs(regions=%s, self_ty=%s, tps=%s)",
574 self.regions.repr(tcx),
575 self.self_ty.repr(tcx),
580 impl Repr for ty::RegionSubsts {
581 fn repr(&self, tcx: ctxt) -> ~str {
583 ty::ErasedRegions => ~"erased",
584 ty::NonerasedRegions(ref regions) => regions.repr(tcx)
589 impl Repr for ty::ParamBounds {
590 fn repr(&self, tcx: ctxt) -> ~str {
592 do self.builtin_bounds.each |b| {
594 ty::BoundStatic => ~"'static",
595 ty::BoundSend => ~"Send",
596 ty::BoundFreeze => ~"Freeze",
597 ty::BoundSized => ~"Sized",
601 for t in self.trait_bounds.iter() {
602 res.push(t.repr(tcx));
608 impl Repr for ty::TraitRef {
609 fn repr(&self, tcx: ctxt) -> ~str {
610 trait_ref_to_str(tcx, self)
614 impl Repr for ast::expr {
615 fn repr(&self, tcx: ctxt) -> ~str {
618 pprust::expr_to_str(self, tcx.sess.intr()))
622 impl Repr for ast::pat {
623 fn repr(&self, tcx: ctxt) -> ~str {
626 pprust::pat_to_str(self, tcx.sess.intr()))
630 impl Repr for ty::bound_region {
631 fn repr(&self, tcx: ctxt) -> ~str {
632 bound_region_ptr_to_str(tcx, *self)
636 impl Repr for ty::Region {
637 fn repr(&self, tcx: ctxt) -> ~str {
638 region_to_str(tcx, "", false, *self)
642 impl Repr for ast::def_id {
643 fn repr(&self, tcx: ctxt) -> ~str {
644 // Unfortunately, there seems to be no way to attempt to print
645 // a path for a def-id, so I'll just make a best effort for now
646 // and otherwise fallback to just printing the crate/node pair
647 if self.crate == ast::LOCAL_CRATE {
648 match tcx.items.find(&self.node) {
649 Some(&ast_map::node_item(*)) |
650 Some(&ast_map::node_foreign_item(*)) |
651 Some(&ast_map::node_method(*)) |
652 Some(&ast_map::node_trait_method(*)) |
653 Some(&ast_map::node_variant(*)) |
654 Some(&ast_map::node_struct_ctor(*)) => {
655 return fmt!("%?:%s", *self, ty::item_path_str(tcx, *self));
660 return fmt!("%?", *self);
664 impl Repr for ty::ty_param_bounds_and_ty {
665 fn repr(&self, tcx: ctxt) -> ~str {
666 fmt!("ty_param_bounds_and_ty {generics: %s, ty: %s}",
667 self.generics.repr(tcx),
672 impl Repr for ty::Generics {
673 fn repr(&self, tcx: ctxt) -> ~str {
674 fmt!("Generics {type_param_defs: %s, region_param: %?}",
675 self.type_param_defs.repr(tcx),
680 impl Repr for ty::Method {
681 fn repr(&self, tcx: ctxt) -> ~str {
682 fmt!("method {ident: %s, generics: %s, transformed_self_ty: %s, \
683 fty: %s, explicit_self: %s, vis: %s, def_id: %s}",
684 self.ident.repr(tcx),
685 self.generics.repr(tcx),
686 self.transformed_self_ty.repr(tcx),
688 self.explicit_self.repr(tcx),
690 self.def_id.repr(tcx))
694 impl Repr for ast::ident {
695 fn repr(&self, _tcx: ctxt) -> ~str {
696 token::ident_to_str(self).to_owned()
700 impl Repr for ast::explicit_self_ {
701 fn repr(&self, _tcx: ctxt) -> ~str {
706 impl Repr for ast::visibility {
707 fn repr(&self, _tcx: ctxt) -> ~str {
712 impl Repr for ty::BareFnTy {
713 fn repr(&self, tcx: ctxt) -> ~str {
714 fmt!("BareFnTy {purity: %?, abis: %s, sig: %s}",
721 impl Repr for ty::FnSig {
722 fn repr(&self, tcx: ctxt) -> ~str {
723 fn_sig_to_str(tcx, self)
727 impl Repr for typeck::method_map_entry {
728 fn repr(&self, tcx: ctxt) -> ~str {
729 fmt!("method_map_entry {self_arg: %s, \
732 self.self_ty.repr(tcx),
733 self.explicit_self.repr(tcx),
734 self.origin.repr(tcx))
738 impl Repr for typeck::method_origin {
739 fn repr(&self, tcx: ctxt) -> ~str {
741 &typeck::method_static(def_id) => {
742 fmt!("method_static(%s)", def_id.repr(tcx))
744 &typeck::method_param(ref p) => {
747 &typeck::method_trait(def_id, n, st) => {
748 fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n,
755 impl Repr for typeck::method_param {
756 fn repr(&self, tcx: ctxt) -> ~str {
757 fmt!("method_param(%s,%?,%?,%?)",
758 self.trait_id.repr(tcx),
765 impl Repr for ty::RegionVid {
766 fn repr(&self, _tcx: ctxt) -> ~str {
771 impl Repr for ty::TraitStore {
772 fn repr(&self, tcx: ctxt) -> ~str {
774 &ty::BoxTraitStore => ~"@Trait",
775 &ty::UniqTraitStore => ~"~Trait",
776 &ty::RegionTraitStore(r) => fmt!("&%s Trait", r.repr(tcx))
781 impl Repr for ty::vstore {
782 fn repr(&self, tcx: ctxt) -> ~str {
783 vstore_to_str(tcx, *self)
787 impl Repr for ast_map::path_elt {
788 fn repr(&self, tcx: ctxt) -> ~str {
790 ast_map::path_mod(id) => id.repr(tcx),
791 ast_map::path_name(id) => id.repr(tcx)
796 impl Repr for ty::BuiltinBound {
797 fn repr(&self, _tcx: ctxt) -> ~str {
802 impl UserString for ty::BuiltinBound {
803 fn user_string(&self, _tcx: ctxt) -> ~str {
805 ty::BoundStatic => ~"'static",
806 ty::BoundSend => ~"Send",
807 ty::BoundFreeze => ~"Freeze",
808 ty::BoundSized => ~"Sized",
813 impl Repr for ty::BuiltinBounds {
814 fn repr(&self, tcx: ctxt) -> ~str {
815 self.user_string(tcx)
820 fn repr(&self, tcx: ctxt) -> ~str {
821 tcx.sess.codemap.span_to_str(*self)
825 impl<A:UserString> UserString for @A {
826 fn user_string(&self, tcx: ctxt) -> ~str {
827 let this: &A = &**self;
828 this.user_string(tcx)
832 impl UserString for ty::BuiltinBounds {
833 fn user_string(&self, tcx: ctxt) -> ~str {
834 if self.is_empty() { ~"<no-bounds>" } else {
835 let mut result = ~[];
837 result.push(bb.user_string(tcx));
845 impl UserString for ty::TraitRef {
846 fn user_string(&self, tcx: ctxt) -> ~str {
847 let path = ty::item_path(tcx, self.def_id);
848 let base = ast_map::path_to_str(path, tcx.sess.intr());
849 if tcx.sess.verbose() && self.substs.self_ty.is_some() {
850 let mut all_tps = self.substs.tps.clone();
851 for &t in self.substs.self_ty.iter() { all_tps.push(t); }
852 parameterized(tcx, base, &self.substs.regions, all_tps)
854 parameterized(tcx, base, &self.substs.regions, self.substs.tps)
859 impl UserString for ty::t {
860 fn user_string(&self, tcx: ctxt) -> ~str {
861 ty_to_str(tcx, *self)