]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc/util/ppaux.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc / util / ppaux.rs
index 80344a9894fb144a5a614faf57df0a47cbbfdb63..312cab245442a1845e8434e66155f97b6ec2743a 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-use metadata::encoder;
-use middle::ty::{ReSkolemized, ReVar};
-use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
-use middle::ty::{br_fresh, ctxt, field};
-use middle::ty::{mt, t, param_ty};
-use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region,
-                 re_empty};
-use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum};
-use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure};
-use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
-use middle::ty::{ty_ptr, ty_rptr, ty_self, ty_tup, ty_type, ty_uniq};
-use middle::ty::{ty_trait, ty_int};
-use middle::ty::{ty_uint, ty_unboxed_vec, ty_infer};
-use middle::ty;
-use middle::typeck;
-use syntax::abi::AbiSet;
-use syntax::ast_map;
-use syntax::codemap::span;
+use hir::def_id::DefId;
+use ty::subst::{self, Subst, Substs};
+use hir::map::definitions::DefPathData;
+use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
+use ty::{TyBool, TyChar, TyAdt};
+use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
+use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
+use ty::TyClosure;
+use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
+use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::fold::{TypeFolder, TypeVisitor};
+
+use std::cell::Cell;
+use std::fmt;
+use std::usize;
+
+use syntax::abi::Abi;
 use syntax::parse::token;
-use syntax::print::pprust;
-use syntax::{ast, ast_util};
-
-/// Produces a string suitable for debugging output.
-pub trait Repr {
-    fn repr(&self, tcx: ctxt) -> ~str;
-}
-
-/// Produces a string suitable for showing to the user.
-pub trait UserString {
-    fn user_string(&self, tcx: ctxt) -> ~str;
-}
-
-pub fn note_and_explain_region(cx: ctxt,
-                               prefix: &str,
-                               region: ty::Region,
-                               suffix: &str) {
-    match explain_region_and_span(cx, region) {
-      (ref str, Some(span)) => {
-        cx.sess.span_note(
-            span,
-            fmt!("%s%s%s", prefix, (*str), suffix));
-      }
-      (ref str, None) => {
-        cx.sess.note(
-            fmt!("%s%s%s", prefix, (*str), suffix));
-      }
-    }
-}
-
-/// Returns a string like "the block at 27:31" that attempts to explain a
-/// lifetime in a way it might plausibly be understood.
-pub fn explain_region(cx: ctxt, region: ty::Region) -> ~str {
-  let (res, _) = explain_region_and_span(cx, region);
-  return res;
-}
-
-
-pub fn explain_region_and_span(cx: ctxt, region: ty::Region)
-                            -> (~str, Option<span>) {
-    return match region {
-      re_scope(node_id) => {
-        match cx.items.find(&node_id) {
-          Some(&ast_map::node_block(ref blk)) => {
-            explain_span(cx, "block", blk.span)
-          }
-          Some(&ast_map::node_callee_scope(expr)) => {
-              explain_span(cx, "callee", expr.span)
-          }
-          Some(&ast_map::node_expr(expr)) => {
-            match expr.node {
-              ast::expr_call(*) => explain_span(cx, "call", expr.span),
-              ast::expr_method_call(*) => {
-                explain_span(cx, "method call", expr.span)
-              },
-              ast::expr_match(*) => explain_span(cx, "match", expr.span),
-              _ => explain_span(cx, "expression", expr.span)
-            }
-          }
-          Some(&ast_map::node_stmt(stmt)) => {
-              explain_span(cx, "statement", stmt.span)
-          }
-          Some(&ast_map::node_item(it, _)) if (match it.node {
-                ast::item_fn(*) => true, _ => false}) => {
-              explain_span(cx, "function body", it.span)
-          }
-          Some(_) | None => {
-            // this really should not happen
-            (fmt!("unknown scope: %d.  Please report a bug.", node_id),
-             None)
-          }
-        }
-      }
-
-      re_free(ref fr) => {
-        let prefix = match fr.bound_region {
-          br_anon(idx) => fmt!("the anonymous lifetime #%u defined on",
-                               idx + 1),
-          br_fresh(_) => fmt!("an anonymous lifetime defined on"),
-          _ => fmt!("the lifetime %s as defined on",
-                    bound_region_ptr_to_str(cx, fr.bound_region))
-        };
+use syntax::ast::CRATE_NODE_ID;
+use hir;
 
-        match cx.items.find(&fr.scope_id) {
-          Some(&ast_map::node_block(ref blk)) => {
-            let (msg, opt_span) = explain_span(cx, "block", blk.span);
-            (fmt!("%s %s", prefix, msg), opt_span)
-          }
-          Some(_) | None => {
-            // this really should not happen
-            (fmt!("%s node %d", prefix, fr.scope_id), None)
-          }
-        }
-      }
+pub fn verbose() -> bool {
+    ty::tls::with(|tcx| tcx.sess.verbose())
+}
 
-      re_static => { (~"the static lifetime", None) }
+fn fn_sig(f: &mut fmt::Formatter,
+          inputs: &[Ty],
+          variadic: bool,
+          output: Ty)
+          -> fmt::Result {
+    write!(f, "(")?;
+    let mut inputs = inputs.iter();
+    if let Some(&ty) = inputs.next() {
+        write!(f, "{}", ty)?;
+        for &ty in inputs {
+            write!(f, ", {}", ty)?;
+        }
+        if variadic {
+            write!(f, ", ...")?;
+        }
+    }
+    write!(f, ")")?;
+    if !output.is_nil() {
+        write!(f, " -> {}", output)?;
+    }
 
-      re_empty => { (~"the empty lifetime", None) }
+    Ok(())
+}
 
-      // I believe these cases should not occur (except when debugging,
-      // perhaps)
-      re_infer(_) | re_bound(_) => {
-        (fmt!("lifetime %?", region), None)
-      }
+pub fn parameterized(f: &mut fmt::Formatter,
+                     substs: &subst::Substs,
+                     mut did: DefId,
+                     projections: &[ty::ProjectionPredicate])
+                     -> fmt::Result {
+    let key = ty::tls::with(|tcx| tcx.def_key(did));
+    let mut item_name = if let Some(name) = key.disambiguated_data.data.get_opt_name() {
+        Some(name)
+    } else {
+        did.index = key.parent.unwrap_or_else(
+            || bug!("finding type for {:?}, encountered def-id {:?} with no parent",
+                    did, did));
+        parameterized(f, substs, did, projections)?;
+        return write!(f, "::{}", key.disambiguated_data.data.as_interned_str());
     };
 
-    fn explain_span(cx: ctxt, heading: &str, span: span)
-        -> (~str, Option<span>)
-    {
-        let lo = cx.sess.codemap.lookup_char_pos_adj(span.lo);
-        (fmt!("the %s at %u:%u", heading,
-              lo.line, lo.col.to_uint()), Some(span))
+    let mut verbose = false;
+    let mut num_supplied_defaults = 0;
+    let mut has_self = false;
+    let mut num_regions = 0;
+    let mut num_types = 0;
+    let mut is_value_path = false;
+    let fn_trait_kind = ty::tls::with(|tcx| {
+        // Unfortunately, some kinds of items (e.g., closures) don't have
+        // generics. So walk back up the find the closest parent that DOES
+        // have them.
+        let mut item_def_id = did;
+        loop {
+            let key = tcx.def_key(item_def_id);
+            match key.disambiguated_data.data {
+                DefPathData::TypeNs(_) => {
+                    break;
+                }
+                DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => {
+                    is_value_path = true;
+                    break;
+                }
+                _ => {
+                    // if we're making a symbol for something, there ought
+                    // to be a value or type-def or something in there
+                    // *somewhere*
+                    item_def_id.index = key.parent.unwrap_or_else(|| {
+                        bug!("finding type for {:?}, encountered def-id {:?} with no \
+                             parent", did, item_def_id);
+                    });
+                }
+            }
+        }
+        let mut generics = tcx.lookup_generics(item_def_id);
+        let mut path_def_id = did;
+        verbose = tcx.sess.verbose();
+        has_self = generics.has_self;
+
+        let mut child_types = 0;
+        if let Some(def_id) = generics.parent {
+            // Methods.
+            assert!(is_value_path);
+            child_types = generics.types.len();
+            generics = tcx.lookup_generics(def_id);
+            num_regions = generics.regions.len();
+            num_types = generics.types.len();
+
+            if has_self {
+                write!(f, "<{} as ", substs.type_at(0))?;
+            }
+
+            path_def_id = def_id;
+        } else {
+            item_name = None;
+
+            if is_value_path {
+                // Functions.
+                assert_eq!(has_self, false);
+            } else {
+                // Types and traits.
+                num_regions = generics.regions.len();
+                num_types = generics.types.len();
+            }
+        }
+
+        if !verbose {
+            if generics.types.last().map_or(false, |def| def.default.is_some()) {
+                if let Some(substs) = tcx.lift(&substs) {
+                    let tps = substs.types().rev().skip(child_types);
+                    for (def, actual) in generics.types.iter().rev().zip(tps) {
+                        if def.default.subst(tcx, substs) != Some(actual) {
+                            break;
+                        }
+                        num_supplied_defaults += 1;
+                    }
+                }
+            }
+        }
+
+        write!(f, "{}", tcx.item_path_str(path_def_id))?;
+        Ok(tcx.lang_items.fn_trait_kind(path_def_id))
+    })?;
+
+    if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
+        let projection_ty = projections[0].ty;
+        if let TyTuple(ref args) = substs.type_at(1).sty {
+            return fn_sig(f, args, false, projection_ty);
+        }
     }
-}
 
-pub fn bound_region_ptr_to_str(cx: ctxt, br: bound_region) -> ~str {
-    bound_region_to_str(cx, "&", true, br)
-}
+    let empty = Cell::new(true);
+    let start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
+        if empty.get() {
+            empty.set(false);
+            write!(f, "{}", start)
+        } else {
+            write!(f, "{}", cont)
+        }
+    };
+
+    let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| {
+        // Don't print any regions if they're all erased.
+        let regions = || substs.regions().skip(skip).take(count);
+        if regions().all(|r: &ty::Region| *r == ty::ReErased) {
+            return Ok(());
+        }
 
-pub fn bound_region_to_str(cx: ctxt,
-                           prefix: &str, space: bool,
-                           br: bound_region) -> ~str {
-    let space_str = if space { " " } else { "" };
+        for region in regions() {
+            let region: &ty::Region = region;
+            start_or_continue(f, start, ", ")?;
+            if verbose {
+                write!(f, "{:?}", region)?;
+            } else {
+                let s = region.to_string();
+                if s.is_empty() {
+                    // This happens when the value of the region
+                    // parameter is not easily serialized. This may be
+                    // because the user omitted it in the first place,
+                    // or because it refers to some block in the code,
+                    // etc. I'm not sure how best to serialize this.
+                    write!(f, "'_")?;
+                } else {
+                    write!(f, "{}", s)?;
+                }
+            }
+        }
+
+        Ok(())
+    };
 
-    if cx.sess.verbose() { return fmt!("%s%?%s", prefix, br, space_str); }
+    print_regions(f, "<", 0, num_regions)?;
 
-    match br {
-      br_named(id)         => fmt!("%s'%s%s", prefix, cx.sess.str_of(id), space_str),
-      br_self              => fmt!("%s'self%s", prefix, space_str),
-      br_anon(_)           => prefix.to_str(),
-      br_fresh(_)          => prefix.to_str(),
-      br_cap_avoid(_, br)  => bound_region_to_str(cx, prefix, space, *br)
+    let tps = substs.types().take(num_types - num_supplied_defaults)
+                            .skip(has_self as usize);
+
+    for ty in tps {
+        start_or_continue(f, "<", ", ")?;
+        write!(f, "{}", ty)?;
     }
-}
 
-pub fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
-    match cx.items.find(&node_id) {
-      Some(&ast_map::node_block(ref blk)) => {
-        fmt!("<block at %s>",
-             cx.sess.codemap.span_to_str(blk.span))
-      }
-      Some(&ast_map::node_expr(expr)) => {
-        match expr.node {
-          ast::expr_call(*) => {
-            fmt!("<call at %s>",
-                 cx.sess.codemap.span_to_str(expr.span))
-          }
-          ast::expr_match(*) => {
-            fmt!("<match at %s>",
-                 cx.sess.codemap.span_to_str(expr.span))
-          }
-          ast::expr_assign_op(*) |
-          ast::expr_unary(*) |
-          ast::expr_binary(*) |
-          ast::expr_index(*) => {
-            fmt!("<method at %s>",
-                 cx.sess.codemap.span_to_str(expr.span))
-          }
-          _ => {
-            fmt!("<expression at %s>",
-                 cx.sess.codemap.span_to_str(expr.span))
-          }
+    for projection in projections {
+        start_or_continue(f, "<", ", ")?;
+        write!(f, "{}={}",
+               projection.projection_ty.item_name,
+               projection.ty)?;
+    }
+
+    start_or_continue(f, "", ">")?;
+
+    // For values, also print their name and type parameters.
+    if is_value_path {
+        empty.set(true);
+
+        if has_self {
+            write!(f, ">")?;
         }
-      }
-      None => {
-        fmt!("<unknown-%d>", node_id)
-      }
-      _ => { cx.sess.bug(
-          fmt!("re_scope refers to %s",
-               ast_map::node_id_to_str(cx.items, node_id,
-                                       token::get_ident_interner()))) }
+
+        if let Some(item_name) = item_name {
+            write!(f, "::{}", item_name)?;
+        }
+
+        print_regions(f, "::<", num_regions, usize::MAX)?;
+
+        // FIXME: consider being smart with defaults here too
+        for ty in substs.types().skip(num_types) {
+            start_or_continue(f, "::<", ", ")?;
+            write!(f, "{}", ty)?;
+        }
+
+        start_or_continue(f, "", ">")?;
     }
+
+    Ok(())
 }
 
-// In general, if you are giving a region error message,
-// you should use `explain_region()` or, better yet,
-// `note_and_explain_region()`
-pub fn region_ptr_to_str(cx: ctxt, region: Region) -> ~str {
-    region_to_str(cx, "&", true, region)
+fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
+                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                   original: &ty::Binder<T>,
+                                   lifted: Option<ty::Binder<U>>) -> fmt::Result
+    where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx>
+{
+    // Replace any anonymous late-bound regions with named
+    // variants, using gensym'd identifiers, so that we can
+    // clearly differentiate between named and unnamed regions in
+    // the output. We'll probably want to tweak this over time to
+    // decide just how much information to give.
+    let value = if let Some(v) = lifted {
+        v
+    } else {
+        return write!(f, "{}", original.0);
+    };
+
+    let mut empty = true;
+    let mut start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
+        if empty {
+            empty = false;
+            write!(f, "{}", start)
+        } else {
+            write!(f, "{}", cont)
+        }
+    };
+
+    let new_value = tcx.replace_late_bound_regions(&value, |br| {
+        let _ = start_or_continue(f, "for<", ", ");
+        let br = match br {
+            ty::BrNamed(_, name, _) => {
+                let _ = write!(f, "{}", name);
+                br
+            }
+            ty::BrAnon(_) |
+            ty::BrFresh(_) |
+            ty::BrEnv => {
+                let name = token::intern("'r");
+                let _ = write!(f, "{}", name);
+                ty::BrNamed(tcx.map.local_def_id(CRATE_NODE_ID),
+                            name,
+                            ty::Issue32330::WontChange)
+            }
+        };
+        tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
+    }).0;
+
+    start_or_continue(f, "", "> ")?;
+    write!(f, "{}", new_value)
 }
 
-pub fn region_to_str(cx: ctxt, prefix: &str, space: bool, region: Region) -> ~str {
-    let space_str = if space { " " } else { "" };
+/// This curious type is here to help pretty-print trait objects. In
+/// a trait object, the projections are stored separately from the
+/// main trait bound, but in fact we want to package them together
+/// when printing out; they also have separate binders, but we want
+/// them to share a binder when we print them out. (And the binder
+/// pretty-printing logic is kind of clever and we don't want to
+/// reproduce it.) So we just repackage up the structure somewhat.
+///
+/// Right now there is only one trait in an object that can have
+/// projection bounds, so we just stuff them altogether. But in
+/// reality we should eventually sort things out better.
+#[derive(Clone, Debug)]
+struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>,
+                                 Vec<ty::ProjectionPredicate<'tcx>>);
+
+impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.0.visit_with(visitor) || self.1.visit_with(visitor)
+    }
+}
 
-    if cx.sess.verbose() {
-        return fmt!("%s%?%s", prefix, region, space_str);
+impl<'tcx> fmt::Display for TraitAndProjections<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let TraitAndProjections(ref trait_ref, ref projection_bounds) = *self;
+        parameterized(f, trait_ref.substs,
+                      trait_ref.def_id,
+                      projection_bounds)
     }
+}
+
+impl<'tcx> fmt::Display for ty::TraitObject<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // Generate the main trait ref, including associated types.
+        ty::tls::with(|tcx| {
+            // Use a type that can't appear in defaults of type parameters.
+            let dummy_self = tcx.mk_infer(ty::FreshTy(0));
+
+            let principal = tcx.lift(&self.principal)
+                               .expect("could not lift TraitRef for printing")
+                               .with_self_ty(tcx, dummy_self).0;
+            let projections = self.projection_bounds.iter().map(|p| {
+                tcx.lift(p)
+                    .expect("could not lift projection for printing")
+                    .with_self_ty(tcx, dummy_self).0
+            }).collect();
+
+            let tap = ty::Binder(TraitAndProjections(principal, projections));
+            in_binder(f, tcx, &ty::Binder(""), Some(tap))
+        })?;
+
+        // Builtin bounds.
+        for bound in &self.builtin_bounds {
+            write!(f, " + {:?}", bound)?;
+        }
 
-    // These printouts are concise.  They do not contain all the information
-    // the user might want to diagnose an error, but there is basically no way
-    // to fit that into a short string.  Hence the recommendation to use
-    // `explain_region()` or `note_and_explain_region()`.
-    match region {
-        re_scope(_) => prefix.to_str(),
-        re_bound(br) => bound_region_to_str(cx, prefix, space, br),
-        re_free(ref fr) => bound_region_to_str(cx, prefix, space, fr.bound_region),
-        re_infer(ReSkolemized(_, br)) => {
-            bound_region_to_str(cx, prefix, space, br)
+        // FIXME: It'd be nice to compute from context when this bound
+        // is implied, but that's non-trivial -- we'd perhaps have to
+        // use thread-local data of some kind? There are also
+        // advantages to just showing the region, since it makes
+        // people aware that it's there.
+        let bound = self.region_bound.to_string();
+        if !bound.is_empty() {
+            write!(f, " + {}", bound)?;
         }
-        re_infer(ReVar(_)) => prefix.to_str(),
-        re_static => fmt!("%s'static%s", prefix, space_str),
-        re_empty => fmt!("%s'<empty>%s", prefix, space_str)
+
+        Ok(())
     }
 }
 
-fn mutability_to_str(m: ast::mutability) -> ~str {
-    match m {
-        ast::m_mutbl => ~"mut ",
-        ast::m_imm => ~"",
-        ast::m_const => ~"const "
+impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TypeParameterDef({}, {:?}, {})",
+               self.name,
+               self.def_id,
+               self.index)
     }
 }
 
-pub fn mt_to_str(cx: ctxt, m: &mt) -> ~str {
-    mt_to_str_wrapped(cx, "", m, "")
+impl<'tcx> fmt::Debug for ty::RegionParameterDef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "RegionParameterDef({}, {:?}, {}, {:?})",
+               self.name,
+               self.def_id,
+               self.index,
+               self.bounds)
+    }
 }
 
-pub fn mt_to_str_wrapped(cx: ctxt, before: &str, m: &mt, after: &str) -> ~str {
-    let mstr = mutability_to_str(m.mutbl);
-    return fmt!("%s%s%s%s", mstr, before, ty_to_str(cx, m.ty), after);
+impl<'tcx> fmt::Debug for ty::TyS<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", *self)
+    }
 }
 
-pub fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str {
-    match vs {
-      ty::vstore_fixed(n) => fmt!("%u", n),
-      ty::vstore_uniq => ~"~",
-      ty::vstore_box => ~"@",
-      ty::vstore_slice(r) => region_ptr_to_str(cx, r)
+impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}{}",
+               if self.mutbl == hir::MutMutable { "mut " } else { "" },
+               self.ty)
     }
 }
 
-pub fn trait_store_to_str(cx: ctxt, s: ty::TraitStore) -> ~str {
-    match s {
-      ty::UniqTraitStore => ~"~",
-      ty::BoxTraitStore => ~"@",
-      ty::RegionTraitStore(r) => region_ptr_to_str(cx, r)
+impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ItemSubsts({:?})", self.substs)
     }
 }
 
-pub fn vstore_ty_to_str(cx: ctxt, mt: &mt, vs: ty::vstore) -> ~str {
-    match vs {
-        ty::vstore_fixed(_) => {
-            fmt!("[%s, .. %s]", mt_to_str(cx, mt), vstore_to_str(cx, vs))
-        }
-        _ => {
-            fmt!("%s%s", vstore_to_str(cx, vs), mt_to_str_wrapped(cx, "[", mt, "]"))
-        }
+impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // when printing out the debug representation, we don't need
+        // to enumerate the `for<...>` etc because the debruijn index
+        // tells you everything you need to know.
+        write!(f, "<{:?} as {}>", self.self_ty(), *self)
     }
 }
 
-pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
-    let tstrs = ts.map(|t| ty_to_str(cx, *t));
-    fmt!("(%s)", tstrs.connect(", "))
+impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| {
+            let dummy_self = tcx.mk_infer(ty::FreshTy(0));
+
+            let trait_ref = tcx.lift(&ty::Binder(*self))
+                               .expect("could not lift TraitRef for printing")
+                               .with_self_ty(tcx, dummy_self).0;
+            parameterized(f, trait_ref.substs, trait_ref.def_id, &[])
+        })
+    }
 }
 
-pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
-    fmt!("fn%s -> %s",
-         tys_to_str(cx, typ.inputs.map(|a| *a)),
-         ty_to_str(cx, typ.output))
+impl<'tcx> fmt::Debug for ty::TraitDef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TraitDef(generics={:?}, trait_ref={:?})",
+               self.generics, self.trait_ref)
+    }
 }
 
-pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str {
-    trait_ref.user_string(cx)
+impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| {
+            write!(f, "{}", tcx.item_path_str(self.did))
+        })
+    }
 }
 
-pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
-    fn fn_input_to_str(cx: ctxt, input: ty::t) -> ~str {
-        ty_to_str(cx, input)
+impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::adjustment::AdjustNeverToAny(ref target) => {
+                write!(f, "AdjustNeverToAny({:?})", target)
+            }
+            ty::adjustment::AdjustReifyFnPointer => {
+                write!(f, "AdjustReifyFnPointer")
+            }
+            ty::adjustment::AdjustUnsafeFnPointer => {
+                write!(f, "AdjustUnsafeFnPointer")
+            }
+            ty::adjustment::AdjustMutToConstPointer => {
+                write!(f, "AdjustMutToConstPointer")
+            }
+            ty::adjustment::AdjustDerefRef(ref data) => {
+                write!(f, "{:?}", data)
+            }
+        }
     }
-    fn bare_fn_to_str(cx: ctxt,
-                      purity: ast::purity,
-                      abis: AbiSet,
-                      ident: Option<ast::ident>,
-                      sig: &ty::FnSig)
-                      -> ~str {
-        let mut s = ~"extern ";
+}
 
-        s.push_str(abis.to_str());
-        s.push_char(' ');
+impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
+               self.autoderefs, self.unsize, self.autoref)
+    }
+}
 
-        match purity {
-            ast::impure_fn => {}
-            _ => {
-                s.push_str(purity.to_str());
-                s.push_char(' ');
+impl<'tcx> fmt::Debug for ty::TraitObject<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let mut empty = true;
+        let mut maybe_continue = |f: &mut fmt::Formatter| {
+            if empty {
+                empty = false;
+                Ok(())
+            } else {
+                write!(f, " + ")
             }
         };
 
-        s.push_str("fn");
+        maybe_continue(f)?;
+        write!(f, "{:?}", self.principal)?;
+
+        let region_str = format!("{:?}", self.region_bound);
+        if !region_str.is_empty() {
+            maybe_continue(f)?;
+            write!(f, "{}", region_str)?;
+        }
+
+        for bound in &self.builtin_bounds {
+            maybe_continue(f)?;
+            write!(f, "{:?}", bound)?;
+        }
 
-        match ident {
-          Some(i) => {
-              s.push_char(' ');
-              s.push_str(cx.sess.str_of(i));
-          }
-          _ => { }
+        for projection_bound in &self.projection_bounds {
+            maybe_continue(f)?;
+            write!(f, "{:?}", projection_bound)?;
         }
 
-        push_sig_to_str(cx, &mut s, sig);
+        Ok(())
+    }
+}
 
-        return s;
+impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::Predicate::Trait(ref a) => write!(f, "{:?}", a),
+            ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty),
+            ty::Predicate::ObjectSafe(trait_def_id) => {
+                write!(f, "ObjectSafe({:?})", trait_def_id)
+            }
+            ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind)
+            }
+        }
     }
-    fn closure_to_str(cx: ctxt, cty: &ty::ClosureTy) -> ~str
-    {
-        let mut s = cty.sigil.to_str();
+}
+
+impl fmt::Display for ty::BoundRegion {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if verbose() {
+            return write!(f, "{:?}", *self);
+        }
 
-        match (cty.sigil, cty.region) {
-            (ast::ManagedSigil, ty::re_static) |
-            (ast::OwnedSigil, ty::re_static) => {}
+        match *self {
+            BrNamed(_, name, _) => write!(f, "{}", name),
+            BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
+        }
+    }
+}
 
-            (_, region) => {
-                s.push_str(region_to_str(cx, "", true, region));
+impl fmt::Debug for ty::BoundRegion {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            BrAnon(n) => write!(f, "BrAnon({:?})", n),
+            BrFresh(n) => write!(f, "BrFresh({:?})", n),
+            BrNamed(did, name, issue32330) => {
+                write!(f, "BrNamed({:?}:{:?}, {:?}, {:?})",
+                       did.krate, did.index, name, issue32330)
             }
+            BrEnv => "BrEnv".fmt(f),
         }
+    }
+}
 
-        match cty.purity {
-            ast::impure_fn => {}
-            _ => {
-                s.push_str(cty.purity.to_str());
-                s.push_char(' ');
+impl fmt::Debug for ty::Region {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::ReEarlyBound(ref data) => {
+                write!(f, "ReEarlyBound({}, {})",
+                       data.index,
+                       data.name)
             }
-        };
 
-        match cty.onceness {
-            ast::Many => {}
-            ast::Once => {
-                s.push_str(cty.onceness.to_str());
-                s.push_char(' ');
+            ty::ReLateBound(binder_id, ref bound_region) => {
+                write!(f, "ReLateBound({:?}, {:?})",
+                       binder_id,
+                       bound_region)
             }
-        };
 
-        s.push_str("fn");
+            ty::ReFree(ref fr) => write!(f, "{:?}", fr),
 
-        if !cty.bounds.is_empty() {
-            s.push_str(":");
-        }
-        s.push_str(cty.bounds.repr(cx));
+            ty::ReScope(id) => {
+                write!(f, "ReScope({:?})", id)
+            }
 
-        push_sig_to_str(cx, &mut s, &cty.sig);
+            ty::ReStatic => write!(f, "ReStatic"),
 
-        return s;
-    }
-    fn push_sig_to_str(cx: ctxt, s: &mut ~str, sig: &ty::FnSig) {
-        s.push_char('(');
-        let strs = sig.inputs.map(|a| fn_input_to_str(cx, *a));
-        s.push_str(strs.connect(", "));
-        s.push_char(')');
-        if ty::get(sig.output).sty != ty_nil {
-            s.push_str(" -> ");
-            if ty::type_is_bot(sig.output) {
-                s.push_char('!');
-            } else {
-                s.push_str(ty_to_str(cx, sig.output));
-            }
-        }
-    }
-    fn method_to_str(cx: ctxt, m: ty::Method) -> ~str {
-        bare_fn_to_str(cx,
-                       m.fty.purity,
-                       m.fty.abis,
-                       Some(m.ident),
-                       &m.fty.sig) + ";"
-    }
-    fn field_to_str(cx: ctxt, f: field) -> ~str {
-        return fmt!("%s: %s", cx.sess.str_of(f.ident), mt_to_str(cx, &f.mt));
-    }
-
-    // if there is an id, print that instead of the structural type:
-    /*for ty::type_def_id(typ).iter().advance |def_id| {
-        // note that this typedef cannot have type parameters
-        return ast_map::path_to_str(ty::item_path(cx, *def_id),
-                                    cx.sess.intr());
-    }*/
-
-    // pretty print the structural type representation:
-    return match ty::get(typ).sty {
-      ty_nil => ~"()",
-      ty_bot => ~"!",
-      ty_bool => ~"bool",
-      ty_int(ast::ty_i) => ~"int",
-      ty_int(ast::ty_char) => ~"char",
-      ty_int(t) => ast_util::int_ty_to_str(t),
-      ty_uint(ast::ty_u) => ~"uint",
-      ty_uint(t) => ast_util::uint_ty_to_str(t),
-      ty_float(ast::ty_f) => ~"float",
-      ty_float(t) => ast_util::float_ty_to_str(t),
-      ty_box(ref tm) => ~"@" + mt_to_str(cx, tm),
-      ty_uniq(ref tm) => ~"~" + mt_to_str(cx, tm),
-      ty_ptr(ref tm) => ~"*" + mt_to_str(cx, tm),
-      ty_rptr(r, ref tm) => {
-        region_ptr_to_str(cx, r) + mt_to_str(cx, tm)
-      }
-      ty_unboxed_vec(ref tm) => { fmt!("unboxed_vec<%s>", mt_to_str(cx, tm)) }
-      ty_type => ~"type",
-      ty_tup(ref elems) => {
-        let strs = elems.map(|elem| ty_to_str(cx, *elem));
-        ~"(" + strs.connect(",") + ")"
-      }
-      ty_closure(ref f) => {
-          closure_to_str(cx, f)
-      }
-      ty_bare_fn(ref f) => {
-          bare_fn_to_str(cx, f.purity, f.abis, None, &f.sig)
-      }
-      ty_infer(infer_ty) => infer_ty.to_str(),
-      ty_err => ~"[type error]",
-      ty_param(param_ty {idx: id, def_id: did}) => {
-          let mut parm = (('T' as uint) + id) as char;
-          if (parm as uint) > ('Z' as uint) {
-              parm = (parm as uint - 26) as char;
-          }
-
-          if cx.sess.verbose() {
-              fmt!("%c:%?", parm, did)
-          } else {
-              fmt!("%c", parm)
-          }
-      }
-      ty_self(*) => ~"Self",
-      ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
-        let path = ty::item_path(cx, did);
-        let base = ast_map::path_to_str(path, cx.sess.intr());
-        parameterized(cx, base, substs.self_r, substs.tps)
-      }
-      ty_trait(did, ref substs, s, mutbl, ref bounds) => {
-        let path = ty::item_path(cx, did);
-        let base = ast_map::path_to_str(path, cx.sess.intr());
-        let ty = parameterized(cx, base, substs.self_r, substs.tps);
-        let bound_sep = if bounds.is_empty() { "" } else { ":" };
-        let bound_str = bounds.repr(cx);
-        fmt!("%s%s%s%s%s", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
-                           bound_sep, bound_str)
-      }
-      ty_evec(ref mt, vs) => {
-        vstore_ty_to_str(cx, mt, vs)
-      }
-      ty_estr(vs) => fmt!("%s%s", vstore_to_str(cx, vs), "str"),
-      ty_opaque_box => ~"@?",
-      ty_opaque_closure_ptr(ast::BorrowedSigil) => ~"&closure",
-      ty_opaque_closure_ptr(ast::ManagedSigil) => ~"@closure",
-      ty_opaque_closure_ptr(ast::OwnedSigil) => ~"~closure",
-    }
-}
-
-pub fn parameterized(cx: ctxt,
-                     base: &str,
-                     self_r: Option<ty::Region>,
-                     tps: &[ty::t]) -> ~str {
-
-    let mut strs = ~[];
-    match self_r {
-        None => (),
-        Some(r) => {
-            strs.push(region_to_str(cx, "", false, r))
+            ty::ReVar(ref vid) => {
+                write!(f, "{:?}", vid)
+            }
+
+            ty::ReSkolemized(id, ref bound_region) => {
+                write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
+            }
+
+            ty::ReEmpty => write!(f, "ReEmpty"),
+
+            ty::ReErased => write!(f, "ReErased")
         }
-    };
+    }
+}
 
-    for tps.iter().advance |t| {
-        strs.push(ty_to_str(cx, *t))
+impl<'tcx> fmt::Debug for ty::ClosureTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ClosureTy({},{:?},{})",
+               self.unsafety,
+               self.sig,
+               self.abi)
     }
+}
 
-    if strs.len() > 0u {
-        fmt!("%s<%s>", base, strs.connect(","))
-    } else {
-        fmt!("%s", base)
+impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ClosureUpvar({:?},{:?})",
+               self.def,
+               self.ty)
     }
 }
 
-pub fn ty_to_short_str(cx: ctxt, typ: t) -> ~str {
-    let mut s = encoder::encoded_ty(cx, typ);
-    if s.len() >= 32u { s = s.slice(0u, 32u).to_owned(); }
-    return s;
+impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ParameterEnvironment(\
+            free_substs={:?}, \
+            implicit_region_bound={:?}, \
+            caller_bounds={:?})",
+            self.free_substs,
+            self.implicit_region_bound,
+            self.caller_bounds)
+    }
 }
 
-impl<T:Repr> Repr for Option<T> {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        match self {
-            &None => ~"None",
-            &Some(ref t) => fmt!("Some(%s)", t.repr(tcx))
+impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
+            ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
+            ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
         }
     }
 }
 
-/*
-Annoyingly, these conflict with @ast::expr.
+impl fmt::Display for ty::Region {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if verbose() {
+            return write!(f, "{:?}", *self);
+        }
 
-impl<T:Repr> Repr for @T {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        (&**self).repr(tcx)
+        // These printouts are concise.  They do not contain all the information
+        // the user might want to diagnose an error, but there is basically no way
+        // to fit that into a short string.  Hence the recommendation to use
+        // `explain_region()` or `note_and_explain_region()`.
+        match *self {
+            ty::ReEarlyBound(ref data) => {
+                write!(f, "{}", data.name)
+            }
+            ty::ReLateBound(_, br) |
+            ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
+            ty::ReSkolemized(_, br) => {
+                write!(f, "{}", br)
+            }
+            ty::ReScope(_) |
+            ty::ReVar(_) |
+            ty::ReErased => Ok(()),
+            ty::ReStatic => write!(f, "'static"),
+            ty::ReEmpty => write!(f, "'<empty>"),
+        }
     }
 }
 
-impl<T:Repr> Repr for ~T {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        (&**self).repr(tcx)
+impl fmt::Debug for ty::FreeRegion {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ReFree({:?}, {:?})",
+               self.scope, self.bound_region)
     }
 }
-*/
 
-fn repr_vec<T:Repr>(tcx: ctxt, v: &[T]) -> ~str {
-    fmt!("[%s]", v.map(|t| t.repr(tcx)).connect(","))
+impl fmt::Debug for ty::Variance {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(match *self {
+            ty::Covariant => "+",
+            ty::Contravariant => "-",
+            ty::Invariant => "o",
+            ty::Bivariant => "*",
+        })
+    }
 }
 
-impl<'self, T:Repr> Repr for &'self [T] {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        repr_vec(tcx, *self)
+impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "GenericPredicates({:?})", self.predicates)
     }
 }
 
-// This is necessary to handle types like Option<@~[T]>, for which
-// autoderef cannot convert the &[T] handler
-impl<T:Repr> Repr for @~[T] {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        repr_vec(tcx, **self)
+impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "InstantiatedPredicates({:?})",
+               self.predicates)
     }
 }
 
-impl Repr for ty::TypeParameterDef {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("TypeParameterDef {%?, bounds: %s}",
-             self.def_id, self.bounds.repr(tcx))
+impl<'tcx> fmt::Debug for ty::ImplOrTraitItem<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ImplOrTraitItem(")?;
+        match *self {
+            ty::ImplOrTraitItem::MethodTraitItem(ref i) => write!(f, "{:?}", i),
+            ty::ImplOrTraitItem::ConstTraitItem(ref i) => write!(f, "{:?}", i),
+            ty::ImplOrTraitItem::TypeTraitItem(ref i) => write!(f, "{:?}", i),
+        }?;
+        write!(f, ")")
     }
 }
 
-impl Repr for ty::t {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        ty_to_str(tcx, *self)
+impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "fn")?;
+        fn_sig(f, &self.inputs, self.variadic, self.output)
     }
 }
 
-impl Repr for ty::substs {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("substs(self_r=%s, self_ty=%s, tps=%s)",
-             self.self_r.repr(tcx),
-             self.self_ty.repr(tcx),
-             self.tps.repr(tcx))
+impl fmt::Display for ty::BuiltinBounds {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let mut bounds = self.iter();
+        if let Some(bound) = bounds.next() {
+            write!(f, "{:?}", bound)?;
+            for bound in bounds {
+                write!(f, " + {:?}", bound)?;
+            }
+        }
+        Ok(())
     }
 }
 
-impl Repr for ty::ParamBounds {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        let mut res = ~[];
-        for self.builtin_bounds.each |b| {
-            res.push(match b {
-                ty::BoundCopy => ~"Copy",
-                ty::BoundStatic => ~"'static",
-                ty::BoundSend => ~"Send",
-                ty::BoundFreeze => ~"Freeze",
-                ty::BoundSized => ~"Sized",
-            });
-        }
-        for self.trait_bounds.iter().advance |t| {
-            res.push(t.repr(tcx));
-        }
-        res.connect("+")
+impl fmt::Debug for ty::TyVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "_#{}t", self.index)
     }
 }
 
-impl Repr for ty::TraitRef {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        trait_ref_to_str(tcx, self)
+impl fmt::Debug for ty::IntVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "_#{}i", self.index)
     }
 }
 
-impl Repr for @ast::expr {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("expr(%d: %s)",
-             self.id,
-             pprust::expr_to_str(*self, tcx.sess.intr()))
+impl fmt::Debug for ty::FloatVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "_#{}f", self.index)
     }
 }
 
-impl Repr for @ast::pat {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("pat(%d: %s)",
-             self.id,
-             pprust::pat_to_str(*self, tcx.sess.intr()))
+impl fmt::Debug for ty::RegionVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "'_#{}r", self.index)
     }
 }
 
-impl Repr for ty::Region {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        region_to_str(tcx, "", false, *self)
+impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "({:?}; variadic: {})->{:?}", self.inputs, self.variadic, self.output)
     }
 }
 
-impl Repr for ast::def_id {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        // Unfortunately, there seems to be no way to attempt to print
-        // a path for a def-id, so I'll just make a best effort for now
-        // and otherwise fallback to just printing the crate/node pair
-        if self.crate == ast::local_crate {
-            match tcx.items.find(&self.node) {
-                Some(&ast_map::node_item(*)) |
-                Some(&ast_map::node_foreign_item(*)) |
-                Some(&ast_map::node_method(*)) |
-                Some(&ast_map::node_trait_method(*)) |
-                Some(&ast_map::node_variant(*)) |
-                Some(&ast_map::node_struct_ctor(*)) => {
-                    return fmt!("%?:%s", *self, ty::item_path_str(tcx, *self));
-                }
-                _ => {}
-            }
+impl fmt::Debug for ty::InferTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::TyVar(ref v) => v.fmt(f),
+            ty::IntVar(ref v) => v.fmt(f),
+            ty::FloatVar(ref v) => v.fmt(f),
+            ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
+            ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
+            ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
         }
-        return fmt!("%?", *self);
     }
 }
 
-impl Repr for ty::ty_param_bounds_and_ty {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("ty_param_bounds_and_ty {generics: %s, ty: %s}",
-             self.generics.repr(tcx),
-             self.ty.repr(tcx))
+impl fmt::Debug for ty::IntVarValue {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::IntType(ref v) => v.fmt(f),
+            ty::UintType(ref v) => v.fmt(f),
+        }
     }
 }
 
-impl Repr for ty::Generics {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("Generics {type_param_defs: %s, region_param: %?}",
-             self.type_param_defs.repr(tcx),
-             self.region_param)
+// The generic impl doesn't work yet because projections are not
+// normalized under HRTB.
+/*impl<T> fmt::Display for ty::Binder<T>
+    where T: fmt::Display + for<'a> ty::Lift<'a>,
+          for<'a> <T as ty::Lift<'a>>::Lifted: fmt::Display + TypeFoldable<'a>
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
-}
+}*/
 
-impl Repr for ty::Method {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("method {ident: %s, generics: %s, transformed_self_ty: %s, \
-              fty: %s, explicit_self: %s, vis: %s, def_id: %s}",
-             self.ident.repr(tcx),
-             self.generics.repr(tcx),
-             self.transformed_self_ty.repr(tcx),
-             self.fty.repr(tcx),
-             self.explicit_self.repr(tcx),
-             self.vis.repr(tcx),
-             self.def_id.repr(tcx))
+impl<'tcx> fmt::Display for ty::Binder<ty::TraitRef<'tcx>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl Repr for ast::ident {
-    fn repr(&self, _tcx: ctxt) -> ~str {
-        token::ident_to_str(self).to_owned()
+impl<'tcx> fmt::Display for ty::Binder<ty::TraitPredicate<'tcx>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl Repr for ast::explicit_self_ {
-    fn repr(&self, _tcx: ctxt) -> ~str {
-        fmt!("%?", *self)
+impl<'tcx> fmt::Display for ty::Binder<ty::EquatePredicate<'tcx>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl Repr for ast::visibility {
-    fn repr(&self, _tcx: ctxt) -> ~str {
-        fmt!("%?", *self)
+impl<'tcx> fmt::Display for ty::Binder<ty::ProjectionPredicate<'tcx>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl Repr for ty::BareFnTy {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("BareFnTy {purity: %?, abis: %s, sig: %s}",
-             self.purity,
-             self.abis.to_str(),
-             self.sig.repr(tcx))
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl Repr for ty::FnSig {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fn_sig_to_str(tcx, self)
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<&'tcx ty::Region,
+                                                             &'tcx ty::Region>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl Repr for typeck::method_map_entry {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("method_map_entry {self_arg: %s, \
-              explicit_self: %s, \
-              origin: %s}",
-             self.self_ty.repr(tcx),
-             self.explicit_self.repr(tcx),
-             self.origin.repr(tcx))
+impl<'tcx> fmt::Display for ty::TraitRef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        parameterized(f, self.substs, self.def_id, &[])
     }
 }
 
-impl Repr for typeck::method_origin {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        match self {
-            &typeck::method_super(def_id, n) => {
-                fmt!("method_super(%s, %?)",
-                     def_id.repr(tcx), n)
+impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            TyBool => write!(f, "bool"),
+            TyChar => write!(f, "char"),
+            TyInt(t) => write!(f, "{}", t.ty_to_string()),
+            TyUint(t) => write!(f, "{}", t.ty_to_string()),
+            TyFloat(t) => write!(f, "{}", t.ty_to_string()),
+            TyBox(typ) => write!(f, "Box<{}>",  typ),
+            TyRawPtr(ref tm) => {
+                write!(f, "*{} {}", match tm.mutbl {
+                    hir::MutMutable => "mut",
+                    hir::MutImmutable => "const",
+                },  tm.ty)
             }
-            &typeck::method_static(def_id) => {
-                fmt!("method_static(%s)", def_id.repr(tcx))
+            TyRef(r, ref tm) => {
+                write!(f, "&")?;
+                let s = r.to_string();
+                write!(f, "{}", s)?;
+                if !s.is_empty() {
+                    write!(f, " ")?;
+                }
+                write!(f, "{}", tm)
+            }
+            TyNever => write!(f, "!"),
+            TyTuple(ref tys) => {
+                write!(f, "(")?;
+                let mut tys = tys.iter();
+                if let Some(&ty) = tys.next() {
+                    write!(f, "{},", ty)?;
+                    if let Some(&ty) = tys.next() {
+                        write!(f, " {}", ty)?;
+                        for &ty in tys {
+                            write!(f, ", {}", ty)?;
+                        }
+                    }
+                }
+                write!(f, ")")
+            }
+            TyFnDef(def_id, substs, ref bare_fn) => {
+                if bare_fn.unsafety == hir::Unsafety::Unsafe {
+                    write!(f, "unsafe ")?;
+                }
+
+                if bare_fn.abi != Abi::Rust {
+                    write!(f, "extern {} ", bare_fn.abi)?;
+                }
+
+                write!(f, "{} {{", bare_fn.sig.0)?;
+                parameterized(f, substs, def_id, &[])?;
+                write!(f, "}}")
             }
-            &typeck::method_param(ref p) => {
-                p.repr(tcx)
+            TyFnPtr(ref bare_fn) => {
+                if bare_fn.unsafety == hir::Unsafety::Unsafe {
+                    write!(f, "unsafe ")?;
+                }
+
+                if bare_fn.abi != Abi::Rust {
+                    write!(f, "extern {} ", bare_fn.abi)?;
+                }
+
+                write!(f, "{}", bare_fn.sig.0)
             }
-            &typeck::method_trait(def_id, n, st) => {
-                fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n,
-                     st.repr(tcx))
+            TyInfer(infer_ty) => write!(f, "{}", infer_ty),
+            TyError => write!(f, "[type error]"),
+            TyParam(ref param_ty) => write!(f, "{}", param_ty),
+            TyAdt(def, substs) => {
+                ty::tls::with(|tcx| {
+                    if def.did.is_local() &&
+                          !tcx.tcache.borrow().contains_key(&def.did) {
+                        write!(f, "{}<..>", tcx.item_path_str(def.did))
+                    } else {
+                        parameterized(f, substs, def.did, &[])
+                    }
+                })
             }
-            &typeck::method_self(def_id, n) => {
-                fmt!("method_self(%s, %?)", def_id.repr(tcx), n)
+            TyTrait(ref data) => write!(f, "{}", data),
+            ty::TyProjection(ref data) => write!(f, "{}", data),
+            ty::TyAnon(def_id, substs) => {
+                ty::tls::with(|tcx| {
+                    // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+                    // by looking up the projections associated with the def_id.
+                    let item_predicates = tcx.lookup_predicates(def_id);
+                    let substs = tcx.lift(&substs).unwrap_or_else(|| {
+                        Substs::empty(tcx)
+                    });
+                    let bounds = item_predicates.instantiate(tcx, substs);
+
+                    let mut first = true;
+                    let mut is_sized = false;
+                    write!(f, "impl")?;
+                    for predicate in bounds.predicates {
+                        if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
+                            // Don't print +Sized, but rather +?Sized if absent.
+                            if Some(trait_ref.def_id()) == tcx.lang_items.sized_trait() {
+                                is_sized = true;
+                                continue;
+                            }
+
+                            write!(f, "{}{}", if first { " " } else { "+" }, trait_ref)?;
+                            first = false;
+                        }
+                    }
+                    if !is_sized {
+                        write!(f, "{}?Sized", if first { " " } else { "+" })?;
+                    }
+                    Ok(())
+                })
             }
+            TyStr => write!(f, "str"),
+            TyClosure(did, substs) => ty::tls::with(|tcx| {
+                write!(f, "[closure")?;
+
+                if let Some(node_id) = tcx.map.as_local_node_id(did) {
+                    write!(f, "@{:?}", tcx.map.span(node_id))?;
+                    let mut sep = " ";
+                    tcx.with_freevars(node_id, |freevars| {
+                        for (freevar, upvar_ty) in freevars.iter().zip(substs.upvar_tys) {
+                            let def_id = freevar.def.def_id();
+                            let node_id = tcx.map.as_local_node_id(def_id).unwrap();
+                            write!(f,
+                                        "{}{}:{}",
+                                        sep,
+                                        tcx.local_var_name_str(node_id),
+                                        upvar_ty)?;
+                            sep = ", ";
+                        }
+                        Ok(())
+                    })?
+                } else {
+                    // cross-crate closure types should only be
+                    // visible in trans bug reports, I imagine.
+                    write!(f, "@{:?}", did)?;
+                    let mut sep = " ";
+                    for (index, upvar_ty) in substs.upvar_tys.iter().enumerate() {
+                        write!(f, "{}{}:{}", sep, index, upvar_ty)?;
+                        sep = ", ";
+                    }
+                }
+
+                write!(f, "]")
+            }),
+            TyArray(ty, sz) => write!(f, "[{}; {}]",  ty, sz),
+            TySlice(ty) => write!(f, "[{}]",  ty)
         }
     }
 }
 
-impl Repr for typeck::method_param {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        fmt!("method_param(%s,%?,%?,%?)",
-             self.trait_id.repr(tcx),
-             self.method_num,
-             self.param_num,
-             self.bound_num)
+impl<'tcx> fmt::Display for ty::TyS<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.sty)
     }
 }
 
-impl Repr for ty::TraitStore {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        match self {
-            &ty::BoxTraitStore => ~"@Trait",
-            &ty::UniqTraitStore => ~"~Trait",
-            &ty::RegionTraitStore(r) => fmt!("&%s Trait", r.repr(tcx))
-        }
+impl fmt::Debug for ty::UpvarId {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "UpvarId({};`{}`;{})",
+               self.var_id,
+               ty::tls::with(|tcx| tcx.local_var_name_str(self.var_id)),
+               self.closure_expr_id)
     }
 }
 
-impl Repr for ty::vstore {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        vstore_to_str(tcx, *self)
+impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "UpvarBorrow({:?}, {:?})",
+               self.kind, self.region)
     }
 }
 
-impl Repr for ast_map::path_elt {
-    fn repr(&self, tcx: ctxt) -> ~str {
+impl fmt::Display for ty::InferTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let print_var_ids = verbose();
         match *self {
-            ast_map::path_mod(id) => id.repr(tcx),
-            ast_map::path_name(id) => id.repr(tcx)
+            ty::TyVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
+            ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
+            ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
+            ty::TyVar(_) => write!(f, "_"),
+            ty::IntVar(_) => write!(f, "{}", "{integer}"),
+            ty::FloatVar(_) => write!(f, "{}", "{float}"),
+            ty::FreshTy(v) => write!(f, "FreshTy({})", v),
+            ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
+            ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
         }
     }
 }
 
-impl Repr for ty::BuiltinBound {
-    fn repr(&self, _tcx: ctxt) -> ~str {
-        fmt!("%?", *self)
+impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(match *self {
+            ty::ExplicitSelfCategory::Static => "static",
+            ty::ExplicitSelfCategory::ByValue => "self",
+            ty::ExplicitSelfCategory::ByReference(_, hir::MutMutable) => {
+                "&mut self"
+            }
+            ty::ExplicitSelfCategory::ByReference(_, hir::MutImmutable) => "&self",
+            ty::ExplicitSelfCategory::ByBox => "Box<self>",
+        })
     }
 }
 
-impl UserString for ty::BuiltinBound {
-    fn user_string(&self, _tcx: ctxt) -> ~str {
-        match *self {
-            ty::BoundCopy => ~"Copy",
-            ty::BoundStatic => ~"'static",
-            ty::BoundSend => ~"Send",
-            ty::BoundFreeze => ~"Freeze",
-            ty::BoundSized => ~"Sized",
-        }
+impl fmt::Display for ty::ParamTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.name)
     }
 }
 
-impl Repr for ty::BuiltinBounds {
-    fn repr(&self, tcx: ctxt) -> ~str {
-        self.user_string(tcx)
+impl fmt::Debug for ty::ParamTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}/#{}", self, self.idx)
     }
 }
 
-impl UserString for ty::BuiltinBounds {
-    fn user_string(&self, tcx: ctxt) -> ~str {
-        if self.is_empty() { ~"<no-bounds>" } else {
-            let mut result = ~[];
-            for self.each |bb| {
-                result.push(bb.user_string(tcx));
-            }
-            result.connect("+")
-        }
+impl<'tcx, T, U> fmt::Display for ty::OutlivesPredicate<T,U>
+    where T: fmt::Display, U: fmt::Display
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{} : {}", self.0, self.1)
     }
 }
 
-impl UserString for ty::TraitRef {
-    fn user_string(&self, tcx: ctxt) -> ~str {
-        let path = ty::item_path(tcx, self.def_id);
-        let base = ast_map::path_to_str(path, tcx.sess.intr());
-        if tcx.sess.verbose() && self.substs.self_ty.is_some() {
-            let mut all_tps = copy self.substs.tps;
-            for self.substs.self_ty.iter().advance |&t| { all_tps.push(t); }
-            parameterized(tcx, base, self.substs.self_r, all_tps)
-        } else {
-            parameterized(tcx, base, self.substs.self_r,
-                          self.substs.tps)
+impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{} == {}", self.0, self.1)
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TraitPredicate({:?})",
+               self.trait_ref)
+    }
+}
+
+impl<'tcx> fmt::Display for ty::TraitPredicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}: {}", self.trait_ref.self_ty(), self.trait_ref)
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ProjectionPredicate({:?}, {:?})",
+               self.projection_ty,
+               self.ty)
+    }
+}
+
+impl<'tcx> fmt::Display for ty::ProjectionPredicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{} == {}",
+               self.projection_ty,
+               self.ty)
+    }
+}
+
+impl<'tcx> fmt::Display for ty::ProjectionTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{:?}::{}",
+               self.trait_ref,
+               self.item_name)
+    }
+}
+
+impl fmt::Display for ty::ClosureKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::ClosureKind::Fn => write!(f, "Fn"),
+            ty::ClosureKind::FnMut => write!(f, "FnMut"),
+            ty::ClosureKind::FnOnce => write!(f, "FnOnce"),
         }
     }
 }
 
-impl UserString for ty::t {
-    fn user_string(&self, tcx: ctxt) -> ~str {
-        ty_to_str(tcx, *self)
+impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::Predicate::Trait(ref data) => write!(f, "{}", data),
+            ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate),
+            ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate),
+            ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate),
+            ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate),
+            ty::Predicate::WellFormed(ty) => write!(f, "{} well-formed", ty),
+            ty::Predicate::ObjectSafe(trait_def_id) =>
+                ty::tls::with(|tcx| {
+                    write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id))
+                }),
+            ty::Predicate::ClosureKind(closure_def_id, kind) =>
+                ty::tls::with(|tcx| {
+                    write!(f, "the closure `{}` implements the trait `{}`",
+                           tcx.item_path_str(closure_def_id), kind)
+                }),
+        }
     }
 }