about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-06-19 20:43:14 +0000
committerbors <bors@rust-lang.org>2015-06-19 20:43:14 +0000
commite4efb47b9d23a96ff4684df80360bbed0ec68bc9 (patch)
tree73901ba3b10563a5e7949ab7c2c71ea8a35788e8 /src
parent89485b2b6b643019c1748d456898c8774e2331de (diff)
parent6eed1662af4b72a829b65d7227bdcbdff1220be9 (diff)
downloadrust-e4efb47b9d23a96ff4684df80360bbed0ec68bc9.tar.gz
rust-e4efb47b9d23a96ff4684df80360bbed0ec68bc9.zip
Auto merge of #26351 - eddyb:tls-tcx, r=nikomatsakis
Pre-requisite for splitting the type context into global and local parts.
The `Repr` and `UserString` traits were also replaced by `Debug` and `Display`.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/metadata/tydecode.rs2
-rw-r--r--src/librustc/middle/astconv_util.rs3
-rw-r--r--src/librustc/middle/astencode.rs5
-rw-r--r--src/librustc/middle/check_const.rs3
-rw-r--r--src/librustc/middle/check_match.rs10
-rw-r--r--src/librustc/middle/check_rvalues.rs5
-rw-r--r--src/librustc/middle/const_eval.rs9
-rw-r--r--src/librustc/middle/effect.rs17
-rw-r--r--src/librustc/middle/expr_use_visitor.rs75
-rw-r--r--src/librustc/middle/free_region.rs12
-rw-r--r--src/librustc/middle/implicator.rs59
-rw-r--r--src/librustc/middle/infer/bivariate.rs5
-rw-r--r--src/librustc/middle/infer/combine.rs20
-rw-r--r--src/librustc/middle/infer/equate.rs11
-rw-r--r--src/librustc/middle/infer/error_reporting.rs175
-rw-r--r--src/librustc/middle/infer/glb.rs7
-rw-r--r--src/librustc/middle/infer/higher_ranked/mod.rs83
-rw-r--r--src/librustc/middle/infer/lattice.rs7
-rw-r--r--src/librustc/middle/infer/lub.rs7
-rw-r--r--src/librustc/middle/infer/mod.rs198
-rw-r--r--src/librustc/middle/infer/region_inference/graphviz.rs5
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs199
-rw-r--r--src/librustc/middle/infer/resolve.rs5
-rw-r--r--src/librustc/middle/infer/sub.rs9
-rw-r--r--src/librustc/middle/intrinsicck.rs29
-rw-r--r--src/librustc/middle/mem_categorization.rs174
-rw-r--r--src/librustc/middle/stability.rs5
-rw-r--r--src/librustc/middle/subst.rs39
-rw-r--r--src/librustc/middle/traits/coherence.rs50
-rw-r--r--src/librustc/middle/traits/error_reporting.rs74
-rw-r--r--src/librustc/middle/traits/fulfill.rs49
-rw-r--r--src/librustc/middle/traits/mod.rs48
-rw-r--r--src/librustc/middle/traits/object_safety.rs23
-rw-r--r--src/librustc/middle/traits/project.rs155
-rw-r--r--src/librustc/middle/traits/select.rs323
-rw-r--r--src/librustc/middle/traits/util.rs156
-rw-r--r--src/librustc/middle/ty.rs799
-rw-r--r--src/librustc/middle/ty_fold.rs33
-rw-r--r--src/librustc/middle/ty_match.rs11
-rw-r--r--src/librustc/middle/ty_relate/mod.rs26
-rw-r--r--src/librustc/util/ppaux.rs1808
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs47
-rw-r--r--src/librustc_borrowck/borrowck/fragments.rs44
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs12
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/lifetime.rs12
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs40
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs5
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/restrictions.rs3
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs122
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs26
-rw-r--r--src/librustc_driver/driver.rs272
-rw-r--r--src/librustc_driver/lib.rs10
-rw-r--r--src/librustc_driver/pretty.rs63
-rw-r--r--src/librustc_driver/test.rs103
-rw-r--r--src/librustc_lint/builtin.rs4
-rw-r--r--src/librustc_resolve/lib.rs4
-rw-r--r--src/librustc_trans/back/link.rs4
-rw-r--r--src/librustc_trans/save/dump_csv.rs119
-rw-r--r--src/librustc_trans/save/mod.rs91
-rw-r--r--src/librustc_trans/trans/_match.rs54
-rw-r--r--src/librustc_trans/trans/adt.rs6
-rw-r--r--src/librustc_trans/trans/base.rs43
-rw-r--r--src/librustc_trans/trans/callee.rs54
-rw-r--r--src/librustc_trans/trans/cleanup.rs15
-rw-r--r--src/librustc_trans/trans/closure.rs15
-rw-r--r--src/librustc_trans/trans/common.rs59
-rw-r--r--src/librustc_trans/trans/consts.rs35
-rw-r--r--src/librustc_trans/trans/context.rs33
-rw-r--r--src/librustc_trans/trans/controlflow.rs9
-rw-r--r--src/librustc_trans/trans/datum.rs5
-rw-r--r--src/librustc_trans/trans/debuginfo/metadata.rs21
-rw-r--r--src/librustc_trans/trans/debuginfo/type_names.rs4
-rw-r--r--src/librustc_trans/trans/declare.rs15
-rw-r--r--src/librustc_trans/trans/expr.rs59
-rw-r--r--src/librustc_trans/trans/foreign.rs39
-rw-r--r--src/librustc_trans/trans/glue.rs28
-rw-r--r--src/librustc_trans/trans/intrinsic.rs13
-rw-r--r--src/librustc_trans/trans/meth.rs75
-rw-r--r--src/librustc_trans/trans/monomorphize.rs35
-rw-r--r--src/librustc_trans/trans/tvec.rs19
-rw-r--r--src/librustc_trans/trans/type_of.rs28
-rw-r--r--src/librustc_typeck/astconv.rs84
-rw-r--r--src/librustc_typeck/check/_match.rs9
-rw-r--r--src/librustc_typeck/check/assoc.rs13
-rw-r--r--src/librustc_typeck/check/callee.rs29
-rw-r--r--src/librustc_typeck/check/cast.rs9
-rw-r--r--src/librustc_typeck/check/closure.rs43
-rw-r--r--src/librustc_typeck/check/coercion.rs41
-rw-r--r--src/librustc_typeck/check/compare_method.rs87
-rw-r--r--src/librustc_typeck/check/demand.rs7
-rw-r--r--src/librustc_typeck/check/dropck.rs67
-rw-r--r--src/librustc_typeck/check/method/confirm.rs76
-rw-r--r--src/librustc_typeck/check/method/mod.rs35
-rw-r--r--src/librustc_typeck/check/method/probe.rs175
-rw-r--r--src/librustc_typeck/check/method/suggest.rs13
-rw-r--r--src/librustc_typeck/check/mod.rs189
-rw-r--r--src/librustc_typeck/check/op.rs37
-rw-r--r--src/librustc_typeck/check/regionck.rs168
-rw-r--r--src/librustc_typeck/check/upvar.rs37
-rw-r--r--src/librustc_typeck/check/wf.rs17
-rw-r--r--src/librustc_typeck/check/writeback.rs21
-rw-r--r--src/librustc_typeck/coherence/mod.rs61
-rw-r--r--src/librustc_typeck/coherence/orphan.rs20
-rw-r--r--src/librustc_typeck/coherence/overlap.rs15
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs5
-rw-r--r--src/librustc_typeck/collect.rs70
-rw-r--r--src/librustc_typeck/lib.rs29
-rw-r--r--src/librustc_typeck/variance.rs34
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/core.rs103
-rw-r--r--src/librustdoc/visit_ast.rs4
-rw-r--r--src/libsyntax/ast.rs76
-rw-r--r--src/libsyntax/codemap.rs18
-rw-r--r--src/test/compile-fail/object-lifetime-default.rs2
-rw-r--r--src/test/run-make/execution-engine/test.rs27
116 files changed, 3525 insertions, 4477 deletions
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 240aaae0e55..c19ba19f5b7 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -51,6 +51,7 @@
 #![feature(ref_slice)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
+#![feature(scoped_tls)]
 #![feature(slice_bytes)]
 #![feature(slice_extras)]
 #![feature(slice_patterns)]
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index ad650fcfb11..693ccc13f1e 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -898,7 +898,7 @@ fn parse_builtin_bounds<F>(st: &mut PState, mut _conv: F) -> ty::BuiltinBounds w
 fn parse_builtin_bounds_<F>(st: &mut PState, _conv: &mut F) -> ty::BuiltinBounds where
     F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
 {
-    let mut builtin_bounds = ty::empty_builtin_bounds();
+    let mut builtin_bounds = ty::BuiltinBounds::empty();
 
     loop {
         match next(st) {
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
index 698cf105ae5..33d37b28589 100644
--- a/src/librustc/middle/astconv_util.rs
+++ b/src/librustc/middle/astconv_util.rs
@@ -17,7 +17,6 @@
 use middle::def;
 use middle::ty::{self, Ty};
 use syntax::ast;
-use util::ppaux::Repr;
 
 pub const NO_REGIONS: usize = 1;
 pub const NO_TPS: usize = 2;
@@ -63,7 +62,7 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
         let def = match tcx.def_map.borrow().get(&ast_ty.id) {
             None => {
                 tcx.sess.span_bug(ast_ty.span,
-                                  &format!("unbound path {}", path.repr(tcx)))
+                                  &format!("unbound path {:?}", path))
             }
             Some(d) => d.full_def()
         };
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index ad228404a9c..21e2ad19881 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -31,7 +31,6 @@ use middle::privacy::{AllPublic, LastMod};
 use middle::subst;
 use middle::subst::VecPerParamSpace;
 use middle::ty::{self, Ty, MethodCall, MethodCallee, MethodOrigin};
-use util::ppaux::ty_to_string;
 
 use syntax::{ast, ast_util, codemap, fold};
 use syntax::codemap::Span;
@@ -1623,8 +1622,8 @@ fn decode_side_tables(dcx: &DecodeContext,
                     }
                     c::tag_table_node_type => {
                         let ty = val_dsr.read_ty(dcx);
-                        debug!("inserting ty for node {}: {}",
-                               id, ty_to_string(dcx.tcx, ty));
+                        debug!("inserting ty for node {}: {:?}",
+                               id,  ty);
                         dcx.tcx.node_type_insert(id, ty);
                     }
                     c::tag_table_item_subst => {
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index d80eedf354a..8af6946d3c3 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -33,7 +33,6 @@ use middle::mem_categorization as mc;
 use middle::traits;
 use middle::ty::{self, Ty};
 use util::nodemap::NodeMap;
-use util::ppaux::Repr;
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -300,7 +299,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &ast::Item) {
-        debug!("visit_item(item={})", i.repr(self.tcx));
+        debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
         match i.node {
             ast::ItemStatic(_, ast::MutImmutable, ref expr) => {
                 self.check_static_type(&**expr);
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index ea95536b811..e1f8e24253b 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -36,7 +36,6 @@ use syntax::print::pprust::pat_to_string;
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax::visit::{self, Visitor, FnKind};
-use util::ppaux::ty_to_string;
 use util::nodemap::FnvHashMap;
 
 pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
@@ -209,9 +208,8 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) {
                 if !type_is_empty(cx.tcx, pat_ty) {
                     // We know the type is inhabited, so this must be wrong
                     span_err!(cx.tcx.sess, ex.span, E0002,
-                        "non-exhaustive patterns: type {} is non-empty",
-                        ty_to_string(cx.tcx, pat_ty)
-                    );
+                              "non-exhaustive patterns: type {} is non-empty",
+                              pat_ty);
                 }
                 // If the type *is* empty, it's vacuously exhaustive
                 return;
@@ -244,11 +242,11 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
                             span_warn!(cx.tcx.sess, p.span, E0170,
                                 "pattern binding `{}` is named the same as one \
                                  of the variants of the type `{}`",
-                                &token::get_ident(ident.node), ty_to_string(cx.tcx, pat_ty));
+                                &token::get_ident(ident.node), pat_ty);
                             fileline_help!(cx.tcx.sess, p.span,
                                 "if you meant to match on a variant, \
                                  consider making the path in the pattern qualified: `{}::{}`",
-                                ty_to_string(cx.tcx, pat_ty), &token::get_ident(ident.node));
+                                pat_ty, &token::get_ident(ident.node));
                         }
                     }
                 }
diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs
index 6985ca27861..f5934751c58 100644
--- a/src/librustc/middle/check_rvalues.rs
+++ b/src/librustc/middle/check_rvalues.rs
@@ -15,7 +15,6 @@ use middle::expr_use_visitor as euv;
 use middle::mem_categorization as mc;
 use middle::ty::ParameterEnvironment;
 use middle::ty;
-use util::ppaux::ty_to_string;
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -59,11 +58,11 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
                span: Span,
                cmt: mc::cmt<'tcx>,
                _: euv::ConsumeMode) {
-        debug!("consume; cmt: {:?}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
+        debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
         if !ty::type_is_sized(Some(self.param_env), self.tcx, span, cmt.ty) {
             span_err!(self.tcx.sess, span, E0161,
                 "cannot move a value of type {0}: the size of {0} cannot be statically determined",
-                ty_to_string(self.tcx, cmt.ty));
+                cmt.ty);
         }
     }
 
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index f64765f9090..23ad3f0d4b9 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -23,7 +23,6 @@ use middle::pat_util::def_to_path;
 use middle::ty::{self, Ty};
 use middle::astconv_util::ast_ty_to_prim_ty;
 use util::num::ToPrimitive;
-use util::ppaux::Repr;
 
 use syntax::ast::{self, Expr};
 use syntax::ast_util;
@@ -1030,8 +1029,8 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
                                                            rcvr_self,
                                                            Vec::new()));
     let trait_substs = tcx.mk_substs(trait_substs);
-    debug!("resolve_trait_associated_const: trait_substs={}",
-           trait_substs.repr(tcx));
+    debug!("resolve_trait_associated_const: trait_substs={:?}",
+           trait_substs);
     let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
                                               substs: trait_substs });
 
@@ -1052,10 +1051,10 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
         }
         Err(e) => {
             tcx.sess.span_bug(ti.span,
-                              &format!("Encountered error `{}` when trying \
+                              &format!("Encountered error `{:?}` when trying \
                                         to select an implementation for \
                                         constant trait item reference.",
-                                       e.repr(tcx)))
+                                       e))
         }
     };
 
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index d23c8a4bc1e..bb63ec42d8c 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -15,7 +15,6 @@ use self::UnsafeContext::*;
 use middle::def;
 use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
-use util::ppaux;
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -66,8 +65,8 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
             ast::ExprIndex(ref base, _) => ty::node_id_to_type(self.tcx, base.id),
             _ => return
         };
-        debug!("effect: checking index with base type {}",
-                ppaux::ty_to_string(self.tcx, base_type));
+        debug!("effect: checking index with base type {:?}",
+                 base_type);
         match base_type.sty {
             ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) => if ty::TyStr == ty.sty {
                 span_err!(self.tcx.sess, e.span, E0134,
@@ -142,8 +141,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             ast::ExprMethodCall(_, _, _) => {
                 let method_call = MethodCall::expr(expr.id);
                 let base_type = self.tcx.method_map.borrow().get(&method_call).unwrap().ty;
-                debug!("effect: method call case, base type is {}",
-                       ppaux::ty_to_string(self.tcx, base_type));
+                debug!("effect: method call case, base type is {:?}",
+                        base_type);
                 if type_is_unsafe_function(base_type) {
                     self.require_unsafe(expr.span,
                                         "invocation of unsafe method")
@@ -151,16 +150,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             }
             ast::ExprCall(ref base, _) => {
                 let base_type = ty::node_id_to_type(self.tcx, base.id);
-                debug!("effect: call case, base type is {}",
-                       ppaux::ty_to_string(self.tcx, base_type));
+                debug!("effect: call case, base type is {:?}",
+                        base_type);
                 if type_is_unsafe_function(base_type) {
                     self.require_unsafe(expr.span, "call to unsafe function")
                 }
             }
             ast::ExprUnary(ast::UnDeref, ref base) => {
                 let base_type = ty::node_id_to_type(self.tcx, base.id);
-                debug!("effect: unary case, base type is {}",
-                       ppaux::ty_to_string(self.tcx, base_type));
+                debug!("effect: unary case, base type is {:?}",
+                        base_type);
                 if let ty::TyRawPtr(_) = base_type.sty {
                     self.require_unsafe(expr.span, "dereference of raw pointer")
                 }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 3c9a4def5c8..ab67c68be12 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -27,7 +27,6 @@ use middle::ty::{self};
 use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
 use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
 use middle::ty::{MethodStatic, MethodStaticClosure};
-use util::ppaux::Repr;
 
 use syntax::{ast, ast_util};
 use syntax::ptr::P;
@@ -362,8 +361,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                         consume_id: ast::NodeId,
                         consume_span: Span,
                         cmt: mc::cmt<'tcx>) {
-        debug!("delegate_consume(consume_id={}, cmt={})",
-               consume_id, cmt.repr(self.tcx()));
+        debug!("delegate_consume(consume_id={}, cmt={:?})",
+               consume_id, cmt);
 
         let mode = copy_or_move(self.typer, &cmt, DirectRefMove);
         self.delegate.consume(consume_id, consume_span, cmt, mode);
@@ -376,7 +375,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     }
 
     pub fn consume_expr(&mut self, expr: &ast::Expr) {
-        debug!("consume_expr(expr={})", expr.repr(self.tcx()));
+        debug!("consume_expr(expr={:?})", expr);
 
         let cmt = return_if_err!(self.mc.cat_expr(expr));
         self.delegate_consume(expr.id, expr.span, cmt);
@@ -397,8 +396,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                    r: ty::Region,
                    bk: ty::BorrowKind,
                    cause: LoanCause) {
-        debug!("borrow_expr(expr={}, r={}, bk={})",
-               expr.repr(self.tcx()), r.repr(self.tcx()), bk.repr(self.tcx()));
+        debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})",
+               expr, r, bk);
 
         let cmt = return_if_err!(self.mc.cat_expr(expr));
         self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
@@ -414,7 +413,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     }
 
     pub fn walk_expr(&mut self, expr: &ast::Expr) {
-        debug!("walk_expr(expr={})", expr.repr(self.tcx()));
+        debug!("walk_expr(expr={:?})", expr);
 
         self.walk_adjustment(expr);
 
@@ -618,8 +617,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
 
     fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) {
         let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee));
-        debug!("walk_callee: callee={} callee_ty={}",
-               callee.repr(self.tcx()), callee_ty.repr(self.tcx()));
+        debug!("walk_callee: callee={:?} callee_ty={:?}",
+               callee, callee_ty);
         let call_scope = region::CodeExtent::from_node_id(call.id);
         match callee_ty.sty {
             ty::TyBareFn(..) => {
@@ -637,7 +636,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                         None => {
                             self.tcx().sess.span_bug(
                                 callee.span,
-                                &format!("unexpected callee type {}", callee_ty.repr(self.tcx())))
+                                &format!("unexpected callee type {}", callee_ty))
                         }
                     };
                 match overloaded_call_type {
@@ -811,7 +810,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     fn walk_autoderefs(&mut self,
                        expr: &ast::Expr,
                        autoderefs: usize) {
-        debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
+        debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs);
 
         for i in 0..autoderefs {
             let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
@@ -828,8 +827,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                     let (m, r) = match self_ty.sty {
                         ty::TyRef(r, ref m) => (m.mutbl, r),
                         _ => self.tcx().sess.span_bug(expr.span,
-                                &format!("bad overloaded deref type {}",
-                                    method_ty.repr(self.tcx())))
+                                &format!("bad overloaded deref type {:?}",
+                                    method_ty))
                     };
                     let bk = ty::BorrowKind::from_mutbl(m);
                     self.delegate.borrow(expr.id, expr.span, cmt,
@@ -842,9 +841,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     fn walk_autoderefref(&mut self,
                          expr: &ast::Expr,
                          adj: &ty::AutoDerefRef<'tcx>) {
-        debug!("walk_autoderefref expr={} adj={}",
-               expr.repr(self.tcx()),
-               adj.repr(self.tcx()));
+        debug!("walk_autoderefref expr={:?} adj={:?}",
+               expr,
+               adj);
 
         self.walk_autoderefs(expr, adj.autoderefs);
 
@@ -875,9 +874,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                     opt_autoref: Option<ty::AutoRef<'tcx>>)
                     -> mc::cmt<'tcx>
     {
-        debug!("walk_autoref(expr.id={} cmt_derefd={} opt_autoref={:?})",
+        debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
                expr.id,
-               cmt_base.repr(self.tcx()),
+               cmt_base,
                opt_autoref);
 
         let cmt_base_ty = cmt_base.ty;
@@ -901,9 +900,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             }
 
             ty::AutoUnsafe(m) => {
-                debug!("walk_autoref: expr.id={} cmt_base={}",
+                debug!("walk_autoref: expr.id={} cmt_base={:?}",
                        expr.id,
-                       cmt_base.repr(self.tcx()));
+                       cmt_base);
 
                 // Converting from a &T to *T (or &mut T to *mut T) is
                 // treated as borrowing it for the enclosing temporary
@@ -1011,8 +1010,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                                cmt_discr: mc::cmt<'tcx>,
                                pat: &ast::Pat,
                                mode: &mut TrackMatchMode) {
-        debug!("determine_pat_move_mode cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
-               pat.repr(self.tcx()));
+        debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
+               pat);
         return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
             let tcx = self.tcx();
             let def_map = &self.tcx().def_map;
@@ -1043,8 +1042,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                 cmt_discr: mc::cmt<'tcx>,
                 pat: &ast::Pat,
                 match_mode: MatchMode) {
-        debug!("walk_pat cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
-               pat.repr(self.tcx()));
+        debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr,
+               pat);
 
         let mc = &self.mc;
         let typer = self.typer;
@@ -1054,9 +1053,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             if pat_util::pat_is_binding(def_map, pat) {
                 let tcx = typer.tcx();
 
-                debug!("binding cmt_pat={} pat={} match_mode={:?}",
-                       cmt_pat.repr(tcx),
-                       pat.repr(tcx),
+                debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
+                       cmt_pat,
+                       pat,
                        match_mode);
 
                 // pat_ty: the type of the binding being produced.
@@ -1160,9 +1159,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                                     mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
                                 };
 
-                            debug!("variant downcast_cmt={} pat={}",
-                                   downcast_cmt.repr(tcx),
-                                   pat.repr(tcx));
+                            debug!("variant downcast_cmt={:?} pat={:?}",
+                                   downcast_cmt,
+                                   pat);
 
                             delegate.matched_pat(pat, downcast_cmt, match_mode);
                         }
@@ -1172,9 +1171,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                             // namespace; we encounter the former on
                             // e.g. patterns for unit structs).
 
-                            debug!("struct cmt_pat={} pat={}",
-                                   cmt_pat.repr(tcx),
-                                   pat.repr(tcx));
+                            debug!("struct cmt_pat={:?} pat={:?}",
+                                   cmt_pat,
+                                   pat);
 
                             delegate.matched_pat(pat, cmt_pat, match_mode);
                         }
@@ -1192,9 +1191,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                             // pattern.
 
                             if !tcx.sess.has_errors() {
-                                let msg = format!("Pattern has unexpected type: {:?} and type {}",
+                                let msg = format!("Pattern has unexpected type: {:?} and type {:?}",
                                                   def,
-                                                  cmt_pat.ty.repr(tcx));
+                                                  cmt_pat.ty);
                                 tcx.sess.span_bug(pat.span, &msg)
                             }
                         }
@@ -1209,9 +1208,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                             // reported.
 
                             if !tcx.sess.has_errors() {
-                                let msg = format!("Pattern has unexpected def: {:?} and type {}",
+                                let msg = format!("Pattern has unexpected def: {:?} and type {:?}",
                                                   def,
-                                                  cmt_pat.ty.repr(tcx));
+                                                  cmt_pat.ty);
                                 tcx.sess.span_bug(pat.span, &msg[..])
                             }
                         }
@@ -1237,7 +1236,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     }
 
     fn walk_captures(&mut self, closure_expr: &ast::Expr) {
-        debug!("walk_captures({})", closure_expr.repr(self.tcx()));
+        debug!("walk_captures({:?})", closure_expr);
 
         ty::with_freevars(self.tcx(), closure_expr.id, |freevars| {
             for freevar in freevars {
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index 0c8a956f686..e08da94c731 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -14,7 +14,6 @@ use middle::implicator::Implication;
 use middle::ty::{self, FreeRegion};
 use util::common::can_reach;
 use util::nodemap::FnvHashMap;
-use util::ppaux::Repr;
 
 #[derive(Clone)]
 pub struct FreeRegionMap {
@@ -29,11 +28,10 @@ impl FreeRegionMap {
     }
 
     pub fn relate_free_regions_from_implications<'tcx>(&mut self,
-                                                       tcx: &ty::ctxt<'tcx>,
                                                        implications: &[Implication<'tcx>])
     {
         for implication in implications {
-            debug!("implication: {}", implication.repr(tcx));
+            debug!("implication: {:?}", implication);
             match *implication {
                 Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
                     self.relate_free_regions(free_a, free_b);
@@ -50,7 +48,7 @@ impl FreeRegionMap {
     pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
                                                      tcx: &ty::ctxt<'tcx>,
                                                      predicates: &[ty::Predicate<'tcx>]) {
-        debug!("relate_free_regions_from_predicates(predicates={})", predicates.repr(tcx));
+        debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
         for predicate in predicates {
             match *predicate {
                 ty::Predicate::Projection(..) |
@@ -68,9 +66,9 @@ impl FreeRegionMap {
                         _ => {
                             // All named regions are instantiated with free regions.
                             tcx.sess.bug(
-                                &format!("record_region_bounds: non free region: {} / {}",
-                                         r_a.repr(tcx),
-                                         r_b.repr(tcx)));
+                                &format!("record_region_bounds: non free region: {:?} / {:?}",
+                                         r_a,
+                                         r_b));
                         }
                     }
                 }
diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs
index fc9636ae366..d26df43286d 100644
--- a/src/librustc/middle/implicator.rs
+++ b/src/librustc/middle/implicator.rs
@@ -21,10 +21,10 @@ use syntax::codemap::Span;
 
 use util::common::ErrorReported;
 use util::nodemap::FnvHashSet;
-use util::ppaux::Repr;
 
 // Helper functions related to manipulating region types.
 
+#[derive(Debug)]
 pub enum Implication<'tcx> {
     RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
     RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
@@ -53,10 +53,10 @@ pub fn implications<'a,'tcx>(
     span: Span)
     -> Vec<Implication<'tcx>>
 {
-    debug!("implications(body_id={}, ty={}, outer_region={})",
+    debug!("implications(body_id={}, ty={:?}, outer_region={:?})",
            body_id,
-           ty.repr(closure_typer.tcx()),
-           outer_region.repr(closure_typer.tcx()));
+           ty,
+           outer_region);
 
     let mut stack = Vec::new();
     stack.push((outer_region, None));
@@ -68,7 +68,7 @@ pub fn implications<'a,'tcx>(
                               out: Vec::new(),
                               visited: FnvHashSet() };
     wf.accumulate_from_ty(ty);
-    debug!("implications: out={}", wf.out.repr(closure_typer.tcx()));
+    debug!("implications: out={:?}", wf.out);
     wf.out
 }
 
@@ -78,8 +78,8 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
     }
 
     fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
-        debug!("accumulate_from_ty(ty={})",
-               ty.repr(self.tcx()));
+        debug!("accumulate_from_ty(ty={:?})",
+               ty);
 
         // When expanding out associated types, we can visit a cyclic
         // set of types. Issue #23003.
@@ -312,8 +312,8 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
     fn accumulate_from_assoc_types_transitive(&mut self,
                                               data: &ty::PolyTraitPredicate<'tcx>)
     {
-        debug!("accumulate_from_assoc_types_transitive({})",
-               data.repr(self.tcx()));
+        debug!("accumulate_from_assoc_types_transitive({:?})",
+               data);
 
         for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
             match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) {
@@ -326,8 +326,8 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
     fn accumulate_from_assoc_types(&mut self,
                                    trait_ref: ty::TraitRef<'tcx>)
     {
-        debug!("accumulate_from_assoc_types({})",
-               trait_ref.repr(self.tcx()));
+        debug!("accumulate_from_assoc_types({:?})",
+               trait_ref);
 
         let trait_def_id = trait_ref.def_id;
         let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
@@ -336,8 +336,8 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
                      .iter()
                      .map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name))
                      .collect();
-        debug!("accumulate_from_assoc_types: assoc_type_projections={}",
-               assoc_type_projections.repr(self.tcx()));
+        debug!("accumulate_from_assoc_types: assoc_type_projections={:?}",
+               assoc_type_projections);
         let tys = match self.fully_normalize(&assoc_type_projections) {
             Ok(tys) => { tys }
             Err(ErrorReported) => { return; }
@@ -400,7 +400,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
     }
 
     fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
-        where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx>
+        where T : TypeFoldable<'tcx> + ty::HasProjectionTypes
     {
         let value =
             traits::fully_normalize(self.infcx,
@@ -454,34 +454,3 @@ pub fn object_region_bounds<'tcx>(
     let predicates = ty::predicates(tcx, open_ty, &param_bounds);
     ty::required_region_bounds(tcx, open_ty, predicates)
 }
-
-impl<'tcx> Repr<'tcx> for Implication<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            Implication::RegionSubRegion(_, ref r_a, ref r_b) => {
-                format!("RegionSubRegion({}, {})",
-                        r_a.repr(tcx),
-                        r_b.repr(tcx))
-            }
-
-            Implication::RegionSubGeneric(_, ref r, ref p) => {
-                format!("RegionSubGeneric({}, {})",
-                        r.repr(tcx),
-                        p.repr(tcx))
-            }
-
-            Implication::RegionSubClosure(_, ref a, ref b, ref c) => {
-                format!("RegionSubClosure({}, {}, {})",
-                        a.repr(tcx),
-                        b.repr(tcx),
-                        c.repr(tcx))
-            }
-
-            Implication::Predicate(ref def_id, ref p) => {
-                format!("Predicate({}, {})",
-                        def_id.repr(tcx),
-                        p.repr(tcx))
-            }
-        }
-    }
-}
diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs
index 1ab01453c0f..742ad3f29b7 100644
--- a/src/librustc/middle/infer/bivariate.rs
+++ b/src/librustc/middle/infer/bivariate.rs
@@ -31,7 +31,6 @@ use super::type_variable::{BiTo};
 use middle::ty::{self, Ty};
 use middle::ty::TyVar;
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::{Repr};
 
 pub struct Bivariate<'a, 'tcx: 'a> {
     fields: CombineFields<'a, 'tcx>
@@ -73,8 +72,8 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> {
     }
 
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("{}.tys({}, {})", self.tag(),
-               a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+        debug!("{}.tys({:?}, {:?})", self.tag(),
+               a, b);
         if a == b { return Ok(a); }
 
         let infcx = self.fields.infcx;
diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index 864e9ed0b97..17d545212c2 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -47,7 +47,6 @@ use middle::ty::{self, Ty};
 use middle::ty_fold;
 use middle::ty_fold::{TypeFolder, TypeFoldable};
 use middle::ty_relate::{self, Relate, RelateResult, TypeRelation};
-use util::ppaux::Repr;
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -187,7 +186,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
                        b_vid: ty::TyVid)
                        -> RelateResult<'tcx, ()>
     {
-        let tcx = self.infcx.tcx;
         let mut stack = Vec::new();
         stack.push((a_ty, dir, b_vid));
         loop {
@@ -213,10 +211,10 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
                 Some(e) => e,
             };
 
-            debug!("instantiate(a_ty={} dir={:?} b_vid={})",
-                   a_ty.repr(tcx),
+            debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})",
+                   a_ty,
                    dir,
-                   b_vid.repr(tcx));
+                   b_vid);
 
             // Check whether `vid` has been instantiated yet.  If not,
             // make a generalized form of `ty` and instantiate with
@@ -230,10 +228,10 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
                         EqTo => self.generalize(a_ty, b_vid, false),
                         BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true),
                     });
-                    debug!("instantiate(a_ty={}, dir={:?}, \
-                                        b_vid={}, generalized_ty={})",
-                           a_ty.repr(tcx), dir, b_vid.repr(tcx),
-                           generalized_ty.repr(tcx));
+                    debug!("instantiate(a_ty={:?}, dir={:?}, \
+                                        b_vid={:?}, generalized_ty={:?})",
+                           a_ty, dir, b_vid,
+                           generalized_ty);
                     self.infcx.type_variables
                         .borrow_mut()
                         .instantiate_and_push(
@@ -335,8 +333,8 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
             ty::ReEarlyBound(..) => {
                 self.tcx().sess.span_bug(
                     self.span,
-                    &format!("Encountered early bound region when generalizing: {}",
-                            r.repr(self.tcx())));
+                    &format!("Encountered early bound region when generalizing: {:?}",
+                            r));
             }
 
             // Always make a fresh region variable for skolemized regions;
diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs
index da0bca89042..cbbf73d9420 100644
--- a/src/librustc/middle/infer/equate.rs
+++ b/src/librustc/middle/infer/equate.rs
@@ -16,7 +16,6 @@ use super::type_variable::{EqTo};
 use middle::ty::{self, Ty};
 use middle::ty::TyVar;
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::{Repr};
 
 pub struct Equate<'a, 'tcx: 'a> {
     fields: CombineFields<'a, 'tcx>
@@ -45,8 +44,8 @@ impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
     }
 
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("{}.tys({}, {})", self.tag(),
-               a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+        debug!("{}.tys({:?}, {:?})", self.tag(),
+               a, b);
         if a == b { return Ok(a); }
 
         let infcx = self.fields.infcx;
@@ -75,10 +74,10 @@ impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
     }
 
     fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
-        debug!("{}.regions({}, {})",
+        debug!("{}.regions({:?}, {:?})",
                self.tag(),
-               a.repr(self.fields.infcx.tcx),
-               b.repr(self.fields.infcx.tcx));
+               a,
+               b);
         let origin = Subtype(self.fields.trace.clone());
         self.fields.infcx.region_vars.make_eqregion(origin, a, b);
         Ok(a)
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 37cc5d34299..4ae618d45b7 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -75,25 +75,141 @@ use std::collections::HashSet;
 use ast_map;
 use middle::def;
 use middle::infer;
+use middle::region;
 use middle::subst;
 use middle::ty::{self, Ty};
 use middle::ty::{Region, ReFree};
+
 use std::cell::{Cell, RefCell};
 use std::char::from_u32;
-use std::string::String;
+use std::fmt;
 use syntax::ast;
 use syntax::ast_util::name_to_dummy_lifetime;
 use syntax::owned_slice::OwnedSlice;
-use syntax::codemap;
+use syntax::codemap::{Pos, Span};
 use syntax::parse::token;
 use syntax::print::pprust;
 use syntax::ptr::P;
-use util::ppaux::bound_region_to_string;
-use util::ppaux::note_and_explain_region;
 
-// Note: only import UserString, not Repr, since user-facing error
-// messages shouldn't include debug serializations.
-use util::ppaux::UserString;
+pub fn note_and_explain_region(tcx: &ty::ctxt,
+                               prefix: &str,
+                               region: ty::Region,
+                               suffix: &str) {
+    fn item_scope_tag(item: &ast::Item) -> &'static str {
+        match item.node {
+            ast::ItemImpl(..) => "impl",
+            ast::ItemStruct(..) => "struct",
+            ast::ItemEnum(..) => "enum",
+            ast::ItemTrait(..) => "trait",
+            ast::ItemFn(..) => "function body",
+            _ => "item"
+        }
+    }
+
+    fn explain_span(tcx: &ty::ctxt, heading: &str, span: Span)
+                    -> (String, Option<Span>) {
+        let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo);
+        (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
+         Some(span))
+    }
+
+    let (description, span) = match region {
+        ty::ReScope(scope) => {
+            let new_string;
+            let unknown_scope = || {
+                format!("{}unknown scope: {:?}{}.  Please report a bug.",
+                        prefix, scope, suffix)
+            };
+            let span = match scope.span(&tcx.map) {
+                Some(s) => s,
+                None => return tcx.sess.note(&unknown_scope())
+            };
+            let tag = match tcx.map.find(scope.node_id()) {
+                Some(ast_map::NodeBlock(_)) => "block",
+                Some(ast_map::NodeExpr(expr)) => match expr.node {
+                    ast::ExprCall(..) => "call",
+                    ast::ExprMethodCall(..) => "method call",
+                    ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let",
+                    ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) =>  "while let",
+                    ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) =>  "for",
+                    ast::ExprMatch(..) => "match",
+                    _ => "expression",
+                },
+                Some(ast_map::NodeStmt(_)) => "statement",
+                Some(ast_map::NodeItem(it)) => item_scope_tag(&*it),
+                Some(_) | None => {
+                    return tcx.sess.span_note(span, &unknown_scope());
+                }
+            };
+            let scope_decorated_tag = match scope {
+                region::CodeExtent::Misc(_) => tag,
+                region::CodeExtent::ParameterScope { .. } => {
+                    "scope of parameters for function"
+                }
+                region::CodeExtent::DestructionScope(_) => {
+                    new_string = format!("destruction scope surrounding {}", tag);
+                    &new_string[..]
+                }
+                region::CodeExtent::Remainder(r) => {
+                    new_string = format!("block suffix following statement {}",
+                                         r.first_statement_index);
+                    &new_string[..]
+                }
+            };
+            explain_span(tcx, scope_decorated_tag, span)
+        }
+
+        ty::ReFree(ref fr) => {
+            let prefix = match fr.bound_region {
+                ty::BrAnon(idx) => {
+                    format!("the anonymous lifetime #{} defined on", idx + 1)
+                }
+                ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
+                _ => {
+                    format!("the lifetime {} as defined on",
+                            fr.bound_region)
+                }
+            };
+
+            match tcx.map.find(fr.scope.node_id) {
+                Some(ast_map::NodeBlock(ref blk)) => {
+                    let (msg, opt_span) = explain_span(tcx, "block", blk.span);
+                    (format!("{} {}", prefix, msg), opt_span)
+                }
+                Some(ast_map::NodeItem(it)) => {
+                    let tag = item_scope_tag(&*it);
+                    let (msg, opt_span) = explain_span(tcx, tag, it.span);
+                    (format!("{} {}", prefix, msg), opt_span)
+                }
+                Some(_) | None => {
+                    // this really should not happen
+                    (format!("{} unknown free region bounded by scope {:?}",
+                             prefix, fr.scope), None)
+                }
+            }
+        }
+
+        ty::ReStatic => ("the static lifetime".to_owned(), None),
+
+        ty::ReEmpty => ("the empty lifetime".to_owned(), None),
+
+        ty::ReEarlyBound(ref data) => {
+            (format!("{}", token::get_name(data.name)), None)
+        }
+
+        // I believe these cases should not occur (except when debugging,
+        // perhaps)
+        ty::ReInfer(_) | ty::ReLateBound(..) => {
+            (format!("lifetime {:?}", region), None)
+        }
+    };
+    let message = format!("{}{}{}", prefix, description, suffix);
+    if let Some(span) = span {
+        tcx.sess.span_note(span, &message);
+    } else {
+        tcx.sess.note(&message);
+    }
+}
 
 pub trait ErrorReporting<'tcx> {
     fn report_region_errors(&self,
@@ -110,7 +226,7 @@ pub trait ErrorReporting<'tcx> {
 
     fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
 
-    fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
+    fn expected_found_str<T: fmt::Display + Resolvable<'tcx>>(
         &self,
         exp_found: &ty::expected_found<T>)
         -> Option<String>;
@@ -162,7 +278,7 @@ trait ErrorReportingHelpers<'tcx> {
                                 ident: ast::Ident,
                                 opt_explicit_self: Option<&ast::ExplicitSelf_>,
                                 generics: &ast::Generics,
-                                span: codemap::Span);
+                                span: Span);
 }
 
 impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
@@ -361,7 +477,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
             "{}: {} ({})",
                  trace.origin,
                  expected_found_str,
-                 ty::type_err_to_str(self.tcx, terr));
+                 terr);
 
         match trace.origin {
             infer::MatchExpressionArm(_, arm_span) =>
@@ -388,7 +504,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
+    fn expected_found_str<T: fmt::Display + Resolvable<'tcx>>(
         &self,
         exp_found: &ty::expected_found<T>)
         -> Option<String>
@@ -404,8 +520,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
         }
 
         Some(format!("expected `{}`, found `{}`",
-                     expected.user_string(self.tcx),
-                     found.user_string(self.tcx)))
+                     expected,
+                     found))
     }
 
     fn report_generic_bound_failure(&self,
@@ -421,9 +537,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
 
         let labeled_user_string = match bound_kind {
             GenericKind::Param(ref p) =>
-                format!("the parameter type `{}`", p.user_string(self.tcx)),
+                format!("the parameter type `{}`", p),
             GenericKind::Projection(ref p) =>
-                format!("the associated type `{}`", p.user_string(self.tcx)),
+                format!("the associated type `{}`", p),
         };
 
         match sub {
@@ -435,8 +551,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                     origin.span(),
                     &format!(
                         "consider adding an explicit lifetime bound `{}: {}`...",
-                        bound_kind.user_string(self.tcx),
-                        sub.user_string(self.tcx)));
+                        bound_kind,
+                        sub));
             }
 
             ty::ReStatic => {
@@ -447,7 +563,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                     origin.span(),
                     &format!(
                         "consider adding an explicit lifetime bound `{}: 'static`...",
-                        bound_kind.user_string(self.tcx)));
+                        bound_kind));
             }
 
             _ => {
@@ -459,7 +575,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                     origin.span(),
                     &format!(
                         "consider adding an explicit lifetime bound for `{}`",
-                        bound_kind.user_string(self.tcx)));
+                        bound_kind));
                 note_and_explain_region(
                     self.tcx,
                     &format!("{} must be valid for ", labeled_user_string),
@@ -1431,7 +1547,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
                                 ident: ast::Ident,
                                 opt_explicit_self: Option<&ast::ExplicitSelf_>,
                                 generics: &ast::Generics,
-                                span: codemap::Span) {
+                                span: Span) {
         let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, ident,
                                                  opt_explicit_self, generics);
         let msg = format!("consider using an explicit lifetime \
@@ -1441,6 +1557,13 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
 
     fn report_inference_failure(&self,
                                 var_origin: RegionVariableOrigin) {
+        let br_string = |br: ty::BoundRegion| {
+            let mut s = br.to_string();
+            if !s.is_empty() {
+                s.push_str(" ");
+            }
+            s
+        };
         let var_description = match var_origin {
             infer::MiscVariable(_) => "".to_string(),
             infer::PatternRegion(_) => " for pattern".to_string(),
@@ -1448,17 +1571,15 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
             infer::Autoref(_) => " for autoref".to_string(),
             infer::Coercion(_) => " for automatic coercion".to_string(),
             infer::LateBoundRegion(_, br, infer::FnCall) => {
-                format!(" for {}in function call",
-                        bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
+                format!(" for lifetime parameter {}in function call",
+                        br_string(br))
             }
             infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
-                format!(" for {}in generic type",
-                        bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
+                format!(" for lifetime parameter {}in generic type", br_string(br))
             }
             infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
-                format!(" for {}in trait containing associated type `{}`",
-                        bound_region_to_string(self.tcx, "lifetime parameter ", true, br),
-                        token::get_name(type_name))
+                format!(" for lifetime parameter {}in trait containing associated type `{}`",
+                        br_string(br), token::get_name(type_name))
             }
             infer::EarlyBoundRegion(_, name) => {
                 format!(" for lifetime parameter `{}`",
diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs
index 5822fb0f2d4..d6b03266b1f 100644
--- a/src/librustc/middle/infer/glb.rs
+++ b/src/librustc/middle/infer/glb.rs
@@ -16,7 +16,6 @@ use super::Subtype;
 
 use middle::ty::{self, Ty};
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::Repr;
 
 /// "Greatest lower bound" (common subtype)
 pub struct Glb<'a, 'tcx: 'a> {
@@ -55,10 +54,10 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
     }
 
     fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
-        debug!("{}.regions({}, {})",
+        debug!("{}.regions({:?}, {:?})",
                self.tag(),
-               a.repr(self.fields.infcx.tcx),
-               b.repr(self.fields.infcx.tcx));
+               a,
+               b);
 
         let origin = Subtype(self.fields.trace.clone());
         Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b))
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index 3d946aa2fbc..7b26f6b1537 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -20,7 +20,6 @@ use middle::ty_fold::{self, TypeFoldable};
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
 use syntax::codemap::Span;
 use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::Repr;
 
 pub trait HigherRankedRelations<'a,'tcx> {
     fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
@@ -46,10 +45,8 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
                             -> RelateResult<'tcx, Binder<T>>
         where T: Relate<'a,'tcx>
     {
-        let tcx = self.infcx.tcx;
-
-        debug!("higher_ranked_sub(a={}, b={})",
-               a.repr(tcx), b.repr(tcx));
+        debug!("higher_ranked_sub(a={:?}, b={:?})",
+               a, b);
 
         // Rather than checking the subtype relationship between `a` and `b`
         // as-is, we need to do some extra work here in order to make sure
@@ -75,8 +72,8 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
             let (b_prime, skol_map) =
                 self.infcx.skolemize_late_bound_regions(b, snapshot);
 
-            debug!("a_prime={}", a_prime.repr(tcx));
-            debug!("b_prime={}", b_prime.repr(tcx));
+            debug!("a_prime={:?}", a_prime);
+            debug!("b_prime={:?}", b_prime);
 
             // Compare types now that bound regions have been replaced.
             let result = try!(self.sub().relate(&a_prime, &b_prime));
@@ -98,8 +95,8 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
                 }
             }
 
-            debug!("higher_ranked_sub: OK result={}",
-                   result.repr(tcx));
+            debug!("higher_ranked_sub: OK result={:?}",
+                   result);
 
             Ok(ty::Binder(result))
         });
@@ -125,7 +122,7 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
                 try!(self.lub().relate(&a_with_fresh, &b_with_fresh));
             let result0 =
                 self.infcx.resolve_type_vars_if_possible(&result0);
-            debug!("lub result0 = {}", result0.repr(self.tcx()));
+            debug!("lub result0 = {:?}", result0);
 
             // Generalize the regions appearing in result0 if possible
             let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
@@ -137,10 +134,10 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
                     |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
                                                     &new_vars, &a_map, r));
 
-            debug!("lub({},{}) = {}",
-                   a.repr(self.tcx()),
-                   b.repr(self.tcx()),
-                   result1.repr(self.tcx()));
+            debug!("lub({:?},{:?}) = {:?}",
+                   a,
+                   b,
+                   result1);
 
             Ok(ty::Binder(result1))
         });
@@ -198,8 +195,8 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
     fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
         where T: Relate<'a,'tcx>
     {
-        debug!("higher_ranked_glb({}, {})",
-               a.repr(self.tcx()), b.repr(self.tcx()));
+        debug!("higher_ranked_glb({:?}, {:?})",
+               a, b);
 
         // Make a snapshot so we can examine "all bindings that were
         // created as part of this type comparison".
@@ -219,7 +216,7 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
                 try!(self.glb().relate(&a_with_fresh, &b_with_fresh));
             let result0 =
                 self.infcx.resolve_type_vars_if_possible(&result0);
-            debug!("glb result0 = {}", result0.repr(self.tcx()));
+            debug!("glb result0 = {:?}", result0);
 
             // Generalize the regions appearing in result0 if possible
             let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
@@ -233,10 +230,10 @@ impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> {
                                                     &a_map, &a_vars, &b_vars,
                                                     r));
 
-            debug!("glb({},{}) = {}",
-                   a.repr(self.tcx()),
-                   b.repr(self.tcx()),
-                   result1.repr(self.tcx()));
+            debug!("glb({:?},{:?}) = {:?}",
+                   a,
+                   b,
+                   result1);
 
             Ok(ty::Binder(result1))
         });
@@ -451,9 +448,9 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
             !escaping_region_vars.contains(&r)
         });
 
-        debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}",
-               region_vars.repr(self.tcx),
-               escaping_types.repr(self.tcx));
+        debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
+               region_vars,
+               escaping_types);
 
         region_vars
     }
@@ -520,7 +517,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                                binder: &ty::Binder<T>,
                                                snapshot: &CombinedSnapshot)
                                                -> (T, SkolemizationMap)
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     /*!
      * Replace all regions bound by `binder` with skolemized regions and
@@ -534,10 +531,10 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
         infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
     });
 
-    debug!("skolemize_bound_regions(binder={}, result={}, map={})",
-           binder.repr(infcx.tcx),
-           result.repr(infcx.tcx),
-           map.repr(infcx.tcx));
+    debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
+           binder,
+           result,
+           map);
 
     (result, map)
 }
@@ -555,8 +552,8 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
      * hold. See `README.md` for more details.
      */
 
-    debug!("leak_check: skol_map={}",
-           skol_map.repr(infcx.tcx));
+    debug!("leak_check: skol_map={:?}",
+           skol_map);
 
     let new_vars = infcx.region_vars_confined_to_snapshot(snapshot);
     for (&skol_br, &skol) in skol_map {
@@ -573,10 +570,10 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                 }
             };
 
-            debug!("{} (which replaced {}) is tainted by {}",
-                   skol.repr(infcx.tcx),
-                   skol_br.repr(infcx.tcx),
-                   tainted_region.repr(infcx.tcx));
+            debug!("{:?} (which replaced {:?}) is tainted by {:?}",
+                   skol,
+                   skol_br,
+                   tainted_region);
 
             // A is not as polymorphic as B:
             return Err((skol_br, tainted_region));
@@ -618,13 +615,13 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                              snapshot: &CombinedSnapshot,
                              value: &T)
                              -> T
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok());
 
-    debug!("plug_leaks(skol_map={}, value={})",
-           skol_map.repr(infcx.tcx),
-           value.repr(infcx.tcx));
+    debug!("plug_leaks(skol_map={:?}, value={:?})",
+           skol_map,
+           value);
 
     // Compute a mapping from the "taint set" of each skolemized
     // region back to the `ty::BoundRegion` that it originally
@@ -640,8 +637,8 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
         })
         .collect();
 
-    debug!("plug_leaks: inv_skol_map={}",
-           inv_skol_map.repr(infcx.tcx));
+    debug!("plug_leaks: inv_skol_map={:?}",
+           inv_skol_map);
 
     // Remove any instantiated type variables from `value`; those can hide
     // references to regions from the `fold_regions` code below.
@@ -669,8 +666,8 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
         }
     });
 
-    debug!("plug_leaks: result={}",
-           result.repr(infcx.tcx));
+    debug!("plug_leaks: result={:?}",
+           result);
 
     result
 }
diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs
index d634b8231eb..7b34fda2406 100644
--- a/src/librustc/middle/infer/lattice.rs
+++ b/src/librustc/middle/infer/lattice.rs
@@ -35,7 +35,6 @@ use super::InferCtxt;
 use middle::ty::TyVar;
 use middle::ty::{self, Ty};
 use middle::ty_relate::{RelateResult, TypeRelation};
-use util::ppaux::Repr;
 
 pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> {
     fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
@@ -51,10 +50,10 @@ pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L,
                                                         -> RelateResult<'tcx, Ty<'tcx>>
     where 'tcx: 'a
 {
-    debug!("{}.lattice_tys({}, {})",
+    debug!("{}.lattice_tys({:?}, {:?})",
            this.tag(),
-           a.repr(this.tcx()),
-           b.repr(this.tcx()));
+           a,
+           b);
 
     if a == b {
         return Ok(a);
diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs
index f456687be13..9d993ead5ca 100644
--- a/src/librustc/middle/infer/lub.rs
+++ b/src/librustc/middle/infer/lub.rs
@@ -16,7 +16,6 @@ use super::Subtype;
 
 use middle::ty::{self, Ty};
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::Repr;
 
 /// "Least upper bound" (common supertype)
 pub struct Lub<'a, 'tcx: 'a> {
@@ -55,10 +54,10 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
     }
 
     fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
-        debug!("{}.regions({}, {})",
+        debug!("{}.regions({:?}, {:?})",
                self.tag(),
-               a.repr(self.tcx()),
-               b.repr(self.tcx()));
+               a,
+               b);
 
         let origin = Subtype(self.fields.trace.clone());
         Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b))
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index c0e3a5e8961..2df335b5c3c 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -36,8 +36,6 @@ use syntax::ast;
 use syntax::codemap;
 use syntax::codemap::Span;
 use util::nodemap::FnvHashMap;
-use util::ppaux::ty_to_string;
-use util::ppaux::{Repr, UserString};
 
 use self::combine::CombineFields;
 use self::region_inference::{RegionVarBindings, RegionSnapshot};
@@ -161,7 +159,7 @@ pub enum ValuePairs<'tcx> {
 /// encounter an error or subtyping constraint.
 ///
 /// See `error_reporting.rs` for more details.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct TypeTrace<'tcx> {
     origin: TypeOrigin,
     values: ValuePairs<'tcx>,
@@ -331,8 +329,8 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                                   b: Ty<'tcx>)
                                   -> Ty<'tcx>
 {
-    debug!("common_supertype({}, {})",
-           a.repr(cx.tcx), b.repr(cx.tcx));
+    debug!("common_supertype({:?}, {:?})",
+           a, b);
 
     let trace = TypeTrace {
         origin: origin,
@@ -356,7 +354,7 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                           b: Ty<'tcx>)
                           -> UnitResult<'tcx>
 {
-    debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+    debug!("mk_subty({:?} <: {:?})", a, b);
     cx.sub_types(a_is_expected, origin, a, b)
 }
 
@@ -364,7 +362,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                               a: Ty<'tcx>,
                               b: Ty<'tcx>)
                               -> UnitResult<'tcx> {
-    debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+    debug!("can_mk_subty({:?} <: {:?})", a, b);
     cx.probe(|_| {
         let trace = TypeTrace {
             origin: Misc(codemap::DUMMY_SP),
@@ -384,7 +382,7 @@ pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                          origin: SubregionOrigin<'tcx>,
                          a: ty::Region,
                          b: ty::Region) {
-    debug!("mk_subr({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+    debug!("mk_subr({:?} <: {:?})", a, b);
     let snapshot = cx.region_vars.start_snapshot();
     cx.region_vars.make_subregion(origin, a, b);
     cx.region_vars.commit(snapshot);
@@ -397,7 +395,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                          b: Ty<'tcx>)
                          -> UnitResult<'tcx>
 {
-    debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+    debug!("mk_eqty({:?} <: {:?})", a, b);
     cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
 }
 
@@ -408,8 +406,8 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                                    b: ty::PolyTraitRef<'tcx>)
                                    -> UnitResult<'tcx>
 {
-    debug!("mk_sub_trait_refs({} <: {})",
-           a.repr(cx.tcx), b.repr(cx.tcx));
+    debug!("mk_sub_trait_refs({:?} <: {:?})",
+           a, b);
     cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
 }
 
@@ -638,7 +636,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                      b: Ty<'tcx>)
                      -> UnitResult<'tcx>
     {
-        debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
+        debug!("sub_types({:?} <: {:?})", a, b);
         self.commit_if_ok(|_| {
             let trace = TypeTrace::types(origin, a_is_expected, a, b);
             self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
@@ -665,9 +663,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                           b: ty::TraitRef<'tcx>)
                           -> UnitResult<'tcx>
     {
-        debug!("sub_trait_refs({} <: {})",
-               a.repr(self.tcx),
-               b.repr(self.tcx));
+        debug!("sub_trait_refs({:?} <: {:?})",
+               a,
+               b);
         self.commit_if_ok(|_| {
             let trace = TypeTrace {
                 origin: origin,
@@ -684,9 +682,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                b: ty::PolyTraitRef<'tcx>)
                                -> UnitResult<'tcx>
     {
-        debug!("sub_poly_trait_refs({} <: {})",
-               a.repr(self.tcx),
-               b.repr(self.tcx));
+        debug!("sub_poly_trait_refs({:?} <: {:?})",
+               a,
+               b);
         self.commit_if_ok(|_| {
             let trace = TypeTrace {
                 origin: origin,
@@ -709,7 +707,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                            value: &ty::Binder<T>,
                                            snapshot: &CombinedSnapshot)
                                            -> (T, SkolemizationMap)
-        where T : TypeFoldable<'tcx> + Repr<'tcx>
+        where T : TypeFoldable<'tcx>
     {
         /*! See `higher_ranked::skolemize_late_bound_regions` */
 
@@ -734,7 +732,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                          snapshot: &CombinedSnapshot,
                          value: &T)
                          -> T
-        where T : TypeFoldable<'tcx> + Repr<'tcx>
+        where T : TypeFoldable<'tcx>
     {
         /*! See `higher_ranked::plug_leaks` */
 
@@ -862,8 +860,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
-        ty_to_string(self.tcx,
-                     self.resolve_type_vars_if_possible(&t))
+        self.resolve_type_vars_if_possible(&t).to_string()
     }
 
     pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
@@ -872,8 +869,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
-        let t = self.resolve_type_vars_if_possible(t);
-        t.user_string(self.tcx)
+        self.resolve_type_vars_if_possible(t).to_string()
     }
 
     pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
@@ -981,7 +977,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             Some(t) if ty::type_is_error(t) => (),
             _ => {
                 let error_str = err.map_or("".to_string(), |t_err| {
-                    format!(" ({})", ty::type_err_to_str(self.tcx, t_err))
+                    format!(" ({})", t_err)
                 });
 
                 self.tcx.sess.span_err(sp, &format!("{}{}",
@@ -1035,7 +1031,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         lbrct: LateBoundRegionConversionTime,
         value: &ty::Binder<T>)
         -> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
-        where T : TypeFoldable<'tcx> + Repr<'tcx>
+        where T : TypeFoldable<'tcx>
     {
         ty_fold::replace_late_bound_regions(
             self.tcx,
@@ -1049,18 +1045,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                 kind: GenericKind<'tcx>,
                                 a: ty::Region,
                                 bs: Vec<ty::Region>) {
-        debug!("verify_generic_bound({}, {} <: {})",
-               kind.repr(self.tcx),
-               a.repr(self.tcx),
-               bs.repr(self.tcx));
+        debug!("verify_generic_bound({:?}, {:?} <: {:?})",
+               kind,
+               a,
+               bs);
 
         self.region_vars.verify_generic_bound(origin, kind, a, bs);
     }
 
     pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>
-        where T: Relate<'b,'tcx> + Repr<'tcx>
+        where T: Relate<'b,'tcx> + fmt::Debug
     {
-        debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
+        debug!("can_equate({:?}, {:?})", a, b);
         self.probe(|_| {
             // Gin up a dummy trace, since this won't be committed
             // anyhow. We should make this typetrace stuff more
@@ -1101,9 +1097,9 @@ impl<'tcx> TypeTrace<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for TypeTrace<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt) -> String {
-        format!("TypeTrace({})", self.origin.repr(tcx))
+impl<'tcx> fmt::Debug for TypeTrace<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TypeTrace({:?})", self.origin)
     }
 }
 
@@ -1125,44 +1121,6 @@ impl TypeOrigin {
     }
 }
 
-impl<'tcx> Repr<'tcx> for TypeOrigin {
-    fn repr(&self, tcx: &ty::ctxt) -> String {
-        match *self {
-            MethodCompatCheck(a) => {
-                format!("MethodCompatCheck({})", a.repr(tcx))
-            }
-            ExprAssignable(a) => {
-                format!("ExprAssignable({})", a.repr(tcx))
-            }
-            Misc(a) => format!("Misc({})", a.repr(tcx)),
-            RelateTraitRefs(a) => {
-                format!("RelateTraitRefs({})", a.repr(tcx))
-            }
-            RelateSelfType(a) => {
-                format!("RelateSelfType({})", a.repr(tcx))
-            }
-            RelateOutputImplTypes(a) => {
-                format!("RelateOutputImplTypes({})", a.repr(tcx))
-            }
-            MatchExpressionArm(a, b) => {
-                format!("MatchExpressionArm({}, {})", a.repr(tcx), b.repr(tcx))
-            }
-            IfExpression(a) => {
-                format!("IfExpression({})", a.repr(tcx))
-            }
-            IfExpressionWithNoElse(a) => {
-                format!("IfExpressionWithNoElse({})", a.repr(tcx))
-            }
-            RangeExpression(a) => {
-                format!("RangeExpression({})", a.repr(tcx))
-            }
-            EquatePredicate(a) => {
-                format!("EquatePredicate({})", a.repr(tcx))
-            }
-        }
-    }
-}
-
 impl<'tcx> SubregionOrigin<'tcx> {
     pub fn span(&self) -> Span {
         match *self {
@@ -1192,70 +1150,6 @@ impl<'tcx> SubregionOrigin<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            Subtype(ref a) => {
-                format!("Subtype({})", a.repr(tcx))
-            }
-            InfStackClosure(a) => {
-                format!("InfStackClosure({})", a.repr(tcx))
-            }
-            InvokeClosure(a) => {
-                format!("InvokeClosure({})", a.repr(tcx))
-            }
-            DerefPointer(a) => {
-                format!("DerefPointer({})", a.repr(tcx))
-            }
-            FreeVariable(a, b) => {
-                format!("FreeVariable({}, {})", a.repr(tcx), b)
-            }
-            IndexSlice(a) => {
-                format!("IndexSlice({})", a.repr(tcx))
-            }
-            RelateObjectBound(a) => {
-                format!("RelateObjectBound({})", a.repr(tcx))
-            }
-            RelateParamBound(a, b) => {
-                format!("RelateParamBound({},{})",
-                        a.repr(tcx),
-                        b.repr(tcx))
-            }
-            RelateRegionParamBound(a) => {
-                format!("RelateRegionParamBound({})",
-                        a.repr(tcx))
-            }
-            RelateDefaultParamBound(a, b) => {
-                format!("RelateDefaultParamBound({},{})",
-                        a.repr(tcx),
-                        b.repr(tcx))
-            }
-            Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
-            ReborrowUpvar(a, b) => {
-                format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
-            }
-            ReferenceOutlivesReferent(_, a) => {
-                format!("ReferenceOutlivesReferent({})", a.repr(tcx))
-            }
-            ExprTypeIsNotInScope(a, b) => {
-                format!("ExprTypeIsNotInScope({}, {})",
-                        a.repr(tcx),
-                        b.repr(tcx))
-            }
-            BindingTypeIsNotValidAtDecl(a) => {
-                format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
-            }
-            CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)),
-            CallArg(a) => format!("CallArg({})", a.repr(tcx)),
-            CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
-            Operand(a) => format!("Operand({})", a.repr(tcx)),
-            AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
-            AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
-            SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)),
-        }
-    }
-}
-
 impl RegionVariableOrigin {
     pub fn span(&self) -> Span {
         match *self {
@@ -1271,33 +1165,3 @@ impl RegionVariableOrigin {
         }
     }
 }
-
-impl<'tcx> Repr<'tcx> for RegionVariableOrigin {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            MiscVariable(a) => {
-                format!("MiscVariable({})", a.repr(tcx))
-            }
-            PatternRegion(a) => {
-                format!("PatternRegion({})", a.repr(tcx))
-            }
-            AddrOfRegion(a) => {
-                format!("AddrOfRegion({})", a.repr(tcx))
-            }
-            Autoref(a) => format!("Autoref({})", a.repr(tcx)),
-            Coercion(a) => format!("Coercion({})", a.repr(tcx)),
-            EarlyBoundRegion(a, b) => {
-                format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx))
-            }
-            LateBoundRegion(a, b, c) => {
-                format!("LateBoundRegion({},{},{:?})", a.repr(tcx), b.repr(tcx), c)
-            }
-            BoundRegionInCoherence(a) => {
-                format!("bound_regionInCoherence({})", a.repr(tcx))
-            }
-            UpvarRegion(a, b) => {
-                format!("UpvarRegion({}, {})", a.repr(tcx), b.repr(tcx))
-            }
-        }
-    }
-}
diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs
index 5a06a5193bf..869f4d011ce 100644
--- a/src/librustc/middle/infer/region_inference/graphviz.rs
+++ b/src/librustc/middle/infer/region_inference/graphviz.rs
@@ -24,7 +24,6 @@ use super::Constraint;
 use middle::infer::SubregionOrigin;
 use middle::infer::region_inference::RegionVarBindings;
 use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::Repr;
 
 use std::borrow::Cow;
 use std::collections::hash_map::Entry::Vacant;
@@ -191,13 +190,13 @@ impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
             Node::RegionVid(n_vid) =>
                 dot::LabelText::label(format!("{:?}", n_vid)),
             Node::Region(n_rgn) =>
-                dot::LabelText::label(format!("{}", n_rgn.repr(self.tcx))),
+                dot::LabelText::label(format!("{:?}", n_rgn)),
         }
     }
     fn edge_label(&self, e: &Edge) -> dot::LabelText {
         match *e {
             Edge::Constraint(ref c) =>
-                dot::LabelText::label(format!("{}", self.map.get(c).unwrap().repr(self.tcx))),
+                dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap())),
             Edge::EnclScope(..) =>
                 dot::LabelText::label(format!("(enclosed)")),
         }
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index a6906e7b2d3..ddd352fcb43 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -30,10 +30,10 @@ use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
 use middle::ty_relate::RelateResult;
 use util::common::indenter;
 use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::{Repr, UserString};
 
 use std::cell::{Cell, RefCell};
 use std::cmp::Ordering::{self, Less, Greater, Equal};
+use std::fmt;
 use std::iter::repeat;
 use std::u32;
 use syntax::ast;
@@ -68,7 +68,7 @@ pub enum Verify<'tcx> {
     VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec<Region>),
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
 pub enum GenericKind<'tcx> {
     Param(ty::ParamTy),
     Projection(ty::ProjectionTy<'tcx>),
@@ -323,8 +323,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         if self.in_snapshot() {
             self.undo_log.borrow_mut().push(AddVar(vid));
         }
-        debug!("created new region variable {:?} with origin {}",
-               vid, origin.repr(self.tcx));
+        debug!("created new region variable {:?} with origin {:?}",
+               vid, origin);
         return vid;
     }
 
@@ -391,8 +391,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: add_constraint({})",
-               constraint.repr(self.tcx));
+        debug!("RegionVarBindings: add_constraint({:?})",
+               constraint);
 
         if self.constraints.borrow_mut().insert(constraint, origin).is_none() {
             if self.in_snapshot() {
@@ -406,8 +406,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         // cannot add verifys once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: add_verify({})",
-               verify.repr(self.tcx));
+        debug!("RegionVarBindings: add_verify({:?})",
+               verify);
 
         let mut verifys = self.verifys.borrow_mut();
         let index = verifys.len();
@@ -425,8 +425,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 
         let mut givens = self.givens.borrow_mut();
         if givens.insert((sub, sup)) {
-            debug!("add_given({} <= {:?})",
-                   sub.repr(self.tcx),
+            debug!("add_given({:?} <= {:?})",
+                   sub,
                    sup);
 
             self.undo_log.borrow_mut().push(AddGiven(sub, sup));
@@ -452,10 +452,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: make_subregion({}, {}) due to {}",
-               sub.repr(self.tcx),
-               sup.repr(self.tcx),
-               origin.repr(self.tcx));
+        debug!("RegionVarBindings: make_subregion({:?}, {:?}) due to {:?}",
+               sub,
+               sup,
+               origin);
 
         match (sub, sup) {
           (ReEarlyBound(..), ReEarlyBound(..)) => {
@@ -471,9 +471,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
           (_, ReLateBound(..)) => {
             self.tcx.sess.span_bug(
                 origin.span(),
-                &format!("cannot relate bound region: {} <= {}",
-                        sub.repr(self.tcx),
-                        sup.repr(self.tcx)));
+                &format!("cannot relate bound region: {:?} <= {:?}",
+                        sub,
+                        sup));
           }
           (_, ReStatic) => {
             // all regions are subregions of static, so we can ignore this
@@ -510,9 +510,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: lub_regions({}, {})",
-               a.repr(self.tcx),
-               b.repr(self.tcx));
+        debug!("RegionVarBindings: lub_regions({:?}, {:?})",
+               a,
+               b);
         match (a, b) {
             (ReStatic, _) | (_, ReStatic) => {
                 ReStatic // nothing lives longer than static
@@ -535,9 +535,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
-        debug!("RegionVarBindings: glb_regions({}, {})",
-               a.repr(self.tcx),
-               b.repr(self.tcx));
+        debug!("RegionVarBindings: glb_regions({:?}, {:?})",
+               a,
+               b);
         match (a, b) {
             (ReStatic, r) | (r, ReStatic) => {
                 // static lives longer than everything else
@@ -563,7 +563,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             }
             Some(ref values) => {
                 let r = lookup(values, rid);
-                debug!("resolve_var({:?}) = {}", rid, r.repr(self.tcx));
+                debug!("resolve_var({:?}) = {:?}", rid, r);
                 r
             }
         }
@@ -620,7 +620,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
     /// made---`r0` itself will be the first entry. This is used when checking whether skolemized
     /// regions are being improperly related to other regions.
     pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec<Region> {
-        debug!("tainted(mark={:?}, r0={})", mark, r0.repr(self.tcx));
+        debug!("tainted(mark={:?}, r0={:?})", mark, r0);
         let _indenter = indenter();
 
         // `result_set` acts as a worklist: we explore all outgoing
@@ -731,9 +731,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
           (ReEarlyBound(..), _) |
           (_, ReEarlyBound(..)) => {
             self.tcx.sess.bug(
-                &format!("cannot relate bound region: LUB({}, {})",
-                        a.repr(self.tcx),
-                        b.repr(self.tcx)));
+                &format!("cannot relate bound region: LUB({:?}, {:?})",
+                        a,
+                        b));
           }
 
           (ReStatic, _) | (_, ReStatic) => {
@@ -836,9 +836,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             (ReEarlyBound(..), _) |
             (_, ReEarlyBound(..)) => {
               self.tcx.sess.bug(
-                  &format!("cannot relate bound region: GLB({}, {})",
-                          a.repr(self.tcx),
-                          b.repr(self.tcx)));
+                  &format!("cannot relate bound region: GLB({:?}, {:?})",
+                          a,
+                          b));
             }
 
             (ReStatic, r) | (r, ReStatic) => {
@@ -959,7 +959,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 #[derive(Copy, Clone, PartialEq, Debug)]
 enum Classification { Expanding, Contracting }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum VarValue { NoValue, Value(Region), ErrorValue }
 
 struct VarData {
@@ -1013,18 +1013,18 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
     fn dump_constraints(&self) {
         debug!("----() Start constraint listing ()----");
         for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
-            debug!("Constraint {} => {}", idx, constraint.repr(self.tcx));
+            debug!("Constraint {} => {:?}", idx, constraint);
         }
     }
 
     fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Expansion", |constraint| {
-            debug!("expansion: constraint={} origin={}",
-                   constraint.repr(self.tcx),
+            debug!("expansion: constraint={:?} origin={:?}",
+                   constraint,
                    self.constraints.borrow()
                                    .get(constraint)
                                    .unwrap()
-                                   .repr(self.tcx));
+                                   );
             match *constraint {
               ConstrainRegSubVar(a_region, b_vid) => {
                 let b_data = &mut var_data[b_vid.index as usize];
@@ -1054,10 +1054,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                    b_data: &mut VarData)
                    -> bool
     {
-        debug!("expand_node({}, {:?} == {})",
-               a_region.repr(self.tcx),
+        debug!("expand_node({:?}, {:?} == {:?})",
+               a_region,
                b_vid,
-               b_data.value.repr(self.tcx));
+               b_data.value);
 
         // Check if this relationship is implied by a given.
         match a_region {
@@ -1073,8 +1073,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         b_data.classification = Expanding;
         match b_data.value {
           NoValue => {
-            debug!("Setting initial value of {:?} to {}",
-                   b_vid, a_region.repr(self.tcx));
+            debug!("Setting initial value of {:?} to {:?}",
+                   b_vid, a_region);
 
             b_data.value = Value(a_region);
             return true;
@@ -1086,10 +1086,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 return false;
             }
 
-            debug!("Expanding value of {:?} from {} to {}",
+            debug!("Expanding value of {:?} from {:?} to {:?}",
                    b_vid,
-                   cur_region.repr(self.tcx),
-                   lub.repr(self.tcx));
+                   cur_region,
+                   lub);
 
             b_data.value = Value(lub);
             return true;
@@ -1105,12 +1105,12 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                    free_regions: &FreeRegionMap,
                    var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Contraction", |constraint| {
-            debug!("contraction: constraint={} origin={}",
-                   constraint.repr(self.tcx),
+            debug!("contraction: constraint={:?} origin={:?}",
+                   constraint,
                    self.constraints.borrow()
                                    .get(constraint)
                                    .unwrap()
-                                   .repr(self.tcx));
+                                   );
             match *constraint {
               ConstrainRegSubVar(..) => {
                 // This is an expansion constraint.  Ignore.
@@ -1139,9 +1139,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                      a_data: &mut VarData,
                      b_region: Region)
                      -> bool {
-        debug!("contract_node({:?} == {}/{:?}, {})",
-               a_vid, a_data.value.repr(self.tcx),
-               a_data.classification, b_region.repr(self.tcx));
+        debug!("contract_node({:?} == {:?}/{:?}, {:?})",
+               a_vid, a_data.value,
+               a_data.classification, b_region);
 
         return match a_data.value {
             NoValue => {
@@ -1171,10 +1171,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                       -> bool
         {
             if !free_regions.is_subregion_of(this.tcx, a_region, b_region) {
-                debug!("Setting {:?} to ErrorValue: {} not subregion of {}",
+                debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
                        a_vid,
-                       a_region.repr(this.tcx),
-                       b_region.repr(this.tcx));
+                       a_region,
+                       b_region);
                 a_data.value = ErrorValue;
             }
             false
@@ -1192,19 +1192,19 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                     if glb == a_region {
                         false
                     } else {
-                        debug!("Contracting value of {:?} from {} to {}",
+                        debug!("Contracting value of {:?} from {:?} to {:?}",
                                a_vid,
-                               a_region.repr(this.tcx),
-                               glb.repr(this.tcx));
+                               a_region,
+                               glb);
                         a_data.value = Value(glb);
                         true
                     }
                 }
                 Err(_) => {
-                    debug!("Setting {:?} to ErrorValue: no glb of {}, {}",
+                    debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
                            a_vid,
-                           a_region.repr(this.tcx),
-                           b_region.repr(this.tcx));
+                           a_region,
+                           b_region);
                     a_data.value = ErrorValue;
                     false
                 }
@@ -1229,9 +1229,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                         continue;
                     }
 
-                    debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}",
-                           sub.repr(self.tcx),
-                           sup.repr(self.tcx));
+                    debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
+                           sub,
+                           sup);
                     errors.push(ConcreteFailure((*origin).clone(), sub, sup));
                 }
 
@@ -1431,10 +1431,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         self.tcx.sess.span_bug(
             (*self.var_origins.borrow())[node_idx.index as usize].span(),
             &format!("collect_error_for_expanding_node() could not find error \
-                    for var {:?}, lower_bounds={}, upper_bounds={}",
+                    for var {:?}, lower_bounds={:?}, upper_bounds={:?}",
                     node_idx,
-                    lower_bounds.repr(self.tcx),
-                    upper_bounds.repr(self.tcx)));
+                    lower_bounds,
+                    upper_bounds));
     }
 
     fn collect_error_for_contracting_node(
@@ -1478,9 +1478,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         self.tcx.sess.span_bug(
             (*self.var_origins.borrow())[node_idx.index as usize].span(),
             &format!("collect_error_for_contracting_node() could not find error \
-                     for var {:?}, upper_bounds={}",
+                     for var {:?}, upper_bounds={:?}",
                     node_idx,
-                    upper_bounds.repr(self.tcx)));
+                    upper_bounds));
     }
 
     fn collect_concrete_regions(&self,
@@ -1578,8 +1578,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             for (constraint, _) in self.constraints.borrow().iter() {
                 let edge_changed = body(constraint);
                 if edge_changed {
-                    debug!("Updated due to constraint {}",
-                           constraint.repr(self.tcx));
+                    debug!("Updated due to constraint {:?}",
+                           constraint);
                     changed = true;
                 }
             }
@@ -1589,31 +1589,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 
 }
 
-impl<'tcx> Repr<'tcx> for Constraint {
-    fn repr(&self, tcx: &ty::ctxt) -> String {
-        match *self {
-            ConstrainVarSubVar(a, b) => {
-                format!("ConstrainVarSubVar({}, {})", a.repr(tcx), b.repr(tcx))
-            }
-            ConstrainRegSubVar(a, b) => {
-                format!("ConstrainRegSubVar({}, {})", a.repr(tcx), b.repr(tcx))
-            }
-            ConstrainVarSubReg(a, b) => {
-                format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
-            }
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for Verify<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for Verify<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             VerifyRegSubReg(_, ref a, ref b) => {
-                format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
+                write!(f, "VerifyRegSubReg({:?}, {:?})", a, b)
             }
             VerifyGenericBound(_, ref p, ref a, ref bs) => {
-                format!("VerifyGenericBound({}, {}, {})",
-                        p.repr(tcx), a.repr(tcx), bs.repr(tcx))
+                write!(f, "VerifyGenericBound({:?}, {:?}, {:?})", p, a, bs)
             }
         }
     }
@@ -1634,38 +1617,28 @@ fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
     }
 }
 
-impl<'tcx> Repr<'tcx> for VarValue {
-    fn repr(&self, tcx: &ty::ctxt) -> String {
-        match *self {
-            NoValue => format!("NoValue"),
-            Value(r) => format!("Value({})", r.repr(tcx)),
-            ErrorValue => format!("ErrorValue"),
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for RegionAndOrigin<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("RegionAndOrigin({},{})",
-                self.region.repr(tcx),
-                self.origin.repr(tcx))
+impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "RegionAndOrigin({:?},{:?})",
+               self.region,
+               self.origin)
     }
 }
 
-impl<'tcx> Repr<'tcx> for GenericKind<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for GenericKind<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            GenericKind::Param(ref p) => p.repr(tcx),
-            GenericKind::Projection(ref p) => p.repr(tcx),
+            GenericKind::Param(ref p) => write!(f, "{:?}", p),
+            GenericKind::Projection(ref p) => write!(f, "{:?}", p),
         }
     }
 }
 
-impl<'tcx> UserString<'tcx> for GenericKind<'tcx> {
-    fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Display for GenericKind<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            GenericKind::Param(ref p) => p.user_string(tcx),
-            GenericKind::Projection(ref p) => p.user_string(tcx),
+            GenericKind::Param(ref p) => write!(f, "{}", p),
+            GenericKind::Projection(ref p) => write!(f, "{}", p),
         }
     }
 }
diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs
index 62e56d2e2d7..b67437fd127 100644
--- a/src/librustc/middle/infer/resolve.rs
+++ b/src/librustc/middle/infer/resolve.rs
@@ -11,7 +11,6 @@
 use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty};
 use middle::ty::{self, Ty};
 use middle::ty_fold::{self, TypeFoldable};
-use util::ppaux::Repr;
 
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC TYPE RESOLVER
@@ -95,8 +94,8 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
                 }
                 ty::TyInfer(_) => {
                     self.infcx.tcx.sess.bug(
-                        &format!("Unexpected type in full type resolver: {}",
-                                t.repr(self.infcx.tcx)));
+                        &format!("Unexpected type in full type resolver: {:?}",
+                                t));
                 }
                 _ => {
                     ty_fold::super_fold_ty(self, t)
diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs
index 9d6854eba43..2b7f9a74b8b 100644
--- a/src/librustc/middle/infer/sub.rs
+++ b/src/librustc/middle/infer/sub.rs
@@ -16,7 +16,6 @@ use super::type_variable::{SubtypeOf, SupertypeOf};
 use middle::ty::{self, Ty};
 use middle::ty::TyVar;
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::{Repr};
 
 /// "Greatest lower bound" (common subtype)
 pub struct Sub<'a, 'tcx: 'a> {
@@ -49,7 +48,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
     }
 
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
+        debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
 
         if a == b { return Ok(a); }
 
@@ -85,10 +84,10 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
     }
 
     fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
-        debug!("{}.regions({}, {})",
+        debug!("{}.regions({:?}, {:?})",
                self.tag(),
-               a.repr(self.tcx()),
-               b.repr(self.tcx()));
+               a,
+               b);
         let origin = Subtype(self.fields.trace.clone());
         self.fields.infcx.region_vars.make_subregion(origin, a, b);
         Ok(a)
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index f76cfebf7b9..c4d924d676c 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -14,7 +14,8 @@ use middle::def::DefFn;
 use middle::subst::{Subst, Substs, EnumeratedItems};
 use middle::ty::{TransmuteRestriction, ctxt, TyBareFn};
 use middle::ty::{self, Ty};
-use util::ppaux::Repr;
+
+use std::fmt;
 
 use syntax::abi::RustIntrinsic;
 use syntax::ast::DefId;
@@ -202,15 +203,15 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
 
         match types_in_scope.next() {
             None => {
-                debug!("with_each_combination(substs={})",
-                       substs.repr(self.tcx));
+                debug!("with_each_combination(substs={:?})",
+                       substs);
 
                 callback(substs);
             }
 
             Some((space, index, &param_ty)) => {
-                debug!("with_each_combination: space={:?}, index={}, param_ty={}",
-                       space, index, param_ty.repr(self.tcx));
+                debug!("with_each_combination: space={:?}, index={}, param_ty={:?}",
+                       space, index, param_ty);
 
                 if !ty::type_is_sized(Some(param_env), self.tcx, span, param_ty) {
                     debug!("with_each_combination: param_ty is not known to be sized");
@@ -228,7 +229,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
     }
 
     fn push_transmute_restriction(&self, restriction: TransmuteRestriction<'tcx>) {
-        debug!("Pushing transmute restriction: {}", restriction.repr(self.tcx));
+        debug!("Pushing transmute restriction: {:?}", restriction);
         self.tcx.transmute_restrictions.borrow_mut().push(restriction);
     }
 }
@@ -277,13 +278,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for TransmuteRestriction<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("TransmuteRestriction(id={}, original=({},{}), substituted=({},{}))",
-                self.id,
-                self.original_from.repr(tcx),
-                self.original_to.repr(tcx),
-                self.substituted_from.repr(tcx),
-                self.substituted_to.repr(tcx))
+impl<'tcx> fmt::Debug for TransmuteRestriction<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TransmuteRestriction(id={}, original=({:?},{:?}), substituted=({:?},{:?}))",
+               self.id,
+               self.original_from,
+               self.original_to,
+               self.substituted_from,
+               self.substituted_to)
     }
 }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 9d0a1821deb..ca8de74b35b 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -78,18 +78,16 @@ use middle::def;
 use middle::region;
 use middle::ty::{self, Ty};
 use util::nodemap::NodeMap;
-use util::ppaux::{Repr, UserString};
 
 use syntax::ast::{MutImmutable, MutMutable};
 use syntax::ast;
 use syntax::codemap::Span;
-use syntax::print::pprust;
-use syntax::parse::token;
 
 use std::cell::RefCell;
+use std::fmt;
 use std::rc::Rc;
 
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, PartialEq)]
 pub enum categorization<'tcx> {
     cat_rvalue(ty::Region),                    // temporary val, argument is its scope
     cat_static_item,
@@ -103,14 +101,14 @@ pub enum categorization<'tcx> {
 }
 
 // Represents any kind of upvar
-#[derive(Clone, Copy, PartialEq, Debug)]
+#[derive(Clone, Copy, PartialEq)]
 pub struct Upvar {
     pub id: ty::UpvarId,
     pub kind: ty::ClosureKind
 }
 
 // different kinds of pointers:
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum PointerKind {
     /// `Box<T>`
     Unique,
@@ -127,7 +125,7 @@ pub enum PointerKind {
 
 // We use the term "interior" to mean "something reachable from the
 // base without a pointer dereference", e.g. a field
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum InteriorKind {
     InteriorField(FieldName),
     InteriorElement(InteriorOffsetKind, ElementKind),
@@ -184,7 +182,7 @@ pub enum Note {
 // dereference, but its type is the type *before* the dereference
 // (`@T`). So use `cmt.ty` to find the type of the value in a consistent
 // fashion. For more details, see the method `cat_pattern`
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, PartialEq)]
 pub struct cmt_<'tcx> {
     pub id: ast::NodeId,           // id of expr/pat producing this value
     pub span: Span,                // span of same expr/pat
@@ -418,7 +416,6 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
     }
 
     fn pat_ty(&self, pat: &ast::Pat) -> McResult<Ty<'tcx>> {
-        let tcx = self.typer.tcx();
         let base_ty = try!(self.typer.node_ty(pat.id));
         // FIXME (Issue #18207): This code detects whether we are
         // looking at a `ref x`, and if so, figures out what the type
@@ -436,8 +433,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             }
             _ => base_ty,
         };
-        debug!("pat_ty(pat={}) base_ty={} ret_ty={}",
-               pat.repr(tcx), base_ty.repr(tcx), ret_ty.repr(tcx));
+        debug!("pat_ty(pat={:?}) base_ty={:?} ret_ty={:?}",
+               pat, base_ty, ret_ty);
         Ok(ret_ty)
     }
 
@@ -460,9 +457,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                     ty::AdjustReifyFnPointer |
                     ty::AdjustUnsafeFnPointer |
                     ty::AdjustDerefRef(_) => {
-                        debug!("cat_expr({}): {}",
-                               adjustment.repr(self.tcx()),
-                               expr.repr(self.tcx()));
+                        debug!("cat_expr({:?}): {:?}",
+                               adjustment,
+                               expr);
                         // Result is an rvalue.
                         let expr_ty = try!(self.expr_ty_adjusted(expr));
                         Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
@@ -477,9 +474,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                                autoderefs: usize)
                                -> McResult<cmt<'tcx>> {
         let mut cmt = try!(self.cat_expr_unadjusted(expr));
-        debug!("cat_expr_autoderefd: autoderefs={}, cmt={}",
+        debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
                autoderefs,
-               cmt.repr(self.tcx()));
+               cmt);
         for deref in 1..autoderefs + 1 {
             cmt = try!(self.cat_deref(expr, cmt, deref, None));
         }
@@ -487,7 +484,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
     }
 
     pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
-        debug!("cat_expr: id={} expr={}", expr.id, expr.repr(self.tcx()));
+        debug!("cat_expr: id={} expr={:?}", expr.id, expr);
 
         let expr_ty = try!(self.expr_ty(expr));
         match expr.node {
@@ -498,10 +495,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
 
           ast::ExprField(ref base, f_name) => {
             let base_cmt = try!(self.cat_expr(&**base));
-            debug!("cat_expr(cat_field): id={} expr={} base={}",
+            debug!("cat_expr(cat_field): id={} expr={:?} base={:?}",
                    expr.id,
-                   expr.repr(self.tcx()),
-                   base_cmt.repr(self.tcx()));
+                   expr,
+                   base_cmt);
             Ok(self.cat_field(expr, base_cmt, f_name.node.name, expr_ty))
           }
 
@@ -524,8 +521,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                     let elem_ty = match ret_ty.sty {
                         ty::TyRef(_, mt) => mt.ty,
                         _ => {
-                            debug!("cat_expr_unadjusted: return type of overloaded index is {}?",
-                                   ret_ty.repr(self.tcx()));
+                            debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
+                                   ret_ty);
                             return Err(());
                         }
                     };
@@ -583,8 +580,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                    expr_ty: Ty<'tcx>,
                    def: def::Def)
                    -> McResult<cmt<'tcx>> {
-        debug!("cat_def: id={} expr={} def={:?}",
-               id, expr_ty.repr(self.tcx()), def);
+        debug!("cat_def: id={} expr={:?} def={:?}",
+               id, expr_ty, def);
 
         match def {
           def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
@@ -635,9 +632,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                   _ => {
                       self.tcx().sess.span_bug(
                           span,
-                          &format!("Upvar of non-closure {} - {}",
+                          &format!("Upvar of non-closure {} - {:?}",
                                   fn_node_id,
-                                  ty.repr(self.tcx())));
+                                  ty));
                   }
               }
           }
@@ -746,7 +743,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         };
 
         let ret = Rc::new(cmt_result);
-        debug!("cat_upvar ret={}", ret.repr(self.tcx()));
+        debug!("cat_upvar ret={:?}", ret);
         Ok(ret)
     }
 
@@ -817,7 +814,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             note: NoteClosureEnv(upvar_id)
         };
 
-        debug!("env_deref ret {}", ret.repr(self.tcx()));
+        debug!("env_deref ret {:?}", ret);
 
         ret
     }
@@ -855,7 +852,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             ty::ReStatic
         };
         let ret = self.cat_rvalue(id, span, re, expr_ty);
-        debug!("cat_rvalue_node ret {}", ret.repr(self.tcx()));
+        debug!("cat_rvalue_node ret {:?}", ret);
         ret
     }
 
@@ -872,7 +869,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             ty:expr_ty,
             note: NoteNone
         });
-        debug!("cat_rvalue ret {}", ret.repr(self.tcx()));
+        debug!("cat_rvalue ret {:?}", ret);
         ret
     }
 
@@ -890,7 +887,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             ty: f_ty,
             note: NoteNone
         });
-        debug!("cat_field ret {}", ret.repr(self.tcx()));
+        debug!("cat_field ret {:?}", ret);
         ret
     }
 
@@ -908,7 +905,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             ty: f_ty,
             note: NoteNone
         });
-        debug!("cat_tup_field ret {}", ret.repr(self.tcx()));
+        debug!("cat_tup_field ret {:?}", ret);
         ret
     }
 
@@ -925,7 +922,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         let method_ty = self.typer.node_method_ty(method_call);
 
         debug!("cat_deref: method_call={:?} method_ty={:?}",
-               method_call, method_ty.map(|ty| ty.repr(self.tcx())));
+               method_call, method_ty.map(|ty| ty));
 
         let base_cmt = match method_ty {
             Some(method_ty) => {
@@ -943,12 +940,12 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                                               mt.ty,
                                               deref_context,
                                                 /* implicit: */ false);
-                debug!("cat_deref ret {}", ret.repr(self.tcx()));
+                debug!("cat_deref ret {:?}", ret);
                 ret
             }
             None => {
-                debug!("Explicit deref of non-derefable type: {}",
-                       base_cmt_ty.repr(self.tcx()));
+                debug!("Explicit deref of non-derefable type: {:?}",
+                       base_cmt_ty);
                 return Err(());
             }
         }
@@ -991,7 +988,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             ty: deref_ty,
             note: NoteNone
         });
-        debug!("cat_deref_common ret {}", ret.repr(self.tcx()));
+        debug!("cat_deref_common ret {:?}", ret);
         Ok(ret)
     }
 
@@ -1042,7 +1039,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         let m = base_cmt.mutbl.inherit();
         let ret = interior(elt, base_cmt.clone(), base_cmt.ty,
                            m, context, element_ty);
-        debug!("cat_index ret {}", ret.repr(self.tcx()));
+        debug!("cat_index ret {:?}", ret);
         return Ok(ret);
 
         fn interior<'tcx, N: ast_node>(elt: &N,
@@ -1096,7 +1093,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                 base_cmt
             }
         };
-        debug!("deref_vec ret {}", ret.repr(self.tcx()));
+        debug!("deref_vec ret {:?}", ret);
         Ok(ret)
     }
 
@@ -1155,7 +1152,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             ty: interior_ty,
             note: NoteNone
         });
-        debug!("cat_imm_interior ret={}", ret.repr(self.tcx()));
+        debug!("cat_imm_interior ret={:?}", ret);
         ret
     }
 
@@ -1173,7 +1170,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             ty: downcast_ty,
             note: NoteNone
         });
-        debug!("cat_downcast ret={}", ret.repr(self.tcx()));
+        debug!("cat_downcast ret={:?}", ret);
         ret
     }
 
@@ -1233,9 +1230,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         // step out of sync again. So you'll see below that we always
         // get the type of the *subpattern* and use that.
 
-        debug!("cat_pattern: id={} pat={} cmt={}",
-               pat.id, pprust::pat_to_string(pat),
-               cmt.repr(self.tcx()));
+        debug!("cat_pattern: {:?} cmt={:?}",
+               pat,
+               cmt);
 
         (*op)(self, cmt.clone(), pat);
 
@@ -1521,7 +1518,7 @@ impl<'tcx> cmt_<'tcx> {
                 let upvar = self.upvar();
                 match upvar.as_ref().map(|i| &i.cat) {
                     Some(&cat_upvar(ref var)) => {
-                        var.user_string(tcx)
+                        var.to_string()
                     }
                     Some(_) => unreachable!(),
                     None => {
@@ -1561,7 +1558,7 @@ impl<'tcx> cmt_<'tcx> {
                 "pattern-bound indexed content".to_string()
             }
             cat_upvar(ref var) => {
-                var.user_string(tcx)
+                var.to_string()
             }
             cat_downcast(ref cmt, _) => {
                 cmt.descriptive_string(tcx)
@@ -1570,33 +1567,36 @@ impl<'tcx> cmt_<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for cmt_<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("{{{} id:{} m:{:?} ty:{}}}",
-                self.cat.repr(tcx),
-                self.id,
-                self.mutbl,
-                self.ty.repr(tcx))
+impl<'tcx> fmt::Debug for cmt_<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{{{:?} id:{} m:{:?} ty:{:?}}}",
+               self.cat,
+               self.id,
+               self.mutbl,
+               self.ty)
     }
 }
 
-impl<'tcx> Repr<'tcx> for categorization<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for categorization<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            cat_static_item |
-            cat_rvalue(..) |
-            cat_local(..) |
-            cat_upvar(..) => {
-                format!("{:?}", *self)
+            cat_static_item => write!(f, "static"),
+            cat_rvalue(r) => write!(f, "rvalue({:?})", r),
+            cat_local(id) => {
+               let name = ty::tls::with(|tcx| ty::local_var_name_str(tcx, id));
+               write!(f, "local({})", name)
+            }
+            cat_upvar(upvar) => {
+                write!(f, "upvar({:?})", upvar)
             }
             cat_deref(ref cmt, derefs, ptr) => {
-                format!("{}-{}{}->", cmt.cat.repr(tcx), ptr.repr(tcx), derefs)
+                write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs)
             }
             cat_interior(ref cmt, interior) => {
-                format!("{}.{}", cmt.cat.repr(tcx), interior.repr(tcx))
+                write!(f, "{:?}.{:?}", cmt.cat, interior)
             }
             cat_downcast(ref cmt, _) => {
-                format!("{}->(enum)", cmt.cat.repr(tcx))
+                write!(f, "{:?}->(enum)", cmt.cat)
             }
         }
     }
@@ -1615,39 +1615,33 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
     }
 }
 
-impl<'tcx> Repr<'tcx> for PointerKind {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl fmt::Debug for PointerKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            Unique => {
-                format!("Box")
-            }
+            Unique => write!(f, "Box"),
             BorrowedPtr(ty::ImmBorrow, ref r) |
             Implicit(ty::ImmBorrow, ref r) => {
-                format!("&{}", r.repr(tcx))
+                write!(f, "&{:?}", r)
             }
             BorrowedPtr(ty::MutBorrow, ref r) |
             Implicit(ty::MutBorrow, ref r) => {
-                format!("&{} mut", r.repr(tcx))
+                write!(f, "&{:?} mut", r)
             }
             BorrowedPtr(ty::UniqueImmBorrow, ref r) |
             Implicit(ty::UniqueImmBorrow, ref r) => {
-                format!("&{} uniq", r.repr(tcx))
-            }
-            UnsafePtr(_) => {
-                format!("*")
+                write!(f, "&{:?} uniq", r)
             }
+            UnsafePtr(_) => write!(f, "*")
         }
     }
 }
 
-impl<'tcx> Repr<'tcx> for InteriorKind {
-    fn repr(&self, _tcx: &ty::ctxt) -> String {
+impl fmt::Debug for InteriorKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            InteriorField(NamedField(fld)) => {
-                token::get_name(fld).to_string()
-            }
-            InteriorField(PositionalField(i)) => format!("#{}", i),
-            InteriorElement(..) => "[]".to_string(),
+            InteriorField(NamedField(fld)) => write!(f, "{}", fld),
+            InteriorField(PositionalField(i)) => write!(f, "#{}", i),
+            InteriorElement(..) => write!(f, "[]"),
         }
     }
 }
@@ -1664,25 +1658,19 @@ fn element_kind(t: Ty) -> ElementKind {
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::ClosureKind {
-    fn repr(&self, _: &ty::ctxt) -> String {
-        format!("Upvar({:?})", self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for Upvar {
-    fn repr(&self, tcx: &ty::ctxt) -> String {
-        format!("Upvar({})", self.kind.repr(tcx))
+impl fmt::Debug for Upvar {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{:?}/{:?}", self.id, self.kind)
     }
 }
 
-impl<'tcx> UserString<'tcx> for Upvar {
-    fn user_string(&self, _: &ty::ctxt) -> String {
+impl fmt::Display for Upvar {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let kind = match self.kind {
             ty::FnClosureKind => "Fn",
             ty::FnMutClosureKind => "FnMut",
             ty::FnOnceClosureKind => "FnOnce",
         };
-        format!("captured outer variable in an `{}` closure", kind)
+        write!(f, "captured outer variable in an `{}` closure", kind)
     }
 }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 861fa97d50b..3f00d9ba5e9 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -28,7 +28,6 @@ use syntax::attr::{Stability, AttrMetaMethods};
 use syntax::visit::{FnKind, Visitor};
 use syntax::feature_gate::emit_feature_err;
 use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
-use util::ppaux::Repr;
 
 use std::mem::replace;
 
@@ -450,7 +449,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
                     tcx.sess.span_bug(e.span,
                                       &format!("stability::check_expr: struct construction \
                                                 of non-struct, type {:?}",
-                                               type_.repr(tcx)));
+                                               type_));
                 }
             }
         }
@@ -551,7 +550,7 @@ pub fn lookup<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability>
 }
 
 fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
-    debug!("lookup(id={})", id.repr(tcx));
+    debug!("lookup(id={:?})", id);
 
     // is this definition the implementation of a trait method?
     match ty::trait_item_of_item(tcx, id) {
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 75af3366397..c3c29d0ade8 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -15,7 +15,6 @@ pub use self::RegionSubsts::*;
 
 use middle::ty::{self, Ty};
 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
-use util::ppaux::Repr;
 
 use std::fmt;
 use std::iter::IntoIterator;
@@ -29,7 +28,7 @@ use syntax::codemap::{Span, DUMMY_SP};
 /// identify each in-scope parameter by an *index* and a *parameter
 /// space* (which indices where the parameter is defined; see
 /// `ParamSpace`).
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Substs<'tcx> {
     pub types: VecPerParamSpace<Ty<'tcx>>,
     pub regions: RegionSubsts,
@@ -38,7 +37,7 @@ pub struct Substs<'tcx> {
 /// Represents the values to use when substituting lifetime parameters.
 /// If the value is `ErasedRegions`, then this subst is occurring during
 /// trans, and all region parameters will be replaced with `ty::ReStatic`.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub enum RegionSubsts {
     ErasedRegions,
     NonerasedRegions(VecPerParamSpace<ty::Region>)
@@ -240,13 +239,11 @@ pub struct SeparateVecsPerParamSpace<T> {
 }
 
 impl<T: fmt::Debug> fmt::Debug for VecPerParamSpace<T> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(fmt, "VecPerParamSpace {{"));
-        for space in &ParamSpace::all() {
-            try!(write!(fmt, "{:?}: {:?}, ", *space, self.get_slice(*space)));
-        }
-        try!(write!(fmt, "}}"));
-        Ok(())
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "[{:?};{:?};{:?}]",
+               self.get_slice(TypeSpace),
+               self.get_slice(SelfSpace),
+               self.get_slice(FnSpace))
     }
 }
 
@@ -620,10 +617,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                                 self.tcx().sess.span_bug(
                                     span,
                                     &format!("Type parameter out of range \
-                                              when substituting in region {} (root type={}) \
+                                              when substituting in region {} (root type={:?}) \
                                               (space={:?}, index={})",
-                                             data.name.as_str(),
-                                             self.root_ty.repr(self.tcx()),
+                                             data.name,
+                                             self.root_ty,
                                              data.space,
                                              data.index));
                             }
@@ -675,14 +672,14 @@ impl<'a,'tcx> SubstFolder<'a,'tcx> {
                 let span = self.span.unwrap_or(DUMMY_SP);
                 self.tcx().sess.span_bug(
                     span,
-                    &format!("Type parameter `{}` ({}/{:?}/{}) out of range \
-                                 when substituting (root type={}) substs={}",
-                            p.repr(self.tcx()),
-                            source_ty.repr(self.tcx()),
+                    &format!("Type parameter `{:?}` ({:?}/{:?}/{}) out of range \
+                                 when substituting (root type={:?}) substs={:?}",
+                            p,
+                            source_ty,
                             p.space,
                             p.idx,
-                            self.root_ty.repr(self.tcx()),
-                            self.substs.repr(self.tcx())));
+                            self.root_ty,
+                            self.substs));
             }
         };
 
@@ -733,14 +730,14 @@ impl<'a,'tcx> SubstFolder<'a,'tcx> {
     /// is that only in the second case have we passed through a fn binder.
     fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
         debug!("shift_regions(ty={:?}, region_binders_passed={:?}, type_has_escaping_regions={:?})",
-               ty.repr(self.tcx()), self.region_binders_passed, ty::type_has_escaping_regions(ty));
+               ty, self.region_binders_passed, ty::type_has_escaping_regions(ty));
 
         if self.region_binders_passed == 0 || !ty::type_has_escaping_regions(ty) {
             return ty;
         }
 
         let result = ty_fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
-        debug!("shift_regions: shifted result = {:?}", result.repr(self.tcx()));
+        debug!("shift_regions: shifted result = {:?}", result);
 
         result
     }
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index dcf37e7d56a..a826836b10c 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -22,7 +22,6 @@ use middle::ty::{self, ToPolyTraitRef, Ty};
 use middle::infer::{self, InferCtxt};
 use syntax::ast;
 use syntax::codemap::{DUMMY_SP, Span};
-use util::ppaux::Repr;
 
 #[derive(Copy, Clone)]
 struct InferIsLocal(bool);
@@ -34,10 +33,10 @@ pub fn overlapping_impls(infcx: &InferCtxt,
                          -> bool
 {
     debug!("impl_can_satisfy(\
-           impl1_def_id={}, \
-           impl2_def_id={})",
-           impl1_def_id.repr(infcx.tcx),
-           impl2_def_id.repr(infcx.tcx));
+           impl1_def_id={:?}, \
+           impl2_def_id={:?})",
+           impl1_def_id,
+           impl2_def_id);
 
     let param_env = &ty::empty_parameter_environment(infcx.tcx);
     let selcx = &mut SelectionContext::intercrate(infcx, param_env);
@@ -53,9 +52,9 @@ fn overlap(selcx: &mut SelectionContext,
            b_def_id: ast::DefId)
            -> bool
 {
-    debug!("overlap(a_def_id={}, b_def_id={})",
-           a_def_id.repr(selcx.tcx()),
-           b_def_id.repr(selcx.tcx()));
+    debug!("overlap(a_def_id={:?}, b_def_id={:?})",
+           a_def_id,
+           b_def_id);
 
     let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
                                                                 a_def_id,
@@ -65,9 +64,9 @@ fn overlap(selcx: &mut SelectionContext,
                                                                 b_def_id,
                                                                 util::fresh_type_vars_for_impl);
 
-    debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx()));
+    debug!("overlap: a_trait_ref={:?}", a_trait_ref);
 
-    debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx()));
+    debug!("overlap: b_trait_ref={:?}", b_trait_ref);
 
     // Does `a <: b` hold? If not, no overlap.
     if let Err(_) = infer::mk_sub_poly_trait_refs(selcx.infcx(),
@@ -81,7 +80,6 @@ fn overlap(selcx: &mut SelectionContext,
     debug!("overlap: subtraitref check succeeded");
 
     // Are any of the obligations unsatisfiable? If so, no overlap.
-    let tcx = selcx.tcx();
     let infcx = selcx.infcx();
     let opt_failing_obligation =
         a_obligations.iter()
@@ -90,7 +88,7 @@ fn overlap(selcx: &mut SelectionContext,
                      .find(|o| !selcx.evaluate_obligation(o));
 
     if let Some(failing_obligation) = opt_failing_obligation {
-        debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx));
+        debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
         return false
     }
 
@@ -99,7 +97,7 @@ fn overlap(selcx: &mut SelectionContext,
 
 pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
 {
-    debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx));
+    debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
 
     // if the orphan rules pass, that means that no ancestor crate can
     // impl this, so it's up to us.
@@ -155,7 +153,7 @@ fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     let Normalized { value: predicates, obligations: normalization_obligations2 } =
         project::normalize(selcx, ObligationCause::dummy(), &predicates);
     let impl_obligations =
-        util::predicates_for_generics(selcx.tcx(), ObligationCause::dummy(), 0, &predicates);
+        util::predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
 
     let impl_obligations: Vec<_> =
         impl_obligations.into_iter()
@@ -181,17 +179,17 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
                           impl_def_id: ast::DefId)
                           -> Result<(), OrphanCheckErr<'tcx>>
 {
-    debug!("orphan_check({})", impl_def_id.repr(tcx));
+    debug!("orphan_check({:?})", impl_def_id);
 
     // We only except this routine to be invoked on implementations
     // of a trait, not inherent implementations.
     let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap();
-    debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx));
+    debug!("orphan_check: trait_ref={:?}", trait_ref);
 
     // If the *trait* is local to the crate, ok.
     if trait_ref.def_id.krate == ast::LOCAL_CRATE {
-        debug!("trait {} is local to current crate",
-               trait_ref.def_id.repr(tcx));
+        debug!("trait {:?} is local to current crate",
+               trait_ref.def_id);
         return Ok(());
     }
 
@@ -203,8 +201,8 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
                                 infer_is_local: InferIsLocal)
                                 -> Result<(), OrphanCheckErr<'tcx>>
 {
-    debug!("orphan_check_trait_ref(trait_ref={}, infer_is_local={})",
-           trait_ref.repr(tcx), infer_is_local.0);
+    debug!("orphan_check_trait_ref(trait_ref={:?}, infer_is_local={})",
+           trait_ref, infer_is_local.0);
 
     // First, create an ordered iterator over all the type parameters to the trait, with the self
     // type appearing first.
@@ -215,14 +213,14 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
     // some local type.
     for input_ty in input_tys {
         if ty_is_local(tcx, input_ty, infer_is_local) {
-            debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx));
+            debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
 
             // First local input type. Check that there are no
             // uncovered type parameters.
             let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local);
             for uncovered_ty in uncovered_tys {
                 if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) {
-                    debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+                    debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
                     return Err(OrphanCheckErr::UncoveredTy(param));
                 }
             }
@@ -235,7 +233,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>,
         // parameters reachable.
         if !infer_is_local.0 {
             if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
-                debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+                debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
                 return Err(OrphanCheckErr::UncoveredTy(param));
             }
         }
@@ -295,7 +293,7 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
                                  infer_is_local: InferIsLocal)
                                  -> bool
 {
-    debug!("ty_is_local_constructor({})", ty.repr(tcx));
+    debug!("ty_is_local_constructor({:?})", ty);
 
     match ty.sty {
         ty::TyBool |
@@ -336,8 +334,8 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
         ty::TyClosure(..) |
         ty::TyError => {
             tcx.sess.bug(
-                &format!("ty_is_local invoked on unexpected type: {}",
-                        ty.repr(tcx)))
+                &format!("ty_is_local invoked on unexpected type: {:?}",
+                        ty))
         }
     }
 }
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index 2d65c5dd626..8618f521529 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -28,9 +28,9 @@ use middle::infer::InferCtxt;
 use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
 use middle::ty_fold::TypeFoldable;
 use std::collections::HashMap;
+use std::fmt;
 use syntax::codemap::{DUMMY_SP, Span};
 use syntax::attr::{AttributeMethods, AttrMetaMethods};
-use util::ppaux::{Repr, UserString};
 
 pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                            errors: &Vec<FulfillmentError<'tcx>>) {
@@ -68,8 +68,8 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
     if !infcx.tcx.sess.has_errors() || !predicate.references_error() {
         span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
                 "type mismatch resolving `{}`: {}",
-                predicate.user_string(infcx.tcx),
-                ty::type_err_to_str(infcx.tcx, &error.err));
+                predicate,
+                error.err);
         note_obligation_cause(infcx, obligation);
     }
 }
@@ -87,16 +87,16 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                 item.meta().span
             };
             let def = ty::lookup_trait_def(infcx.tcx, def_id);
-            let trait_str = def.trait_ref.user_string(infcx.tcx);
+            let trait_str = def.trait_ref.to_string();
             if let Some(ref istring) = item.value_str() {
                 let mut generic_map = def.generics.types.iter_enumerated()
                                          .map(|(param, i, gen)| {
                                                (gen.name.as_str().to_string(),
                                                 trait_ref.substs.types.get(param, i)
-                                                         .user_string(infcx.tcx))
+                                                         .to_string())
                                               }).collect::<HashMap<String, String>>();
                 generic_map.insert("Self".to_string(),
-                                   trait_ref.self_ty().user_string(infcx.tcx));
+                                   trait_ref.self_ty().to_string());
                 let parser = Parser::new(&istring);
                 let mut errored = false;
                 let err: String = parser.filter_map(|p| {
@@ -157,13 +157,13 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
                                           obligation: &Obligation<'tcx, T>)
                                           -> !
-    where T: UserString<'tcx> + TypeFoldable<'tcx>
+    where T: fmt::Display + TypeFoldable<'tcx>
 {
     let predicate =
         infcx.resolve_type_vars_if_possible(&obligation.predicate);
     span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
               "overflow evaluating the requirement `{}`",
-              predicate.user_string(infcx.tcx));
+              predicate);
 
     suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
 
@@ -184,7 +184,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                     span_err!(infcx.tcx.sess, obligation.cause.span, E0276,
                             "the requirement `{}` appears on the impl \
                             method but not on the corresponding trait method",
-                            obligation.predicate.user_string(infcx.tcx));;
+                            obligation.predicate);;
                 }
                 _ => {
                     match obligation.predicate {
@@ -197,8 +197,8 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                 let trait_ref = trait_predicate.to_poly_trait_ref();
                                 span_err!(infcx.tcx.sess, obligation.cause.span, E0277,
                                         "the trait `{}` is not implemented for the type `{}`",
-                                        trait_ref.user_string(infcx.tcx),
-                                        trait_ref.self_ty().user_string(infcx.tcx));
+                                        trait_ref,
+                                        trait_ref.self_ty());
                                 // Check if it has a custom "#[rustc_on_unimplemented]"
                                 // error message, report with that message if it does
                                 let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
@@ -216,8 +216,8 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                                                &predicate).err().unwrap();
                             span_err!(infcx.tcx.sess, obligation.cause.span, E0278,
                                     "the requirement `{}` is not satisfied (`{}`)",
-                                    predicate.user_string(infcx.tcx),
-                                    ty::type_err_to_str(infcx.tcx, &err));
+                                    predicate,
+                                    err);
                         }
 
                         ty::Predicate::RegionOutlives(ref predicate) => {
@@ -226,8 +226,8 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                                                       &predicate).err().unwrap();
                             span_err!(infcx.tcx.sess, obligation.cause.span, E0279,
                                     "the requirement `{}` is not satisfied (`{}`)",
-                                    predicate.user_string(infcx.tcx),
-                                    ty::type_err_to_str(infcx.tcx, &err));
+                                    predicate,
+                                    err);
                         }
 
                         ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
@@ -235,7 +235,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                     infcx.resolve_type_vars_if_possible(&obligation.predicate);
                                 span_err!(infcx.tcx.sess, obligation.cause.span, E0280,
                                         "the requirement `{}` is not satisfied",
-                                        predicate.user_string(infcx.tcx));
+                                        predicate);
                         }
                     }
                 }
@@ -249,10 +249,10 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                 span_err!(infcx.tcx.sess, obligation.cause.span, E0281,
                         "type mismatch: the type `{}` implements the trait `{}`, \
                         but the trait `{}` is required ({})",
-                        expected_trait_ref.self_ty().user_string(infcx.tcx),
-                        expected_trait_ref.user_string(infcx.tcx),
-                        actual_trait_ref.user_string(infcx.tcx),
-                        ty::type_err_to_str(infcx.tcx, e));
+                        expected_trait_ref.self_ty(),
+                        expected_trait_ref,
+                        actual_trait_ref,
+                        e);
                     note_obligation_cause(infcx, obligation);
             }
         }
@@ -282,7 +282,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                         infcx.tcx.sess.span_note(
                             obligation.cause.span,
                             &format!("method `{}` has no receiver",
-                                    method.name.user_string(infcx.tcx)));
+                                    method.name));
                     }
 
                     ObjectSafetyViolation::Method(method,
@@ -291,7 +291,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                             obligation.cause.span,
                             &format!("method `{}` references the `Self` type \
                                     in its arguments or return type",
-                                    method.name.user_string(infcx.tcx)));
+                                    method.name));
                     }
 
                     ObjectSafetyViolation::Method(method,
@@ -299,7 +299,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                         infcx.tcx.sess.span_note(
                             obligation.cause.span,
                             &format!("method `{}` has generic type parameters",
-                                    method.name.user_string(infcx.tcx)));
+                                    method.name));
                     }
                 }
             }
@@ -316,9 +316,9 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 
     let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate);
 
-    debug!("maybe_report_ambiguity(predicate={}, obligation={})",
-           predicate.repr(infcx.tcx),
-           obligation.repr(infcx.tcx));
+    debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
+           predicate,
+           obligation);
 
     match predicate {
         ty::Predicate::Trait(ref data) => {
@@ -349,11 +349,11 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                         span_err!(infcx.tcx.sess, obligation.cause.span, E0282,
                                 "unable to infer enough type information about `{}`; \
                                  type annotations or generic parameter binding required",
-                                self_ty.user_string(infcx.tcx));
+                                self_ty);
                     } else {
                         span_err!(infcx.tcx.sess, obligation.cause.span, E0283,
                                 "type annotations required: cannot resolve `{}`",
-                                predicate.user_string(infcx.tcx));;
+                                predicate);;
                         note_obligation_cause(infcx, obligation);
                     }
                 }
@@ -365,8 +365,8 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                         "coherence failed to report ambiguity: \
                          cannot locate the impl of the trait `{}` for \
                          the type `{}`",
-                        trait_ref.user_string(infcx.tcx),
-                        self_ty.user_string(infcx.tcx)));
+                        trait_ref,
+                        self_ty));
             }
         }
 
@@ -374,7 +374,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
             if !infcx.tcx.sess.has_errors() {
                 span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
                         "type annotations required: cannot resolve `{}`",
-                        predicate.user_string(infcx.tcx));;
+                        predicate);;
                 note_obligation_cause(infcx, obligation);
             }
         }
@@ -383,7 +383,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 
 fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
                                       obligation: &Obligation<'tcx, T>)
-    where T: UserString<'tcx>
+    where T: fmt::Display
 {
     note_obligation_cause_code(infcx,
                                &obligation.predicate,
@@ -395,7 +395,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
                                            predicate: &T,
                                            cause_span: Span,
                                            cause_code: &ObligationCauseCode<'tcx>)
-    where T: UserString<'tcx>
+    where T: fmt::Display
 {
     let tcx = infcx.tcx;
     match *cause_code {
@@ -463,7 +463,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
             let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
             span_note!(tcx.sess, cause_span,
                        "required because it appears within the type `{}`",
-                       parent_trait_ref.0.self_ty().user_string(infcx.tcx));
+                       parent_trait_ref.0.self_ty());
             let parent_predicate = parent_trait_ref.as_predicate();
             note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
         }
@@ -471,8 +471,8 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
             let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
             span_note!(tcx.sess, cause_span,
                        "required because of the requirements on the impl of `{}` for `{}`",
-                       parent_trait_ref.user_string(infcx.tcx),
-                       parent_trait_ref.0.self_ty().user_string(infcx.tcx));
+                       parent_trait_ref,
+                       parent_trait_ref.0.self_ty());
             let parent_predicate = parent_trait_ref.as_predicate();
             note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
         }
@@ -480,7 +480,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
             span_note!(tcx.sess, cause_span,
                       "the requirement `{}` appears on the impl method \
                       but not on the corresponding trait method",
-                      predicate.user_string(infcx.tcx));
+                      predicate);
         }
     }
 }
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index b9117745db2..593a71a30fe 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -10,11 +10,11 @@
 
 use middle::infer::InferCtxt;
 use middle::ty::{self, RegionEscape, Ty};
+
 use std::collections::HashSet;
-use std::default::Default;
+use std::fmt;
 use syntax::ast;
 use util::common::ErrorReported;
-use util::ppaux::Repr;
 use util::nodemap::NodeMap;
 
 use super::CodeAmbiguity;
@@ -137,8 +137,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
                                          cause: ObligationCause<'tcx>)
                                          -> Ty<'tcx>
     {
-        debug!("normalize_associated_type(projection_ty={})",
-               projection_ty.repr(infcx.tcx));
+        debug!("normalize_associated_type(projection_ty={:?})",
+               projection_ty);
 
         assert!(!projection_ty.has_escaping_regions());
 
@@ -151,7 +151,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
             self.register_predicate_obligation(infcx, obligation);
         }
 
-        debug!("normalize_associated_type: result={}", normalized.value.repr(infcx.tcx));
+        debug!("normalize_associated_type: result={:?}", normalized.value);
 
         normalized.value
     }
@@ -171,12 +171,11 @@ impl<'tcx> FulfillmentContext<'tcx> {
     }
 
     pub fn register_region_obligation<'a>(&mut self,
-                                          infcx: &InferCtxt<'a,'tcx>,
                                           t_a: Ty<'tcx>,
                                           r_b: ty::Region,
                                           cause: ObligationCause<'tcx>)
     {
-        register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
+        register_region_obligation(t_a, r_b, cause, &mut self.region_obligations);
     }
 
     pub fn register_predicate_obligation<'a>(&mut self,
@@ -190,11 +189,11 @@ impl<'tcx> FulfillmentContext<'tcx> {
         assert!(!obligation.has_escaping_regions());
 
         if self.is_duplicate_or_add(infcx.tcx, &obligation.predicate) {
-            debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
+            debug!("register_predicate({:?}) -- already seen, skip", obligation);
             return;
         }
 
-        debug!("register_predicate({})", obligation.repr(infcx.tcx));
+        debug!("register_predicate({:?})", obligation);
         self.predicates.push(obligation);
     }
 
@@ -366,7 +365,6 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
      * type inference.
      */
 
-    let tcx = selcx.tcx();
     match obligation.predicate {
         ty::Predicate::Trait(ref data) => {
             let trait_obligation = obligation.with(data.clone());
@@ -379,9 +377,9 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                     true
                 }
                 Err(selection_err) => {
-                    debug!("predicate: {} error: {}",
-                           obligation.repr(tcx),
-                           selection_err.repr(tcx));
+                    debug!("predicate: {:?} error: {:?}",
+                           obligation,
+                           selection_err);
                     errors.push(
                         FulfillmentError::new(
                             obligation.clone(),
@@ -430,7 +428,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                         CodeSelectionError(Unimplemented)));
             } else {
                 let ty::OutlivesPredicate(t_a, r_b) = binder.0;
-                register_region_obligation(tcx, t_a, r_b,
+                register_region_obligation(t_a, r_b,
                                            obligation.cause.clone(),
                                            region_obligations);
             }
@@ -440,9 +438,9 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
         ty::Predicate::Projection(ref data) => {
             let project_obligation = obligation.with(data.clone());
             let result = project::poly_project_and_unify_type(selcx, &project_obligation);
-            debug!("process_predicate: poly_project_and_unify_type({}) returned {}",
-                   project_obligation.repr(tcx),
-                   result.repr(tcx));
+            debug!("process_predicate: poly_project_and_unify_type({:?}) returned {:?}",
+                   project_obligation,
+                   result);
             match result {
                 Ok(Some(obligations)) => {
                     new_obligations.extend(obligations);
@@ -463,16 +461,15 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     }
 }
 
-impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("RegionObligation(sub_region={}, sup_type={})",
-                self.sub_region.repr(tcx),
-                self.sup_type.repr(tcx))
+impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
+               self.sub_region,
+               self.sup_type)
     }
 }
 
-fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                    t_a: Ty<'tcx>,
+fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
                                     r_b: ty::Region,
                                     cause: ObligationCause<'tcx>,
                                     region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
@@ -481,8 +478,8 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                sub_region: r_b,
                                                cause: cause };
 
-    debug!("register_region_obligation({})",
-           region_obligation.repr(tcx));
+    debug!("register_region_obligation({:?})",
+           region_obligation);
 
     region_obligations.entry(region_obligation.cause.body_id).or_insert(vec![])
         .push(region_obligation);
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index b4b53c003ea..e3c122e2f1f 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -23,7 +23,6 @@ use middle::infer::{self, fixup_err_to_string, InferCtxt};
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
-use util::ppaux::Repr;
 
 pub use self::error_reporting::report_fulfillment_errors;
 pub use self::error_reporting::report_overflow_error;
@@ -219,7 +218,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
 /// ### The type parameter `N`
 ///
 /// See explanation on `VtableImplData`.
-#[derive(Debug,Clone)]
+#[derive(Clone)]
 pub enum Vtable<'tcx, N> {
     /// Vtable identifying a particular impl.
     VtableImpl(VtableImplData<'tcx, N>),
@@ -277,13 +276,13 @@ pub struct VtableClosureData<'tcx, N> {
     pub nested: Vec<N>
 }
 
-#[derive(Debug, Clone)]
+#[derive(Clone)]
 pub struct VtableDefaultImplData<N> {
     pub trait_def_id: ast::DefId,
     pub nested: Vec<N>
 }
 
-#[derive(Debug,Clone)]
+#[derive(Clone)]
 pub struct VtableBuiltinData<N> {
     pub nested: Vec<N>
 }
@@ -300,12 +299,11 @@ pub struct VtableObjectData<'tcx> {
 }
 
 /// Creates predicate obligations from the generic bounds.
-pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                     cause: ObligationCause<'tcx>,
+pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
                                      generic_bounds: &ty::InstantiatedPredicates<'tcx>)
                                      -> PredicateObligations<'tcx>
 {
-    util::predicates_for_generics(tcx, cause, 0, generic_bounds)
+    util::predicates_for_generics(cause, 0, generic_bounds)
 }
 
 /// Determines whether the type `ty` is known to meet `bound` and
@@ -320,8 +318,8 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                                                  span: Span)
                                                  -> bool
 {
-    debug!("type_known_to_meet_builtin_bound(ty={}, bound={:?})",
-           ty.repr(infcx.tcx),
+    debug!("type_known_to_meet_builtin_bound(ty={:?}, bound={:?})",
+           ty,
            bound);
 
     let mut fulfill_cx = FulfillmentContext::new(false);
@@ -338,16 +336,16 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
     // assume it is move; linear is always ok.
     match fulfill_cx.select_all_or_error(infcx, typer) {
         Ok(()) => {
-            debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} success",
-                   ty.repr(infcx.tcx),
+            debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
+                   ty,
                    bound);
             true
         }
         Err(e) => {
-            debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} errors={}",
-                   ty.repr(infcx.tcx),
+            debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
+                   ty,
                    bound,
-                   e.repr(infcx.tcx));
+                   e);
             false
         }
     }
@@ -377,8 +375,8 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
     let span = cause.span;
     let body_id = cause.body_id;
 
-    debug!("normalize_param_env_or_error(unnormalized_env={})",
-           unnormalized_env.repr(tcx));
+    debug!("normalize_param_env_or_error(unnormalized_env={:?})",
+           unnormalized_env);
 
     let predicates: Vec<_> =
         util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.clone())
@@ -393,8 +391,8 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
     // constructed, but I am not currently doing so out of laziness.
     // -nmatsakis
 
-    debug!("normalize_param_env_or_error: elaborated-predicates={}",
-           predicates.repr(tcx));
+    debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
+           predicates);
 
     let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
 
@@ -434,25 +432,23 @@ pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                   cause: ObligationCause<'tcx>,
                                   value: &T)
                                   -> Result<T, Vec<FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+    where T : TypeFoldable<'tcx> + HasProjectionTypes
 {
-    let tcx = closure_typer.tcx();
-
-    debug!("normalize_param_env(value={})", value.repr(tcx));
+    debug!("normalize_param_env(value={:?})", value);
 
     let mut selcx = &mut SelectionContext::new(infcx, closure_typer);
     let mut fulfill_cx = FulfillmentContext::new(false);
     let Normalized { value: normalized_value, obligations } =
         project::normalize(selcx, cause, value);
-    debug!("normalize_param_env: normalized_value={} obligations={}",
-           normalized_value.repr(tcx),
-           obligations.repr(tcx));
+    debug!("normalize_param_env: normalized_value={:?} obligations={:?}",
+           normalized_value,
+           obligations);
     for obligation in obligations {
         fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
     }
     try!(fulfill_cx.select_all_or_error(infcx, closure_typer));
     let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
-    debug!("normalize_param_env: resolved_value={}", resolved_value.repr(tcx));
+    debug!("normalize_param_env: resolved_value={:?}", resolved_value);
     Ok(resolved_value)
 }
 
diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs
index cf8e391bf54..afb30716c36 100644
--- a/src/librustc/middle/traits/object_safety.rs
+++ b/src/librustc/middle/traits/object_safety.rs
@@ -25,8 +25,8 @@ use middle::traits;
 use middle::ty::{self, ToPolyTraitRef, Ty};
 use std::rc::Rc;
 use syntax::ast;
-use util::ppaux::Repr;
 
+#[derive(Debug)]
 pub enum ObjectSafetyViolation<'tcx> {
     /// Self : Sized declared on the trait
     SizedSelf,
@@ -70,7 +70,7 @@ pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
         result
     });
 
-    debug!("is_object_safe({}) = {}", trait_def_id.repr(tcx), result);
+    debug!("is_object_safe({:?}) = {}", trait_def_id, result);
 
     result
 }
@@ -111,9 +111,9 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
         violations.push(ObjectSafetyViolation::SupertraitSelf);
     }
 
-    debug!("object_safety_violations_for_trait(trait_def_id={}) = {}",
-           trait_def_id.repr(tcx),
-           violations.repr(tcx));
+    debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
+           trait_def_id,
+           violations);
 
     violations
 }
@@ -352,19 +352,6 @@ fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
     error
 }
 
-impl<'tcx> Repr<'tcx> for ObjectSafetyViolation<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            ObjectSafetyViolation::SizedSelf =>
-                format!("SizedSelf"),
-            ObjectSafetyViolation::SupertraitSelf =>
-                format!("SupertraitSelf"),
-            ObjectSafetyViolation::Method(ref m, code) =>
-                format!("Method({},{:?})", m.repr(tcx), code),
-        }
-    }
-}
-
 fn is_self<'tcx>(ty: Ty<'tcx>) -> bool {
     match ty.sty {
         ty::TyParam(ref data) => data.space == subst::SelfSpace,
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 71946aa79ce..3ac58dafa4a 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -28,7 +28,8 @@ use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
 use syntax::parse::token;
 use util::common::FN_OUTPUT_NAME;
-use util::ppaux::Repr;
+
+use std::fmt;
 
 pub type PolyProjectionObligation<'tcx> =
     Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
@@ -40,6 +41,7 @@ pub type ProjectionTyObligation<'tcx> =
     Obligation<'tcx, ty::ProjectionTy<'tcx>>;
 
 /// When attempting to resolve `<T as TraitRef>::Name` ...
+#[derive(Debug)]
 pub enum ProjectionTyError<'tcx> {
     /// ...we found multiple sources of information and couldn't resolve the ambiguity.
     TooManyCandidates,
@@ -53,7 +55,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
     pub err: ty::type_err<'tcx>
 }
 
-#[derive(PartialEq, Eq)]
+#[derive(PartialEq, Eq, Debug)]
 enum ProjectionTyCandidate<'tcx> {
     ParamEnv(ty::PolyProjectionPredicate<'tcx>),
     Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
@@ -76,8 +78,8 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
     obligation: &PolyProjectionObligation<'tcx>)
     -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
 {
-    debug!("poly_project_and_unify_type(obligation={})",
-           obligation.repr(selcx.tcx()));
+    debug!("poly_project_and_unify_type(obligation={:?})",
+           obligation);
 
     let infcx = selcx.infcx();
     infcx.commit_if_ok(|snapshot| {
@@ -109,8 +111,8 @@ fn project_and_unify_type<'cx,'tcx>(
     obligation: &ProjectionObligation<'tcx>)
     -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
 {
-    debug!("project_and_unify_type(obligation={})",
-           obligation.repr(selcx.tcx()));
+    debug!("project_and_unify_type(obligation={:?})",
+           obligation);
 
     let Normalized { value: normalized_ty, obligations } =
         match opt_normalize_projection_type(selcx,
@@ -124,9 +126,9 @@ fn project_and_unify_type<'cx,'tcx>(
             }
         };
 
-    debug!("project_and_unify_type: normalized_ty={} obligations={}",
-           normalized_ty.repr(selcx.tcx()),
-           obligations.repr(selcx.tcx()));
+    debug!("project_and_unify_type: normalized_ty={:?} obligations={:?}",
+           normalized_ty,
+           obligations);
 
     let infcx = selcx.infcx();
     let origin = infer::RelateOutputImplTypes(obligation.cause.span);
@@ -138,8 +140,8 @@ fn project_and_unify_type<'cx,'tcx>(
 
 fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>,
                                                     obligation: &ProjectionObligation<'tcx>) {
-    debug!("consider_unification_despite_ambiguity(obligation={})",
-           obligation.repr(selcx.tcx()));
+    debug!("consider_unification_despite_ambiguity(obligation={:?})",
+           obligation);
 
     let def_id = obligation.predicate.projection_ty.trait_ref.def_id;
     match selcx.tcx().lang_items.fn_trait_kind(def_id) {
@@ -173,7 +175,7 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
                     &ty::Binder(ret_type));
 
             debug!("consider_unification_despite_ambiguity: ret_type={:?}",
-                   ret_type.repr(selcx.tcx()));
+                   ret_type);
             let origin = infer::RelateOutputImplTypes(obligation.cause.span);
             let obligation_ty = obligation.predicate.ty;
             match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
@@ -193,7 +195,7 @@ pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
                                cause: ObligationCause<'tcx>,
                                value: &T)
                                -> Normalized<'tcx, T>
-    where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+    where T : TypeFoldable<'tcx> + HasProjectionTypes
 {
     normalize_with_depth(selcx, cause, 0, value)
 }
@@ -204,7 +206,7 @@ pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tc
                                           depth: usize,
                                           value: &T)
                                           -> Normalized<'tcx, T>
-    where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+    where T : TypeFoldable<'tcx> + HasProjectionTypes
 {
     let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
     let result = normalizer.fold(value);
@@ -236,7 +238,7 @@ impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> {
         }
     }
 
-    fn fold<T:TypeFoldable<'tcx> + HasProjectionTypes + Clone>(&mut self, value: &T) -> T {
+    fn fold<T:TypeFoldable<'tcx> + HasProjectionTypes>(&mut self, value: &T) -> T {
         let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
 
         if !value.has_projection_types() {
@@ -354,9 +356,9 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
     -> Option<NormalizedTy<'tcx>>
 {
     debug!("normalize_projection_type(\
-           projection_ty={}, \
+           projection_ty={:?}, \
            depth={})",
-           projection_ty.repr(selcx.tcx()),
+           projection_ty,
            depth);
 
     let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
@@ -367,18 +369,17 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
             // an impl, where-clause etc) and hence we must
             // re-normalize it
 
-            debug!("normalize_projection_type: projected_ty={} depth={} obligations={}",
-                   projected_ty.repr(selcx.tcx()),
+            debug!("normalize_projection_type: projected_ty={:?} depth={} obligations={:?}",
+                   projected_ty,
                    depth,
-                   obligations.repr(selcx.tcx()));
+                   obligations);
 
             if ty::type_has_projection(projected_ty) {
-                let tcx = selcx.tcx();
                 let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
                 let normalized_ty = normalizer.fold(&projected_ty);
 
-                debug!("normalize_projection_type: normalized_ty={} depth={}",
-                       normalized_ty.repr(tcx),
+                debug!("normalize_projection_type: normalized_ty={:?} depth={}",
+                       normalized_ty,
                        depth);
 
                 obligations.extend(normalizer.obligations);
@@ -394,8 +395,8 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
             }
         }
         Ok(ProjectedTy::NoProgress(projected_ty)) => {
-            debug!("normalize_projection_type: projected_ty={} no progress",
-                   projected_ty.repr(selcx.tcx()));
+            debug!("normalize_projection_type: projected_ty={:?} no progress",
+                   projected_ty);
             Some(Normalized {
                 value: projected_ty,
                 obligations: vec!()
@@ -449,8 +450,8 @@ fn project_type<'cx,'tcx>(
     obligation: &ProjectionTyObligation<'tcx>)
     -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>>
 {
-    debug!("project(obligation={})",
-           obligation.repr(selcx.tcx()));
+    debug!("project(obligation={:?})",
+           obligation);
 
     let recursion_limit = selcx.tcx().sess.recursion_limit.get();
     if obligation.recursion_depth >= recursion_limit {
@@ -461,7 +462,7 @@ fn project_type<'cx,'tcx>(
     let obligation_trait_ref =
         selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate.trait_ref);
 
-    debug!("project: obligation_trait_ref={}", obligation_trait_ref.repr(selcx.tcx()));
+    debug!("project: obligation_trait_ref={:?}", obligation_trait_ref);
 
     if obligation_trait_ref.references_error() {
         return Ok(ProjectedTy::Progress(selcx.tcx().types.err, vec!()));
@@ -589,12 +590,12 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
     env_predicates: I)
     where I: Iterator<Item=ty::Predicate<'tcx>>
 {
-    debug!("assemble_candidates_from_predicates(obligation={})",
-           obligation.repr(selcx.tcx()));
+    debug!("assemble_candidates_from_predicates(obligation={:?})",
+           obligation);
     let infcx = selcx.infcx();
     for predicate in env_predicates {
-        debug!("assemble_candidates_from_predicates: predicate={}",
-               predicate.repr(selcx.tcx()));
+        debug!("assemble_candidates_from_predicates: predicate={:?}",
+               predicate);
         match predicate {
             ty::Predicate::Projection(ref data) => {
                 let same_name = data.item_name() == obligation.predicate.item_name;
@@ -611,10 +612,9 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
                                               obligation_poly_trait_ref).is_ok()
                 });
 
-                debug!("assemble_candidates_from_predicates: candidate {} is_match {} same_name {}",
-                       data.repr(selcx.tcx()),
-                       is_match,
-                       same_name);
+                debug!("assemble_candidates_from_predicates: candidate={:?} \
+                                                             is_match={} same_name={}",
+                       data, is_match, same_name);
 
                 if is_match {
                     candidate_set.vec.push(
@@ -633,16 +633,15 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
     object_ty: Ty<'tcx>)
 {
-    let infcx = selcx.infcx();
-    debug!("assemble_candidates_from_object_type(object_ty={})",
-           object_ty.repr(infcx.tcx));
+    debug!("assemble_candidates_from_object_type(object_ty={:?})",
+           object_ty);
     let data = match object_ty.sty {
         ty::TyTrait(ref data) => data,
         _ => {
             selcx.tcx().sess.span_bug(
                 obligation.cause.span,
-                &format!("assemble_candidates_from_object_type called with non-object: {}",
-                         object_ty.repr(selcx.tcx())));
+                &format!("assemble_candidates_from_object_type called with non-object: {:?}",
+                         object_ty));
         }
     };
     let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
@@ -672,16 +671,16 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
             return Ok(());
         }
         Err(e) => {
-            debug!("assemble_candidates_from_impls: selection error {}",
-                   e.repr(selcx.tcx()));
+            debug!("assemble_candidates_from_impls: selection error {:?}",
+                   e);
             return Err(e);
         }
     };
 
     match vtable {
         super::VtableImpl(data) => {
-            debug!("assemble_candidates_from_impls: impl candidate {}",
-                   data.repr(selcx.tcx()));
+            debug!("assemble_candidates_from_impls: impl candidate {:?}",
+                   data);
 
             candidate_set.vec.push(
                 ProjectionTyCandidate::Impl(data));
@@ -731,8 +730,8 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
             // These traits have no associated types.
             selcx.tcx().sess.span_bug(
                 obligation.cause.span,
-                &format!("Cannot project an associated type from `{}`",
-                         vtable.repr(selcx.tcx())));
+                &format!("Cannot project an associated type from `{:?}`",
+                         vtable));
         }
     }
 
@@ -745,11 +744,9 @@ fn confirm_candidate<'cx,'tcx>(
     candidate: ProjectionTyCandidate<'tcx>)
     -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
 {
-    let infcx = selcx.infcx();
-
-    debug!("confirm_candidate(candidate={}, obligation={})",
-           candidate.repr(infcx.tcx),
-           obligation.repr(infcx.tcx));
+    debug!("confirm_candidate(candidate={:?}, obligation={:?})",
+           candidate,
+           obligation);
 
     match candidate {
         ProjectionTyCandidate::ParamEnv(poly_projection) => {
@@ -813,9 +810,9 @@ fn confirm_callable_candidate<'cx,'tcx>(
 {
     let tcx = selcx.tcx();
 
-    debug!("confirm_callable_candidate({},{})",
-           obligation.repr(tcx),
-           fn_sig.repr(tcx));
+    debug!("confirm_callable_candidate({:?},{:?})",
+           obligation,
+           fn_sig);
 
     // the `Output` associated type is declared on `FnOnce`
     let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap();
@@ -865,10 +862,10 @@ fn confirm_param_env_candidate<'cx,'tcx>(
         Err(e) => {
             selcx.tcx().sess.span_bug(
                 obligation.cause.span,
-                &format!("Failed to unify `{}` and `{}` in projection: {}",
-                         obligation.repr(selcx.tcx()),
-                         projection.repr(selcx.tcx()),
-                         ty::type_err_to_str(selcx.tcx(), &e)));
+                &format!("Failed to unify `{:?}` and `{:?}` in projection: {}",
+                         obligation,
+                         projection,
+                         e));
         }
     }
 
@@ -915,34 +912,8 @@ fn confirm_impl_candidate<'cx,'tcx>(
     }
 
     selcx.tcx().sess.span_bug(obligation.cause.span,
-                              &format!("No associated type for {}",
-                                       trait_ref.repr(selcx.tcx())));
-}
-
-impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            ProjectionTyError::TooManyCandidates =>
-                format!("NoCandidate"),
-            ProjectionTyError::TraitSelectionError(ref e) =>
-                format!("TraitSelectionError({})", e.repr(tcx)),
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            ProjectionTyCandidate::ParamEnv(ref data) =>
-                format!("ParamEnv({})", data.repr(tcx)),
-            ProjectionTyCandidate::Impl(ref data) =>
-                format!("Impl({})", data.repr(tcx)),
-            ProjectionTyCandidate::Closure(ref data) =>
-                format!("Closure({})", data.repr(tcx)),
-            ProjectionTyCandidate::FnPointer(a) =>
-                format!("FnPointer(({}))", a.repr(tcx)),
-        }
-    }
+                              &format!("No associated type for {:?}",
+                                       trait_ref));
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
@@ -954,10 +925,10 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
     }
 }
 
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Normalized<'tcx, T> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Normalized({},{})",
-                self.value.repr(tcx),
-                self.obligations.repr(tcx))
+impl<'tcx, T:fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Normalized({:?},{:?})",
+               self.value,
+               self.obligations)
     }
 }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 8e2a90aa808..1653cac68e6 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -44,12 +44,13 @@ use middle::infer::{InferCtxt, TypeFreshener};
 use middle::ty_fold::TypeFoldable;
 use middle::ty_match;
 use middle::ty_relate::TypeRelation;
+
 use std::cell::RefCell;
+use std::fmt;
 use std::rc::Rc;
 use syntax::{abi, ast};
 use util::common::ErrorReported;
 use util::nodemap::FnvHashMap;
-use util::ppaux::Repr;
 
 pub struct SelectionContext<'cx, 'tcx:'cx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
@@ -298,7 +299,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// type environment by performing unification.
     pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
                   -> SelectionResult<'tcx, Selection<'tcx>> {
-        debug!("select({})", obligation.repr(self.tcx()));
+        debug!("select({:?})", obligation);
         assert!(!obligation.predicate.has_escaping_regions());
 
         let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
@@ -387,8 +388,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                obligation: &PredicateObligation<'tcx>)
                                -> bool
     {
-        debug!("evaluate_obligation({})",
-               obligation.repr(self.tcx()));
+        debug!("evaluate_obligation({:?})",
+               obligation);
 
         self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
             .may_apply()
@@ -440,8 +441,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                           obligation: &PredicateObligation<'tcx>)
                                            -> EvaluationResult<'tcx>
     {
-        debug!("evaluate_predicate_recursively({})",
-               obligation.repr(self.tcx()));
+        debug!("evaluate_predicate_recursively({:?})",
+               obligation);
 
         // Check the cache from the tcx of predicates that we know
         // have been proven elsewhere. This cache only contains
@@ -499,8 +500,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                            obligation: &TraitObligation<'tcx>)
                                            -> EvaluationResult<'tcx>
     {
-        debug!("evaluate_obligation_recursively({})",
-               obligation.repr(self.tcx()));
+        debug!("evaluate_obligation_recursively({:?})",
+               obligation);
 
         let stack = self.push_stack(previous_stack, obligation);
 
@@ -547,8 +548,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                   |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref,
                                                      &prev.fresh_trait_ref)))
         {
-            debug!("evaluate_stack({}) --> unbound argument, recursion -->  ambiguous",
-                   stack.fresh_trait_ref.repr(self.tcx()));
+            debug!("evaluate_stack({:?}) --> unbound argument, recursion -->  ambiguous",
+                   stack.fresh_trait_ref);
             return EvaluatedToAmbig;
         }
 
@@ -576,8 +577,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .skip(1) // skip top-most frame
             .any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref)
         {
-            debug!("evaluate_stack({}) --> recursive",
-                   stack.fresh_trait_ref.repr(self.tcx()));
+            debug!("evaluate_stack({:?}) --> recursive",
+                   stack.fresh_trait_ref);
             return EvaluatedToOk;
         }
 
@@ -595,9 +596,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                          obligation: &TraitObligation<'tcx>)
                          -> bool
     {
-        debug!("evaluate_impl(impl_def_id={}, obligation={})",
-               impl_def_id.repr(self.tcx()),
-               obligation.repr(self.tcx()));
+        debug!("evaluate_impl(impl_def_id={:?}, obligation={:?})",
+               impl_def_id,
+               obligation);
 
         self.infcx.probe(|snapshot| {
             match self.match_impl(impl_def_id, obligation, snapshot) {
@@ -643,16 +644,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // with fresh skolemized types starting from index 0.
         let cache_fresh_trait_pred =
             self.infcx.freshen(stack.obligation.predicate.clone());
-        debug!("candidate_from_obligation(cache_fresh_trait_pred={}, obligation={})",
-               cache_fresh_trait_pred.repr(self.tcx()),
-               stack.repr(self.tcx()));
+        debug!("candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
+               cache_fresh_trait_pred,
+               stack);
         assert!(!stack.obligation.predicate.has_escaping_regions());
 
         match self.check_candidate_cache(&cache_fresh_trait_pred) {
             Some(c) => {
-                debug!("CACHE HIT: cache_fresh_trait_pred={}, candidate={}",
-                       cache_fresh_trait_pred.repr(self.tcx()),
-                       c.repr(self.tcx()));
+                debug!("CACHE HIT: cache_fresh_trait_pred={:?}, candidate={:?}",
+                       cache_fresh_trait_pred,
+                       c);
                 return c;
             }
             None => { }
@@ -662,8 +663,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let candidate = self.candidate_from_obligation_no_cache(stack);
 
         if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) {
-            debug!("CACHE MISS: cache_fresh_trait_pred={}, candidate={}",
-                   cache_fresh_trait_pred.repr(self.tcx()), candidate.repr(self.tcx()));
+            debug!("CACHE MISS: cache_fresh_trait_pred={:?}, candidate={:?}",
+                   cache_fresh_trait_pred, candidate);
             self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone());
         }
 
@@ -692,10 +693,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let mut candidates = candidate_set.vec;
 
-        debug!("assembled {} candidates for {}: {}",
+        debug!("assembled {} candidates for {:?}: {:?}",
                candidates.len(),
-               stack.repr(self.tcx()),
-               candidates.repr(self.tcx()));
+               stack,
+               candidates);
 
         // At this point, we know that each of the entries in the
         // candidate set is *individually* applicable. Now we have to
@@ -735,12 +736,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .any(|j| self.candidate_should_be_dropped_in_favor_of(&candidates[i],
                                                                           &candidates[j]));
                 if is_dup {
-                    debug!("Dropping candidate #{}/{}: {}",
-                           i, candidates.len(), candidates[i].repr(self.tcx()));
+                    debug!("Dropping candidate #{}/{}: {:?}",
+                           i, candidates.len(), candidates[i]);
                     candidates.swap_remove(i);
                 } else {
-                    debug!("Retaining candidate #{}/{}: {}",
-                           i, candidates.len(), candidates[i].repr(self.tcx()));
+                    debug!("Retaining candidate #{}/{}: {:?}",
+                           i, candidates.len(), candidates[i]);
                     i += 1;
                 }
             }
@@ -906,8 +907,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
             Some(ty::BoundCopy) => {
-                debug!("obligation self ty is {}",
-                       obligation.predicate.0.self_ty().repr(self.tcx()));
+                debug!("obligation self ty is {:?}",
+                       obligation.predicate.0.self_ty());
 
                 // User-defined copy impls are permitted, but only for
                 // structs and enums.
@@ -957,9 +958,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let poly_trait_predicate =
             self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
 
-        debug!("assemble_candidates_for_projected_tys({},{})",
-               obligation.repr(self.tcx()),
-               poly_trait_predicate.repr(self.tcx()));
+        debug!("assemble_candidates_for_projected_tys({:?},{:?})",
+               obligation,
+               poly_trait_predicate);
 
         // FIXME(#20297) -- just examining the self-type is very simplistic
 
@@ -981,8 +982,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => { return; }
         };
 
-        debug!("assemble_candidates_for_projected_tys: trait_def_id={}",
-               trait_def_id.repr(self.tcx()));
+        debug!("assemble_candidates_for_projected_tys: trait_def_id={:?}",
+               trait_def_id);
 
         let result = self.infcx.probe(|snapshot| {
             self.match_projection_obligation_against_bounds_from_trait(obligation,
@@ -1005,9 +1006,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let (skol_trait_predicate, skol_map) =
             self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot);
         debug!("match_projection_obligation_against_bounds_from_trait: \
-                skol_trait_predicate={} skol_map={}",
-               skol_trait_predicate.repr(self.tcx()),
-               skol_map.repr(self.tcx()));
+                skol_trait_predicate={:?} skol_map={:?}",
+               skol_trait_predicate,
+               skol_map);
 
         let projection_trait_ref = match skol_trait_predicate.trait_ref.self_ty().sty {
             ty::TyProjection(ref data) => &data.trait_ref,
@@ -1015,19 +1016,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.tcx().sess.span_bug(
                     obligation.cause.span,
                     &format!("match_projection_obligation_against_bounds_from_trait() called \
-                              but self-ty not a projection: {}",
-                             skol_trait_predicate.trait_ref.self_ty().repr(self.tcx())));
+                              but self-ty not a projection: {:?}",
+                             skol_trait_predicate.trait_ref.self_ty()));
             }
         };
         debug!("match_projection_obligation_against_bounds_from_trait: \
-                projection_trait_ref={}",
-               projection_trait_ref.repr(self.tcx()));
+                projection_trait_ref={:?}",
+               projection_trait_ref);
 
         let trait_predicates = ty::lookup_predicates(self.tcx(), projection_trait_ref.def_id);
         let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
         debug!("match_projection_obligation_against_bounds_from_trait: \
-                bounds={}",
-               bounds.repr(self.tcx()));
+                bounds={:?}",
+               bounds);
 
         let matching_bound =
             util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec())
@@ -1041,8 +1042,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                               snapshot)));
 
         debug!("match_projection_obligation_against_bounds_from_trait: \
-                matching_bound={}",
-               matching_bound.repr(self.tcx()));
+                matching_bound={:?}",
+               matching_bound);
         match matching_bound {
             None => false,
             Some(bound) => {
@@ -1088,8 +1089,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                                   candidates: &mut SelectionCandidateSet<'tcx>)
                                                   -> Result<(),SelectionError<'tcx>>
     {
-        debug!("assemble_candidates_from_caller_bounds({})",
-               stack.obligation.repr(self.tcx()));
+        debug!("assemble_candidates_from_caller_bounds({:?})",
+               stack.obligation);
 
         let all_bounds =
             self.param_env().caller_bounds
@@ -1155,10 +1156,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => { return Ok(()); }
         };
 
-        debug!("assemble_unboxed_candidates: self_ty={} kind={:?} obligation={}",
-               self_ty.repr(self.tcx()),
+        debug!("assemble_unboxed_candidates: self_ty={:?} kind={:?} obligation={:?}",
+               self_ty,
                kind,
-               obligation.repr(self.tcx()));
+               obligation);
 
         match self.closure_typer.closure_kind(closure_def_id) {
             Some(closure_kind) => {
@@ -1221,7 +1222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                       candidates: &mut SelectionCandidateSet<'tcx>)
                                       -> Result<(), SelectionError<'tcx>>
     {
-        debug!("assemble_candidates_from_impls(obligation={})", obligation.repr(self.tcx()));
+        debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
 
         let def = ty::lookup_trait_def(self.tcx(), obligation.predicate.def_id());
 
@@ -1247,7 +1248,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     {
         // OK to skip binder here because the tests we do below do not involve bound regions
         let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
-        debug!("assemble_candidates_from_default_impls(self_ty={})", self_ty.repr(self.tcx()));
+        debug!("assemble_candidates_from_default_impls(self_ty={:?})", self_ty);
 
         let def_id = obligation.predicate.def_id();
 
@@ -1316,8 +1317,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                           obligation: &TraitObligation<'tcx>,
                                           candidates: &mut SelectionCandidateSet<'tcx>)
     {
-        debug!("assemble_candidates_from_object_ty(self_ty={})",
-               self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()).repr(self.tcx()));
+        debug!("assemble_candidates_from_object_ty(self_ty={:?})",
+               self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()));
 
         // Object-safety candidates are only applicable to object-safe
         // traits. Including this check is useful because it helps
@@ -1362,8 +1363,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             };
 
-            debug!("assemble_candidates_from_object_ty: poly_trait_ref={}",
-                   poly_trait_ref.repr(self.tcx()));
+            debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}",
+                   poly_trait_ref);
 
             // see whether the object trait can be upcast to the trait we are looking for
             let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
@@ -1406,8 +1407,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let source = self.infcx.shallow_resolve(self_ty);
         let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
 
-        debug!("assemble_candidates_for_unsizing(source={}, target={})",
-               source.repr(self.tcx()), target.repr(self.tcx()));
+        debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})",
+               source, target);
 
         let may_apply = match (&source.sty, &target.sty) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
@@ -1473,7 +1474,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             candidate: &SelectionCandidate<'tcx>)
                             -> EvaluationResult<'tcx>
     {
-        debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx()));
+        debug!("winnow_candidate: candidate={:?}", candidate);
         let result = self.infcx.probe(|_| {
             let candidate = (*candidate).clone();
             match self.confirm_candidate(stack.obligation, candidate) {
@@ -1565,8 +1566,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     {
         match self.builtin_bound(bound, stack.obligation) {
             Ok(If(..)) => {
-                debug!("builtin_bound: bound={}",
-                       bound.repr(self.tcx()));
+                debug!("builtin_bound: bound={:?}",
+                       bound);
                 candidates.vec.push(BuiltinCandidate(bound));
                 Ok(())
             }
@@ -1774,8 +1775,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::TyInfer(ty::FreshFloatTy(_)) => {
                 self.tcx().sess.bug(
                     &format!(
-                        "asked to assemble builtin bounds of unexpected type: {}",
-                        self_ty.repr(self.tcx())));
+                        "asked to assemble builtin bounds of unexpected type: {:?}",
+                        self_ty));
             }
         };
 
@@ -1837,8 +1838,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::TyInfer(ty::FreshFloatTy(_)) => {
                 self.tcx().sess.bug(
                     &format!(
-                        "asked to assemble constituent types of unexpected type: {}",
-                        t.repr(self.tcx())));
+                        "asked to assemble constituent types of unexpected type: {:?}",
+                        t));
             }
 
             ty::TyBox(referent_ty) => {  // Box<T>
@@ -1972,9 +1973,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                          candidate: SelectionCandidate<'tcx>)
                          -> Result<Selection<'tcx>,SelectionError<'tcx>>
     {
-        debug!("confirm_candidate({}, {})",
-               obligation.repr(self.tcx()),
-               candidate.repr(self.tcx()));
+        debug!("confirm_candidate({:?}, {:?})",
+               obligation,
+               candidate);
 
         match candidate {
             BuiltinCandidate(builtin_bound) => {
@@ -2064,9 +2065,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                param: ty::PolyTraitRef<'tcx>)
                                -> Vec<PredicateObligation<'tcx>>
     {
-        debug!("confirm_param_candidate({},{})",
-               obligation.repr(self.tcx()),
-               param.repr(self.tcx()));
+        debug!("confirm_param_candidate({:?},{:?})",
+               obligation,
+               param);
 
         // During evaluation, we already checked that this
         // where-clause trait-ref could be unified with the obligation
@@ -2076,9 +2077,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             Ok(obligations) => obligations,
             Err(()) => {
                 self.tcx().sess.bug(
-                    &format!("Where clause `{}` was applicable to `{}` but now is not",
-                             param.repr(self.tcx()),
-                             obligation.repr(self.tcx())));
+                    &format!("Where clause `{:?}` was applicable to `{:?}` but now is not",
+                             param,
+                             obligation));
             }
         }
     }
@@ -2089,16 +2090,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                  -> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
                                            SelectionError<'tcx>>
     {
-        debug!("confirm_builtin_candidate({})",
-               obligation.repr(self.tcx()));
+        debug!("confirm_builtin_candidate({:?})",
+               obligation);
 
         match try!(self.builtin_bound(bound, obligation)) {
             If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)),
             AmbiguousBuiltin | ParameterBuiltin => {
                 self.tcx().sess.span_bug(
                     obligation.cause.span,
-                    &format!("builtin bound for {} was ambig",
-                            obligation.repr(self.tcx())));
+                    &format!("builtin bound for {:?} was ambig",
+                            obligation));
             }
         }
     }
@@ -2118,8 +2119,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let obligations = self.collect_predicates_for_types(obligation, trait_def, nested);
 
-        debug!("vtable_builtin_data: obligations={}",
-               obligations.repr(self.tcx()));
+        debug!("vtable_builtin_data: obligations={:?}",
+               obligations);
 
         VtableBuiltinData { nested: obligations }
     }
@@ -2134,9 +2135,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                       trait_def_id: ast::DefId)
                                       -> VtableDefaultImplData<PredicateObligation<'tcx>>
     {
-        debug!("confirm_default_impl_candidate({}, {})",
-               obligation.repr(self.tcx()),
-               trait_def_id.repr(self.tcx()));
+        debug!("confirm_default_impl_candidate({:?}, {:?})",
+               obligation,
+               trait_def_id);
 
         // binder is moved below
         let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
@@ -2145,8 +2146,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             None => {
                 self.tcx().sess.bug(
                     &format!(
-                        "asked to confirm default implementation for ambiguous type: {}",
-                        self_ty.repr(self.tcx())));
+                        "asked to confirm default implementation for ambiguous type: {:?}",
+                        self_ty));
             }
         }
     }
@@ -2156,9 +2157,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                              trait_def_id: ast::DefId)
                                              -> VtableDefaultImplData<PredicateObligation<'tcx>>
     {
-        debug!("confirm_default_impl_object_candidate({}, {})",
-               obligation.repr(self.tcx()),
-               trait_def_id.repr(self.tcx()));
+        debug!("confirm_default_impl_object_candidate({:?}, {:?})",
+               obligation,
+               trait_def_id);
 
         assert!(ty::has_attr(self.tcx(), trait_def_id, "rustc_reflect_like"));
 
@@ -2184,8 +2185,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => {
                 self.tcx().sess.bug(
                     &format!(
-                        "asked to confirm default object implementation for non-object type: {}",
-                        self_ty.repr(self.tcx())));
+                        "asked to confirm default object implementation for non-object type: {:?}",
+                        self_ty));
             }
         }
     }
@@ -2197,7 +2198,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                            nested: ty::Binder<Vec<Ty<'tcx>>>)
                            -> VtableDefaultImplData<PredicateObligation<'tcx>>
     {
-        debug!("vtable_default_impl_data: nested={}", nested.repr(self.tcx()));
+        debug!("vtable_default_impl_data: nested={:?}", nested);
 
         let mut obligations = self.collect_predicates_for_types(obligation,
                                                                 trait_def_id,
@@ -2218,7 +2219,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // no Errors in that code above
         obligations.append(&mut trait_obligations.unwrap());
 
-        debug!("vtable_default_impl_data: obligations={}", obligations.repr(self.tcx()));
+        debug!("vtable_default_impl_data: obligations={:?}", obligations);
 
         VtableDefaultImplData {
             trait_def_id: trait_def_id,
@@ -2232,9 +2233,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                               -> Result<VtableImplData<'tcx, PredicateObligation<'tcx>>,
                                         SelectionError<'tcx>>
     {
-        debug!("confirm_impl_candidate({},{})",
-               obligation.repr(self.tcx()),
-               impl_def_id.repr(self.tcx()));
+        debug!("confirm_impl_candidate({:?},{:?})",
+               obligation,
+               impl_def_id);
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
@@ -2242,7 +2243,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             let (substs, skol_map) =
                 self.rematch_impl(impl_def_id, obligation,
                                   snapshot);
-            debug!("confirm_impl_candidate substs={}", substs.repr(self.tcx()));
+            debug!("confirm_impl_candidate substs={:?}", substs);
             Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
                                 obligation.recursion_depth + 1, skol_map, snapshot))
         })
@@ -2257,11 +2258,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                    snapshot: &infer::CombinedSnapshot)
                    -> VtableImplData<'tcx, PredicateObligation<'tcx>>
     {
-        debug!("vtable_impl(impl_def_id={}, substs={}, recursion_depth={}, skol_map={})",
-               impl_def_id.repr(self.tcx()),
-               substs.repr(self.tcx()),
+        debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})",
+               impl_def_id,
+               substs,
                recursion_depth,
-               skol_map.repr(self.tcx()));
+               skol_map);
 
         let mut impl_obligations =
             self.impl_or_trait_obligations(cause,
@@ -2271,9 +2272,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                            skol_map,
                                            snapshot);
 
-        debug!("vtable_impl: impl_def_id={} impl_obligations={}",
-               impl_def_id.repr(self.tcx()),
-               impl_obligations.repr(self.tcx()));
+        debug!("vtable_impl: impl_def_id={:?} impl_obligations={:?}",
+               impl_def_id,
+               impl_obligations);
 
         impl_obligations.append(&mut substs.obligations);
 
@@ -2286,8 +2287,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 obligation: &TraitObligation<'tcx>)
                                 -> VtableObjectData<'tcx>
     {
-        debug!("confirm_object_candidate({})",
-               obligation.repr(self.tcx()));
+        debug!("confirm_object_candidate({:?})",
+               obligation);
 
         // FIXME skipping binder here seems wrong -- we should
         // probably flatten the binder from the obligation and the
@@ -2328,8 +2329,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                     obligation: &TraitObligation<'tcx>)
                                     -> Result<ty::Ty<'tcx>,SelectionError<'tcx>>
     {
-        debug!("confirm_fn_pointer_candidate({})",
-               obligation.repr(self.tcx()));
+        debug!("confirm_fn_pointer_candidate({:?})",
+               obligation);
 
         // ok to skip binder; it is reintroduced below
         let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
@@ -2355,20 +2356,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                  -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
                                            SelectionError<'tcx>>
     {
-        debug!("confirm_closure_candidate({},{},{})",
-               obligation.repr(self.tcx()),
-               closure_def_id.repr(self.tcx()),
-               substs.repr(self.tcx()));
+        debug!("confirm_closure_candidate({:?},{:?},{:?})",
+               obligation,
+               closure_def_id,
+               substs);
 
         let Normalized {
             value: trait_ref,
             obligations
         } = self.closure_trait_ref(obligation, closure_def_id, substs);
 
-        debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={}, obligations={})",
-               closure_def_id.repr(self.tcx()),
-               trait_ref.repr(self.tcx()),
-               obligations.repr(self.tcx()));
+        debug!("confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
+               closure_def_id,
+               trait_ref,
+               obligations);
 
         try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
                                           obligation.predicate.to_poly_trait_ref(),
@@ -2436,8 +2437,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::no_late_bound_regions(tcx, &obligation.self_ty()).unwrap());
         let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
 
-        debug!("confirm_builtin_unsize_candidate(source={}, target={})",
-               source.repr(tcx), target.repr(tcx));
+        debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})",
+               source, target);
 
         let mut nested = vec![];
         match (&source.sty, &target.sty) {
@@ -2613,9 +2614,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             Ok((substs, skol_map)) => (substs, skol_map),
             Err(()) => {
                 self.tcx().sess.bug(
-                    &format!("Impl {} was matchable against {} but now is not",
-                            impl_def_id.repr(self.tcx()),
-                            obligation.repr(self.tcx())));
+                    &format!("Impl {:?} was matchable against {:?} but now is not",
+                            impl_def_id,
+                            obligation));
             }
         }
     }
@@ -2654,30 +2655,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                           obligation.recursion_depth + 1,
                                           &impl_trait_ref);
 
-        debug!("match_impl(impl_def_id={}, obligation={}, \
-               impl_trait_ref={}, skol_obligation_trait_ref={})",
-               impl_def_id.repr(self.tcx()),
-               obligation.repr(self.tcx()),
-               impl_trait_ref.repr(self.tcx()),
-               skol_obligation_trait_ref.repr(self.tcx()));
+        debug!("match_impl(impl_def_id={:?}, obligation={:?}, \
+               impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
+               impl_def_id,
+               obligation,
+               impl_trait_ref,
+               skol_obligation_trait_ref);
 
         let origin = infer::RelateOutputImplTypes(obligation.cause.span);
         if let Err(e) = self.infcx.sub_trait_refs(false,
                                                   origin,
                                                   impl_trait_ref.value.clone(),
                                                   skol_obligation_trait_ref) {
-            debug!("match_impl: failed sub_trait_refs due to `{}`",
-                   ty::type_err_to_str(self.tcx(), &e));
+            debug!("match_impl: failed sub_trait_refs due to `{}`", e);
             return Err(());
         }
 
         if let Err(e) = self.infcx.leak_check(&skol_map, snapshot) {
-            debug!("match_impl: failed leak check due to `{}`",
-                   ty::type_err_to_str(self.tcx(), &e));
+            debug!("match_impl: failed leak check due to `{}`", e);
             return Err(());
         }
 
-        debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx()));
+        debug!("match_impl: success impl_substs={:?}", impl_substs);
         Ok((Normalized {
             value: impl_substs,
             obligations: impl_trait_ref.obligations
@@ -2728,9 +2727,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             poly_trait_ref: ty::PolyTraitRef<'tcx>)
                             -> Result<(),()>
     {
-        debug!("match_poly_trait_ref: obligation={} poly_trait_ref={}",
-               obligation.repr(self.tcx()),
-               poly_trait_ref.repr(self.tcx()));
+        debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
+               obligation,
+               poly_trait_ref);
 
         let origin = infer::RelateOutputImplTypes(obligation.cause.span);
         match self.infcx.sub_poly_trait_refs(false,
@@ -2769,15 +2768,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty;
         let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs);
 
-        debug!("match_impl_self_types(obligation_self_ty={}, impl_self_ty={})",
-               obligation_self_ty.repr(self.tcx()),
-               impl_self_ty.repr(self.tcx()));
+        debug!("match_impl_self_types(obligation_self_ty={:?}, impl_self_ty={:?})",
+               obligation_self_ty,
+               impl_self_ty);
 
         match self.match_self_types(obligation_cause,
                                     impl_self_ty,
                                     obligation_self_ty) {
             Ok(()) => {
-                debug!("Matched impl_substs={}", impl_substs.repr(self.tcx()));
+                debug!("Matched impl_substs={:?}", impl_substs);
                 Ok(impl_substs)
             }
             Err(()) => {
@@ -2889,15 +2888,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                  snapshot: &infer::CombinedSnapshot)
                                  -> Vec<PredicateObligation<'tcx>>
     {
-        debug!("impl_or_trait_obligations(def_id={})", def_id.repr(self.tcx()));
+        debug!("impl_or_trait_obligations(def_id={:?})", def_id);
 
         let predicates = ty::lookup_predicates(self.tcx(), def_id);
         let predicates = predicates.instantiate(self.tcx(), substs);
         let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates);
         let mut predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates);
         let mut obligations =
-            util::predicates_for_generics(self.tcx(),
-                                          cause,
+            util::predicates_for_generics(cause,
                                           recursion_depth,
                                           &predicates.value);
         obligations.append(&mut predicates.obligations);
@@ -2940,9 +2938,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>)
               -> Vec<ty::PolyTraitRef<'tcx>>
     {
-        debug!("upcast(obj_trait_ref={}, obligation={})",
-               obj_trait_ref.repr(self.tcx()),
-               obligation.repr(self.tcx()));
+        debug!("upcast(obj_trait_ref={:?}, obligation={:?})",
+               obj_trait_ref,
+               obligation);
 
         let obligation_def_id = obligation.predicate.def_id();
         let mut upcast_trait_refs = util::upcast(self.tcx(), obj_trait_ref, obligation_def_id);
@@ -2958,33 +2956,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             self.infcx.probe(|_| self.match_poly_trait_ref(obligation, upcast_trait_ref)).is_ok()
         });
 
-        debug!("upcast: upcast_trait_refs={}", upcast_trait_refs.repr(self.tcx()));
+        debug!("upcast: upcast_trait_refs={:?}", upcast_trait_refs);
         upcast_trait_refs
     }
 }
 
-impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            PhantomFnCandidate => format!("PhantomFnCandidate"),
-            ErrorCandidate => format!("ErrorCandidate"),
-            BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b),
-            BuiltinObjectCandidate => format!("BuiltinObjectCandidate"),
-            BuiltinUnsizeCandidate => format!("BuiltinUnsizeCandidate"),
-            ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
-            ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
-            DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
-            DefaultImplObjectCandidate(t) => format!("DefaultImplObjectCandidate({:?})", t),
-            ProjectionCandidate => format!("ProjectionCandidate"),
-            FnPointerCandidate => format!("FnPointerCandidate"),
-            ObjectCandidate => format!("ObjectCandidate"),
-            ClosureCandidate(c, ref s) => {
-                format!("ClosureCandidate({:?},{})", c, s.repr(tcx))
-            }
-        }
-    }
-}
-
 impl<'tcx> SelectionCache<'tcx> {
     pub fn new() -> SelectionCache<'tcx> {
         SelectionCache {
@@ -3032,10 +3008,9 @@ impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{
     }
 }
 
-impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("TraitObligationStack({})",
-                self.obligation.repr(tcx))
+impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TraitObligationStack({:?})", self.obligation)
     }
 }
 
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index c1205d4a46d..54bcd9d7e66 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -16,7 +16,6 @@ use syntax::ast;
 use syntax::codemap::Span;
 use util::common::ErrorReported;
 use util::nodemap::FnvHashSet;
-use util::ppaux::Repr;
 
 use super::{Obligation, ObligationCause, PredicateObligation,
             VtableImpl, VtableParam, VtableImplData, VtableDefaultImplData};
@@ -125,8 +124,8 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
                               .map(|p| p.subst_supertrait(self.tcx, &data.to_poly_trait_ref()))
                               .collect();
 
-                debug!("super_predicates: data={} predicates={}",
-                       data.repr(self.tcx), predicates.repr(self.tcx));
+                debug!("super_predicates: data={:?} predicates={:?}",
+                       data, predicates);
 
                 // Only keep those bounds that we haven't already
                 // seen.  This is necessary to prevent infinite
@@ -302,33 +301,14 @@ pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
     infcx.fresh_substs_for_generics(span, &impl_generics)
 }
 
-impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableImpl({:?})", self.impl_def_id)
-    }
-}
-
-impl<'tcx, N> fmt::Debug for super::VtableClosureData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableClosure({:?})", self.closure_def_id)
-    }
-}
-
-impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableObject(...)")
-    }
-}
-
 /// See `super::obligations_for_generics`
-pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                     cause: ObligationCause<'tcx>,
+pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
                                      recursion_depth: usize,
                                      generic_bounds: &ty::InstantiatedPredicates<'tcx>)
                                      -> Vec<PredicateObligation<'tcx>>
 {
-    debug!("predicates_for_generics(generic_bounds={})",
-           generic_bounds.repr(tcx));
+    debug!("predicates_for_generics(generic_bounds={:?})",
+           generic_bounds);
 
     generic_bounds.predicates.iter().map(|predicate| {
         Obligation { cause: cause.clone(),
@@ -486,118 +466,84 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
     ty::Binder((trait_ref, sig.0.output.unwrap_or(ty::mk_nil(tcx))))
 }
 
-impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Obligation(predicate={},depth={})",
-                self.predicate.repr(tcx),
-                self.recursion_depth)
+impl<'tcx,O:fmt::Debug> fmt::Debug for super::Obligation<'tcx, O> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Obligation(predicate={:?},depth={})",
+               self.predicate,
+               self.recursion_depth)
     }
 }
 
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::Vtable<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             super::VtableImpl(ref v) =>
-                v.repr(tcx),
+                write!(f, "{:?}", v),
 
             super::VtableDefaultImpl(ref t) =>
-                t.repr(tcx),
+                write!(f, "{:?}", t),
 
             super::VtableClosure(ref d) =>
-                d.repr(tcx),
+                write!(f, "{:?}", d),
 
             super::VtableFnPointer(ref d) =>
-                format!("VtableFnPointer({})",
-                        d.repr(tcx)),
+                write!(f, "VtableFnPointer({:?})", d),
 
             super::VtableObject(ref d) =>
-                format!("VtableObject({})",
-                        d.repr(tcx)),
+                write!(f, "VtableObject({:?})", d),
 
             super::VtableParam(ref n) =>
-                format!("VtableParam({})",
-                        n.repr(tcx)),
+                write!(f, "VtableParam({:?})", n),
 
             super::VtableBuiltin(ref d) =>
-                d.repr(tcx)
+                write!(f, "{:?}", d)
         }
     }
 }
 
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableImplData<'tcx, N> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("VtableImpl(impl_def_id={}, substs={}, nested={})",
-                self.impl_def_id.repr(tcx),
-                self.substs.repr(tcx),
-                self.nested.repr(tcx))
-    }
-}
-
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableClosureData<'tcx, N> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("VtableClosure(closure_def_id={}, substs={}, nested={})",
-                self.closure_def_id.repr(tcx),
-                self.substs.repr(tcx),
-                self.nested.repr(tcx))
-    }
-}
-
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData<N> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("VtableBuiltin(nested={})",
-                self.nested.repr(tcx))
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableImplData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})",
+               self.impl_def_id,
+               self.substs,
+               self.nested)
     }
 }
 
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableDefaultImplData<N> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("VtableDefaultImplData(trait_def_id={}, nested={})",
-                self.trait_def_id.repr(tcx),
-                self.nested.repr(tcx))
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableClosureData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})",
+               self.closure_def_id,
+               self.substs,
+               self.nested)
     }
 }
 
-impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("VtableObject(object_ty={})",
-                self.object_ty.repr(tcx))
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableBuiltinData<N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableBuiltin(nested={:?})", self.nested)
     }
 }
 
-impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            super::Unimplemented =>
-                format!("Unimplemented"),
-
-            super::OutputTypeParameterMismatch(ref a, ref b, ref c) =>
-                format!("OutputTypeParameterMismatch({},{},{})",
-                        a.repr(tcx),
-                        b.repr(tcx),
-                        c.repr(tcx)),
-
-            super::TraitNotObjectSafe(ref tr) =>
-                format!("TraitNotObjectSafe({})",
-                        tr.repr(tcx))
-        }
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableDefaultImplData<N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})",
+               self.trait_def_id,
+               self.nested)
     }
 }
 
-impl<'tcx> Repr<'tcx> for super::FulfillmentError<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("FulfillmentError({},{})",
-                self.obligation.repr(tcx),
-                self.code.repr(tcx))
+impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableObject(object_ty={:?})", self.object_ty)
     }
 }
 
-impl<'tcx> Repr<'tcx> for super::FulfillmentErrorCode<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            super::CodeSelectionError(ref o) => o.repr(tcx),
-            super::CodeProjectionError(ref o) => o.repr(tcx),
-            super::CodeAmbiguity => format!("Ambiguity")
-        }
+impl<'tcx> fmt::Debug for super::FulfillmentError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "FulfillmentError({:?},{:?})",
+               self.obligation,
+               self.code)
     }
 }
 
@@ -611,14 +557,8 @@ impl<'tcx> fmt::Debug for super::FulfillmentErrorCode<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for super::MismatchedProjectionTypes<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        self.err.repr(tcx)
-    }
-}
-
 impl<'tcx> fmt::Debug for super::MismatchedProjectionTypes<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "MismatchedProjectionTypes(..)")
+        write!(f, "MismatchedProjectionTypes({:?})", self.err)
     }
 }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index f5fcb72c5c1..170b98b8831 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -12,7 +12,6 @@
 
 pub use self::terr_vstore_kind::*;
 pub use self::type_err::*;
-pub use self::BuiltinBound::*;
 pub use self::InferTy::*;
 pub use self::InferRegion::*;
 pub use self::ImplOrTraitItemId::*;
@@ -35,6 +34,11 @@ pub use self::IntVarValue::*;
 pub use self::MethodOrigin::*;
 pub use self::CopyImplementationError::*;
 
+pub use self::BuiltinBound::Send as BoundSend;
+pub use self::BuiltinBound::Sized as BoundSized;
+pub use self::BuiltinBound::Copy as BoundCopy;
+pub use self::BuiltinBound::Sync as BoundSync;
+
 use ast_map::{self, LinkedPath};
 use back::svh::Svh;
 use session::Session;
@@ -48,6 +52,7 @@ use middle::def::{self, DefMap, ExportMap};
 use middle::dependency_format;
 use middle::fast_reject;
 use middle::free_region::FreeRegionMap;
+use middle::infer::error_reporting::note_and_explain_region;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::mem_categorization as mc;
 use middle::region;
@@ -61,9 +66,6 @@ use middle::traits;
 use middle::ty;
 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
 use middle::ty_walk::{self, TypeWalker};
-use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
-use util::ppaux::ty_to_string;
-use util::ppaux::{Repr, UserString};
 use util::common::{memoized, ErrorReported};
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::FnvHashMap;
@@ -79,7 +81,7 @@ use std::mem;
 use std::ops;
 use std::rc::Rc;
 use std::vec::IntoIter;
-use collections::enum_set::{EnumSet, CLike};
+use collections::enum_set::{self, EnumSet, CLike};
 use std::collections::{HashMap, HashSet};
 use syntax::abi;
 use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE};
@@ -101,11 +103,10 @@ pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
 
 /// The complete set of all analyses described in this module. This is
 /// produced by the driver and fed to trans and later passes.
-pub struct CrateAnalysis<'tcx> {
+pub struct CrateAnalysis {
     pub export_map: ExportMap,
     pub exported_items: middle::privacy::ExportedItems,
     pub public_items: middle::privacy::PublicItems,
-    pub ty_cx: ty::ctxt<'tcx>,
     pub reachable: NodeSet,
     pub name: String,
     pub glob_map: Option<GlobMap>,
@@ -132,7 +133,7 @@ impl ImplOrTraitItemContainer {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub enum ImplOrTraitItem<'tcx> {
     ConstTraitItem(Rc<AssociatedConst<'tcx>>),
     MethodTraitItem(Rc<Method<'tcx>>),
@@ -295,7 +296,7 @@ pub struct ItemVariances {
     pub regions: VecPerParamSpace<Variance>,
 }
 
-#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug, Copy)]
+#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)]
 pub enum Variance {
     Covariant,      // T<A> <: T<B> iff A <: B -- e.g., function return type
     Invariant,      // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
@@ -303,7 +304,7 @@ pub enum Variance {
     Bivariant,      // T<A> <: T<B>            -- e.g., unused type parameter
 }
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
 pub enum AutoAdjustment<'tcx> {
     AdjustReifyFnPointer,   // go from a fn-item type to a fn-pointer type
     AdjustUnsafeFnPointer,  // go from a safe fn pointer to an unsafe fn pointer
@@ -372,7 +373,7 @@ pub enum AutoAdjustment<'tcx> {
 ///     unsize: Some(Box<[i32]>),
 /// }
 /// ```
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
 pub struct AutoDerefRef<'tcx> {
     /// Step 1. Apply a number of dereferences, producing an lvalue.
     pub autoderefs: usize,
@@ -402,7 +403,7 @@ pub enum CustomCoerceUnsized {
     Struct(usize)
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub enum MethodOrigin<'tcx> {
     // fully statically resolved method
     MethodStatic(ast::DefId),
@@ -420,7 +421,7 @@ pub enum MethodOrigin<'tcx> {
 
 // details for a method invoked with a receiver whose type is a type parameter
 // with a bounded trait.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct MethodParam<'tcx> {
     // the precise trait reference that occurs as a bound -- this may
     // be a supertrait of what the user actually typed. Note that it
@@ -441,7 +442,7 @@ pub struct MethodParam<'tcx> {
 }
 
 // details for a method invoked with a receiver whose type is an object
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct MethodObject<'tcx> {
     // the (super)trait containing the method to be invoked
     pub trait_ref: TraitRef<'tcx>,
@@ -804,6 +805,201 @@ impl<'tcx> ctxt<'tcx> {
     pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
         self.free_region_maps.borrow()[&id].clone()
     }
+
+    pub fn lift<T: ?Sized + Lift<'tcx>>(&self, value: &T) -> Option<T::Lifted> {
+        value.lift_to_tcx(self)
+    }
+}
+
+/// A trait implemented for all X<'a> types which can be safely and
+/// efficiently converted to X<'tcx> as long as they are part of the
+/// provided ty::ctxt<'tcx>.
+/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
+/// by looking them up in their respective interners.
+/// None is returned if the value or one of the components is not part
+/// of the provided context.
+/// For Ty, None can be returned if either the type interner doesn't
+/// contain the TypeVariants key or if the address of the interned
+/// pointer differs. The latter case is possible if a primitive type,
+/// e.g. `()` or `u8`, was interned in a different context.
+pub trait Lift<'tcx> {
+    type Lifted;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted>;
+}
+
+impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
+    type Lifted = (A::Lifted, B::Lifted);
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b)))
+    }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
+    type Lifted = Vec<T::Lifted>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+        let mut result = Vec::with_capacity(self.len());
+        for x in self {
+            if let Some(value) = tcx.lift(x) {
+                result.push(value);
+            } else {
+                return None;
+            }
+        }
+        Some(result)
+    }
+}
+
+impl<'tcx> Lift<'tcx> for Region {
+    type Lifted = Self;
+    fn lift_to_tcx(&self, _: &ctxt<'tcx>) -> Option<Region> {
+        Some(*self)
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
+    type Lifted = Ty<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Ty<'tcx>> {
+        if let Some(&ty) = tcx.interner.borrow().get(&self.sty) {
+            if *self as *const _ == ty as *const _ {
+                return Some(ty);
+            }
+        }
+        None
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
+    type Lifted = &'tcx Substs<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<&'tcx Substs<'tcx>> {
+        if let Some(&substs) = tcx.substs_interner.borrow().get(*self) {
+            if *self as *const _ == substs as *const _ {
+                return Some(substs);
+            }
+        }
+        None
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> {
+    type Lifted = TraitRef<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitRef<'tcx>> {
+        tcx.lift(&self.substs).map(|substs| TraitRef {
+            def_id: self.def_id,
+            substs: substs
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for TraitPredicate<'a> {
+    type Lifted = TraitPredicate<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitPredicate<'tcx>> {
+        tcx.lift(&self.trait_ref).map(|trait_ref| TraitPredicate {
+            trait_ref: trait_ref
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for EquatePredicate<'a> {
+    type Lifted = EquatePredicate<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<EquatePredicate<'tcx>> {
+        tcx.lift(&(self.0, self.1)).map(|(a, b)| EquatePredicate(a, b))
+    }
+}
+
+impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for OutlivesPredicate<A, B> {
+    type Lifted = OutlivesPredicate<A::Lifted, B::Lifted>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&(self.0, self.1)).map(|(a, b)| OutlivesPredicate(a, b))
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ProjectionPredicate<'a> {
+    type Lifted = ProjectionPredicate<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<ProjectionPredicate<'tcx>> {
+        tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| {
+            ProjectionPredicate {
+                projection_ty: ProjectionTy {
+                    trait_ref: trait_ref,
+                    item_name: self.projection_ty.item_name
+                },
+                ty: ty
+            }
+        })
+    }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Binder<T> {
+    type Lifted = Binder<T::Lifted>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.0).map(|x| Binder(x))
+    }
+}
+
+pub mod tls {
+    use ast_map;
+    use middle::ty;
+    use session::Session;
+
+    use std::fmt;
+    use syntax::ast;
+    use syntax::codemap;
+
+    /// Marker type used for the scoped TLS slot.
+    /// The type context cannot be used directly because the scoped TLS
+    /// in libstd doesn't allow types generic over lifetimes.
+    struct ThreadLocalTyCx;
+
+    scoped_thread_local!(static TLS_TCX: ThreadLocalTyCx);
+
+    fn def_id_debug(def_id: ast::DefId, f: &mut fmt::Formatter) -> fmt::Result {
+        // 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
+        with(|tcx| {
+            if def_id.krate == ast::LOCAL_CRATE {
+                match tcx.map.find(def_id.node) {
+                    Some(ast_map::NodeItem(..)) |
+                    Some(ast_map::NodeForeignItem(..)) |
+                    Some(ast_map::NodeImplItem(..)) |
+                    Some(ast_map::NodeTraitItem(..)) |
+                    Some(ast_map::NodeVariant(..)) |
+                    Some(ast_map::NodeStructCtor(..)) => {
+                        return write!(f, "{}", ty::item_path_str(tcx, def_id));
+                    }
+                    _ => {}
+                }
+            }
+            Ok(())
+        })
+    }
+
+    fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
+        with(|tcx| {
+            write!(f, "{}", tcx.sess.codemap().span_to_string(span))
+        })
+    }
+
+    pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
+                                                           -> (Session, R) {
+        let result = ast::DEF_ID_DEBUG.with(|def_id_dbg| {
+            codemap::SPAN_DEBUG.with(|span_dbg| {
+                let original_def_id_debug = def_id_dbg.get();
+                def_id_dbg.set(def_id_debug);
+                let original_span_debug = span_dbg.get();
+                span_dbg.set(span_debug);
+                let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
+                let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
+                def_id_dbg.set(original_def_id_debug);
+                span_dbg.set(original_span_debug);
+                result
+            })
+        });
+        (tcx.sess, result)
+    }
+
+    pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
+        TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) }))
+    }
 }
 
 // Flags that we track on types. These flags are propagated upwards
@@ -928,7 +1124,6 @@ impl<'tcx> ctxt<'tcx> {
     }
 }
 
-#[derive(Debug)]
 pub struct TyS<'tcx> {
     pub sty: TypeVariants<'tcx>,
     pub flags: Cell<TypeFlags>,
@@ -1051,7 +1246,7 @@ pub struct BareFnTy<'tcx> {
     pub sig: PolyFnSig<'tcx>,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct ClosureTy<'tcx> {
     pub unsafety: ast::Unsafety,
     pub abi: abi::Abi,
@@ -1122,7 +1317,7 @@ impl<'tcx> PolyFnSig<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct ParamTy {
     pub space: subst::ParamSpace,
     pub idx: u32,
@@ -1176,7 +1371,7 @@ pub struct DebruijnIndex {
 }
 
 /// Representation of regions:
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Copy)]
 pub enum Region {
     // Region bound in a type or fn declaration which will be
     // substituted 'early' -- that is, at the same time when type
@@ -1224,7 +1419,7 @@ pub struct EarlyBoundRegion {
 /// Upvars do not get their own node-id. Instead, we use the pair of
 /// the original var id (that is, the root variable that is referenced
 /// by the upvar) and the id of the closure expression.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct UpvarId {
     pub var_id: ast::NodeId,
     pub closure_expr_id: ast::NodeId,
@@ -1289,7 +1484,7 @@ pub enum UpvarCapture {
     ByRef(UpvarBorrow),
 }
 
-#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Copy)]
 pub struct UpvarBorrow {
     /// The kind of borrow: by-ref upvars have access to shared
     /// immutable borrows, which are not part of the normal language
@@ -1329,7 +1524,7 @@ impl Region {
 }
 
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
-         RustcEncodable, RustcDecodable, Debug, Copy)]
+         RustcEncodable, RustcDecodable, Copy)]
 /// A "free" region `fr` can be interpreted as "some region
 /// at least as big as the scope `fr.scope`".
 pub struct FreeRegion {
@@ -1338,7 +1533,7 @@ pub struct FreeRegion {
 }
 
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
-         RustcEncodable, RustcDecodable, Debug, Copy)]
+         RustcEncodable, RustcDecodable, Copy, Debug)]
 pub enum BoundRegion {
     /// An anonymous region parameter for a given fn (&T)
     BrAnon(u32),
@@ -1449,7 +1644,7 @@ pub enum TypeVariants<'tcx> {
     TyError,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct TraitTy<'tcx> {
     pub principal: ty::PolyTraitRef<'tcx>,
     pub bounds: ExistentialBounds<'tcx>,
@@ -1520,7 +1715,7 @@ impl<'tcx> TraitTy<'tcx> {
 /// Note that a `TraitRef` introduces a level of region binding, to
 /// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
 /// U>` or higher-ranked object types.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct TraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: &'tcx Substs<'tcx>,
@@ -1655,7 +1850,7 @@ pub enum type_err<'tcx> {
 
 /// Bounds suitable for a named type parameter like `A` in `fn foo<A>`
 /// as well as the existential type parameter in an object type.
-#[derive(PartialEq, Eq, Hash, Clone, Debug)]
+#[derive(PartialEq, Eq, Hash, Clone)]
 pub struct ParamBounds<'tcx> {
     pub region_bounds: Vec<ty::Region>,
     pub builtin_bounds: BuiltinBounds,
@@ -1668,41 +1863,57 @@ pub struct ParamBounds<'tcx> {
 /// major difference between this case and `ParamBounds` is that
 /// general purpose trait bounds are omitted and there must be
 /// *exactly one* region.
-#[derive(PartialEq, Eq, Hash, Clone, Debug)]
+#[derive(PartialEq, Eq, Hash, Clone)]
 pub struct ExistentialBounds<'tcx> {
     pub region_bound: ty::Region,
     pub builtin_bounds: BuiltinBounds,
     pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
 }
 
-pub type BuiltinBounds = EnumSet<BuiltinBound>;
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct BuiltinBounds(EnumSet<BuiltinBound>);
 
-#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
-           Debug, Copy)]
-#[repr(usize)]
-pub enum BuiltinBound {
-    BoundSend,
-    BoundSized,
-    BoundCopy,
-    BoundSync,
+impl BuiltinBounds {
+    pub fn empty() -> BuiltinBounds {
+        BuiltinBounds(EnumSet::new())
+    }
+
+    pub fn iter(&self) -> enum_set::Iter<BuiltinBound> {
+        self.into_iter()
+    }
+}
+
+impl ops::Deref for BuiltinBounds {
+    type Target = EnumSet<BuiltinBound>;
+    fn deref(&self) -> &Self::Target { &self.0 }
+}
+
+impl ops::DerefMut for BuiltinBounds {
+    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
 }
 
-pub fn empty_builtin_bounds() -> BuiltinBounds {
-    EnumSet::new()
+impl<'a> IntoIterator for &'a BuiltinBounds {
+    type Item = BuiltinBound;
+    type IntoIter = enum_set::Iter<BuiltinBound>;
+    fn into_iter(self) -> Self::IntoIter {
+        (**self).into_iter()
+    }
 }
 
-pub fn all_builtin_bounds() -> BuiltinBounds {
-    let mut set = EnumSet::new();
-    set.insert(BoundSend);
-    set.insert(BoundSized);
-    set.insert(BoundSync);
-    set
+#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
+           Debug, Copy)]
+#[repr(usize)]
+pub enum BuiltinBound {
+    Send,
+    Sized,
+    Copy,
+    Sync,
 }
 
 /// An existential bound that does not implement any traits.
 pub fn region_existential_bound<'tcx>(r: ty::Region) -> ExistentialBounds<'tcx> {
     ty::ExistentialBounds { region_bound: r,
-                            builtin_bounds: empty_builtin_bounds(),
+                            builtin_bounds: BuiltinBounds::empty(),
                             projection_bounds: Vec::new() }
 }
 
@@ -1781,7 +1992,7 @@ impl cmp::PartialEq for InferRegion {
 }
 
 impl fmt::Debug for TyVid {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "_#{}t", self.index)
     }
 }
@@ -1837,7 +2048,7 @@ impl fmt::Debug for IntVarValue {
 /// from `T:'a` annotations appearing in the type definition.  If
 /// this is `None`, then the default is inherited from the
 /// surrounding context. See RFC #599 for details.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
 pub enum ObjectLifetimeDefault {
     /// Require an explicit annotation. Occurs when multiple
     /// `T:'a` constraints are found.
@@ -1847,7 +2058,7 @@ pub enum ObjectLifetimeDefault {
     Specific(Region),
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct TypeParameterDef<'tcx> {
     pub name: ast::Name,
     pub def_id: ast::DefId,
@@ -1910,7 +2121,7 @@ impl<'tcx> Generics<'tcx> {
 }
 
 /// Bounds on generics.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct GenericPredicates<'tcx> {
     pub predicates: VecPerParamSpace<Predicate<'tcx>>,
 }
@@ -1940,7 +2151,7 @@ impl<'tcx> GenericPredicates<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub enum Predicate<'tcx> {
     /// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
@@ -2071,7 +2282,7 @@ impl<'tcx> Predicate<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>
 }
@@ -2119,7 +2330,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::R
 /// equality between arbitrary types. Processing an instance of Form
 /// #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
     pub ty: Ty<'tcx>,
@@ -2308,7 +2519,7 @@ impl<'tcx> Predicate<'tcx> {
 /// `[[], [U:Bar<T>]]`.  Now if there were some particular reference
 /// like `Foo<isize,usize>`, then the `InstantiatedPredicates` would be `[[],
 /// [usize:Bar<isize>]]`.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct InstantiatedPredicates<'tcx> {
     pub predicates: VecPerParamSpace<Predicate<'tcx>>,
 }
@@ -2642,8 +2853,8 @@ impl<'tcx> TraitDef<'tcx> {
                        tcx: &ctxt<'tcx>,
                        impl_def_id: DefId,
                        impl_trait_ref: TraitRef<'tcx>) {
-        debug!("TraitDef::record_impl for {}, from {}",
-               self.repr(tcx), impl_trait_ref.repr(tcx));
+        debug!("TraitDef::record_impl for {:?}, from {:?}",
+               self, impl_trait_ref);
 
         // We don't want to borrow_mut after we already populated all impls,
         // so check if an impl is present with an immutable borrow first.
@@ -2811,20 +3022,26 @@ impl<'tcx> CommonTypes<'tcx> {
     }
 }
 
-pub fn mk_ctxt<'tcx>(s: Session,
-                     arenas: &'tcx CtxtArenas<'tcx>,
-                     def_map: DefMap,
-                     named_region_map: resolve_lifetime::NamedRegionMap,
-                     map: ast_map::Map<'tcx>,
-                     freevars: RefCell<FreevarMap>,
-                     region_maps: RegionMaps,
-                     lang_items: middle::lang_items::LanguageItems,
-                     stability: stability::Index<'tcx>) -> ctxt<'tcx>
+/// Create a type context and call the closure with a `&ty::ctxt` reference
+/// to the context. The closure enforces that the type context and any interned
+/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
+/// reference to the context, to allow formatting values that need it.
+pub fn with_ctxt<'tcx, F, R>(s: Session,
+                             arenas: &'tcx CtxtArenas<'tcx>,
+                             def_map: DefMap,
+                             named_region_map: resolve_lifetime::NamedRegionMap,
+                             map: ast_map::Map<'tcx>,
+                             freevars: RefCell<FreevarMap>,
+                             region_maps: RegionMaps,
+                             lang_items: middle::lang_items::LanguageItems,
+                             stability: stability::Index<'tcx>,
+                             f: F) -> (Session, R)
+                             where F: FnOnce(&ctxt<'tcx>) -> R
 {
     let mut interner = FnvHashMap();
     let common_types = CommonTypes::new(&arenas.type_, &mut interner);
 
-    ctxt {
+    tls::enter(ctxt {
         arenas: arenas,
         interner: RefCell::new(interner),
         substs_interner: RefCell::new(FnvHashMap()),
@@ -2886,7 +3103,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
         const_qualif_map: RefCell::new(NodeMap()),
         custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
         cast_kinds: RefCell::new(NodeMap()),
-   }
+   }, f)
 }
 
 // Type constructors
@@ -3490,7 +3707,7 @@ impl<'tcx> ItemSubsts<'tcx> {
 impl<'tcx> ParamBounds<'tcx> {
     pub fn empty() -> ParamBounds<'tcx> {
         ParamBounds {
-            builtin_bounds: empty_builtin_bounds(),
+            builtin_bounds: BuiltinBounds::empty(),
             trait_bounds: Vec::new(),
             region_bounds: Vec::new(),
             projection_bounds: Vec::new(),
@@ -3565,7 +3782,7 @@ pub fn sequence_element_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
         TyArray(ty, _) | TySlice(ty) => ty,
         TyStr => mk_mach_uint(cx, ast::TyU8),
         _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
-                                 ty_to_string(cx, ty))),
+                                  ty)),
     }
 }
 
@@ -4034,8 +4251,8 @@ fn type_impls_bound<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
 
     let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
 
-    debug!("type_impls_bound({}, {:?}) = {:?}",
-           ty.repr(tcx),
+    debug!("type_impls_bound({:?}, {:?}) = {:?}",
+           ty,
            bound,
            is_impld);
 
@@ -4137,23 +4354,19 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
     fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<DefId>,
                            r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool {
         debug!("type_requires({:?}, {:?})?",
-               ::util::ppaux::ty_to_string(cx, r_ty),
-               ::util::ppaux::ty_to_string(cx, ty));
+               r_ty, ty);
 
         let r = r_ty == ty || subtypes_require(cx, seen, r_ty, ty);
 
         debug!("type_requires({:?}, {:?})? {:?}",
-               ::util::ppaux::ty_to_string(cx, r_ty),
-               ::util::ppaux::ty_to_string(cx, ty),
-               r);
+               r_ty, ty, r);
         return r;
     }
 
     fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<DefId>,
                               r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool {
         debug!("subtypes_require({:?}, {:?})?",
-               ::util::ppaux::ty_to_string(cx, r_ty),
-               ::util::ppaux::ty_to_string(cx, ty));
+               r_ty, ty);
 
         let r = match ty.sty {
             // fixed length vectors need special treatment compared to
@@ -4232,9 +4445,7 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
         };
 
         debug!("subtypes_require({:?}, {:?})? {:?}",
-               ::util::ppaux::ty_to_string(cx, r_ty),
-               ::util::ppaux::ty_to_string(cx, ty),
-               r);
+               r_ty, ty, r);
 
         return r;
     }
@@ -4340,8 +4551,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>)
     fn is_type_structurally_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span,
                                             seen: &mut Vec<Ty<'tcx>>,
                                             ty: Ty<'tcx>) -> Representability {
-        debug!("is_type_structurally_recursive: {:?}",
-               ::util::ppaux::ty_to_string(cx, ty));
+        debug!("is_type_structurally_recursive: {:?}", ty);
 
         match ty.sty {
             TyStruct(did, _) | TyEnum(did, _) => {
@@ -4361,8 +4571,8 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>)
                         Some(&seen_type) => {
                             if same_struct_or_enum_def_id(seen_type, did) {
                                 debug!("SelfRecursive: {:?} contains {:?}",
-                                       ::util::ppaux::ty_to_string(cx, seen_type),
-                                       ::util::ppaux::ty_to_string(cx, ty));
+                                       seen_type,
+                                       ty);
                                 return SelfRecursive;
                             }
                         }
@@ -4381,8 +4591,8 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>)
                     for &seen_type in iter {
                         if same_type(ty, seen_type) {
                             debug!("ContainsRecursive: {:?} contains {:?}",
-                                   ::util::ppaux::ty_to_string(cx, seen_type),
-                                   ::util::ppaux::ty_to_string(cx, ty));
+                                   seen_type,
+                                   ty);
                             return ContainsRecursive;
                         }
                     }
@@ -4402,16 +4612,14 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>)
         }
     }
 
-    debug!("is_type_representable: {:?}",
-           ::util::ppaux::ty_to_string(cx, ty));
+    debug!("is_type_representable: {:?}", ty);
 
     // To avoid a stack overflow when checking an enum variant or struct that
     // contains a different, structurally recursive type, maintain a stack
     // of seen types and check recursion for each of them (issues #3008, #3779).
     let mut seen: Vec<Ty> = Vec::new();
     let r = is_type_structurally_recursive(cx, sp, &mut seen, ty);
-    debug!("is_type_representable: {:?} is {:?}",
-           ::util::ppaux::ty_to_string(cx, ty), r);
+    debug!("is_type_representable: {:?} is {:?}", ty, r);
     r
 }
 
@@ -4813,7 +5021,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
                         _ => {
                             cx.sess.bug(
                                 &format!("AdjustReifyFnPointer adjustment on non-fn-item: \
-                                          {}", unadjusted_ty.repr(cx)));
+                                          {:?}", unadjusted_ty));
                         }
                     }
                 }
@@ -4854,7 +5062,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
                                         span,
                                         &format!("the {}th autoderef failed: {}",
                                                 i,
-                                                ty_to_string(cx, adjusted_ty))
+                                                 adjusted_ty)
                                         );
                                 }
                             }
@@ -5096,13 +5304,11 @@ pub fn impl_or_trait_item_idx(id: ast::Name, trait_items: &[ImplOrTraitItem])
     trait_items.iter().position(|m| m.name() == id)
 }
 
-pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String {
+pub fn ty_sort_string(cx: &ctxt, ty: Ty) -> String {
     match ty.sty {
         TyBool | TyChar | TyInt(_) |
-        TyUint(_) | TyFloat(_) | TyStr => {
-            ::util::ppaux::ty_to_string(cx, ty)
-        }
-        TyTuple(ref tys) if tys.is_empty() => ::util::ppaux::ty_to_string(cx, ty),
+        TyUint(_) | TyFloat(_) | TyStr => ty.to_string(),
+        TyTuple(ref tys) if tys.is_empty() => ty.to_string(),
 
         TyEnum(id, _) => format!("enum `{}`", item_path_str(cx, id)),
         TyBox(_) => "box".to_string(),
@@ -5138,138 +5344,132 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String {
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        ty::type_err_to_str(tcx, self)
-    }
-}
-
 /// Explains the source of a type err in a short, human readable way. This is meant to be placed
 /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
 /// afterwards to present additional details, particularly when it comes to lifetime-related
 /// errors.
-pub fn type_err_to_str<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>) -> String {
-    match *err {
-        terr_cyclic_ty => "cyclic type of infinite size".to_string(),
-        terr_mismatch => "types differ".to_string(),
-        terr_unsafety_mismatch(values) => {
-            format!("expected {} fn, found {} fn",
-                    values.expected,
-                    values.found)
-        }
-        terr_abi_mismatch(values) => {
-            format!("expected {} fn, found {} fn",
-                    values.expected,
-                    values.found)
-        }
-        terr_mutability => "values differ in mutability".to_string(),
-        terr_box_mutability => {
-            "boxed values differ in mutability".to_string()
-        }
-        terr_vec_mutability => "vectors differ in mutability".to_string(),
-        terr_ptr_mutability => "pointers differ in mutability".to_string(),
-        terr_ref_mutability => "references differ in mutability".to_string(),
-        terr_ty_param_size(values) => {
-            format!("expected a type with {} type params, \
-                     found one with {} type params",
-                    values.expected,
-                    values.found)
-        }
-        terr_fixed_array_size(values) => {
-            format!("expected an array with a fixed size of {} elements, \
-                     found one with {} elements",
-                    values.expected,
-                    values.found)
-        }
-        terr_tuple_size(values) => {
-            format!("expected a tuple with {} elements, \
-                     found one with {} elements",
-                    values.expected,
-                    values.found)
-        }
-        terr_arg_count => {
-            "incorrect number of function parameters".to_string()
-        }
-        terr_regions_does_not_outlive(..) => {
-            "lifetime mismatch".to_string()
-        }
-        terr_regions_not_same(..) => {
-            "lifetimes are not the same".to_string()
-        }
-        terr_regions_no_overlap(..) => {
-            "lifetimes do not intersect".to_string()
-        }
-        terr_regions_insufficiently_polymorphic(br, _) => {
-            format!("expected bound lifetime parameter {}, \
-                     found concrete lifetime",
-                    bound_region_ptr_to_string(cx, br))
-        }
-        terr_regions_overly_polymorphic(br, _) => {
-            format!("expected concrete lifetime, \
-                     found bound lifetime parameter {}",
-                    bound_region_ptr_to_string(cx, br))
-        }
-        terr_sorts(values) => {
-            // A naive approach to making sure that we're not reporting silly errors such as:
-            // (expected closure, found closure).
-            let expected_str = ty_sort_string(cx, values.expected);
-            let found_str = ty_sort_string(cx, values.found);
-            if expected_str == found_str {
-                format!("expected {}, found a different {}", expected_str, found_str)
-            } else {
-                format!("expected {}, found {}", expected_str, found_str)
+impl<'tcx> fmt::Display for type_err<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            terr_cyclic_ty => write!(f, "cyclic type of infinite size"),
+            terr_mismatch => write!(f, "types differ"),
+            terr_unsafety_mismatch(values) => {
+                write!(f, "expected {} fn, found {} fn",
+                       values.expected,
+                       values.found)
             }
-        }
-        terr_traits(values) => {
-            format!("expected trait `{}`, found trait `{}`",
-                    item_path_str(cx, values.expected),
-                    item_path_str(cx, values.found))
-        }
-        terr_builtin_bounds(values) => {
-            if values.expected.is_empty() {
-                format!("expected no bounds, found `{}`",
-                        values.found.user_string(cx))
-            } else if values.found.is_empty() {
-                format!("expected bounds `{}`, found no bounds",
-                        values.expected.user_string(cx))
-            } else {
-                format!("expected bounds `{}`, found bounds `{}`",
-                        values.expected.user_string(cx),
-                        values.found.user_string(cx))
+            terr_abi_mismatch(values) => {
+                write!(f, "expected {} fn, found {} fn",
+                       values.expected,
+                       values.found)
+            }
+            terr_mutability => write!(f, "values differ in mutability"),
+            terr_box_mutability => {
+                write!(f, "boxed values differ in mutability")
+            }
+            terr_vec_mutability => write!(f, "vectors differ in mutability"),
+            terr_ptr_mutability => write!(f, "pointers differ in mutability"),
+            terr_ref_mutability => write!(f, "references differ in mutability"),
+            terr_ty_param_size(values) => {
+                write!(f, "expected a type with {} type params, \
+                           found one with {} type params",
+                       values.expected,
+                       values.found)
+            }
+            terr_fixed_array_size(values) => {
+                write!(f, "expected an array with a fixed size of {} elements, \
+                           found one with {} elements",
+                       values.expected,
+                       values.found)
+            }
+            terr_tuple_size(values) => {
+                write!(f, "expected a tuple with {} elements, \
+                           found one with {} elements",
+                       values.expected,
+                       values.found)
+            }
+            terr_arg_count => {
+                write!(f, "incorrect number of function parameters")
+            }
+            terr_regions_does_not_outlive(..) => {
+                write!(f, "lifetime mismatch")
+            }
+            terr_regions_not_same(..) => {
+                write!(f, "lifetimes are not the same")
+            }
+            terr_regions_no_overlap(..) => {
+                write!(f, "lifetimes do not intersect")
+            }
+            terr_regions_insufficiently_polymorphic(br, _) => {
+                write!(f, "expected bound lifetime parameter {}, \
+                           found concrete lifetime", br)
+            }
+            terr_regions_overly_polymorphic(br, _) => {
+                write!(f, "expected concrete lifetime, \
+                           found bound lifetime parameter {}", br)
+            }
+            terr_sorts(values) => tls::with(|tcx| {
+                // A naive approach to making sure that we're not reporting silly errors such as:
+                // (expected closure, found closure).
+                let expected_str = ty_sort_string(tcx, values.expected);
+                let found_str = ty_sort_string(tcx, values.found);
+                if expected_str == found_str {
+                    write!(f, "expected {}, found a different {}", expected_str, found_str)
+                } else {
+                    write!(f, "expected {}, found {}", expected_str, found_str)
+                }
+            }),
+            terr_traits(values) => tls::with(|tcx| {
+                write!(f, "expected trait `{}`, found trait `{}`",
+                       item_path_str(tcx, values.expected),
+                       item_path_str(tcx, values.found))
+            }),
+            terr_builtin_bounds(values) => {
+                if values.expected.is_empty() {
+                    write!(f, "expected no bounds, found `{}`",
+                           values.found)
+                } else if values.found.is_empty() {
+                    write!(f, "expected bounds `{}`, found no bounds",
+                           values.expected)
+                } else {
+                    write!(f, "expected bounds `{}`, found bounds `{}`",
+                           values.expected,
+                           values.found)
+                }
+            }
+            terr_integer_as_char => {
+                write!(f, "expected an integral type, found `char`")
+            }
+            terr_int_mismatch(ref values) => {
+                write!(f, "expected `{:?}`, found `{:?}`",
+                       values.expected,
+                       values.found)
+            }
+            terr_float_mismatch(ref values) => {
+                write!(f, "expected `{:?}`, found `{:?}`",
+                       values.expected,
+                       values.found)
+            }
+            terr_variadic_mismatch(ref values) => {
+                write!(f, "expected {} fn, found {} function",
+                       if values.expected { "variadic" } else { "non-variadic" },
+                       if values.found { "variadic" } else { "non-variadic" })
+            }
+            terr_convergence_mismatch(ref values) => {
+                write!(f, "expected {} fn, found {} function",
+                       if values.expected { "converging" } else { "diverging" },
+                       if values.found { "converging" } else { "diverging" })
+            }
+            terr_projection_name_mismatched(ref values) => {
+                write!(f, "expected {}, found {}",
+                       values.expected,
+                       values.found)
+            }
+            terr_projection_bounds_length(ref values) => {
+                write!(f, "expected {} associated type bindings, found {}",
+                       values.expected,
+                       values.found)
             }
-        }
-        terr_integer_as_char => {
-            "expected an integral type, found `char`".to_string()
-        }
-        terr_int_mismatch(ref values) => {
-            format!("expected `{:?}`, found `{:?}`",
-                    values.expected,
-                    values.found)
-        }
-        terr_float_mismatch(ref values) => {
-            format!("expected `{:?}`, found `{:?}`",
-                    values.expected,
-                    values.found)
-        }
-        terr_variadic_mismatch(ref values) => {
-            format!("expected {} fn, found {} function",
-                    if values.expected { "variadic" } else { "non-variadic" },
-                    if values.found { "variadic" } else { "non-variadic" })
-        }
-        terr_convergence_mismatch(ref values) => {
-            format!("expected {} fn, found {} function",
-                    if values.expected { "converging" } else { "diverging" },
-                    if values.found { "converging" } else { "diverging" })
-        }
-        terr_projection_name_mismatched(ref values) => {
-            format!("expected {}, found {}",
-                    token::get_name(values.expected),
-                    token::get_name(values.found))
-        }
-        terr_projection_bounds_length(ref values) => {
-            format!("expected {} associated type bindings, found {}",
-                    values.expected,
-                    values.found)
         }
     }
 }
@@ -5876,7 +6076,7 @@ fn report_discrim_overflow(cx: &ctxt,
     let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
     let computed_value = repr_type.disr_string(computed_value);
     let prev_val = repr_type.disr_string(prev_val);
-    let repr_type = repr_type.to_ty(cx).user_string(cx);
+    let repr_type = repr_type.to_ty(cx);
     span_err!(cx.sess, variant_span, E0370,
               "enum discriminant overflowed on value after {}: {}; \
                set explicitly via {} = {} if that is desired outcome",
@@ -6369,8 +6569,8 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
                                     -> Vec<ty::Region>
 {
     debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})",
-           erased_self_ty.repr(tcx),
-           predicates.repr(tcx));
+           erased_self_ty,
+           predicates);
 
     assert!(!erased_self_ty.has_escaping_regions());
 
@@ -6488,7 +6688,7 @@ pub fn populate_implementations_for_trait_if_necessary(tcx: &ctxt, trait_id: ast
         return;
     }
 
-    debug!("populate_implementations_for_trait_if_necessary: searching for {}", def.repr(tcx));
+    debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
 
     if csearch::is_defaulted_trait(&tcx.sess.cstore, trait_id) {
         record_trait_has_default_impl(tcx, trait_id);
@@ -6736,14 +6936,14 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
     }
 }
 
-impl Variance {
-    pub fn to_string(self) -> &'static str {
-        match self {
+impl fmt::Debug for Variance {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(match *self {
             Covariant => "+",
             Contravariant => "-",
             Invariant => "o",
             Bivariant => "*",
-        }
+        })
     }
 }
 
@@ -6797,7 +6997,7 @@ pub fn construct_free_substs<'a,'tcx>(
                                   defs: &[TypeParameterDef<'tcx>]) {
         for def in defs {
             debug!("construct_parameter_environment(): push_types_from_defs: def={:?}",
-                   def.repr(tcx));
+                   def);
             let ty = ty::mk_param_from_def(tcx, def);
             types.push(def.space, ty);
        }
@@ -6830,8 +7030,8 @@ pub fn construct_parameter_environment<'a,'tcx>(
 
     debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}",
            free_id,
-           free_substs.repr(tcx),
-           predicates.repr(tcx));
+           free_substs,
+           predicates);
 
     //
     // Finally, we have to normalize the bounds in the environment, in
@@ -7087,7 +7287,7 @@ pub fn liberate_late_bound_regions<'tcx, T>(
     all_outlive_scope: region::DestructionScopeData,
     value: &Binder<T>)
     -> T
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     ty_fold::replace_late_bound_regions(
         tcx, value,
@@ -7098,7 +7298,7 @@ pub fn count_late_bound_regions<'tcx, T>(
     tcx: &ty::ctxt<'tcx>,
     value: &Binder<T>)
     -> usize
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     let (_, skol_map) = ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
     skol_map.len()
@@ -7108,7 +7308,7 @@ pub fn binds_late_bound_regions<'tcx, T>(
     tcx: &ty::ctxt<'tcx>,
     value: &Binder<T>)
     -> bool
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     count_late_bound_regions(tcx, value) > 0
 }
@@ -7119,7 +7319,7 @@ pub fn flatten_late_bound_regions<'tcx, T>(
     tcx: &ty::ctxt<'tcx>,
     bound2_value: &Binder<Binder<T>>)
     -> Binder<T>
-    where T: TypeFoldable<'tcx> + Repr<'tcx>
+    where T: TypeFoldable<'tcx>
 {
     let bound0_value = bound2_value.skip_binder().skip_binder();
     let value = ty_fold::fold_regions(tcx, bound0_value, |region, current_depth| {
@@ -7141,7 +7341,7 @@ pub fn no_late_bound_regions<'tcx, T>(
     tcx: &ty::ctxt<'tcx>,
     value: &Binder<T>)
     -> Option<T>
-    where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone
+    where T : TypeFoldable<'tcx>
 {
     if binds_late_bound_regions(tcx, value) {
         None
@@ -7156,7 +7356,7 @@ pub fn erase_late_bound_regions<'tcx, T>(
     tcx: &ty::ctxt<'tcx>,
     value: &Binder<T>)
     -> T
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
 }
@@ -7173,7 +7373,7 @@ pub fn anonymize_late_bound_regions<'tcx, T>(
     tcx: &ctxt<'tcx>,
     sig: &Binder<T>)
     -> Binder<T>
-    where T : TypeFoldable<'tcx> + Repr<'tcx>,
+    where T : TypeFoldable<'tcx>,
 {
     let mut counter = 0;
     ty::Binder(ty_fold::replace_late_bound_regions(tcx, sig, |_| {
@@ -7193,58 +7393,45 @@ impl DebruijnIndex {
     }
 }
 
-impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for AutoAdjustment<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             AdjustReifyFnPointer => {
-                format!("AdjustReifyFnPointer")
+                write!(f, "AdjustReifyFnPointer")
             }
             AdjustUnsafeFnPointer => {
-                format!("AdjustUnsafeFnPointer")
+                write!(f, "AdjustUnsafeFnPointer")
             }
             AdjustDerefRef(ref data) => {
-                data.repr(tcx)
+                write!(f, "{:?}", data)
             }
         }
     }
 }
 
-impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("AutoDerefRef({}, unsize={}, {})",
-                self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for AutoRef<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        match *self {
-            AutoPtr(a, b) => {
-                format!("AutoPtr({},{:?})", a.repr(tcx), b)
-            }
-            AutoUnsafe(ref a) => {
-                format!("AutoUnsafe({:?})", a)
-            }
-        }
+impl<'tcx> fmt::Debug for AutoDerefRef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
+               self.autoderefs, self.unsize, self.autoref)
     }
 }
 
-impl<'tcx> Repr<'tcx> for TraitTy<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("TraitTy({},{})",
-                self.principal.repr(tcx),
-                self.bounds.repr(tcx))
+impl<'tcx> fmt::Debug for TraitTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TraitTy({:?},{:?})",
+               self.principal,
+               self.bounds)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            Predicate::Trait(ref a) => a.repr(tcx),
-            Predicate::Equate(ref pair) => pair.repr(tcx),
-            Predicate::RegionOutlives(ref pair) => pair.repr(tcx),
-            Predicate::TypeOutlives(ref pair) => pair.repr(tcx),
-            Predicate::Projection(ref pair) => pair.repr(tcx),
+            Predicate::Trait(ref a) => write!(f, "{:?}", a),
+            Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
+            Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
+            Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
+            Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
         }
     }
 }
@@ -7450,14 +7637,6 @@ impl<'tcx> RegionEscape for ProjectionTy<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::ProjectionPredicate<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("ProjectionPredicate({}, {})",
-                self.projection_ty.repr(tcx),
-                self.ty.repr(tcx))
-    }
-}
-
 pub trait HasProjectionTypes {
     fn has_projection_types(&self) -> bool;
 }
@@ -7692,48 +7871,46 @@ impl ReferencesError for Region
     }
 }
 
-impl<'tcx> Repr<'tcx> for ClosureTy<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("ClosureTy({},{},{})",
-                self.unsafety,
-                self.sig.repr(tcx),
-                self.abi)
+impl<'tcx> fmt::Debug for ClosureTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ClosureTy({},{:?},{})",
+               self.unsafety,
+               self.sig,
+               self.abi)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ClosureUpvar<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("ClosureUpvar({},{})",
-                self.def.repr(tcx),
-                self.ty.repr(tcx))
+impl<'tcx> fmt::Debug for ClosureUpvar<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ClosureUpvar({:?},{:?})",
+               self.def,
+               self.ty)
     }
 }
 
-impl<'tcx> Repr<'tcx> for field<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("field({},{})",
-                self.name.repr(tcx),
-                self.mt.repr(tcx))
+impl<'tcx> fmt::Debug for field<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "field({},{})", self.name, self.mt)
     }
 }
 
-impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("ParameterEnvironment(\
-            free_substs={}, \
-            implicit_region_bound={}, \
-            caller_bounds={})",
-            self.free_substs.repr(tcx),
-            self.implicit_region_bound.repr(tcx),
-            self.caller_bounds.repr(tcx))
+impl<'a, 'tcx> fmt::Debug for ParameterEnvironment<'a, '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<'tcx> Repr<'tcx> for ObjectLifetimeDefault {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for ObjectLifetimeDefault {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ObjectLifetimeDefault::Ambiguous => format!("Ambiguous"),
-            ObjectLifetimeDefault::Specific(ref r) => r.repr(tcx),
+            ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
+            ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
         }
     }
 }
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index cc91ccbfbd4..63c46032479 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -38,19 +38,20 @@ use middle::subst;
 use middle::subst::VecPerParamSpace;
 use middle::ty::{self, Ty};
 use middle::traits;
+
+use std::fmt;
 use std::rc::Rc;
 use syntax::abi;
 use syntax::ast;
 use syntax::owned_slice::OwnedSlice;
 use util::nodemap::FnvHashMap;
-use util::ppaux::Repr;
 
 ///////////////////////////////////////////////////////////////////////////
 // Two generic traits
 
 /// The TypeFoldable trait is implemented for every type that can be folded.
 /// Basically, every type that has a corresponding method in TypeFolder.
-pub trait TypeFoldable<'tcx>: Repr<'tcx> + Clone {
+pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
 }
 
@@ -74,7 +75,7 @@ pub trait TypeFolder<'tcx> : Sized {
     fn exit_region_binder(&mut self) { }
 
     fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
-        where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone
+        where T : TypeFoldable<'tcx>
     {
         // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`.
         super_fold_binder(self, t)
@@ -197,7 +198,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
     }
 }
 
-impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>+Clone> TypeFoldable<'tcx> for ty::Binder<T> {
+impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
     fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
         folder.fold_binder(self)
     }
@@ -842,13 +843,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
             ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
-                debug!("RegionFolder.fold_region({}) skipped bound region (current depth={})",
-                       r.repr(self.tcx()), self.current_depth);
+                debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
+                       r, self.current_depth);
                 r
             }
             _ => {
-                debug!("RegionFolder.fold_region({}) folding free region (current_depth={})",
-                       r.repr(self.tcx()), self.current_depth);
+                debug!("RegionFolder.fold_region({:?}) folding free region (current_depth={})",
+                       r, self.current_depth);
                 (self.fld_r)(r, self.current_depth)
             }
         }
@@ -885,9 +886,9 @@ pub fn replace_late_bound_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
                                             mut f: F)
                                             -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
     where F : FnMut(ty::BoundRegion) -> ty::Region,
-          T : TypeFoldable<'tcx> + Repr<'tcx>,
+          T : TypeFoldable<'tcx>,
 {
-    debug!("replace_late_bound_regions({})", value.repr(tcx));
+    debug!("replace_late_bound_regions({:?})", value);
     let mut replacer = RegionReplacer::new(tcx, &mut f);
     let result = value.skip_binder().fold_with(&mut replacer);
     (result, replacer.map)
@@ -916,8 +917,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
             ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
-                debug!("RegionReplacer.fold_region({}) folding region (current_depth={})",
-                       r.repr(self.tcx()), self.current_depth);
+                debug!("RegionReplacer.fold_region({:?}) folding region (current_depth={})",
+                       r, self.current_depth);
                 let fld_r = &mut self.fld_r;
                 let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
                 if let ty::ReLateBound(debruijn1, br) = region {
@@ -994,10 +995,10 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region {
     }
 }
 
-pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>>(tcx: &ty::ctxt<'tcx>,
-                                                            amount: u32, value: &T) -> T {
-    debug!("shift_regions(value={}, amount={})",
-           value.repr(tcx), amount);
+pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>,
+                                                 amount: u32, value: &T) -> T {
+    debug!("shift_regions(value={:?}, amount={})",
+           value, amount);
 
     value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| {
         shift_region(region, amount)
diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty_match.rs
index 241a27aa0cd..135118820a7 100644
--- a/src/librustc/middle/ty_match.rs
+++ b/src/librustc/middle/ty_match.rs
@@ -10,7 +10,6 @@
 
 use middle::ty::{self, Ty};
 use middle::ty_relate::{self, Relate, TypeRelation, RelateResult};
-use util::ppaux::Repr;
 
 /// A type "A" *matches* "B" if the fresh types in B could be
 /// substituted with values so as to make it equal to A. Matching is
@@ -53,16 +52,16 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> {
     }
 
     fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
-        debug!("{}.regions({}, {})",
+        debug!("{}.regions({:?}, {:?})",
                self.tag(),
-               a.repr(self.tcx()),
-               b.repr(self.tcx()));
+               a,
+               b);
         Ok(a)
     }
 
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("{}.tys({}, {})", self.tag(),
-               a.repr(self.tcx()), b.repr(self.tcx()));
+        debug!("{}.tys({:?}, {:?})", self.tag(),
+               a, b);
         if a == b { return Ok(a); }
 
         match (&a.sty, &b.sty) {
diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs
index 91169af4adb..b8c212fe3f2 100644
--- a/src/librustc/middle/ty_relate/mod.rs
+++ b/src/librustc/middle/ty_relate/mod.rs
@@ -19,7 +19,6 @@ use middle::ty_fold::TypeFoldable;
 use std::rc::Rc;
 use syntax::abi;
 use syntax::ast;
-use util::ppaux::Repr;
 
 pub type RelateResult<'tcx, T> = Result<T, ty::type_err<'tcx>>;
 
@@ -79,10 +78,10 @@ impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::mt<'tcx> {
                  -> RelateResult<'tcx, ty::mt<'tcx>>
         where R: TypeRelation<'a,'tcx>
     {
-        debug!("{}.mts({}, {})",
+        debug!("{}.mts({:?}, {:?})",
                relation.tag(),
-               a.repr(relation.tcx()),
-               b.repr(relation.tcx()));
+               a,
+               b);
         if a.mutbl != b.mutbl {
             Err(ty::terr_mutability)
         } else {
@@ -107,10 +106,10 @@ fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R,
                                     -> RelateResult<'tcx, Substs<'tcx>>
     where R: TypeRelation<'a,'tcx>
 {
-    debug!("substs: item_def_id={} a_subst={} b_subst={}",
-           item_def_id.repr(relation.tcx()),
-           a_subst.repr(relation.tcx()),
-           b_subst.repr(relation.tcx()));
+    debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}",
+           item_def_id,
+           a_subst,
+           b_subst);
 
     let variances;
     let opt_variances = if relation.tcx().variance_computed.get() {
@@ -191,14 +190,13 @@ fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R,
                                       -> RelateResult<'tcx, Vec<ty::Region>>
     where R: TypeRelation<'a,'tcx>
 {
-    let tcx = relation.tcx();
     let num_region_params = a_rs.len();
 
-    debug!("relate_region_params(a_rs={}, \
-            b_rs={}, variances={})",
-           a_rs.repr(tcx),
-           b_rs.repr(tcx),
-           variances.repr(tcx));
+    debug!("relate_region_params(a_rs={:?}, \
+            b_rs={:?}, variances={:?})",
+           a_rs,
+           b_rs,
+           variances);
 
     assert_eq!(num_region_params,
                variances.map_or(num_region_params,
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 7341420c553..485d856ac25 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -9,16 +9,12 @@
 // except according to those terms.
 
 
-use ast_map;
-use middle::def;
-use middle::region;
-use middle::subst::{VecPerParamSpace,Subst};
-use middle::subst;
+use middle::subst::{self, Subst};
 use middle::ty::{BoundRegion, BrAnon, BrNamed};
 use middle::ty::{ReEarlyBound, BrFresh, ctxt};
 use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty};
 use middle::ty::{ReSkolemized, ReVar, BrEnv};
-use middle::ty::{mt, Ty, ParamTy};
+use middle::ty::{mt, Ty};
 use middle::ty::{TyBool, TyChar, TyStruct, TyEnum};
 use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn};
 use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple};
@@ -27,484 +23,117 @@ use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
 use middle::ty;
 use middle::ty_fold::{self, TypeFoldable};
 
-use std::collections::HashMap;
-use std::collections::hash_state::HashState;
-use std::hash::Hash;
-use std::rc::Rc;
+use std::fmt;
 use syntax::abi;
-use syntax::codemap::{Span, Pos};
 use syntax::parse::token;
-use syntax::print::pprust;
-use syntax::ptr::P;
 use syntax::{ast, ast_util};
-use syntax::owned_slice::OwnedSlice;
 
-/// Produces a string suitable for debugging output.
-pub trait Repr<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String;
+pub fn verbose() -> bool {
+    ty::tls::with(|tcx| tcx.sess.verbose())
 }
 
-/// Produces a string suitable for showing to the user.
-pub trait UserString<'tcx> : Repr<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String;
-}
-
-pub fn note_and_explain_region(cx: &ctxt,
-                               prefix: &str,
-                               region: ty::Region,
-                               suffix: &str) -> Option<Span> {
-    match explain_region_and_span(cx, region) {
-      (ref str, Some(span)) => {
-        cx.sess.span_note(
-            span,
-            &format!("{}{}{}", prefix, *str, suffix));
-        Some(span)
-      }
-      (ref str, None) => {
-        cx.sess.note(
-            &format!("{}{}{}", prefix, *str, suffix));
-        None
-      }
-    }
-}
-
-/// When a free region is associated with `item`, how should we describe the item in the error
-/// message.
-fn item_scope_tag(item: &ast::Item) -> &'static str {
-    match item.node {
-        ast::ItemImpl(..) => "impl",
-        ast::ItemStruct(..) => "struct",
-        ast::ItemEnum(..) => "enum",
-        ast::ItemTrait(..) => "trait",
-        ast::ItemFn(..) => "function body",
-        _ => "item"
-    }
-}
-
-pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
-                            -> (String, Option<Span>) {
-    return match region {
-      ReScope(scope) => {
-        let new_string;
-        let on_unknown_scope = || {
-          (format!("unknown scope: {:?}.  Please report a bug.", scope), None)
-        };
-        let span = match scope.span(&cx.map) {
-          Some(s) => s,
-          None => return on_unknown_scope(),
-        };
-        let tag = match cx.map.find(scope.node_id()) {
-          Some(ast_map::NodeBlock(_)) => "block",
-          Some(ast_map::NodeExpr(expr)) => match expr.node {
-              ast::ExprCall(..) => "call",
-              ast::ExprMethodCall(..) => "method call",
-              ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let",
-              ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) =>  "while let",
-              ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) =>  "for",
-              ast::ExprMatch(..) => "match",
-              _ => "expression",
-          },
-          Some(ast_map::NodeStmt(_)) => "statement",
-          Some(ast_map::NodeItem(it)) => item_scope_tag(&*it),
-          Some(_) | None => {
-            // this really should not happen
-            return on_unknown_scope();
-          }
-        };
-        let scope_decorated_tag = match scope {
-            region::CodeExtent::Misc(_) => tag,
-            region::CodeExtent::ParameterScope { .. } => {
-                "scope of parameters for function"
-            }
-            region::CodeExtent::DestructionScope(_) => {
-                new_string = format!("destruction scope surrounding {}", tag);
-                &*new_string
-            }
-            region::CodeExtent::Remainder(r) => {
-                new_string = format!("block suffix following statement {}",
-                                     r.first_statement_index);
-                &*new_string
-            }
-        };
-        explain_span(cx, scope_decorated_tag, span)
-
-      }
-
-      ReFree(ref fr) => {
-        let prefix = match fr.bound_region {
-          BrAnon(idx) => {
-              format!("the anonymous lifetime #{} defined on", idx + 1)
-          }
-          BrFresh(_) => "an anonymous lifetime defined on".to_string(),
-          _ => {
-              format!("the lifetime {} as defined on",
-                      bound_region_ptr_to_string(cx, fr.bound_region))
-          }
-        };
-
-        match cx.map.find(fr.scope.node_id) {
-          Some(ast_map::NodeBlock(ref blk)) => {
-              let (msg, opt_span) = explain_span(cx, "block", blk.span);
-              (format!("{} {}", prefix, msg), opt_span)
-          }
-          Some(ast_map::NodeItem(it)) => {
-              let tag = item_scope_tag(&*it);
-              let (msg, opt_span) = explain_span(cx, tag, it.span);
-              (format!("{} {}", prefix, msg), opt_span)
-          }
-          Some(_) | None => {
-              // this really should not happen
-              (format!("{} unknown free region bounded by scope {:?}", prefix, fr.scope), None)
-          }
+fn fn_sig(f: &mut fmt::Formatter,
+          inputs: &[Ty],
+          variadic: bool,
+          output: ty::FnOutput)
+          -> fmt::Result {
+    try!(write!(f, "("));
+    let mut inputs = inputs.iter();
+    if let Some(&ty) = inputs.next() {
+        try!(write!(f, "{}", ty));
+        for &ty in inputs {
+            try!(write!(f, ", {}", ty));
         }
-      }
-
-      ReStatic => { ("the static lifetime".to_string(), None) }
-
-      ReEmpty => { ("the empty lifetime".to_string(), None) }
-
-      ReEarlyBound(ref data) => {
-        (format!("{}", token::get_name(data.name)), None)
-      }
-
-      // I believe these cases should not occur (except when debugging,
-      // perhaps)
-      ty::ReInfer(_) | ty::ReLateBound(..) => {
-        (format!("lifetime {:?}", region), None)
-      }
-    };
-
-    fn explain_span(cx: &ctxt, heading: &str, span: Span)
-                    -> (String, Option<Span>) {
-        let lo = cx.sess.codemap().lookup_char_pos_adj(span.lo);
-        (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
-         Some(span))
-    }
-}
-
-pub fn bound_region_ptr_to_string(cx: &ctxt, br: BoundRegion) -> String {
-    bound_region_to_string(cx, "", false, br)
-}
-
-pub fn bound_region_to_string(cx: &ctxt,
-                           prefix: &str, space: bool,
-                           br: BoundRegion) -> String {
-    let space_str = if space { " " } else { "" };
-
-    if cx.sess.verbose() {
-        return format!("{}{}{}", prefix, br.repr(cx), space_str)
-    }
-
-    match br {
-        BrNamed(_, name) => {
-            format!("{}{}{}", prefix, token::get_name(name), space_str)
+        if variadic {
+            try!(write!(f, ", ..."));
         }
-        BrAnon(_) | BrFresh(_) | BrEnv => prefix.to_string()
-    }
-}
-
-// 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_string(cx: &ctxt, region: Region) -> String {
-    region_to_string(cx, "&", true, region)
-}
-
-pub fn region_to_string(cx: &ctxt, prefix: &str, space: bool, region: Region) -> String {
-    let space_str = if space { " " } else { "" };
-
-    if cx.sess.verbose() {
-        return format!("{}{}{}", prefix, region.repr(cx), space_str)
     }
+    try!(write!(f, ")"));
 
-    // 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 {
-        ty::ReScope(_) => prefix.to_string(),
-        ty::ReEarlyBound(ref data) => {
-            token::get_name(data.name).to_string()
+    match output {
+        ty::FnConverging(ty) => {
+            if !ty::type_is_nil(ty) {
+                try!(write!(f, " -> {}", ty));
+            }
+            Ok(())
         }
-        ty::ReLateBound(_, br) => bound_region_to_string(cx, prefix, space, br),
-        ty::ReFree(ref fr) => bound_region_to_string(cx, prefix, space, fr.bound_region),
-        ty::ReInfer(ReSkolemized(_, br)) => {
-            bound_region_to_string(cx, prefix, space, br)
+        ty::FnDiverging => {
+            write!(f, " -> !")
         }
-        ty::ReInfer(ReVar(_)) => prefix.to_string(),
-        ty::ReStatic => format!("{}'static{}", prefix, space_str),
-        ty::ReEmpty => format!("{}'<empty>{}", prefix, space_str),
     }
 }
 
-pub fn mutability_to_string(m: ast::Mutability) -> String {
-    match m {
-        ast::MutMutable => "mut ".to_string(),
-        ast::MutImmutable => "".to_string(),
-    }
-}
-
-pub fn mt_to_string<'tcx>(cx: &ctxt<'tcx>, m: &mt<'tcx>) -> String {
-    format!("{}{}",
-        mutability_to_string(m.mutbl),
-        ty_to_string(cx, m.ty))
-}
-
-pub fn vec_map_to_string<T, F>(ts: &[T], f: F) -> String where
-    F: FnMut(&T) -> String,
+fn parameterized<GG>(f: &mut fmt::Formatter,
+                     substs: &subst::Substs,
+                     did: ast::DefId,
+                     projections: &[ty::ProjectionPredicate],
+                     get_generics: GG)
+                     -> fmt::Result
+    where GG: for<'tcx> FnOnce(&ty::ctxt<'tcx>) -> ty::Generics<'tcx>
 {
-    let tstrs = ts.iter().map(f).collect::<Vec<String>>();
-    format!("[{}]", tstrs.connect(", "))
-}
-
-pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
-    fn bare_fn_to_string<'tcx>(cx: &ctxt<'tcx>,
-                               opt_def_id: Option<ast::DefId>,
-                               unsafety: ast::Unsafety,
-                               abi: abi::Abi,
-                               ident: Option<ast::Ident>,
-                               sig: &ty::PolyFnSig<'tcx>)
-                               -> String {
-        let mut s = String::new();
-
-        match unsafety {
-            ast::Unsafety::Normal => {}
-            ast::Unsafety::Unsafe => {
-                s.push_str(&unsafety.to_string());
-                s.push(' ');
-            }
-        };
-
-        if abi != abi::Rust {
-            s.push_str(&format!("extern {} ", abi.to_string()));
-        };
-
-        s.push_str("fn");
-
-        match ident {
-            Some(i) => {
-                s.push(' ');
-                s.push_str(&token::get_ident(i));
-            }
-            _ => { }
-        }
-
-        push_sig_to_string(cx, &mut s, '(', ')', sig);
-
-        match opt_def_id {
-            Some(def_id) => {
-                s.push_str(" {");
-                let path_str = ty::item_path_str(cx, def_id);
-                s.push_str(&path_str[..]);
-                s.push_str("}");
-            }
-            None => { }
-        }
-
-        s
-    }
-
-    fn closure_to_string<'tcx>(cx: &ctxt<'tcx>,
-                               cty: &ty::ClosureTy<'tcx>,
-                               did: &ast::DefId)
-                               -> String {
-        let mut s = String::new();
-        s.push_str("[closure");
-        push_sig_to_string(cx, &mut s, '(', ')', &cty.sig);
-        if cx.sess.verbose() {
-            s.push_str(&format!(" id={:?}]", did));
+    let (fn_trait_kind, verbose) = try!(ty::tls::with(|tcx| {
+        try!(write!(f, "{}", ty::item_path_str(tcx, did)));
+        Ok((tcx.lang_items.fn_trait_kind(did), tcx.sess.verbose()))
+    }));
+
+    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 {
-            s.push(']');
-        }
-        s
-    }
-
-    fn push_sig_to_string<'tcx>(cx: &ctxt<'tcx>,
-                                s: &mut String,
-                                bra: char,
-                                ket: char,
-                                sig: &ty::PolyFnSig<'tcx>) {
-        s.push(bra);
-        let strs = sig.0.inputs
-            .iter()
-            .map(|a| ty_to_string(cx, *a))
-            .collect::<Vec<_>>();
-        s.push_str(&strs.connect(", "));
-        if sig.0.variadic {
-            s.push_str(", ...");
-        }
-        s.push(ket);
-
-        match sig.0.output {
-            ty::FnConverging(t) => {
-                if !ty::type_is_nil(t) {
-                   s.push_str(" -> ");
-                   s.push_str(&ty_to_string(cx, t));
-                }
-            }
-            ty::FnDiverging => {
-                s.push_str(" -> !");
-            }
-        }
-    }
-
-    fn infer_ty_to_string(cx: &ctxt, ty: ty::InferTy) -> String {
-        let print_var_ids = cx.sess.verbose();
-        match ty {
-            ty::TyVar(ref vid) if print_var_ids => vid.repr(cx),
-            ty::IntVar(ref vid) if print_var_ids => vid.repr(cx),
-            ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx),
-            ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"),
-            ty::FreshTy(v) => format!("FreshTy({})", v),
-            ty::FreshIntTy(v) => format!("FreshIntTy({})", v),
-            ty::FreshFloatTy(v) => format!("FreshFloatTy({})", v)
-        }
-    }
-
-    // pretty print the structural type representation:
-    match typ.sty {
-        TyBool => "bool".to_string(),
-        TyChar => "char".to_string(),
-        TyInt(t) => ast_util::int_ty_to_string(t, None).to_string(),
-        TyUint(t) => ast_util::uint_ty_to_string(t, None).to_string(),
-        TyFloat(t) => ast_util::float_ty_to_string(t).to_string(),
-        TyBox(typ) => format!("Box<{}>", ty_to_string(cx, typ)),
-        TyRawPtr(ref tm) => {
-            format!("*{} {}", match tm.mutbl {
-                ast::MutMutable => "mut",
-                ast::MutImmutable => "const",
-            }, ty_to_string(cx, tm.ty))
-        }
-        TyRef(r, ref tm) => {
-            let mut buf = region_ptr_to_string(cx, *r);
-            buf.push_str(&mt_to_string(cx, tm));
-            buf
-        }
-        TyTuple(ref elems) => {
-            let strs = elems
-                .iter()
-                .map(|elem| ty_to_string(cx, *elem))
-                .collect::<Vec<_>>();
-            match &strs[..] {
-                [ref string] => format!("({},)", string),
-                strs => format!("({})", strs.connect(", "))
-            }
-        }
-        TyBareFn(opt_def_id, ref f) => {
-            bare_fn_to_string(cx, opt_def_id, f.unsafety, f.abi, None, &f.sig)
-        }
-        TyInfer(infer_ty) => infer_ty_to_string(cx, infer_ty),
-        TyError => "[type error]".to_string(),
-        TyParam(ref param_ty) => param_ty.user_string(cx),
-        TyEnum(did, substs) | TyStruct(did, substs) => {
-            let base = ty::item_path_str(cx, did);
-            parameterized(cx, &base, substs, did, &[],
-                          || ty::lookup_item_type(cx, did).generics)
-        }
-        TyTrait(ref data) => {
-            data.user_string(cx)
-        }
-        ty::TyProjection(ref data) => {
-            format!("<{} as {}>::{}",
-                    data.trait_ref.self_ty().user_string(cx),
-                    data.trait_ref.user_string(cx),
-                    data.item_name.user_string(cx))
-        }
-        TyStr => "str".to_string(),
-        TyClosure(ref did, substs) => {
-            let closure_tys = cx.closure_tys.borrow();
-            closure_tys.get(did).map(|closure_type| {
-                closure_to_string(cx, &closure_type.subst(cx, substs), did)
-            }).unwrap_or_else(|| {
-                let id_str = if cx.sess.verbose() {
-                    format!(" id={:?}", did)
-                } else {
-                    "".to_owned()
-                };
-
-
-                if did.krate == ast::LOCAL_CRATE {
-                    let span = cx.map.span(did.node);
-                    format!("[closure {}{}]", span.repr(cx), id_str)
-                } else {
-                    format!("[closure{}]", id_str)
-                }
-            })
+            write!(f, "{}", cont)
         }
-        TyArray(t, sz) => {
-            format!("[{}; {}]", ty_to_string(cx, t), sz)
-        }
-        TySlice(t) => {
-            format!("[{}]", ty_to_string(cx, t))
-        }
-    }
-}
-
-pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory)
-                                     -> &'static str {
-    match *category {
-        ty::StaticExplicitSelfCategory => "static",
-        ty::ByValueExplicitSelfCategory => "self",
-        ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => {
-            "&mut self"
-        }
-        ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self",
-        ty::ByBoxExplicitSelfCategory => "Box<self>",
-    }
-}
+    };
 
-pub fn parameterized<'tcx,GG>(cx: &ctxt<'tcx>,
-                              base: &str,
-                              substs: &subst::Substs<'tcx>,
-                              did: ast::DefId,
-                              projections: &[ty::ProjectionPredicate<'tcx>],
-                              get_generics: GG)
-                              -> String
-    where GG : FnOnce() -> ty::Generics<'tcx>
-{
-    if cx.sess.verbose() {
-        let mut strings = vec![];
+    if verbose {
         match substs.regions {
             subst::ErasedRegions => {
-                strings.push(format!(".."));
+                try!(start_or_continue(f, "<", ", "));
+                try!(write!(f, ".."));
             }
             subst::NonerasedRegions(ref regions) => {
                 for region in regions {
-                    strings.push(region.repr(cx));
+                    try!(start_or_continue(f, "<", ", "));
+                    try!(write!(f, "{:?}", region));
                 }
             }
         }
-        for ty in &substs.types {
-            strings.push(ty.repr(cx));
+        for &ty in &substs.types {
+            try!(start_or_continue(f, "<", ", "));
+            try!(write!(f, "{}", ty));
         }
         for projection in projections {
-            strings.push(format!("{}={}",
-                                 projection.projection_ty.item_name.user_string(cx),
-                                 projection.ty.user_string(cx)));
+            try!(start_or_continue(f, "<", ", "));
+            try!(write!(f, "{}={}",
+                        projection.projection_ty.item_name,
+                        projection.ty));
         }
-        return if strings.is_empty() {
-            format!("{}", base)
-        } else {
-            format!("{}<{}>", base, strings.connect(","))
-        };
+        return start_or_continue(f, "", ">");
     }
 
-    let mut strs = Vec::new();
+    if fn_trait_kind.is_some() && projections.len() == 1 {
+        let projection_ty = projections[0].ty;
+        if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty {
+            return fn_sig(f, args, false, ty::FnConverging(projection_ty));
+        }
+    }
 
     match substs.regions {
         subst::ErasedRegions => { }
         subst::NonerasedRegions(ref regions) => {
             for &r in regions {
-                let s = region_to_string(cx, "", false, r);
+                try!(start_or_continue(f, "<", ", "));
+                let s = r.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.
-                    strs.push(format!("'_"));
+                    try!(write!(f, "'_"));
                 } else {
-                    strs.push(s)
+                    try!(write!(f, "{}", s));
                 }
             }
         }
@@ -515,162 +144,99 @@ pub fn parameterized<'tcx,GG>(cx: &ctxt<'tcx>,
     // ICEs trying to fetch the generics early in the pipeline. This
     // is kind of a hacky workaround in that -Z verbose is required to
     // avoid those ICEs.
-    let generics = get_generics();
-
-    let has_self = substs.self_ty().is_some();
     let tps = substs.types.get_slice(subst::TypeSpace);
-    let ty_params = generics.types.get_slice(subst::TypeSpace);
-    let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some());
-    let num_defaults = if has_defaults {
-        ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| {
-            match def.default {
-                Some(default) => {
-                    if !has_self && ty::type_has_self(default) {
-                        // In an object type, there is no `Self`, and
-                        // thus if the default value references Self,
-                        // the user will be required to give an
-                        // explicit value. We can't even do the
-                        // substitution below to check without causing
-                        // an ICE. (#18956).
-                        false
-                    } else {
-                        default.subst(cx, substs) == actual
+    let num_defaults = ty::tls::with(|tcx| {
+        let generics = get_generics(tcx);
+
+        let has_self = substs.self_ty().is_some();
+        let ty_params = generics.types.get_slice(subst::TypeSpace);
+        if ty_params.last().map_or(false, |def| def.default.is_some()) {
+            let substs = tcx.lift(&substs);
+            ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| {
+                match def.default {
+                    Some(default) => {
+                        if !has_self && ty::type_has_self(default) {
+                            // In an object type, there is no `Self`, and
+                            // thus if the default value references Self,
+                            // the user will be required to give an
+                            // explicit value. We can't even do the
+                            // substitution below to check without causing
+                            // an ICE. (#18956).
+                            false
+                        } else {
+                            let default = tcx.lift(&default);
+                            substs.and_then(|substs| default.subst(tcx, substs)) == Some(actual)
+                        }
                     }
+                    None => false
                 }
-                None => false
-            }
-        }).count()
-    } else {
-        0
-    };
+            }).count()
+        } else {
+            0
+        }
+    });
 
-    for t in &tps[..tps.len() - num_defaults] {
-        strs.push(ty_to_string(cx, *t))
+    for &ty in &tps[..tps.len() - num_defaults] {
+        try!(start_or_continue(f, "<", ", "));
+        try!(write!(f, "{}", ty));
     }
 
     for projection in projections {
-        strs.push(format!("{}={}",
-                          projection.projection_ty.item_name.user_string(cx),
-                          projection.ty.user_string(cx)));
-    }
-
-    if cx.lang_items.fn_trait_kind(did).is_some() && projections.len() == 1 {
-        let projection_ty = projections[0].ty;
-        let tail =
-            if ty::type_is_nil(projection_ty) {
-                format!("")
-            } else {
-                format!(" -> {}", projection_ty.user_string(cx))
-            };
-        format!("{}({}){}",
-                base,
-                if strs[0].starts_with("(") && strs[0].ends_with(",)") {
-                    &strs[0][1 .. strs[0].len() - 2] // Remove '(' and ',)'
-                } else if strs[0].starts_with("(") && strs[0].ends_with(")") {
-                    &strs[0][1 .. strs[0].len() - 1] // Remove '(' and ')'
-                } else {
-                    &strs[0][..]
-                },
-                tail)
-    } else if !strs.is_empty() {
-        format!("{}<{}>", base, strs.connect(", "))
-    } else {
-        format!("{}", base)
+        try!(start_or_continue(f, "<", ", "));
+        try!(write!(f, "{}={}",
+                    projection.projection_ty.item_name,
+                    projection.ty));
     }
-}
 
-pub fn ty_to_short_str<'tcx>(cx: &ctxt<'tcx>, typ: Ty<'tcx>) -> String {
-    let mut s = typ.repr(cx).to_string();
-    if s.len() >= 32 {
-        s = (&s[0..32]).to_string();
-    }
-    return s;
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Option<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        match self {
-            &None => "None".to_string(),
-            &Some(ref t) => t.repr(tcx),
-        }
-    }
+    start_or_continue(f, "", ">")
 }
 
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for P<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        (**self).repr(tcx)
-    }
-}
+fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter,
+                         tcx: &ty::ctxt<'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);
+    };
 
-impl<'tcx,T:Repr<'tcx>,U:Repr<'tcx>> Repr<'tcx> for Result<T,U> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        match self {
-            &Ok(ref t) => t.repr(tcx),
-            &Err(ref u) => format!("Err({})", u.repr(tcx))
+    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)
         }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for () {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        "()".to_string()
-    }
-}
-
-impl<'a, 'tcx, T: ?Sized +Repr<'tcx>> Repr<'tcx> for &'a T {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        Repr::repr(*self, tcx)
-    }
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Rc<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        (&**self).repr(tcx)
-    }
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Box<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        (&**self).repr(tcx)
-    }
-}
-
-fn repr_vec<'tcx, T:Repr<'tcx>>(tcx: &ctxt<'tcx>, v: &[T]) -> String {
-    vec_map_to_string(v, |t| t.repr(tcx))
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for [T] {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        repr_vec(tcx, self)
-    }
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for OwnedSlice<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        repr_vec(tcx, &self[..])
-    }
-}
-
-// This is necessary to handle types like Option<Vec<T>>, for which
-// autoderef cannot convert the &[T] handler
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Vec<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        repr_vec(tcx, &self[..])
-    }
-}
+    };
 
-impl<'tcx, T:UserString<'tcx>> UserString<'tcx> for Vec<T> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        let strs: Vec<String> =
-            self.iter().map(|t| t.user_string(tcx)).collect();
-        strs.connect(", ")
-    }
-}
+    let new_value = ty_fold::replace_late_bound_regions(tcx, &value, |br| {
+        let _ = start_or_continue(f, "for<", ", ");
+        ty::ReLateBound(ty::DebruijnIndex::new(1), 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(ast_util::local_def(ast::DUMMY_NODE_ID), name)
+            }
+        })
+    }).0;
 
-impl<'tcx> Repr<'tcx> for def::Def {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
+    try!(start_or_continue(f, "", "> "));
+    write!(f, "{}", new_value)
 }
 
 /// This curious type is here to help pretty-print trait objects. In
@@ -684,904 +250,624 @@ impl<'tcx> Repr<'tcx> for def::Def {
 /// 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.
-type TraitAndProjections<'tcx> =
-    (ty::TraitRef<'tcx>, Vec<ty::ProjectionPredicate<'tcx>>);
-
-impl<'tcx> UserString<'tcx> for TraitAndProjections<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        let &(ref trait_ref, ref projection_bounds) = self;
-        let base = ty::item_path_str(tcx, trait_ref.def_id);
-        parameterized(tcx,
-                      &base,
-                      trait_ref.substs,
-                      trait_ref.def_id,
-                      &projection_bounds[..],
-                      || ty::lookup_trait_def(tcx, trait_ref.def_id).generics.clone())
+#[derive(Clone, Debug)]
+struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec<ty::ProjectionPredicate<'tcx>>);
+
+impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
+    fn fold_with<F:ty_fold::TypeFolder<'tcx>>(&self, folder: &mut F)
+                                              -> TraitAndProjections<'tcx> {
+        TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
     }
 }
 
-impl<'tcx> UserString<'tcx> for ty::TraitTy<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        let &ty::TraitTy { ref principal, ref bounds } = self;
-
-        let mut components = vec![];
+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,
+                      |tcx| ty::lookup_trait_def(tcx, trait_ref.def_id).generics.clone())
+    }
+}
 
-        let tap: ty::Binder<TraitAndProjections<'tcx>> =
-            ty::Binder((principal.0.clone(),
-                        bounds.projection_bounds.iter().map(|x| x.0.clone()).collect()));
+impl<'tcx> fmt::Display for ty::TraitTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let bounds = &self.bounds;
 
         // Generate the main trait ref, including associated types.
-        components.push(tap.user_string(tcx));
+        try!(ty::tls::with(|tcx| {
+            let principal = tcx.lift(&self.principal.0)
+                               .expect("could not lift TraitRef for printing");
+            let projections = tcx.lift(&bounds.projection_bounds[..])
+                                 .expect("could not lift projections for printing");
+            let projections = projections.map_in_place(|p| p.0);
+
+            let tap = ty::Binder(TraitAndProjections(principal, projections));
+            in_binder(f, tcx, &ty::Binder(""), Some(tap))
+        }));
 
         // Builtin bounds.
         for bound in &bounds.builtin_bounds {
-            components.push(bound.user_string(tcx));
+            try!(write!(f, " + {:?}", bound));
         }
 
         // Region, if not obviously implied by builtin bounds.
         if bounds.region_bound != ty::ReStatic {
             // Region bound is implied by builtin bounds:
-            components.push(bounds.region_bound.user_string(tcx));
+            let bound = bounds.region_bound.to_string();
+            if !bound.is_empty() {
+                try!(write!(f, " + {}", bound));
+            }
         }
 
-        components.retain(|s| !s.is_empty());
-
-        components.connect(" + ")
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::TypeParameterDef<'tcx> {
-    fn repr(&self, _tcx: &ctxt<'tcx>) -> String {
-        format!("TypeParameterDef({:?}, {:?}/{})",
-                self.def_id,
-                self.space,
-                self.index)
+        Ok(())
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::RegionParameterDef {
-    fn repr(&self, tcx: &ctxt) -> String {
-        format!("RegionParameterDef(name={}, def_id={}, bounds={})",
-                token::get_name(self.name),
-                self.def_id.repr(tcx),
-                self.bounds.repr(tcx))
+impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TypeParameterDef({:?}, {:?}/{})",
+               self.def_id, self.space, self.index)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::TyS<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        ty_to_string(tcx, self)
+impl<'tcx> fmt::Debug for ty::TyS<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", *self)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::mt<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        mt_to_string(tcx, self)
+impl<'tcx> fmt::Display for ty::mt<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}{}",
+               if self.mutbl == ast::MutMutable { "mut " } else { "" },
+               self.ty)
     }
 }
 
-impl<'tcx> Repr<'tcx> for subst::Substs<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("Substs[types={}, regions={}]",
-                       self.types.repr(tcx),
-                       self.regions.repr(tcx))
+impl<'tcx> fmt::Debug for subst::Substs<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Substs[types={:?}, regions={:?}]",
+               self.types, self.regions)
     }
 }
 
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for subst::VecPerParamSpace<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("[{};{};{}]",
-                self.get_slice(subst::TypeSpace).repr(tcx),
-                self.get_slice(subst::SelfSpace).repr(tcx),
-                self.get_slice(subst::FnSpace).repr(tcx))
+impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ItemSubsts({:?})", self.substs)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::ItemSubsts<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("ItemSubsts({})", self.substs.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for subst::RegionSubsts {
-    fn repr(&self, tcx: &ctxt) -> String {
+impl fmt::Debug for subst::RegionSubsts {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            subst::ErasedRegions => "erased".to_string(),
-            subst::NonerasedRegions(ref regions) => regions.repr(tcx)
+            subst::ErasedRegions => write!(f, "erased"),
+            subst::NonerasedRegions(ref regions) => write!(f, "{:?}", regions)
         }
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::BuiltinBounds {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        let mut res = Vec::new();
-        for b in self {
-            res.push(match b {
-                ty::BoundSend => "Send".to_string(),
-                ty::BoundSized => "Sized".to_string(),
-                ty::BoundCopy => "Copy".to_string(),
-                ty::BoundSync => "Sync".to_string(),
-            });
-        }
-        res.connect("+")
-    }
-}
 
-impl<'tcx> Repr<'tcx> for ty::ParamBounds<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        let mut res = Vec::new();
-        res.push(self.builtin_bounds.repr(tcx));
-        for t in &self.trait_bounds {
-            res.push(t.repr(tcx));
+impl<'tcx> fmt::Debug for ty::ParamBounds<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        try!(write!(f, "{:?}", self.builtin_bounds));
+        let mut bounds = self.trait_bounds.iter();
+        if self.builtin_bounds.is_empty() {
+            if let Some(bound) = bounds.next() {
+                try!(write!(f, "{:?}", bound));
+            }
+        }
+        for bound in bounds {
+            try!(write!(f, " + {:?}", bound));
         }
-        res.connect("+")
+        Ok(())
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+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.
-        let base = ty::item_path_str(tcx, self.def_id);
-        let result = parameterized(tcx, &base, self.substs, self.def_id, &[],
-                      || ty::lookup_trait_def(tcx, self.def_id).generics.clone());
         match self.substs.self_ty() {
-            None => result,
-            Some(sty) => format!("<{} as {}>", sty.repr(tcx), result)
+            None => write!(f, "{}", *self),
+            Some(self_ty) => write!(f, "<{:?} as {}>", self_ty, *self)
         }
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::TraitDef<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("TraitDef(generics={}, trait_ref={})",
-                self.generics.repr(tcx),
-                self.trait_ref.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::TraitItem {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        let kind = match self.node {
-            ast::ConstTraitItem(..) => "ConstTraitItem",
-            ast::MethodTraitItem(..) => "MethodTraitItem",
-            ast::TypeTraitItem(..) => "TypeTraitItem",
-        };
-        format!("{}({}, id={})", kind, self.ident, self.id)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Expr {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("expr({}: {})", self.id, pprust::expr_to_string(self))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Path {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("path({})", pprust::path_to_string(self))
-    }
-}
-
-impl<'tcx> UserString<'tcx> for ast::Path {
-    fn user_string(&self, _tcx: &ctxt) -> String {
-        pprust::path_to_string(self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Ty {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("type({})", pprust::ty_to_string(self))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Item {
-    fn repr(&self, tcx: &ctxt) -> String {
-        format!("item({})", tcx.map.node_to_string(self.id))
+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)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ast::Lifetime {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Stmt {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("stmt({}: {})",
-                ast_util::stmt_id(self),
-                pprust::stmt_to_string(self))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Pat {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("pat({}: {})", self.id, pprust::pat_to_string(self))
-    }
-}
+impl fmt::Display for ty::BoundRegion {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if verbose() {
+            return write!(f, "{:?}", *self);
+        }
 
-impl<'tcx> Repr<'tcx> for ty::BoundRegion {
-    fn repr(&self, tcx: &ctxt) -> String {
         match *self {
-            ty::BrAnon(id) => format!("BrAnon({})", id),
-            ty::BrNamed(id, name) => {
-                format!("BrNamed({}, {})", id.repr(tcx), token::get_name(name))
-            }
-            ty::BrFresh(id) => format!("BrFresh({})", id),
-            ty::BrEnv => "BrEnv".to_string()
+            BrNamed(_, name) => write!(f, "{}", name),
+            BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
         }
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::Region {
-    fn repr(&self, tcx: &ctxt) -> String {
+impl fmt::Debug for ty::Region {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::ReEarlyBound(ref data) => {
-                format!("ReEarlyBound({}, {:?}, {}, {})",
-                        data.param_id,
-                        data.space,
-                        data.index,
-                        token::get_name(data.name))
+                write!(f, "ReEarlyBound({}, {:?}, {}, {})",
+                       data.param_id,
+                       data.space,
+                       data.index,
+                       data.name)
             }
 
             ty::ReLateBound(binder_id, ref bound_region) => {
-                format!("ReLateBound({:?}, {})",
-                        binder_id,
-                        bound_region.repr(tcx))
+                write!(f, "ReLateBound({:?}, {:?})",
+                       binder_id,
+                       bound_region)
             }
 
-            ty::ReFree(ref fr) => fr.repr(tcx),
+            ty::ReFree(ref fr) => write!(f, "{:?}", fr),
 
             ty::ReScope(id) => {
-                format!("ReScope({:?})", id)
+                write!(f, "ReScope({:?})", id)
             }
 
-            ty::ReStatic => {
-                "ReStatic".to_string()
-            }
+            ty::ReStatic => write!(f, "ReStatic"),
 
             ty::ReInfer(ReVar(ref vid)) => {
-                format!("{:?}", vid)
+                write!(f, "{:?}", vid)
             }
 
             ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
-                format!("re_skolemized({}, {})", id, bound_region.repr(tcx))
+                write!(f, "ReSkolemized({}, {:?})", id, bound_region)
             }
 
-            ty::ReEmpty => {
-                "ReEmpty".to_string()
-            }
+            ty::ReEmpty => write!(f, "ReEmpty")
         }
     }
 }
 
-impl<'tcx> UserString<'tcx> for ty::Region {
-    fn user_string(&self, tcx: &ctxt) -> String {
-        region_to_string(tcx, "", false, *self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::FreeRegion {
-    fn repr(&self, tcx: &ctxt) -> String {
-        format!("ReFree({}, {})",
-                self.scope.repr(tcx),
-                self.bound_region.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for region::CodeExtent {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        match *self {
-            region::CodeExtent::ParameterScope { fn_id, body_id } =>
-                format!("ParameterScope({}, {})", fn_id, body_id),
-            region::CodeExtent::Misc(node_id) =>
-                format!("Misc({})", node_id),
-            region::CodeExtent::DestructionScope(node_id) =>
-                format!("DestructionScope({})", node_id),
-            region::CodeExtent::Remainder(rem) =>
-                format!("Remainder({}, {})", rem.block, rem.first_statement_index),
+impl fmt::Display for ty::Region {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if verbose() {
+            return write!(f, "{:?}", *self);
         }
-    }
-}
 
-impl<'tcx> Repr<'tcx> for region::DestructionScopeData {
-    fn repr(&self, _tcx: &ctxt) -> String {
+        // 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 {
-            region::DestructionScopeData{ node_id } =>
-                format!("DestructionScopeData {{ node_id: {} }}", node_id),
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::DefId {
-    fn repr(&self, tcx: &ctxt) -> String {
-        // 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.krate == ast::LOCAL_CRATE {
-            match tcx.map.find(self.node) {
-                Some(ast_map::NodeItem(..)) |
-                Some(ast_map::NodeForeignItem(..)) |
-                Some(ast_map::NodeImplItem(..)) |
-                Some(ast_map::NodeTraitItem(..)) |
-                Some(ast_map::NodeVariant(..)) |
-                Some(ast_map::NodeStructCtor(..)) => {
-                    return format!(
-                                "{:?}:{}",
-                                *self,
-                                ty::item_path_str(tcx, *self))
-                }
-                _ => {}
+            ty::ReEarlyBound(ref data) => {
+                write!(f, "{}", data.name)
+            }
+            ty::ReLateBound(_, br) |
+            ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
+            ty::ReInfer(ReSkolemized(_, br)) => {
+                write!(f, "{}", br)
             }
+            ty::ReScope(_) |
+            ty::ReInfer(ReVar(_)) => Ok(()),
+            ty::ReStatic => write!(f, "'static"),
+            ty::ReEmpty => write!(f, "'<empty>"),
         }
-        return format!("{:?}", *self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::TypeScheme<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("TypeScheme {{generics: {}, ty: {}}}",
-                self.generics.repr(tcx),
-                self.ty.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::Generics<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("Generics(types: {}, regions: {})",
-                self.types.repr(tcx),
-                self.regions.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::GenericPredicates<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("GenericPredicates(predicates: {})",
-                self.predicates.repr(tcx))
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::InstantiatedPredicates<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("InstantiatedPredicates({})",
-                self.predicates.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)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::ItemVariances {
-    fn repr(&self, tcx: &ctxt) -> String {
-        format!("ItemVariances(types={}, \
-                regions={})",
-                self.types.repr(tcx),
-                self.regions.repr(tcx))
+impl fmt::Debug for ty::ItemVariances {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ItemVariances(types={:?}, regions={:?})",
+               self.types, self.regions)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::Variance {
-    fn repr(&self, _: &ctxt) -> String {
-        // The first `.to_string()` returns a &'static str (it is not an implementation
-        // of the ToString trait). Because of that, we need to call `.to_string()` again
-        // if we want to have a `String`.
-        let result: &'static str = (*self).to_string();
-        result.to_string()
+impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "GenericPredicates({:?})", self.predicates)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::ImplOrTraitItem<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("ImplOrTraitItem({})",
-                match *self {
-                    ty::ImplOrTraitItem::MethodTraitItem(ref i) => i.repr(tcx),
-                    ty::ImplOrTraitItem::ConstTraitItem(ref i) => i.repr(tcx),
-                    ty::ImplOrTraitItem::TypeTraitItem(ref i) => i.repr(tcx),
-                })
+impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "InstantiatedPredicates({:?})",
+               self.predicates)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("AssociatedConst(name: {}, ty: {}, vis: {}, def_id: {})",
-                self.name.repr(tcx),
-                self.ty.repr(tcx),
-                self.vis.repr(tcx),
-                self.def_id.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::AssociatedType<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("AssociatedType(name: {}, vis: {}, def_id: {})",
-                self.name.repr(tcx),
-                self.vis.repr(tcx),
-                self.def_id.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::Method<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("Method(name: {}, generics: {}, predicates: {}, fty: {}, \
-                 explicit_self: {}, vis: {}, def_id: {})",
-                self.name.repr(tcx),
-                self.generics.repr(tcx),
-                self.predicates.repr(tcx),
-                self.fty.repr(tcx),
-                self.explicit_self.repr(tcx),
-                self.vis.repr(tcx),
-                self.def_id.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Name {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        token::get_name(*self).to_string()
-    }
-}
-
-impl<'tcx> UserString<'tcx> for ast::Name {
-    fn user_string(&self, _tcx: &ctxt) -> String {
-        token::get_name(*self).to_string()
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Ident {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        token::get_ident(*self).to_string()
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::ExplicitSelf_ {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Visibility {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::BareFnTy<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("BareFnTy {{unsafety: {}, abi: {}, sig: {}}}",
-                self.unsafety,
-                self.abi.to_string(),
-                self.sig.repr(tcx))
+impl<'tcx> fmt::Debug for ty::ImplOrTraitItem<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        try!(write!(f, "ImplOrTraitItem("));
+        try!(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<'tcx> Repr<'tcx> for ty::FnSig<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("fn{} -> {}", self.inputs.repr(tcx), self.output.repr(tcx))
+impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        try!(write!(f, "fn"));
+        fn_sig(f, &self.inputs, self.variadic, self.output)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::FnOutput<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for ty::MethodOrigin<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ty::FnConverging(ty) =>
-                format!("FnConverging({0})", ty.repr(tcx)),
-            ty::FnDiverging =>
-                "FnDiverging".to_string()
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::MethodCallee<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("MethodCallee {{origin: {}, ty: {}, {}}}",
-                self.origin.repr(tcx),
-                self.ty.repr(tcx),
-                self.substs.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::MethodOrigin<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        match self {
-            &ty::MethodStatic(def_id) => {
-                format!("MethodStatic({})", def_id.repr(tcx))
-            }
-            &ty::MethodStaticClosure(def_id) => {
-                format!("MethodStaticClosure({})", def_id.repr(tcx))
+            ty::MethodStatic(def_id) => {
+                write!(f, "MethodStatic({:?})", def_id)
             }
-            &ty::MethodTypeParam(ref p) => {
-                p.repr(tcx)
+            ty::MethodStaticClosure(def_id) => {
+                write!(f, "MethodStaticClosure({:?})", def_id)
             }
-            &ty::MethodTraitObject(ref p) => {
-                p.repr(tcx)
-            }
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::MethodParam<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("MethodParam({},{})",
-                self.trait_ref.repr(tcx),
-                self.method_num)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::MethodObject<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("MethodObject({},{},{})",
-                self.trait_ref.repr(tcx),
-                self.method_num,
-                self.vtable_index)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::BuiltinBound {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
-}
-
-impl<'tcx> UserString<'tcx> for ty::BuiltinBound {
-    fn user_string(&self, _tcx: &ctxt) -> String {
-        match *self {
-            ty::BoundSend => "Send".to_string(),
-            ty::BoundSized => "Sized".to_string(),
-            ty::BoundCopy => "Copy".to_string(),
-            ty::BoundSync => "Sync".to_string(),
+            ty::MethodTypeParam(ref p) => write!(f, "{:?}", p),
+            ty::MethodTraitObject(ref p) => write!(f, "{:?}", p)
         }
     }
 }
 
-impl<'tcx> Repr<'tcx> for Span {
-    fn repr(&self, tcx: &ctxt) -> String {
-        tcx.sess.codemap().span_to_string(*self).to_string()
+impl<'tcx> fmt::Debug for ty::MethodParam<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "MethodParam({:?},{})",
+               self.trait_ref,
+               self.method_num)
     }
 }
 
-impl<'tcx, A:UserString<'tcx>> UserString<'tcx> for Rc<A> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        let this: &A = &**self;
-        this.user_string(tcx)
+impl<'tcx> fmt::Debug for ty::MethodObject<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "MethodObject({:?},{},{})",
+               self.trait_ref,
+               self.method_num,
+               self.vtable_index)
     }
 }
 
-impl<'tcx> UserString<'tcx> for ty::ParamBounds<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        let mut result = Vec::new();
-        let s = self.builtin_bounds.user_string(tcx);
-        if !s.is_empty() {
-            result.push(s);
+impl<'tcx> fmt::Display for ty::ParamBounds<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        try!(write!(f, "{}", self.builtin_bounds));
+        let mut bounds = self.trait_bounds.iter();
+        if self.builtin_bounds.is_empty() {
+            if let Some(bound) = bounds.next() {
+                try!(write!(f, "{}", bound));
+            }
         }
-        for n in &self.trait_bounds {
-            result.push(n.user_string(tcx));
+        for bound in bounds {
+            try!(write!(f, " + {}", bound));
         }
-        result.connect(" + ")
+        Ok(())
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        let mut res = Vec::new();
+impl<'tcx> fmt::Debug for ty::ExistentialBounds<'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, " + ")
+            }
+        };
 
-        let region_str = self.region_bound.repr(tcx);
+        let region_str = format!("{:?}", self.region_bound);
         if !region_str.is_empty() {
-            res.push(region_str);
+            try!(maybe_continue(f));
+            try!(write!(f, "{}", region_str));
         }
 
         for bound in &self.builtin_bounds {
-            res.push(bound.repr(tcx));
+            try!(maybe_continue(f));
+            try!(write!(f, "{:?}", bound));
         }
 
         for projection_bound in &self.projection_bounds {
-            res.push(projection_bound.repr(tcx));
+            try!(maybe_continue(f));
+            try!(write!(f, "{:?}", projection_bound));
         }
 
-        res.connect("+")
-    }
-}
-
-impl<'tcx> UserString<'tcx> for ty::BuiltinBounds {
-    fn user_string(&self, tcx: &ctxt) -> String {
-        self.iter()
-            .map(|bb| bb.user_string(tcx))
-            .collect::<Vec<String>>()
-            .connect("+")
-            .to_string()
+        Ok(())
     }
 }
 
-impl<'tcx, T> UserString<'tcx> for ty::Binder<T>
-    where T : UserString<'tcx> + TypeFoldable<'tcx>
-{
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        // 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 mut names = Vec::new();
-        let (unbound_value, _) = ty_fold::replace_late_bound_regions(tcx, self, |br| {
-            ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
-                ty::BrNamed(_, name) => {
-                    names.push(token::get_name(name));
-                    br
-                }
-                ty::BrAnon(_) |
-                ty::BrFresh(_) |
-                ty::BrEnv => {
-                    let name = token::gensym("'r");
-                    names.push(token::get_name(name));
-                    ty::BrNamed(ast_util::local_def(ast::DUMMY_NODE_ID), name)
-                }
-            })
-        });
-        let names: Vec<_> = names.iter().map(|s| &s[..]).collect();
-
-        let value_str = unbound_value.user_string(tcx);
-        if names.is_empty() {
-            value_str
-        } else {
-            format!("for<{}> {}", names.connect(","), value_str)
+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() {
+            try!(write!(f, "{:?}", bound));
+            for bound in bounds {
+                try!(write!(f, " + {:?}", bound));
+            }
         }
+        Ok(())
     }
 }
 
-impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        let path_str = ty::item_path_str(tcx, self.def_id);
-        parameterized(tcx, &path_str, self.substs, self.def_id, &[],
-                      || ty::lookup_trait_def(tcx, self.def_id).generics.clone())
+// 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<'tcx> UserString<'tcx> for Ty<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        ty_to_string(tcx, *self)
+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<'tcx> UserString<'tcx> for ast::Ident {
-    fn user_string(&self, _tcx: &ctxt) -> String {
-        token::get_name(self.name).to_string()
+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<'tcx> Repr<'tcx> for abi::Abi {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        self.to_string()
+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<'tcx> UserString<'tcx> for abi::Abi {
-    fn user_string(&self, _tcx: &ctxt) -> String {
-        self.to_string()
+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<'tcx> Repr<'tcx> for ty::UpvarId {
-    fn repr(&self, tcx: &ctxt) -> String {
-        format!("UpvarId({};`{}`;{})",
-                self.var_id,
-                ty::local_var_name_str(tcx, self.var_id),
-                self.closure_expr_id)
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'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<'tcx> Repr<'tcx> for ast::Mutability {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
+impl fmt::Display for ty::Binder<ty::OutlivesPredicate<ty::Region, ty::Region>> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::BorrowKind {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
+impl<'tcx> fmt::Display for ty::TraitRef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        parameterized(f, self.substs, self.def_id, &[],
+                      |tcx| ty::lookup_trait_def(tcx, self.def_id).generics.clone())
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::UpvarBorrow {
-    fn repr(&self, tcx: &ctxt) -> String {
-        format!("UpvarBorrow({}, {})",
-                self.kind.repr(tcx),
-                self.region.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::UpvarCapture {
-    fn repr(&self, tcx: &ctxt) -> String {
+impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ty::UpvarCapture::ByValue => format!("ByValue"),
-            ty::UpvarCapture::ByRef(ref data) => format!("ByRef({})", data.repr(tcx)),
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::IntVid {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::FloatVid {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::RegionVid {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::TyVid {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::IntVarValue {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
-}
+            TyBool => write!(f, "bool"),
+            TyChar => write!(f, "char"),
+            TyInt(t) => write!(f, "{}", ast_util::int_ty_to_string(t, None)),
+            TyUint(t) => write!(f, "{}", ast_util::uint_ty_to_string(t, None)),
+            TyFloat(t) => write!(f, "{}", ast_util::float_ty_to_string(t)),
+            TyBox(typ) => write!(f, "Box<{}>",  typ),
+            TyRawPtr(ref tm) => {
+                write!(f, "*{} {}", match tm.mutbl {
+                    ast::MutMutable => "mut",
+                    ast::MutImmutable => "const",
+                },  tm.ty)
+            }
+            TyRef(r, ref tm) => {
+                try!(write!(f, "&"));
+                let s = r.to_string();
+                try!(write!(f, "{}", s));
+                if !s.is_empty() {
+                    try!(write!(f, " "));
+                }
+                write!(f, "{}", tm)
+            }
+            TyTuple(ref tys) => {
+                try!(write!(f, "("));
+                let mut tys = tys.iter();
+                if let Some(&ty) = tys.next() {
+                    try!(write!(f, "{},", ty));
+                    if let Some(&ty) = tys.next() {
+                        try!(write!(f, " {}", ty));
+                        for &ty in tys {
+                            try!(write!(f, ", {}", ty));
+                        }
+                    }
+                }
+                write!(f, ")")
+            }
+            TyBareFn(opt_def_id, ref bare_fn) => {
+                if bare_fn.unsafety == ast::Unsafety::Unsafe {
+                    try!(write!(f, "unsafe "));
+                }
 
-impl<'tcx> Repr<'tcx> for ast::IntTy {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
-}
+                if bare_fn.abi != abi::Rust {
+                    try!(write!(f, "extern {} ", bare_fn.abi));
+                }
 
-impl<'tcx> Repr<'tcx> for ast::UintTy {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
-}
+                try!(write!(f, "{}", bare_fn.sig.0));
 
-impl<'tcx> Repr<'tcx> for ast::FloatTy {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
+                if let Some(def_id) = opt_def_id {
+                    try!(write!(f, " {{{}}}", ty::tls::with(|tcx| {
+                        ty::item_path_str(tcx, def_id)
+                    })));
+                }
+                Ok(())
+            }
+            TyInfer(infer_ty) => write!(f, "{}", infer_ty),
+            TyError => write!(f, "[type error]"),
+            TyParam(ref param_ty) => write!(f, "{}", param_ty),
+            TyEnum(did, substs) | TyStruct(did, substs) => {
+                parameterized(f, substs, did, &[],
+                              |tcx| ty::lookup_item_type(tcx, did).generics)
+            }
+            TyTrait(ref data) => write!(f, "{}", data),
+            ty::TyProjection(ref data) => write!(f, "{}", data),
+            TyStr => write!(f, "str"),
+            TyClosure(ref did, substs) => ty::tls::with(|tcx| {
+                try!(write!(f, "[closure"));
+                let closure_tys = tcx.closure_tys.borrow();
+                try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| {
+                    tcx.lift(&substs).map(|substs| sig.subst(tcx, substs))
+                }).map(|sig| {
+                    fn_sig(f, &sig.0.inputs, false, sig.0.output)
+                }).unwrap_or_else(|| {
+                    if did.krate == ast::LOCAL_CRATE {
+                        try!(write!(f, " {:?}", tcx.map.span(did.node)));
+                    }
+                    Ok(())
+                }));
+                if verbose() {
+                    try!(write!(f, " id={:?}", did));
+                }
+                write!(f, "]")
+            }),
+            TyArray(ty, sz) => write!(f, "[{}; {}]",  ty, sz),
+            TySlice(ty) => write!(f, "[{}]",  ty)
+        }
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::ExplicitSelfCategory {
-    fn repr(&self, _: &ctxt) -> String {
-        explicit_self_category_to_str(self).to_string()
+impl<'tcx> fmt::Display for ty::TyS<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.sty)
     }
 }
 
-impl<'tcx> UserString<'tcx> for ParamTy {
-    fn user_string(&self, _tcx: &ctxt) -> String {
-        format!("{}", token::get_name(self.name))
+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| ty::local_var_name_str(tcx, self.var_id)),
+               self.closure_expr_id)
     }
 }
 
-impl<'tcx> Repr<'tcx> for ParamTy {
-    fn repr(&self, tcx: &ctxt) -> String {
-        let ident = self.user_string(tcx);
-        format!("{}/{:?}.{}", ident, self.space, self.idx)
+impl fmt::Debug for ty::UpvarBorrow {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "UpvarBorrow({:?}, {:?})",
+               self.kind, self.region)
     }
 }
 
-impl<'tcx, A:Repr<'tcx>, B:Repr<'tcx>> Repr<'tcx> for (A,B) {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        let &(ref a, ref b) = self;
-        format!("({},{})", a.repr(tcx), b.repr(tcx))
+impl fmt::Display for ty::InferTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let print_var_ids = verbose();
+        match *self {
+            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(_) | ty::IntVar(_) | ty::FloatVar(_) => write!(f, "_"),
+            ty::FreshTy(v) => write!(f, "FreshTy({})", v),
+            ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
+            ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
+        }
     }
 }
 
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder<T> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("Binder({})", self.0.repr(tcx))
+impl fmt::Display for ty::ExplicitSelfCategory {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(match *self {
+            ty::StaticExplicitSelfCategory => "static",
+            ty::ByValueExplicitSelfCategory => "self",
+            ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => {
+                "&mut self"
+            }
+            ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self",
+            ty::ByBoxExplicitSelfCategory => "Box<self>",
+        })
     }
 }
 
-impl<'tcx, S, K, V> Repr<'tcx> for HashMap<K, V, S>
-    where K: Hash + Eq + Repr<'tcx>,
-          V: Repr<'tcx>,
-          S: HashState,
-{
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("HashMap({})",
-                self.iter()
-                    .map(|(k,v)| format!("{} => {}", k.repr(tcx), v.repr(tcx)))
-                    .collect::<Vec<String>>()
-                    .connect(", "))
+impl fmt::Display for ty::ParamTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.name)
     }
 }
 
-impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate<T,U>
-    where T : Repr<'tcx> + TypeFoldable<'tcx>,
-          U : Repr<'tcx> + TypeFoldable<'tcx>,
-{
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("OutlivesPredicate({}, {})",
-                self.0.repr(tcx),
-                self.1.repr(tcx))
+impl fmt::Debug for ty::ParamTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}/{:?}.{}", self, self.space, self.idx)
     }
 }
 
-impl<'tcx, T, U> UserString<'tcx> for ty::OutlivesPredicate<T,U>
-    where T : UserString<'tcx> + TypeFoldable<'tcx>,
-          U : UserString<'tcx> + TypeFoldable<'tcx>,
+impl<'tcx, T, U> fmt::Display for ty::OutlivesPredicate<T,U>
+    where T: fmt::Display, U: fmt::Display
 {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("{} : {}",
-                self.0.user_string(tcx),
-                self.1.user_string(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for ty::EquatePredicate<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("EquatePredicate({}, {})",
-                self.0.repr(tcx),
-                self.1.repr(tcx))
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{} : {}", self.0, self.1)
     }
 }
 
-impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("{} == {}",
-                self.0.user_string(tcx),
-                self.1.user_string(tcx))
+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> Repr<'tcx> for ty::TraitPredicate<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("TraitPredicate({})",
-                self.trait_ref.repr(tcx))
+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> UserString<'tcx> for ty::TraitPredicate<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("{} : {}",
-                self.trait_ref.self_ty().user_string(tcx),
-                self.trait_ref.user_string(tcx))
+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> UserString<'tcx> for ty::ProjectionPredicate<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("{} == {}",
-                self.projection_ty.user_string(tcx),
-                self.ty.user_string(tcx))
+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> Repr<'tcx> for ty::ProjectionTy<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("{}::{}",
-                self.trait_ref.repr(tcx),
-                self.item_name.repr(tcx))
+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> UserString<'tcx> for ty::ProjectionTy<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("<{} as {}>::{}",
-                self.trait_ref.self_ty().user_string(tcx),
-                self.trait_ref.user_string(tcx),
-                self.item_name.user_string(tcx))
+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<'tcx> UserString<'tcx> for ty::Predicate<'tcx> {
-    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ty::Predicate::Trait(ref data) => data.user_string(tcx),
-            ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx),
-            ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx),
-            ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx),
-            ty::Predicate::Projection(ref predicate) => predicate.user_string(tcx),
+            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),
         }
     }
 }
-
-impl<'tcx> Repr<'tcx> for ast::Unsafety {
-    fn repr(&self, _: &ctxt<'tcx>) -> String {
-        format!("{:?}", *self)
-    }
-}
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 90bc918c4b1..49933441cf0 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -24,7 +24,6 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::region;
 use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
 use syntax::ast;
 use syntax::codemap::Span;
 
@@ -97,8 +96,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                consume_span: Span,
                cmt: mc::cmt<'tcx>,
                mode: euv::ConsumeMode) {
-        debug!("consume(consume_id={}, cmt={}, mode={:?})",
-               consume_id, cmt.repr(self.tcx()), mode);
+        debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
+               consume_id, cmt, mode);
 
         self.consume_common(consume_id, consume_span, cmt, mode);
     }
@@ -112,9 +111,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                    consume_pat: &ast::Pat,
                    cmt: mc::cmt<'tcx>,
                    mode: euv::ConsumeMode) {
-        debug!("consume_pat(consume_pat={}, cmt={}, mode={:?})",
-               consume_pat.repr(self.tcx()),
-               cmt.repr(self.tcx()),
+        debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})",
+               consume_pat,
+               cmt,
                mode);
 
         self.consume_common(consume_pat.id, consume_pat.span, cmt, mode);
@@ -128,9 +127,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause)
     {
-        debug!("borrow(borrow_id={}, cmt={}, loan_region={:?}, \
+        debug!("borrow(borrow_id={}, cmt={:?}, loan_region={:?}, \
                bk={:?}, loan_cause={:?})",
-               borrow_id, cmt.repr(self.tcx()), loan_region,
+               borrow_id, cmt, loan_region,
                bk, loan_cause);
 
         match opt_loan_path(&cmt) {
@@ -153,8 +152,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
               assignee_cmt: mc::cmt<'tcx>,
               mode: euv::MutateMode)
     {
-        debug!("mutate(assignment_id={}, assignee_cmt={})",
-               assignment_id, assignee_cmt.repr(self.tcx()));
+        debug!("mutate(assignment_id={}, assignee_cmt={:?})",
+               assignment_id, assignee_cmt);
 
         match opt_loan_path(&assignee_cmt) {
             Some(lp) => {
@@ -384,9 +383,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         //! Checks whether `old_loan` and `new_loan` can safely be issued
         //! simultaneously.
 
-        debug!("report_error_if_loans_conflict(old_loan={}, new_loan={})",
-               old_loan.repr(self.tcx()),
-               new_loan.repr(self.tcx()));
+        debug!("report_error_if_loans_conflict(old_loan={:?}, new_loan={:?})",
+               old_loan,
+               new_loan);
 
         // Should only be called for loans that are in scope at the same time.
         assert!(self.tcx().region_maps.scopes_intersect(old_loan.kill_scope,
@@ -408,9 +407,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         //! prohibit `loan2`. Returns false if an error is reported.
 
         debug!("report_error_if_loan_conflicts_with_restriction(\
-                loan1={}, loan2={})",
-               loan1.repr(self.tcx()),
-               loan2.repr(self.tcx()));
+                loan1={:?}, loan2={:?})",
+               loan1,
+               loan2);
 
         if compatible_borrow_kinds(loan1.kind, loan2.kind) {
             return true;
@@ -672,9 +671,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                        use_path: &LoanPath<'tcx>,
                                        borrow_kind: ty::BorrowKind)
                                        -> UseError<'tcx> {
-        debug!("analyze_restrictions_on_use(expr_id={}, use_path={})",
+        debug!("analyze_restrictions_on_use(expr_id={}, use_path={:?})",
                self.tcx().map.node_to_string(expr_id),
-               use_path.repr(self.tcx()));
+               use_path);
 
         let mut ret = UseOk;
 
@@ -698,8 +697,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                               span: Span,
                               use_kind: MovedValueUseKind,
                               lp: &Rc<LoanPath<'tcx>>) {
-        debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={})",
-               id, use_kind, lp.repr(self.bccx.tcx));
+        debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={:?})",
+               id, use_kind, lp);
 
         // FIXME (22079): if you find yourself tempted to cut and paste
         // the body below and then specializing the error reporting,
@@ -792,7 +791,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                         assignment_span: Span,
                         assignee_cmt: mc::cmt<'tcx>,
                         mode: euv::MutateMode) {
-        debug!("check_assignment(assignee_cmt={})", assignee_cmt.repr(self.tcx()));
+        debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
 
         // Mutable values can be assigned, as long as they obey loans
         // and aliasing restrictions:
@@ -884,7 +883,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             //! `used_mut_nodes` table here.
 
             loop {
-                debug!("mark_variable_as_used_mut(cmt={})", cmt.repr(this.tcx()));
+                debug!("mark_variable_as_used_mut(cmt={:?})", cmt);
                 match cmt.cat.clone() {
                     mc::cat_upvar(mc::Upvar { id: ty::UpvarId { var_id: id, .. }, .. }) |
                     mc::cat_local(id) => {
@@ -929,8 +928,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             //! Safety checks related to writes to aliasable, mutable locations
 
             let guarantor = cmt.guarantor();
-            debug!("check_for_aliasable_mutable_writes(cmt={}, guarantor={})",
-                   cmt.repr(this.tcx()), guarantor.repr(this.tcx()));
+            debug!("check_for_aliasable_mutable_writes(cmt={:?}, guarantor={:?})",
+                   cmt, guarantor);
             if let mc::cat_deref(ref b, _, mc::BorrowedPtr(ty::MutBorrow, _)) = guarantor.cat {
                 // Statically prohibit writes to `&mut` when aliasable
                 check_for_aliasability_violation(this, span, b.clone());
diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index a70b1dfe187..93f5ac529d3 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -22,7 +22,7 @@ use borrowck::move_data::InvalidMovePathIndex;
 use borrowck::move_data::{MoveData, MovePathIndex};
 use rustc::middle::ty;
 use rustc::middle::mem_categorization as mc;
-use rustc::util::ppaux::{Repr, UserString};
+
 use std::mem;
 use std::rc::Rc;
 use syntax::ast;
@@ -42,21 +42,19 @@ enum Fragment {
 }
 
 impl Fragment {
-    fn loan_path_repr<'tcx>(&self, move_data: &MoveData<'tcx>, tcx: &ty::ctxt<'tcx>) -> String {
-        let repr = |mpi| move_data.path_loan_path(mpi).repr(tcx);
+    fn loan_path_repr(&self, move_data: &MoveData) -> String {
+        let lp = |mpi| move_data.path_loan_path(mpi);
         match *self {
-            Just(mpi) => repr(mpi),
-            AllButOneFrom(mpi) => format!("$(allbutone {})", repr(mpi)),
+            Just(mpi) => format!("{:?}", lp(mpi)),
+            AllButOneFrom(mpi) => format!("$(allbutone {:?})", lp(mpi)),
         }
     }
 
-    fn loan_path_user_string<'tcx>(&self,
-                                   move_data: &MoveData<'tcx>,
-                                   tcx: &ty::ctxt<'tcx>) -> String {
-        let user_string = |mpi| move_data.path_loan_path(mpi).user_string(tcx);
+    fn loan_path_user_string(&self, move_data: &MoveData) -> String {
+        let lp = |mpi| move_data.path_loan_path(mpi);
         match *self {
-            Just(mpi) => user_string(mpi),
-            AllButOneFrom(mpi) => format!("$(allbutone {})", user_string(mpi)),
+            Just(mpi) => lp(mpi).to_string(),
+            AllButOneFrom(mpi) => format!("$(allbutone {})", lp(mpi)),
         }
     }
 }
@@ -126,19 +124,19 @@ pub fn instrument_move_fragments<'tcx>(this: &MoveData<'tcx>,
 
     let instrument_all_paths = |kind, vec_rc: &Vec<MovePathIndex>| {
         for (i, mpi) in vec_rc.iter().enumerate() {
-            let render = || this.path_loan_path(*mpi).user_string(tcx);
+            let lp = || this.path_loan_path(*mpi);
             if span_err {
-                tcx.sess.span_err(sp, &format!("{}: `{}`", kind, render()));
+                tcx.sess.span_err(sp, &format!("{}: `{}`", kind, lp()));
             }
             if print {
-                println!("id:{} {}[{}] `{}`", id, kind, i, render());
+                println!("id:{} {}[{}] `{}`", id, kind, i, lp());
             }
         }
     };
 
     let instrument_all_fragments = |kind, vec_rc: &Vec<Fragment>| {
         for (i, f) in vec_rc.iter().enumerate() {
-            let render = || f.loan_path_user_string(this, tcx);
+            let render = || f.loan_path_user_string(this);
             if span_err {
                 tcx.sess.span_err(sp, &format!("{}: `{}`", kind, render()));
             }
@@ -172,11 +170,11 @@ pub fn fixup_fragment_sets<'tcx>(this: &MoveData<'tcx>, tcx: &ty::ctxt<'tcx>) {
     let mut assigned = mem::replace(&mut fragments.assigned_leaf_paths, vec![]);
 
     let path_lps = |mpis: &[MovePathIndex]| -> Vec<String> {
-        mpis.iter().map(|mpi| this.path_loan_path(*mpi).repr(tcx)).collect()
+        mpis.iter().map(|mpi| format!("{:?}", this.path_loan_path(*mpi))).collect()
     };
 
     let frag_lps = |fs: &[Fragment]| -> Vec<String> {
-        fs.iter().map(|f| f.loan_path_repr(this, tcx)).collect()
+        fs.iter().map(|f| f.loan_path_repr(this)).collect()
     };
 
     // First, filter out duplicates
@@ -343,8 +341,8 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>,
             let tuple_idx = match *origin_field_name {
                 mc::PositionalField(tuple_idx) => tuple_idx,
                 mc::NamedField(_) =>
-                    panic!("tuple type {} should not have named fields.",
-                           parent_ty.repr(tcx)),
+                    panic!("tuple type {:?} should not have named fields.",
+                           parent_ty),
             };
             let tuple_len = v.len();
             for i in 0..tuple_len {
@@ -418,8 +416,8 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>,
         }
 
         ref sty_and_variant_info => {
-            let msg = format!("type {} ({:?}) is not fragmentable",
-                              parent_ty.repr(tcx), sty_and_variant_info);
+            let msg = format!("type {:?} ({:?}) is not fragmentable",
+                              parent_ty, sty_and_variant_info);
             let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id));
             tcx.sess.opt_span_bug(opt_span, &msg[..])
         }
@@ -450,8 +448,8 @@ fn add_fragment_sibling_core<'tcx>(this: &MoveData<'tcx>,
     };
     let new_lp_variant = LpExtend(parent, mc, loan_path_elem);
     let new_lp = LoanPath::new(new_lp_variant, new_lp_type.unwrap());
-    debug!("add_fragment_sibling_core(new_lp={}, origin_lp={})",
-           new_lp.repr(tcx), origin_lp.repr(tcx));
+    debug!("add_fragment_sibling_core(new_lp={:?}, origin_lp={:?})",
+           new_lp, origin_lp);
     let mp = this.move_path(tcx, Rc::new(new_lp));
 
     // Do not worry about checking for duplicates here; we will sort
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 43877d592ae..7b6c54dbaca 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -18,7 +18,7 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
 use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
+
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::Span;
@@ -66,8 +66,8 @@ pub fn gather_match_variant<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                       cmt: mc::cmt<'tcx>,
                                       mode: euv::MatchMode) {
     let tcx = bccx.tcx;
-    debug!("gather_match_variant(move_pat={}, cmt={}, mode={:?})",
-           move_pat.id, cmt.repr(tcx), mode);
+    debug!("gather_match_variant(move_pat={}, cmt={:?}, mode={:?})",
+           move_pat.id, cmt, mode);
 
     let opt_lp = opt_loan_path(&cmt);
     match opt_lp {
@@ -115,14 +115,14 @@ fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                          move_data: &MoveData<'tcx>,
                          move_error_collector: &MoveErrorCollector<'tcx>,
                          move_info: GatherMoveInfo<'tcx>) {
-    debug!("gather_move(move_id={}, cmt={})",
-           move_info.id, move_info.cmt.repr(bccx.tcx));
+    debug!("gather_move(move_id={}, cmt={:?})",
+           move_info.id, move_info.cmt);
 
     let potentially_illegal_move =
                 check_and_get_illegal_move_origin(bccx, &move_info.cmt);
     match potentially_illegal_move {
         Some(illegal_move_origin) => {
-            debug!("illegal_move_origin={}", illegal_move_origin.repr(bccx.tcx));
+            debug!("illegal_move_origin={:?}", illegal_move_origin);
             let error = MoveError::with_move_info(illegal_move_origin,
                                                   move_info.span_path_opt);
             move_error_collector.add_error(error);
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index 9f7b4cf26e1..427d78e89b3 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -16,7 +16,7 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::region;
 use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
+
 use syntax::ast;
 use syntax::codemap::Span;
 
@@ -33,8 +33,8 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     //! Reports error if `loan_region` is larger than S
     //! where S is `item_scope` if `cmt` is an upvar,
     //! and is scope of `cmt` otherwise.
-    debug!("guarantee_lifetime(cmt={}, loan_region={})",
-           cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
+    debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
+           cmt, loan_region);
     let ctxt = GuaranteeLifetimeContext {bccx: bccx,
                                          item_scope: item_scope,
                                          span: span,
@@ -65,9 +65,9 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
         //! Main routine. Walks down `cmt` until we find the
         //! "guarantor".  Reports an error if `self.loan_region` is
         //! larger than scope of `cmt`.
-        debug!("guarantee_lifetime.check(cmt={}, loan_region={})",
-               cmt.repr(self.bccx.tcx),
-               self.loan_region.repr(self.bccx.tcx));
+        debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})",
+               cmt,
+               self.loan_region);
 
         match cmt.cat {
             mc::cat_rvalue(..) |
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 012e01507de..f00eb872642 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -22,7 +22,7 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::region;
 use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
+
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::visit;
@@ -76,8 +76,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
                _consume_span: Span,
                cmt: mc::cmt<'tcx>,
                mode: euv::ConsumeMode) {
-        debug!("consume(consume_id={}, cmt={}, mode={:?})",
-               consume_id, cmt.repr(self.tcx()), mode);
+        debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
+               consume_id, cmt, mode);
 
         match mode {
             euv::Move(move_reason) => {
@@ -93,9 +93,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
                    matched_pat: &ast::Pat,
                    cmt: mc::cmt<'tcx>,
                    mode: euv::MatchMode) {
-        debug!("matched_pat(matched_pat={}, cmt={}, mode={:?})",
-               matched_pat.repr(self.tcx()),
-               cmt.repr(self.tcx()),
+        debug!("matched_pat(matched_pat={:?}, cmt={:?}, mode={:?})",
+               matched_pat,
+               cmt,
                mode);
 
         if let mc::cat_downcast(..) = cmt.cat {
@@ -109,9 +109,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
                    consume_pat: &ast::Pat,
                    cmt: mc::cmt<'tcx>,
                    mode: euv::ConsumeMode) {
-        debug!("consume_pat(consume_pat={}, cmt={}, mode={:?})",
-               consume_pat.repr(self.tcx()),
-               cmt.repr(self.tcx()),
+        debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})",
+               consume_pat,
+               cmt,
                mode);
 
         match mode {
@@ -132,9 +132,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause)
     {
-        debug!("borrow(borrow_id={}, cmt={}, loan_region={:?}, \
+        debug!("borrow(borrow_id={}, cmt={:?}, loan_region={:?}, \
                bk={:?}, loan_cause={:?})",
-               borrow_id, cmt.repr(self.tcx()), loan_region,
+               borrow_id, cmt, loan_region,
                bk, loan_cause);
 
         self.guarantee_valid(borrow_id,
@@ -152,8 +152,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
               mode: euv::MutateMode)
     {
         let opt_lp = opt_loan_path(&assignee_cmt);
-        debug!("mutate(assignment_id={}, assignee_cmt={}) opt_lp={:?}",
-               assignment_id, assignee_cmt.repr(self.tcx()), opt_lp);
+        debug!("mutate(assignment_id={}, assignee_cmt={:?}) opt_lp={:?}",
+               assignment_id, assignee_cmt, opt_lp);
 
         match opt_lp {
             Some(lp) => {
@@ -234,10 +234,10 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                        req_kind: ty::BorrowKind,
                        loan_region: ty::Region,
                        cause: euv::LoanCause) {
-        debug!("guarantee_valid(borrow_id={}, cmt={}, \
+        debug!("guarantee_valid(borrow_id={}, cmt={:?}, \
                 req_mutbl={:?}, loan_region={:?})",
                borrow_id,
-               cmt.repr(self.tcx()),
+               cmt,
                req_kind,
                loan_region);
 
@@ -336,8 +336,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
             }
         };
 
-        debug!("guarantee_valid(borrow_id={}), loan={}",
-               borrow_id, loan.repr(self.tcx()));
+        debug!("guarantee_valid(borrow_id={}), loan={:?}",
+               borrow_id, loan);
 
         // let loan_path = loan.loan_path;
         // let loan_gen_scope = loan.gen_scope;
@@ -376,8 +376,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                                       req_kind: ty::BorrowKind)
                                       -> Result<(),()> {
             //! Implements the M-* rules in README.md.
-            debug!("check_mutability(cause={:?} cmt={} req_kind={:?}",
-                   cause, cmt.repr(bccx.tcx), req_kind);
+            debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}",
+                   cause, cmt, req_kind);
             match req_kind {
                 ty::UniqueImmBorrow | ty::ImmBorrow => {
                     match cmt.mutbl {
@@ -507,7 +507,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
 
 pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) {
 
-    debug!("gather_loans_in_static_initializer(expr={})", expr.repr(bccx.tcx));
+    debug!("gather_loans_in_static_initializer(expr={:?})", expr);
 
     let mut sicx = StaticInitializerCtxt {
         bccx: bccx
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index d16e0fdc19f..9a29ed91339 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -12,7 +12,6 @@ use borrowck::BorrowckCtxt;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
 use rustc::middle::ty;
-use rustc::util::ppaux::UserString;
 use std::cell::RefCell;
 use syntax::ast;
 use syntax::codemap;
@@ -130,7 +129,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                 bccx.span_err(move_from.span,
                               &format!("cannot move out of type `{}`, \
                                         a non-copy fixed-size array",
-                                       b.ty.user_string(bccx.tcx)));
+                                       b.ty));
             }
         }
 
@@ -143,7 +142,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                         move_from.span,
                         &format!("cannot move out of type `{}`, \
                                  which defines the `Drop` trait",
-                                b.ty.user_string(bccx.tcx)));
+                                b.ty));
                 },
                 _ => {
                     bccx.span_bug(move_from.span, "this path should not cause illegal move")
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index 56f49a3047b..345f5378f69 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -16,7 +16,6 @@ use borrowck::*;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
 use syntax::codemap::Span;
 
 use borrowck::ToInteriorKind;
@@ -58,7 +57,7 @@ struct RestrictionsContext<'a, 'tcx: 'a> {
 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
     fn restrict(&self,
                 cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> {
-        debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
+        debug!("restrict(cmt={:?})", cmt);
 
         let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
 
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index d7046171616..6369621779c 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -28,14 +28,15 @@ use rustc::middle::dataflow::BitwiseOperator;
 use rustc::middle::dataflow::DataFlowOperator;
 use rustc::middle::dataflow::KillFrom;
 use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::mem_categorization as mc;
 use rustc::middle::free_region::FreeRegionMap;
+use rustc::middle::infer::error_reporting::note_and_explain_region;
+use rustc::middle::mem_categorization as mc;
 use rustc::middle::region;
 use rustc::middle::ty::{self, Ty};
-use rustc::util::ppaux::{note_and_explain_region, Repr, UserString};
+
+use std::fmt;
 use std::mem;
 use std::rc::Rc;
-use std::string::String;
 use syntax::ast;
 use syntax::ast_util;
 use syntax::codemap::Span;
@@ -328,7 +329,7 @@ impl<'tcx> Loan<'tcx> {
     }
 }
 
-#[derive(Eq, Hash, Debug)]
+#[derive(Eq, Hash)]
 pub struct LoanPath<'tcx> {
     kind: LoanPathKind<'tcx>,
     ty: ty::Ty<'tcx>,
@@ -368,7 +369,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as ";
 // information that is not relevant to loan-path analysis. (In
 // particular, the distinction between how precisely a array-element
 // is tracked is irrelevant here.)
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum InteriorKind {
     InteriorField(mc::FieldName),
     InteriorElement(mc::ElementKind),
@@ -681,7 +682,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                   which is {}",
                                  ol,
                                  moved_lp_msg,
-                                 expr_ty.user_string(self.tcx),
+                                 expr_ty,
                                  suggestion));
                 } else {
                     self.tcx.sess.span_note(
@@ -689,7 +690,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                         &format!("`{}` moved here{} because it has type `{}`, which is {}",
                                  ol,
                                  moved_lp_msg,
-                                 expr_ty.user_string(self.tcx),
+                                 expr_ty,
                                  suggestion));
                 }
             }
@@ -702,7 +703,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                              which is moved by default",
                             ol,
                             moved_lp_msg,
-                            pat_ty.user_string(self.tcx)));
+                            pat_ty));
                 self.tcx.sess.fileline_help(span,
                     "use `ref` to override");
             }
@@ -733,7 +734,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                             has type `{}`, which is {}",
                             ol,
                             moved_lp_msg,
-                            expr_ty.user_string(self.tcx),
+                            expr_ty,
                             suggestion));
                 self.tcx.sess.fileline_help(expr_span, help);
             }
@@ -1001,20 +1002,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     "reference must be valid for ",
                     sub_scope,
                     "...");
-                let suggestion = if is_statement_scope(self.tcx, super_scope) {
-                    Some("consider using a `let` binding to increase its lifetime")
-                } else {
-                    None
-                };
-                let span = note_and_explain_region(
+                note_and_explain_region(
                     self.tcx,
                     "...but borrowed value is only valid for ",
                     super_scope,
                     "");
-                match (span, suggestion) {
-                    (_, None) => {},
-                    (Some(span), Some(msg)) => self.tcx.sess.span_help(span, msg),
-                    (None, Some(msg)) => self.tcx.sess.help(msg),
+                if let Some(span) = statement_scope_span(self.tcx, super_scope) {
+                    self.tcx.sess.span_help(span,
+                        "consider using a `let` binding to increase its lifetime");
                 }
             }
 
@@ -1127,16 +1122,16 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     }
 }
 
-fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool {
-     match region {
-         ty::ReScope(scope) => {
-             match tcx.map.find(scope.node_id()) {
-                 Some(ast_map::NodeStmt(_)) => true,
-                 _ => false
-             }
-         }
-         _ => false
-     }
+fn statement_scope_span(tcx: &ty::ctxt, region: ty::Region) -> Option<Span> {
+    match region {
+        ty::ReScope(scope) => {
+            match tcx.map.find(scope.node_id()) {
+                Some(ast_map::NodeStmt(stmt)) => Some(stmt.span),
+                _ => None
+            }
+        }
+        _ => None
+    }
 }
 
 impl BitwiseOperator for LoanDataFlowOperator {
@@ -1153,88 +1148,87 @@ impl DataFlowOperator for LoanDataFlowOperator {
     }
 }
 
-impl<'tcx> Repr<'tcx> for InteriorKind {
-    fn repr(&self, _tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for InteriorKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            InteriorField(mc::NamedField(fld)) =>
-                format!("{}", token::get_name(fld)),
-            InteriorField(mc::PositionalField(i)) => format!("#{}", i),
-            InteriorElement(..) => "[]".to_string(),
+            InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld),
+            InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i),
+            InteriorElement(..) => write!(f, "[]"),
         }
     }
 }
 
-impl<'tcx> Repr<'tcx> for Loan<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Loan_{}({}, {:?}, {:?}-{:?}, {})",
-                 self.index,
-                 self.loan_path.repr(tcx),
-                 self.kind,
-                 self.gen_scope,
-                 self.kill_scope,
-                 self.restricted_paths.repr(tcx))
+impl<'tcx> fmt::Debug for Loan<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Loan_{}({:?}, {:?}, {:?}-{:?}, {:?})",
+               self.index,
+               self.loan_path,
+               self.kind,
+               self.gen_scope,
+               self.kill_scope,
+               self.restricted_paths)
     }
 }
 
-impl<'tcx> Repr<'tcx> for LoanPath<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for LoanPath<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.kind {
             LpVar(id) => {
-                format!("$({})", tcx.map.node_to_string(id))
+                write!(f, "$({})", ty::tls::with(|tcx| tcx.map.node_to_string(id)))
             }
 
             LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => {
-                let s = tcx.map.node_to_string(var_id);
-                format!("$({} captured by id={})", s, closure_expr_id)
+                let s = ty::tls::with(|tcx| tcx.map.node_to_string(var_id));
+                write!(f, "$({} captured by id={})", s, closure_expr_id)
             }
 
             LpDowncast(ref lp, variant_def_id) => {
                 let variant_str = if variant_def_id.krate == ast::LOCAL_CRATE {
-                    ty::item_path_str(tcx, variant_def_id)
+                    ty::tls::with(|tcx| ty::item_path_str(tcx, variant_def_id))
                 } else {
-                    variant_def_id.repr(tcx)
+                    format!("{:?}", variant_def_id)
                 };
-                format!("({}{}{})", lp.repr(tcx), DOWNCAST_PRINTED_OPERATOR, variant_str)
+                write!(f, "({:?}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
             }
 
             LpExtend(ref lp, _, LpDeref(_)) => {
-                format!("{}.*", lp.repr(tcx))
+                write!(f, "{:?}.*", lp)
             }
 
             LpExtend(ref lp, _, LpInterior(ref interior)) => {
-                format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
+                write!(f, "{:?}.{:?}", lp, interior)
             }
         }
     }
 }
 
-impl<'tcx> UserString<'tcx> for LoanPath<'tcx> {
-    fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Display for LoanPath<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.kind {
             LpVar(id) => {
-                format!("$({})", tcx.map.node_to_user_string(id))
+                write!(f, "$({})", ty::tls::with(|tcx| tcx.map.node_to_user_string(id)))
             }
 
             LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => {
-                let s = tcx.map.node_to_user_string(var_id);
-                format!("$({} captured by closure)", s)
+                let s = ty::tls::with(|tcx| tcx.map.node_to_user_string(var_id));
+                write!(f, "$({} captured by closure)", s)
             }
 
             LpDowncast(ref lp, variant_def_id) => {
                 let variant_str = if variant_def_id.krate == ast::LOCAL_CRATE {
-                    ty::item_path_str(tcx, variant_def_id)
+                    ty::tls::with(|tcx| ty::item_path_str(tcx, variant_def_id))
                 } else {
-                    variant_def_id.repr(tcx)
+                    format!("{:?}", variant_def_id)
                 };
-                format!("({}{}{})", lp.user_string(tcx), DOWNCAST_PRINTED_OPERATOR, variant_str)
+                write!(f, "({}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
             }
 
             LpExtend(ref lp, _, LpDeref(_)) => {
-                format!("{}.*", lp.user_string(tcx))
+                write!(f, "{}.*", lp)
             }
 
             LpExtend(ref lp, _, LpInterior(ref interior)) => {
-                format!("{}.{}", lp.user_string(tcx), interior.repr(tcx))
+                write!(f, "{}.{:?}", lp, interior)
             }
         }
     }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 0f56aa9fb1f..b38915612c5 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -22,7 +22,7 @@ use rustc::middle::dataflow::KillFrom;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::ty;
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
-use rustc::util::ppaux::Repr;
+
 use std::cell::RefCell;
 use std::rc::Rc;
 use std::usize;
@@ -313,8 +313,8 @@ impl<'tcx> MoveData<'tcx> {
             }
         };
 
-        debug!("move_path(lp={}, index={:?})",
-               lp.repr(tcx),
+        debug!("move_path(lp={:?}, index={:?})",
+               lp,
                index);
 
         assert_eq!(index.get(), self.paths.borrow().len() - 1);
@@ -364,8 +364,8 @@ impl<'tcx> MoveData<'tcx> {
                     lp: Rc<LoanPath<'tcx>>,
                     id: ast::NodeId,
                     kind: MoveKind) {
-        debug!("add_move(lp={}, id={}, kind={:?})",
-               lp.repr(tcx),
+        debug!("add_move(lp={:?}, id={}, kind={:?})",
+               lp,
                id,
                kind);
 
@@ -394,8 +394,8 @@ impl<'tcx> MoveData<'tcx> {
                           span: Span,
                           assignee_id: ast::NodeId,
                           mode: euv::MutateMode) {
-        debug!("add_assignment(lp={}, assign_id={}, assignee_id={}",
-               lp.repr(tcx), assign_id, assignee_id);
+        debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
+               lp, assign_id, assignee_id);
 
         let path_index = self.move_path(tcx, lp.clone());
 
@@ -415,13 +415,13 @@ impl<'tcx> MoveData<'tcx> {
         };
 
         if self.is_var_path(path_index) {
-            debug!("add_assignment[var](lp={}, assignment={}, path_index={:?})",
-                   lp.repr(tcx), self.var_assignments.borrow().len(), path_index);
+            debug!("add_assignment[var](lp={:?}, assignment={}, path_index={:?})",
+                   lp, self.var_assignments.borrow().len(), path_index);
 
             self.var_assignments.borrow_mut().push(assignment);
         } else {
-            debug!("add_assignment[path](lp={}, path_index={:?})",
-                   lp.repr(tcx), path_index);
+            debug!("add_assignment[path](lp={:?}, path_index={:?})",
+                   lp, path_index);
 
             self.path_assignments.borrow_mut().push(assignment);
         }
@@ -437,8 +437,8 @@ impl<'tcx> MoveData<'tcx> {
                              pattern_id: ast::NodeId,
                              base_lp: Rc<LoanPath<'tcx>>,
                              mode: euv::MatchMode) {
-        debug!("add_variant_match(lp={}, pattern_id={})",
-               lp.repr(tcx), pattern_id);
+        debug!("add_variant_match(lp={:?}, pattern_id={})",
+               lp, pattern_id);
 
         let path_index = self.move_path(tcx, lp.clone());
         let base_path_index = self.move_path(tcx, base_lp.clone());
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index eaac1eb6f2c..a834ed4cb5f 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -65,7 +65,7 @@ pub fn compile_input(sess: Session,
     // We need nested scopes here, because the intermediate results can keep
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
-    let (outputs, trans, sess) = {
+    let (sess, result) = {
         let (outputs, expanded_crate, id) = {
             let krate = phase_1_parse_input(&sess, cfg, input);
 
@@ -119,37 +119,52 @@ pub fn compile_input(sess: Session,
                                                                      &ast_map.krate(),
                                                                      &id[..]));
 
-        let analysis = phase_3_run_analysis_passes(sess,
-                                                   ast_map,
-                                                   &arenas,
-                                                   id,
-                                                   control.make_glob_map);
-
-        controller_entry_point!(after_analysis,
-                                analysis.ty_cx.sess,
-                                CompileState::state_after_analysis(input,
-                                                                   &analysis.ty_cx.sess,
-                                                                   outdir,
-                                                                   analysis.ty_cx.map.krate(),
-                                                                   &analysis,
-                                                                   &analysis.ty_cx));
-
-        if log_enabled!(::log::INFO) {
-            println!("Pre-trans");
-            analysis.ty_cx.print_debug_stats();
-        }
-        let (tcx, trans) = phase_4_translate_to_llvm(analysis);
+        phase_3_run_analysis_passes(sess,
+                                    ast_map,
+                                    &arenas,
+                                    id,
+                                    control.make_glob_map,
+                                    |tcx, analysis| {
+
+            {
+                let state = CompileState::state_after_analysis(input,
+                                                               &tcx.sess,
+                                                               outdir,
+                                                               tcx.map.krate(),
+                                                               &analysis,
+                                                               tcx);
+                (control.after_analysis.callback)(state);
+
+                tcx.sess.abort_if_errors();
+                if control.after_analysis.stop == Compilation::Stop {
+                    return Err(());
+                }
+            }
 
-        if log_enabled!(::log::INFO) {
-            println!("Post-trans");
-            tcx.print_debug_stats();
-        }
+            if log_enabled!(::log::INFO) {
+                println!("Pre-trans");
+                tcx.print_debug_stats();
+            }
+            let trans = phase_4_translate_to_llvm(tcx, analysis);
+
+            if log_enabled!(::log::INFO) {
+                println!("Post-trans");
+                tcx.print_debug_stats();
+            }
+
+            // Discard interned strings as they are no longer required.
+            token::get_ident_interner().clear();
 
-        // Discard interned strings as they are no longer required.
-        token::get_ident_interner().clear();
+            Ok((outputs, trans))
+        })
+    };
 
-        (outputs, trans, tcx.sess)
+    let (outputs, trans) = if let Ok(out) = result {
+        out
+    } else {
+        return;
     };
+
     phase_5_run_llvm_passes(&sess, &trans, &outputs);
 
     controller_entry_point!(after_llvm,
@@ -240,7 +255,7 @@ pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> {
     pub out_dir: Option<&'a Path>,
     pub expanded_crate: Option<&'a ast::Crate>,
     pub ast_map: Option<&'a ast_map::Map<'ast>>,
-    pub analysis: Option<&'a ty::CrateAnalysis<'tcx>>,
+    pub analysis: Option<&'a ty::CrateAnalysis>,
     pub tcx: Option<&'a ty::ctxt<'tcx>>,
     pub trans: Option<&'a trans::CrateTranslation>,
 }
@@ -309,7 +324,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> {
                             session: &'a Session,
                             out_dir: &'a Option<PathBuf>,
                             expanded_crate: &'a ast::Crate,
-                            analysis: &'a ty::CrateAnalysis<'tcx>,
+                            analysis: &'a ty::CrateAnalysis,
                             tcx: &'a ty::ctxt<'tcx>)
                             -> CompileState<'a, 'ast, 'tcx> {
         CompileState {
@@ -578,12 +593,16 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session,
 /// Run the resolution, typechecking, region checking and other
 /// miscellaneous analysis passes on the crate. Return various
 /// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
-                                         ast_map: ast_map::Map<'tcx>,
-                                         arenas: &'tcx ty::CtxtArenas<'tcx>,
-                                         name: String,
-                                         make_glob_map: resolve::MakeGlobMap)
-                                         -> ty::CrateAnalysis<'tcx> {
+pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
+                                               ast_map: ast_map::Map<'tcx>,
+                                               arenas: &'tcx ty::CtxtArenas<'tcx>,
+                                               name: String,
+                                               make_glob_map: resolve::MakeGlobMap,
+                                               f: F)
+                                               -> (Session, R)
+                                               where F: FnOnce(&ty::ctxt<'tcx>,
+                                                               ty::CrateAnalysis) -> R
+{
     let time_passes = sess.time_passes();
     let krate = ast_map.krate();
 
@@ -602,11 +621,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
         glob_map,
     } =
         time(time_passes, "resolution", (),
-             |_| resolve::resolve_crate(&sess,
-                                        &ast_map,
-                                        &lang_items,
-                                        krate,
-                                        make_glob_map));
+             |_| resolve::resolve_crate(&sess, &ast_map, make_glob_map));
 
     // Discard MTWT tables that aren't required past resolution.
     syntax::ext::mtwt::clear_tables();
@@ -631,102 +646,103 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
     time(time_passes, "static item recursion checking", (), |_|
          middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
 
-    let ty_cx = ty::mk_ctxt(sess,
-                            arenas,
-                            def_map,
-                            named_region_map,
-                            ast_map,
-                            freevars,
-                            region_map,
-                            lang_items,
-                            stability::Index::new(krate));
-
-    // passes are timed inside typeck
-    typeck::check_crate(&ty_cx, trait_map);
-
-    time(time_passes, "const checking", (), |_|
-         middle::check_const::check_crate(&ty_cx));
-
-    let (exported_items, public_items) =
-            time(time_passes, "privacy checking", (), |_|
-                 rustc_privacy::check_crate(&ty_cx, &export_map, external_exports));
-
-    // Do not move this check past lint
-    time(time_passes, "stability index", (), |_|
-         ty_cx.stability.borrow_mut().build(&ty_cx, krate, &public_items));
-
-    time(time_passes, "intrinsic checking", (), |_|
-         middle::intrinsicck::check_crate(&ty_cx));
-
-    time(time_passes, "effect checking", (), |_|
-         middle::effect::check_crate(&ty_cx));
-
-    time(time_passes, "match checking", (), |_|
-         middle::check_match::check_crate(&ty_cx));
-
-    time(time_passes, "liveness checking", (), |_|
-         middle::liveness::check_crate(&ty_cx));
-
-    time(time_passes, "borrow checking", (), |_|
-         borrowck::check_crate(&ty_cx));
-
-    time(time_passes, "rvalue checking", (), |_|
-         middle::check_rvalues::check_crate(&ty_cx, krate));
-
-    // Avoid overwhelming user with errors if type checking failed.
-    // I'm not sure how helpful this is, to be honest, but it avoids a
-    // lot of annoying errors in the compile-fail tests (basically,
-    // lint warnings and so on -- kindck used to do this abort, but
-    // kindck is gone now). -nmatsakis
-    ty_cx.sess.abort_if_errors();
-
-    let reachable_map =
-        time(time_passes, "reachability checking", (), |_|
-             reachable::find_reachable(&ty_cx, &exported_items));
-
-    time(time_passes, "death checking", (), |_| {
-        middle::dead::check_crate(&ty_cx,
-                                  &exported_items,
-                                  &reachable_map)
-    });
-
-    let ref lib_features_used =
-        time(time_passes, "stability checking", (), |_|
-             stability::check_unstable_api_usage(&ty_cx));
-
-    time(time_passes, "unused lib feature checking", (), |_|
-         stability::check_unused_or_stable_features(
-             &ty_cx.sess, lib_features_used));
-
-    time(time_passes, "lint checking", (), |_|
-         lint::check_crate(&ty_cx, &exported_items));
-
-    // The above three passes generate errors w/o aborting
-    ty_cx.sess.abort_if_errors();
-
-    ty::CrateAnalysis {
-        export_map: export_map,
-        ty_cx: ty_cx,
-        exported_items: exported_items,
-        public_items: public_items,
-        reachable: reachable_map,
-        name: name,
-        glob_map: glob_map,
-    }
+    ty::with_ctxt(sess,
+                  arenas,
+                  def_map,
+                  named_region_map,
+                  ast_map,
+                  freevars,
+                  region_map,
+                  lang_items,
+                  stability::Index::new(krate),
+                  |tcx| {
+
+        // passes are timed inside typeck
+        typeck::check_crate(tcx, trait_map);
+
+        time(time_passes, "const checking", (), |_|
+            middle::check_const::check_crate(tcx));
+
+        let (exported_items, public_items) =
+                time(time_passes, "privacy checking", (), |_|
+                    rustc_privacy::check_crate(tcx, &export_map, external_exports));
+
+        // Do not move this check past lint
+        time(time_passes, "stability index", (), |_|
+            tcx.stability.borrow_mut().build(tcx, krate, &public_items));
+
+        time(time_passes, "intrinsic checking", (), |_|
+            middle::intrinsicck::check_crate(tcx));
+
+        time(time_passes, "effect checking", (), |_|
+            middle::effect::check_crate(tcx));
+
+        time(time_passes, "match checking", (), |_|
+            middle::check_match::check_crate(tcx));
+
+        time(time_passes, "liveness checking", (), |_|
+            middle::liveness::check_crate(tcx));
+
+        time(time_passes, "borrow checking", (), |_|
+            borrowck::check_crate(tcx));
+
+        time(time_passes, "rvalue checking", (), |_|
+            middle::check_rvalues::check_crate(tcx, krate));
+
+        // Avoid overwhelming user with errors if type checking failed.
+        // I'm not sure how helpful this is, to be honest, but it avoids a
+        // lot of annoying errors in the compile-fail tests (basically,
+        // lint warnings and so on -- kindck used to do this abort, but
+        // kindck is gone now). -nmatsakis
+        tcx.sess.abort_if_errors();
+
+        let reachable_map =
+            time(time_passes, "reachability checking", (), |_|
+                reachable::find_reachable(tcx, &exported_items));
+
+        time(time_passes, "death checking", (), |_| {
+            middle::dead::check_crate(tcx,
+                                      &exported_items,
+                                      &reachable_map)
+        });
+
+        let ref lib_features_used =
+            time(time_passes, "stability checking", (), |_|
+                stability::check_unstable_api_usage(tcx));
+
+        time(time_passes, "unused lib feature checking", (), |_|
+            stability::check_unused_or_stable_features(
+                &tcx.sess, lib_features_used));
+
+        time(time_passes, "lint checking", (), |_|
+            lint::check_crate(tcx, &exported_items));
+
+        // The above three passes generate errors w/o aborting
+        tcx.sess.abort_if_errors();
+
+        f(tcx, ty::CrateAnalysis {
+            export_map: export_map,
+            exported_items: exported_items,
+            public_items: public_items,
+            reachable: reachable_map,
+            name: name,
+            glob_map: glob_map,
+        })
+    })
 }
 
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
-pub fn phase_4_translate_to_llvm<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
-                                       -> (ty::ctxt<'tcx>, trans::CrateTranslation) {
-    let time_passes = analysis.ty_cx.sess.time_passes();
+pub fn phase_4_translate_to_llvm(tcx: &ty::ctxt, analysis: ty::CrateAnalysis)
+                                 -> trans::CrateTranslation {
+    let time_passes = tcx.sess.time_passes();
 
     time(time_passes, "resolving dependency formats", (), |_|
-         dependency_format::calculate(&analysis.ty_cx));
+         dependency_format::calculate(tcx));
 
     // Option dance to work around the lack of stack once closures.
     time(time_passes, "translation", analysis, |analysis|
-         trans::trans_crate(analysis))
+         trans::trans_crate(tcx, analysis))
 }
 
 /// Run LLVM itself, producing a bitcode file, assembly file or object file
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index fe3ffe97981..96d1ab23ad5 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -377,12 +377,10 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
         if sess.opts.debugging_opts.save_analysis {
             control.after_analysis.callback = box |state| {
                 time(state.session.time_passes(),
-                     "save analysis",
-                     state.expanded_crate.unwrap(),
-                     |krate| save::process_crate(state.session,
-                                                 krate,
-                                                 state.analysis.unwrap(),
-                                                 state.out_dir));
+                     "save analysis", (),
+                     |_| save::process_crate(state.tcx.unwrap(),
+                                             state.analysis.unwrap(),
+                                             state.out_dir));
             };
             control.make_glob_map = resolve::MakeGlobMap::Yes;
         }
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index c98052825e1..a40cb94204d 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -25,7 +25,6 @@ use rustc::middle::cfg;
 use rustc::middle::cfg::graphviz::LabelledCFG;
 use rustc::session::Session;
 use rustc::session::config::Input;
-use rustc::util::ppaux;
 use rustc_borrowck as borrowck;
 use rustc_borrowck::graphviz as borrowck_dot;
 use rustc_resolve as resolve;
@@ -148,13 +147,15 @@ impl PpSourceMode {
             }
             PpmTyped => {
                 let ast_map = ast_map.expect("--pretty=typed missing ast_map");
-                let analysis = driver::phase_3_run_analysis_passes(sess,
-                                                                   ast_map,
-                                                                   arenas,
-                                                                   id,
-                                                                   resolve::MakeGlobMap::No);
-                let annotation = TypedAnnotation { analysis: analysis };
-                f(&annotation, payload)
+                driver::phase_3_run_analysis_passes(sess,
+                                                    ast_map,
+                                                    arenas,
+                                                    id,
+                                                    resolve::MakeGlobMap::No,
+                                                    |tcx, _| {
+                    let annotation = TypedAnnotation { tcx: tcx };
+                    f(&annotation, payload)
+                }).1
             }
         }
     }
@@ -284,21 +285,21 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
 }
 
 
-struct TypedAnnotation<'tcx> {
-    analysis: ty::CrateAnalysis<'tcx>,
+struct TypedAnnotation<'a, 'tcx: 'a> {
+    tcx: &'a ty::ctxt<'tcx>,
 }
 
-impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> {
-    fn sess<'a>(&'a self) -> &'a Session { &self.analysis.ty_cx.sess }
+impl<'b, 'tcx> PrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
+    fn sess<'a>(&'a self) -> &'a Session { &self.tcx.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'tcx>> {
-        Some(&self.analysis.ty_cx.map)
+        Some(&self.tcx.map)
     }
 
     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
 }
 
-impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> {
+impl<'a, 'tcx> pprust::PpAnn for TypedAnnotation<'a, 'tcx> {
     fn pre(&self,
            s: &mut pprust::State,
            node: pprust::AnnNode) -> io::Result<()> {
@@ -310,16 +311,13 @@ impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> {
     fn post(&self,
             s: &mut pprust::State,
             node: pprust::AnnNode) -> io::Result<()> {
-        let tcx = &self.analysis.ty_cx;
         match node {
             pprust::NodeExpr(expr) => {
                 try!(pp::space(&mut s.s));
                 try!(pp::word(&mut s.s, "as"));
                 try!(pp::space(&mut s.s));
                 try!(pp::word(&mut s.s,
-                              &ppaux::ty_to_string(
-                                  tcx,
-                                  ty::expr_ty(tcx, expr))));
+                              &ty::expr_ty(self.tcx, expr).to_string()));
                 s.pclose()
             }
             _ => Ok(())
@@ -646,12 +644,14 @@ pub fn pretty_print_input(sess: Session,
             match code {
                 Some(code) => {
                     let variants = gather_flowgraph_variants(&sess);
-                    let analysis = driver::phase_3_run_analysis_passes(sess,
-                                                                       ast_map,
-                                                                       &arenas,
-                                                                       id,
-                                                                       resolve::MakeGlobMap::No);
-                    print_flowgraph(variants, analysis, code, mode, out)
+                    driver::phase_3_run_analysis_passes(sess,
+                                                        ast_map,
+                                                        &arenas,
+                                                        id,
+                                                        resolve::MakeGlobMap::No,
+                                                        |tcx, _| {
+                        print_flowgraph(variants, tcx, code, mode, out)
+                    }).1
                 }
                 None => {
                     let message = format!("--pretty=flowgraph needs \
@@ -682,18 +682,17 @@ pub fn pretty_print_input(sess: Session,
 }
 
 fn print_flowgraph<W: Write>(variants: Vec<borrowck_dot::Variant>,
-                             analysis: ty::CrateAnalysis,
+                             tcx: &ty::ctxt,
                              code: blocks::Code,
                              mode: PpFlowGraphMode,
                              mut out: W) -> io::Result<()> {
-    let ty_cx = &analysis.ty_cx;
     let cfg = match code {
-        blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block),
-        blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()),
+        blocks::BlockCode(block) => cfg::CFG::new(tcx, &*block),
+        blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &*fn_like.body()),
     };
     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
     let lcfg = LabelledCFG {
-        ast_map: &ty_cx.map,
+        ast_map: &tcx.map,
         cfg: &cfg,
         name: format!("node_{}", code.id()),
         labelled_edges: labelled_edges,
@@ -705,14 +704,14 @@ fn print_flowgraph<W: Write>(variants: Vec<borrowck_dot::Variant>,
             return expand_err_details(r);
         }
         blocks::BlockCode(_) => {
-            ty_cx.sess.err("--pretty flowgraph with -Z flowgraph-print \
-                            annotations requires fn-like node id.");
+            tcx.sess.err("--pretty flowgraph with -Z flowgraph-print \
+                          annotations requires fn-like node id.");
             return Ok(())
         }
         blocks::FnLikeCode(fn_like) => {
             let fn_parts = borrowck::FnPartsWithCFG::from_fn_like(&fn_like, &cfg);
             let (bccx, analysis_data) =
-                borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts);
+                borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_parts);
 
             let lcfg = borrowck_dot::DataflowLabeller {
                 inner: lcfg,
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 4091351b5a5..5183fa01a8a 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -28,7 +28,6 @@ use rustc_typeck::middle::infer;
 use rustc_typeck::middle::infer::lub::Lub;
 use rustc_typeck::middle::infer::glb::Glb;
 use rustc_typeck::middle::infer::sub::Sub;
-use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString};
 use rustc::ast_map;
 use rustc::session::{self,config};
 use syntax::{abi, ast};
@@ -126,23 +125,25 @@ fn test_env<F>(source_string: &str,
     // run just enough stuff to build a tcx:
     let lang_items = lang_items::collect_language_items(krate, &sess);
     let resolve::CrateMap { def_map, freevars, .. } =
-        resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
+        resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No);
     let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
     let region_map = region::resolve_crate(&sess, krate);
-    let tcx = ty::mk_ctxt(sess,
-                          &arenas,
-                          def_map,
-                          named_region_map,
-                          ast_map,
-                          freevars,
-                          region_map,
-                          lang_items,
-                          stability::Index::new(krate));
-    let infcx = infer::new_infer_ctxt(&tcx);
-    body(Env { infcx: &infcx });
-    let free_regions = FreeRegionMap::new();
-    infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
-    assert_eq!(tcx.sess.err_count(), expected_err_count);
+    ty::with_ctxt(sess,
+                  &arenas,
+                  def_map,
+                  named_region_map,
+                  ast_map,
+                  freevars,
+                  region_map,
+                  lang_items,
+                  stability::Index::new(krate),
+                  |tcx| {
+        let infcx = infer::new_infer_ctxt(tcx);
+        body(Env { infcx: &infcx });
+        let free_regions = FreeRegionMap::new();
+        infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
+        assert_eq!(tcx.sess.err_count(), expected_err_count);
+    });
 }
 
 impl<'a, 'tcx> Env<'a, 'tcx> {
@@ -186,7 +187,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
                       -> Option<ast::NodeId> {
             assert!(idx < names.len());
             for item in &m.items {
-                if item.ident.user_string(this.infcx.tcx) == names[idx] {
+                if item.ident.to_string() == names[idx] {
                     return search(this, &**item, idx+1, names);
                 }
             }
@@ -225,8 +226,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
     pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
         match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
             Ok(_) => true,
-            Err(ref e) => panic!("Encountered error: {}",
-                                ty::type_err_to_str(self.infcx.tcx, e))
+            Err(ref e) => panic!("Encountered error: {}", e)
         }
     }
 
@@ -239,9 +239,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
 
     pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
         if !self.is_subtype(a, b) {
-            panic!("{} is not a subtype of {}, but it should be",
-                  self.ty_to_string(a),
-                  self.ty_to_string(b));
+            panic!("{} is not a subtype of {}, but it should be", a, b);
         }
     }
 
@@ -250,10 +248,6 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
         self.assert_subtype(b, a);
     }
 
-    pub fn ty_to_string(&self, a: Ty<'tcx>) -> String {
-        ty_to_string(self.infcx.tcx, a)
-    }
-
     pub fn t_fn(&self,
                 input_tys: &[Ty<'tcx>],
                 output_ty: Ty<'tcx>)
@@ -374,8 +368,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
     pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
         match self.lub().relate(&t1, &t2) {
             Ok(t) => t,
-            Err(ref e) => panic!("unexpected error computing LUB: {}",
-                                ty::type_err_to_str(self.infcx.tcx, e))
+            Err(ref e) => panic!("unexpected error computing LUB: {}", e)
         }
     }
 
@@ -385,10 +378,10 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
         match self.sub().relate(&t1, &t2) {
             Ok(_) => { }
             Err(ref e) => {
-                panic!("unexpected error computing sub({},{}): {}",
-                       t1.repr(self.infcx.tcx),
-                       t2.repr(self.infcx.tcx),
-                       ty::type_err_to_str(self.infcx.tcx, e));
+                panic!("unexpected error computing sub({:?},{:?}): {}",
+                       t1,
+                       t2,
+                       e);
             }
         }
     }
@@ -399,9 +392,9 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
         match self.sub().relate(&t1, &t2) {
             Err(_) => { }
             Ok(_) => {
-                panic!("unexpected success computing sub({},{})",
-                       t1.repr(self.infcx.tcx),
-                       t2.repr(self.infcx.tcx));
+                panic!("unexpected success computing sub({:?},{:?})",
+                       t1,
+                       t2);
             }
         }
     }
@@ -413,18 +406,14 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
                 self.assert_eq(t, t_lub);
             }
             Err(ref e) => {
-                panic!("unexpected error in LUB: {}",
-                      ty::type_err_to_str(self.infcx.tcx, e))
+                panic!("unexpected error in LUB: {}", e)
             }
         }
     }
 
     /// Checks that `GLB(t1,t2) == t_glb`
     pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
-        debug!("check_glb(t1={}, t2={}, t_glb={})",
-               self.ty_to_string(t1),
-               self.ty_to_string(t2),
-               self.ty_to_string(t_glb));
+        debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb);
         match self.glb().relate(&t1, &t2) {
             Err(e) => {
                 panic!("unexpected error computing LUB: {:?}", e)
@@ -657,7 +646,7 @@ fn glb_bound_free_infer() {
         let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
         match t_resolve1.sty {
             ty::TyRef(..) => { }
-            _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); }
+            _ => { panic!("t_resolve1={:?}", t_resolve1); }
         }
     })
 }
@@ -699,11 +688,11 @@ fn subst_ty_renumber_bound() {
             env.t_fn(&[t_ptr_bound2], env.t_nil())
         };
 
-        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
-               t_source.repr(env.infcx.tcx),
-               substs.repr(env.infcx.tcx),
-               t_substituted.repr(env.infcx.tcx),
-               t_expected.repr(env.infcx.tcx));
+        debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
+               t_source,
+               substs,
+               t_substituted,
+               t_expected);
 
         assert_eq!(t_substituted, t_expected);
     })
@@ -736,11 +725,11 @@ fn subst_ty_renumber_some_bounds() {
             env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
         };
 
-        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
-               t_source.repr(env.infcx.tcx),
-               substs.repr(env.infcx.tcx),
-               t_substituted.repr(env.infcx.tcx),
-               t_expected.repr(env.infcx.tcx));
+        debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
+               t_source,
+               substs,
+               t_substituted,
+               t_expected);
 
         assert_eq!(t_substituted, t_expected);
     })
@@ -797,11 +786,11 @@ fn subst_region_renumber_region() {
             env.t_fn(&[t_rptr_bound2], env.t_nil())
         };
 
-        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
-               t_source.repr(env.infcx.tcx),
-               substs.repr(env.infcx.tcx),
-               t_substituted.repr(env.infcx.tcx),
-               t_expected.repr(env.infcx.tcx));
+        debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
+               t_source,
+               substs,
+               t_substituted,
+               t_expected);
 
         assert_eq!(t_substituted, t_expected);
     })
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index cc192407160..47713859dd8 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -36,7 +36,6 @@ use middle::{def, pat_util, stability};
 use middle::const_eval::{eval_const_expr_partial, const_int, const_uint};
 use middle::cfg;
 use rustc::ast_map;
-use util::ppaux::ty_to_string;
 use util::nodemap::{FnvHashMap, NodeSet};
 use lint::{Level, Context, LintPass, LintArray, Lint};
 
@@ -495,8 +494,7 @@ impl BoxPointers {
         });
 
         if n_uniq > 0 {
-            let s = ty_to_string(cx.tcx, ty);
-            let m = format!("type uses owned (Box type) pointers: {}", s);
+            let m = format!("type uses owned (Box type) pointers: {}", ty);
             cx.span_lint(BOX_POINTERS, span, &m[..]);
         }
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 787f914718d..5d10b0d9a57 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -55,7 +55,6 @@ use rustc::lint;
 use rustc::metadata::csearch;
 use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
 use rustc::middle::def::*;
-use rustc::middle::lang_items::LanguageItems;
 use rustc::middle::pat_util::pat_bindings;
 use rustc::middle::privacy::*;
 use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
@@ -3689,10 +3688,9 @@ pub enum MakeGlobMap {
 /// Entry point to crate resolution.
 pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
                                ast_map: &'a ast_map::Map<'tcx>,
-                               _: &LanguageItems,
-                               krate: &Crate,
                                make_glob_map: MakeGlobMap)
                                -> CrateMap {
+    let krate = ast_map.krate();
     let mut resolver = Resolver::new(session, ast_map, krate.span, make_glob_map);
 
     build_reduced_graph::build_reduced_graph(&mut resolver, krate);
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index e2c816bb84d..f6f9afa0221 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -25,7 +25,6 @@ use middle::ty::{self, Ty};
 use rustc::ast_map::{PathElem, PathElems, PathName};
 use trans::{CrateContext, CrateTranslation, gensym_name};
 use util::common::time;
-use util::ppaux;
 use util::sha2::{Digest, Sha256};
 use util::fs::fix_windows_verbatim_for_gcc;
 use rustc_back::tempdir::TempDir;
@@ -347,8 +346,7 @@ pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: PathEl
 pub fn mangle_internal_name_by_type_and_seq<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                       t: Ty<'tcx>,
                                                       name: &str) -> String {
-    let s = ppaux::ty_to_string(ccx.tcx(), t);
-    let path = [PathName(token::intern(&s[..])),
+    let path = [PathName(token::intern(&t.to_string())),
                 gensym_name(name)];
     let hash = get_symbol_hash(ccx, t);
     mangle(path.iter().cloned(), Some(&hash[..]))
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index cbc40af4b52..65d9d9809c9 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -52,8 +52,6 @@ use syntax::ptr::P;
 use super::span_utils::SpanUtils;
 use super::recorder::{Recorder, FmtStrs};
 
-use util::ppaux;
-
 macro_rules! down_cast_data {
     ($id:ident, $kind:ident, $this:ident, $sp:expr) => {
         let $id = if let super::Data::$kind(data) = $id {
@@ -67,7 +65,8 @@ macro_rules! down_cast_data {
 pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
     save_ctxt: SaveContext<'l, 'tcx>,
     sess: &'l Session,
-    analysis: &'l ty::CrateAnalysis<'tcx>,
+    tcx: &'l ty::ctxt<'tcx>,
+    analysis: &'l ty::CrateAnalysis,
 
     span: SpanUtils<'l>,
     fmt: FmtStrs<'l>,
@@ -76,28 +75,23 @@ pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
 }
 
 impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
-    pub fn new(sess: &'l Session,
-               analysis: &'l ty::CrateAnalysis<'tcx>,
+    pub fn new(tcx: &'l ty::ctxt<'tcx>,
+               analysis: &'l ty::CrateAnalysis,
                output_file: Box<File>) -> DumpCsvVisitor<'l, 'tcx> {
+        let span_utils = SpanUtils {
+            sess: &tcx.sess,
+            err_count: Cell::new(0)
+        };
         DumpCsvVisitor {
-            sess: sess,
-            save_ctxt: SaveContext::new(sess, analysis, SpanUtils {
-                sess: sess,
-                err_count: Cell::new(0)
-            }),
+            sess: &tcx.sess,
+            tcx: tcx,
+            save_ctxt: SaveContext::new(tcx, span_utils.clone()),
             analysis: analysis,
-            span: SpanUtils {
-                sess: sess,
-                err_count: Cell::new(0)
-            },
+            span: span_utils.clone(),
             fmt: FmtStrs::new(box Recorder {
                                 out: output_file,
                                 dump_spans: false,
-                            },
-                            SpanUtils {
-                                sess: sess,
-                                err_count: Cell::new(0)
-                            }),
+                              }, span_utils),
             cur_scope: 0
         }
     }
@@ -237,11 +231,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
 
     // looks up anything, not just a type
     fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
-        if !self.analysis.ty_cx.def_map.borrow().contains_key(&ref_id) {
+        if !self.tcx.def_map.borrow().contains_key(&ref_id) {
             self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
                                   ref_id));
         }
-        let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def();
+        let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
         match def {
             def::DefPrimTy(_) => None,
             _ => Some(def.def_id()),
@@ -249,7 +243,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
     }
 
     fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
-        let def_map = self.analysis.ty_cx.def_map.borrow();
+        let def_map = self.tcx.def_map.borrow();
         if !def_map.contains_key(&ref_id) {
             self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind",
                                              ref_id));
@@ -291,10 +285,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             collector.visit_pat(&arg.pat);
             let span_utils = self.span.clone();
             for &(id, ref p, _, _) in &collector.collected_paths {
-                let typ =
-                    ppaux::ty_to_string(
-                        &self.analysis.ty_cx,
-                        *self.analysis.ty_cx.node_types().get(&id).unwrap());
+                let typ = self.tcx.node_types().get(&id).unwrap().to_string();
                 // get the span only for the name of the variable (I hope the path is only ever a
                 // variable name, but who knows?)
                 self.fmt.formal_str(p.span,
@@ -320,9 +311,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
         let mut scope_id;
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in, followed by the method's name.
-        let qualname = match ty::impl_of_method(&self.analysis.ty_cx,
-                                                ast_util::local_def(id)) {
-            Some(impl_id) => match self.analysis.ty_cx.map.get(impl_id.node) {
+        let qualname = match ty::impl_of_method(self.tcx, ast_util::local_def(id)) {
+            Some(impl_id) => match self.tcx.map.get(impl_id.node) {
                 NodeItem(item) => {
                     scope_id = item.id;
                     match item.node {
@@ -330,12 +320,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                             let mut result = String::from("<");
                             result.push_str(&ty_to_string(&**ty));
 
-                            match ty::trait_of_item(&self.analysis.ty_cx,
-                                                    ast_util::local_def(id)) {
+                            match ty::trait_of_item(self.tcx, ast_util::local_def(id)) {
                                 Some(def_id) => {
                                     result.push_str(" as ");
                                     result.push_str(
-                                        &ty::item_path_str(&self.analysis.ty_cx, def_id));
+                                        &ty::item_path_str(self.tcx, def_id));
                                 },
                                 None => {}
                             }
@@ -352,16 +341,15 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                 _ => {
                     self.sess.span_bug(span,
                         &format!("Container {} for method {} is not a node item {:?}",
-                                 impl_id.node, id, self.analysis.ty_cx.map.get(impl_id.node)));
+                                 impl_id.node, id, self.tcx.map.get(impl_id.node)));
                 },
             },
-            None => match ty::trait_of_item(&self.analysis.ty_cx,
-                                            ast_util::local_def(id)) {
+            None => match ty::trait_of_item(self.tcx, ast_util::local_def(id)) {
                 Some(def_id) => {
                     scope_id = def_id.node;
-                    match self.analysis.ty_cx.map.get(def_id.node) {
+                    match self.tcx.map.get(def_id.node) {
                         NodeItem(_) => {
-                            format!("::{}", ty::item_path_str(&self.analysis.ty_cx, def_id))
+                            format!("::{}", ty::item_path_str(self.tcx, def_id))
                         }
                         _ => {
                             self.sess.span_bug(span,
@@ -380,8 +368,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
         let qualname = &format!("{}::{}", qualname, &token::get_name(name));
 
         // record the decl for this def (if it has one)
-        let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
-                                             ast_util::local_def(id))
+        let decl_id = ty::trait_item_of_item(self.tcx, ast_util::local_def(id))
             .and_then(|new_id| {
                 let def_id = new_id.def_id();
                 if def_id.node != 0 && def_id != ast_util::local_def(id) {
@@ -538,7 +525,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                      typ: &ast::Ty,
                      expr: &ast::Expr)
     {
-        let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(id));
+        let qualname = format!("::{}", self.tcx.map.path_to_string(id));
 
         let sub_span = self.span.sub_span_after_keyword(span,
                                                         keywords::Const);
@@ -561,7 +548,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                       item: &ast::Item,
                       def: &ast::StructDef,
                       ty_params: &ast::Generics) {
-        let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+        let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
 
         let ctor_id = match def.ctor_id {
             Some(node_id) => node_id,
@@ -691,7 +678,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                      generics: &ast::Generics,
                      trait_refs: &OwnedSlice<ast::TyParamBound>,
                      methods: &[P<ast::TraitItem>]) {
-        let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+        let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
         let val = self.span.snippet(item.span);
         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
         self.fmt.trait_str(item.span,
@@ -758,7 +745,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             return
         }
 
-        let def_map = self.analysis.ty_cx.def_map.borrow();
+        let def_map = self.tcx.def_map.borrow();
         if !def_map.contains_key(&id) {
             self.sess.span_bug(span,
                                &format!("def_map has no key for {} in visit_expr", id));
@@ -789,12 +776,10 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             def::DefMethod(declid, provenence) => {
                 let sub_span = self.span.sub_span_for_meth_name(span);
                 let defid = if declid.krate == ast::LOCAL_CRATE {
-                    let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
-                                                    declid);
+                    let ti = ty::impl_or_trait_item(self.tcx, declid);
                     match provenence {
                         def::FromTrait(def_id) => {
-                            Some(ty::trait_items(&self.analysis.ty_cx,
-                                                 def_id)
+                            Some(ty::trait_items(self.tcx, def_id)
                                     .iter()
                                     .find(|mr| {
                                         mr.name() == ti.name()
@@ -803,16 +788,13 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                                     .def_id())
                         }
                         def::FromImpl(def_id) => {
-                            let impl_items = self.analysis
-                                                 .ty_cx
-                                                 .impl_items
-                                                 .borrow();
+                            let impl_items = self.tcx.impl_items.borrow();
                             Some(impl_items.get(&def_id)
                                            .unwrap()
                                            .iter()
                                            .find(|mr| {
                                                 ty::impl_or_trait_item(
-                                                    &self.analysis.ty_cx,
+                                                    self.tcx,
                                                     mr.def_id()
                                                 ).name() == ti.name()
                                             })
@@ -844,7 +826,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
         // modules or types in the path prefix
         match def {
             def::DefMethod(did, _) => {
-                let ti = ty::impl_or_trait_item(&self.analysis.ty_cx, did);
+                let ti = ty::impl_or_trait_item(self.tcx, did);
                 if let ty::MethodTraitItem(m) = ti {
                     if m.explicit_self == ty::StaticExplicitSelfCategory {
                         self.write_sub_path_trait_truncated(path);
@@ -906,24 +888,21 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
     fn process_method_call(&mut self,
                            ex: &ast::Expr,
                            args: &Vec<P<ast::Expr>>) {
-        let method_map = self.analysis.ty_cx.method_map.borrow();
+        let method_map = self.tcx.method_map.borrow();
         let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
         let (def_id, decl_id) = match method_callee.origin {
             ty::MethodStatic(def_id) |
             ty::MethodStaticClosure(def_id) => {
                 // method invoked on an object with a concrete type (not a static method)
                 let decl_id =
-                    match ty::trait_item_of_item(&self.analysis.ty_cx,
-                                                 def_id) {
+                    match ty::trait_item_of_item(self.tcx, def_id) {
                         None => None,
                         Some(decl_id) => Some(decl_id.def_id()),
                     };
 
                 // This incantation is required if the method referenced is a
                 // trait's default implementation.
-                let def_id = match ty::impl_or_trait_item(&self.analysis
-                                                               .ty_cx,
-                                                          def_id) {
+                let def_id = match ty::impl_or_trait_item(self.tcx, def_id) {
                     ty::MethodTraitItem(method) => {
                         method.provided_source.unwrap_or(def_id)
                     }
@@ -936,14 +915,14 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             }
             ty::MethodTypeParam(ref mp) => {
                 // method invoked on a type parameter
-                let trait_item = ty::trait_item(&self.analysis.ty_cx,
+                let trait_item = ty::trait_item(self.tcx,
                                                 mp.trait_ref.def_id,
                                                 mp.method_num);
                 (None, Some(trait_item.def_id()))
             }
             ty::MethodTraitObject(ref mo) => {
                 // method invoked on a trait instance
-                let trait_item = ty::trait_item(&self.analysis.ty_cx,
+                let trait_item = ty::trait_item(self.tcx,
                                                 mo.trait_ref.def_id,
                                                 mo.method_num);
                 (None, Some(trait_item.def_id()))
@@ -969,12 +948,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             ast::PatStruct(ref path, ref fields, _) => {
                 visit::walk_path(self, path);
 
-                let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
+                let def = self.tcx.def_map.borrow().get(&p.id).unwrap().full_def();
                 let struct_def = match def {
                     def::DefConst(..) | def::DefAssociatedConst(..) => None,
                     def::DefVariant(_, variant_id, _) => Some(variant_id),
                     _ => {
-                        match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
+                        match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, p.id)) {
                             None => {
                                 self.sess.span_bug(p.span,
                                                    &format!("Could not find struct_def for `{}`",
@@ -986,7 +965,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                 };
 
                 if let Some(struct_def) = struct_def {
-                    let struct_fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
+                    let struct_fields = ty::lookup_struct_fields(self.tcx, struct_def);
                     for &Spanned { node: ref field, span } in fields {
                         let sub_span = self.span.span_for_first_ident(span);
                         for f in &struct_fields {
@@ -1145,7 +1124,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
                 self.nest(item.id, |v| visit::walk_mod(v, m));
             }
             ast::ItemTy(ref ty, ref ty_params) => {
-                let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+                let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
                 let value = ty_to_string(&**ty);
                 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
                 self.fmt.typedef_str(item.span,
@@ -1273,10 +1252,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
 
                 self.visit_expr(&**sub_ex);
 
-                let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty;
+                let ty = &ty::expr_ty_adjusted(self.tcx, &**sub_ex).sty;
                 match *ty {
                     ty::TyStruct(def_id, _) => {
-                        let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
+                        let fields = ty::lookup_struct_fields(self.tcx, def_id);
                         for (i, f) in fields.iter().enumerate() {
                             if i == idx.node {
                                 let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
@@ -1342,7 +1321,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
         let mut paths_to_process = vec![];
         // process collected paths
         for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
-            let def_map = self.analysis.ty_cx.def_map.borrow();
+            let def_map = self.tcx.def_map.borrow();
             if !def_map.contains_key(&id) {
                 self.sess.span_bug(p.span,
                                    &format!("def_map has no key for {} in visit_arm",
@@ -1410,8 +1389,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
             } else {
                 "<mutable>".to_string()
             };
-            let types = self.analysis.ty_cx.node_types();
-            let typ = ppaux::ty_to_string(&self.analysis.ty_cx, *types.get(&id).unwrap());
+            let types = self.tcx.node_types();
+            let typ = types.get(&id).unwrap().to_string();
             // Get the span only for the name of the variable (I hope the path
             // is only ever a variable name, but who knows?).
             let sub_span = self.span.span_for_last_ident(p.span);
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 3ea628704eb..fdfb101ed78 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use session::Session;
 use middle::ty;
 use middle::def;
 
@@ -24,8 +23,6 @@ use syntax::parse::token::{self, get_ident, keywords};
 use syntax::visit::{self, Visitor};
 use syntax::print::pprust::ty_to_string;
 
-use util::ppaux;
-
 use self::span_utils::SpanUtils;
 
 
@@ -35,8 +32,7 @@ mod recorder;
 mod dump_csv;
 
 pub struct SaveContext<'l, 'tcx: 'l> {
-    sess: &'l Session,
-    analysis: &'l ty::CrateAnalysis<'tcx>,
+    tcx: &'l ty::ctxt<'tcx>,
     span_utils: SpanUtils<'l>,
 }
 
@@ -143,13 +139,11 @@ pub struct TypeRefData {
 
 
 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
-    pub fn new(sess: &'l Session,
-               analysis: &'l ty::CrateAnalysis<'tcx>,
+    pub fn new(tcx: &'l ty::ctxt<'tcx>,
                span_utils: SpanUtils<'l>)
                -> SaveContext<'l, 'tcx> {
         SaveContext {
-            sess: sess,
-            analysis: analysis,
+            tcx: tcx,
             span_utils: span_utils,
         }
     }
@@ -158,7 +152,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     pub fn get_external_crates(&self) -> Vec<CrateData> {
         let mut result = Vec::new();
 
-        self.sess.cstore.iter_crate_data(|n, cmd| {
+        self.tcx.sess.cstore.iter_crate_data(|n, cmd| {
             result.push(CrateData { name: cmd.name.clone(), number: n });
         });
 
@@ -168,7 +162,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     pub fn get_item_data(&self, item: &ast::Item) -> Data {
         match item.node {
             ast::ItemFn(..) => {
-                let name = self.analysis.ty_cx.map.path_to_string(item.id);
+                let name = self.tcx.map.path_to_string(item.id);
                 let qualname = format!("::{}", name);
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
 
@@ -178,11 +172,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     qualname: qualname,
                     declaration: None,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.tcx.map.get_parent(item.id),
                 })
             }
             ast::ItemStatic(ref typ, mt, ref expr) => {
-                let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+                let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
 
                 // If the variable is immutable, save the initialising expression.
                 let (value, keyword) = match mt {
@@ -197,13 +191,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     name: get_ident(item.ident).to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.tcx.map.get_parent(item.id),
                     value: value,
                     type_value: ty_to_string(&typ),
                 })
             }
             ast::ItemConst(ref typ, ref expr) => {
-                let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+                let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
 
                 Data::VariableData(VariableData {
@@ -211,15 +205,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     name: get_ident(item.ident).to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.tcx.map.get_parent(item.id),
                     value: self.span_utils.snippet(expr.span),
                     type_value: ty_to_string(&typ),
                 })
             }
             ast::ItemMod(ref m) => {
-                let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+                let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
 
-                let cm = self.sess.codemap();
+                let cm = self.tcx.sess.codemap();
                 let filename = cm.span_to_filename(m.inner);
 
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
@@ -229,12 +223,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     name: get_ident(item.ident).to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.tcx.map.get_parent(item.id),
                     filename: filename,
                 })
             },
             ast::ItemEnum(..) => {
-                let enum_name = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+                let enum_name = format!("::{}", self.tcx.map.path_to_string(item.id));
                 let val = self.span_utils.snippet(item.span);
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
 
@@ -243,14 +237,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     value: val,
                     span: sub_span.unwrap(),
                     qualname: enum_name,
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.tcx.map.get_parent(item.id),
                 })
             },
             ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => {
                 let mut type_data = None;
                 let sub_span;
 
-                let parent = self.analysis.ty_cx.map.get_parent(item.id);
+                let parent = self.tcx.map.get_parent(item.id);
 
                 match typ.node {
                     // Common case impl for a struct or something basic.
@@ -294,11 +288,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             ast::NamedField(ident, _) => {
                 let name = get_ident(ident);
                 let qualname = format!("::{}::{}",
-                                       self.analysis.ty_cx.map.path_to_string(parent),
+                                       self.tcx.map.path_to_string(parent),
                                        name);
-                let typ = ppaux::ty_to_string(&self.analysis.ty_cx,
-                                              *self.analysis.ty_cx.node_types()
-                                                  .get(&field.node.id).unwrap());
+                let typ = self.tcx.node_types().get(&field.node.id).unwrap()
+                                               .to_string();
                 let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
                 Some(Data::VariableData(VariableData {
                     id: field.node.id,
@@ -334,26 +327,25 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
         match expr.node {
             ast::ExprField(ref sub_ex, ident) => {
-                let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &sub_ex).sty;
+                let ty = &ty::expr_ty_adjusted(self.tcx, &sub_ex).sty;
                 match *ty {
                     ty::TyStruct(def_id, _) => {
-                        let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
+                        let fields = ty::lookup_struct_fields(self.tcx, def_id);
                         for f in &fields {
                             if f.name == ident.node.name {
                                 let sub_span = self.span_utils.span_for_last_ident(expr.span);
                                 return Some(Data::VariableRefData(VariableRefData {
                                     name: get_ident(ident.node).to_string(),
                                     span: sub_span.unwrap(),
-                                    scope: self.analysis.ty_cx.map.get_parent(expr.id),
+                                    scope: self.tcx.map.get_parent(expr.id),
                                     ref_id: f.id,
                                 }));
                             }
                         }
 
-                        self.sess.span_bug(expr.span,
-                                           &format!("Couldn't find field {} on {:?}",
-                                                    &get_ident(ident.node),
-                                                    ty))
+                        self.tcx.sess.span_bug(expr.span,
+                                               &format!("Couldn't find field {} on {:?}",
+                                                        &get_ident(ident.node), ty))
                     }
                     _ => {
                         debug!("Expected struct type, found {:?}", ty);
@@ -362,13 +354,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 }
             }
             ast::ExprStruct(ref path, _, _) => {
-                let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, expr).sty;
+                let ty = &ty::expr_ty_adjusted(&self.tcx, expr).sty;
                 match *ty {
                     ty::TyStruct(def_id, _) => {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
                         Some(Data::TypeRefData(TypeRefData {
                             span: sub_span.unwrap(),
-                            scope: self.analysis.ty_cx.map.get_parent(expr.id),
+                            scope: self.tcx.map.get_parent(expr.id),
                             ref_id: def_id,
                         }))
                     }
@@ -392,7 +384,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                               struct_id: DefId,
                               parent: NodeId)
                               -> VariableRefData {
-        let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_id);
+        let fields = ty::lookup_struct_fields(&self.tcx, struct_id);
         let field_name = get_ident(field_ref.ident.node).to_string();
         for f in &fields {
             if f.name == field_ref.ident.node.name {
@@ -407,8 +399,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
         }
 
-        self.sess.span_bug(field_ref.span,
-                           &format!("Couldn't find field {}", field_name));
+        self.tcx.sess.span_bug(field_ref.span,
+                               &format!("Couldn't find field {}", field_name));
     }
 
     pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
@@ -417,11 +409,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     }
 
     fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
-        if !self.analysis.ty_cx.def_map.borrow().contains_key(&ref_id) {
-            self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
-                                  ref_id));
+        if !self.tcx.def_map.borrow().contains_key(&ref_id) {
+            self.tcx.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
+                                       ref_id));
         }
-        let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def();
+        let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
         match def {
             def::DefPrimTy(_) => None,
             _ => Some(def.def_id()),
@@ -484,10 +476,10 @@ impl<'v> Visitor<'v> for PathCollector {
 }
 
 #[allow(deprecated)]
-pub fn process_crate(sess: &Session,
-                     krate: &ast::Crate,
+pub fn process_crate(tcx: &ty::ctxt,
                      analysis: &ty::CrateAnalysis,
                      odir: Option<&Path>) {
+    let krate = tcx.map.krate();
     if generated_code(krate.span) {
         return;
     }
@@ -512,10 +504,9 @@ pub fn process_crate(sess: &Session,
         },
     };
 
-    match fs::create_dir_all(&root_path) {
-        Err(e) => sess.err(&format!("Could not create directory {}: {}",
-                           root_path.display(), e)),
-        _ => (),
+    if let Err(e) = fs::create_dir_all(&root_path) {
+        tcx.sess.err(&format!("Could not create directory {}: {}",
+                              root_path.display(), e));
     }
 
     {
@@ -531,12 +522,12 @@ pub fn process_crate(sess: &Session,
         Ok(f) => box f,
         Err(e) => {
             let disp = root_path.display();
-            sess.fatal(&format!("Could not open {}: {}", disp, e));
+            tcx.sess.fatal(&format!("Could not open {}: {}", disp, e));
         }
     };
     root_path.pop();
 
-    let mut visitor = dump_csv::DumpCsvVisitor::new(sess, analysis, output_file);
+    let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, analysis, output_file);
 
     visitor.dump_crate_info(&cratename, krate);
     visit::walk_crate(&mut visitor, krate);
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index d2a7b3198f8..05672153b01 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -217,10 +217,11 @@ use middle::ty::{self, Ty};
 use session::config::{NoDebugInfo, FullDebugInfo};
 use util::common::indenter;
 use util::nodemap::FnvHashMap;
-use util::ppaux::{Repr, vec_map_to_string};
+use util::ppaux;
 
 use std;
 use std::cmp::Ordering;
+use std::fmt;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::ast::{DUMMY_NODE_ID, NodeId};
@@ -371,13 +372,13 @@ struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> {
     pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>>
 }
 
-impl<'a, 'p, 'blk, 'tcx> Repr<'tcx> for Match<'a, 'p, 'blk, 'tcx> {
-    fn repr(&self, tcx: &ty::ctxt) -> String {
-        if tcx.sess.verbose() {
+impl<'a, 'p, 'blk, 'tcx> fmt::Debug for Match<'a, 'p, 'blk, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if ppaux::verbose() {
             // for many programs, this just take too long to serialize
-            self.pats.repr(tcx)
+            write!(f, "{:?}", self.pats)
         } else {
-            format!("{} pats", self.pats.len())
+            write!(f, "{} pats", self.pats.len())
         }
     }
 }
@@ -397,9 +398,9 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                               col: usize,
                                               val: ValueRef)
                                               -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
-    debug!("expand_nested_bindings(bcx={}, m={}, col={}, val={})",
+    debug!("expand_nested_bindings(bcx={}, m={:?}, col={}, val={})",
            bcx.to_str(),
-           m.repr(bcx.tcx()),
+           m,
            col,
            bcx.val_to_string(val));
     let _indenter = indenter();
@@ -437,9 +438,9 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                                           -> Vec<Match<'a, 'p, 'blk, 'tcx>> where
     F: FnMut(&[&'p ast::Pat]) -> Option<Vec<&'p ast::Pat>>,
 {
-    debug!("enter_match(bcx={}, m={}, col={}, val={})",
+    debug!("enter_match(bcx={}, m={:?}, col={}, val={})",
            bcx.to_str(),
-           m.repr(bcx.tcx()),
+           m,
            col,
            bcx.val_to_string(val));
     let _indenter = indenter();
@@ -480,9 +481,9 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                      col: usize,
                                      val: ValueRef)
                                      -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
-    debug!("enter_default(bcx={}, m={}, col={}, val={})",
+    debug!("enter_default(bcx={}, m={:?}, col={}, val={})",
            bcx.to_str(),
-           m.repr(bcx.tcx()),
+           m,
            col,
            bcx.val_to_string(val));
     let _indenter = indenter();
@@ -537,9 +538,9 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
              variant_size: usize,
              val: ValueRef)
              -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
-    debug!("enter_opt(bcx={}, m={}, opt={:?}, col={}, val={})",
+    debug!("enter_opt(bcx={}, m={:?}, opt={:?}, col={}, val={})",
            bcx.to_str(),
-           m.repr(bcx.tcx()),
+           m,
            *opt,
            col,
            bcx.val_to_string(val));
@@ -825,8 +826,7 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                -> Result<'blk, 'tcx> {
         let did = langcall(cx,
                            None,
-                           &format!("comparison of `{}`",
-                                   cx.ty_to_string(rhs_t)),
+                           &format!("comparison of `{}`", rhs_t),
                            StrEqFnLangItem);
         let t = ty::mk_str_slice(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ast::MutImmutable);
         // The comparison function gets the slices by value, so we have to make copies here. Even
@@ -937,11 +937,11 @@ fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                      chk: &FailureHandler,
                                      has_genuine_default: bool)
                                      -> Block<'blk, 'tcx> {
-    debug!("compile_guard(bcx={}, guard_expr={}, m={}, vals={})",
+    debug!("compile_guard(bcx={}, guard_expr={:?}, m={:?}, vals=[{}])",
            bcx.to_str(),
-           bcx.expr_to_string(guard_expr),
-           m.repr(bcx.tcx()),
-           vec_map_to_string(vals, |v| bcx.val_to_string(*v)));
+           guard_expr,
+           m,
+           vals.iter().map(|v| bcx.val_to_string(*v)).collect::<Vec<_>>().connect(", "));
     let _indenter = indenter();
 
     let mut bcx = insert_lllocals(bcx, &data.bindings_map, None);
@@ -983,10 +983,10 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                         vals: &[ValueRef],
                                         chk: &FailureHandler,
                                         has_genuine_default: bool) {
-    debug!("compile_submatch(bcx={}, m={}, vals={})",
+    debug!("compile_submatch(bcx={}, m={:?}, vals=[{}])",
            bcx.to_str(),
-           m.repr(bcx.tcx()),
-           vec_map_to_string(vals, |v| bcx.val_to_string(*v)));
+           m,
+           vals.iter().map(|v| bcx.val_to_string(*v)).collect::<Vec<_>>().connect(", "));
     let _indenter = indenter();
     let _icx = push_ctxt("match::compile_submatch");
     let mut bcx = bcx;
@@ -1696,13 +1696,13 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                     val: ValueRef,
                                     cleanup_scope: cleanup::ScopeId)
                                     -> Block<'blk, 'tcx> {
-    debug!("bind_irrefutable_pat(bcx={}, pat={})",
+    debug!("bind_irrefutable_pat(bcx={}, pat={:?})",
            bcx.to_str(),
-           pat.repr(bcx.tcx()));
+           pat);
 
     if bcx.sess().asm_comments() {
-        add_comment(bcx, &format!("bind_irrefutable_pat(pat={})",
-                                 pat.repr(bcx.tcx())));
+        add_comment(bcx, &format!("bind_irrefutable_pat(pat={:?})",
+                                 pat));
     }
 
     let _indenter = indenter();
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index 68d72ab4241..2a1c2457b9d 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -66,7 +66,6 @@ use trans::machine;
 use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
-use util::ppaux::ty_to_string;
 
 type Hint = attr::ReprAttr;
 
@@ -143,7 +142,7 @@ pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 t: Ty<'tcx>)
                                 -> Rc<Repr<'tcx>> {
-    debug!("Representing: {}", ty_to_string(cx.tcx(), t));
+    debug!("Representing: {}", t);
     match cx.adt_reprs().borrow().get(&t) {
         Some(repr) => return repr.clone(),
         None => {}
@@ -381,8 +380,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             General(ity, fields, dtor_to_init_u8(dtor))
         }
-        _ => cx.sess().bug(&format!("adt::represent_type called on non-ADT type: {}",
-                           ty_to_string(cx.tcx(), t)))
+        _ => cx.sess().bug(&format!("adt::represent_type called on non-ADT type: {}", t))
     }
 }
 
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index b382b71343f..0b212cbeb86 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -80,7 +80,6 @@ use trans::type_of;
 use trans::type_of::*;
 use trans::value::Value;
 use util::common::indenter;
-use util::ppaux::{Repr, ty_to_string};
 use util::sha2::Sha256;
 use util::nodemap::NodeMap;
 
@@ -250,9 +249,7 @@ fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     match bcx.tcx().lang_items.require(it) {
         Ok(id) => id,
         Err(s) => {
-            bcx.sess().fatal(&format!("allocation of `{}` {}",
-                                     bcx.ty_to_string(info_ty),
-                                     s));
+            bcx.sess().fatal(&format!("allocation of `{}` {}", info_ty, s));
         }
     }
 }
@@ -530,8 +527,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
           }
       }
       _ => {
-          cx.sess().unimpl(&format!("type in iter_structural_ty: {}",
-                                   ty_to_string(cx.tcx(), t)))
+          cx.sess().unimpl(&format!("type in iter_structural_ty: {}", t))
       }
     }
     return cx;
@@ -640,8 +636,7 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
             (res, false)
         }
         _ => {
-            cx.sess().bug(&format!("fail-if-zero on unexpected type: {}",
-                                  ty_to_string(cx.tcx(), rhs_t)));
+            cx.sess().bug(&format!("fail-if-zero on unexpected type: {}", rhs_t));
         }
     };
     let bcx = with_cond(cx, is_zero, |bcx| {
@@ -1192,13 +1187,13 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
                              -> FunctionContext<'a, 'tcx> {
     common::validate_substs(param_substs);
 
-    debug!("new_fn_ctxt(path={}, id={}, param_substs={})",
+    debug!("new_fn_ctxt(path={}, id={}, param_substs={:?})",
            if id == !0 {
                "".to_string()
            } else {
                ccx.tcx().map.path_to_string(id).to_string()
            },
-           id, param_substs.repr(ccx.tcx()));
+           id, param_substs);
 
     let uses_outptr = match output_type {
         ty::FnConverging(output_type) => {
@@ -1515,8 +1510,8 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let _icx = push_ctxt("trans_closure");
     attributes::emit_uwtable(llfndecl, true);
 
-    debug!("trans_closure(..., param_substs={})",
-           param_substs.repr(ccx.tcx()));
+    debug!("trans_closure(..., param_substs={:?})",
+           param_substs);
 
     let has_env = match closure_env {
         closure::ClosureEnv::Closure(_) => true,
@@ -1558,8 +1553,8 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
     };
     for monomorphized_arg_type in &monomorphized_arg_types {
-        debug!("trans_closure: monomorphized_arg_type: {}",
-               ty_to_string(ccx.tcx(), *monomorphized_arg_type));
+        debug!("trans_closure: monomorphized_arg_type: {:?}",
+               monomorphized_arg_type);
     }
     debug!("trans_closure: function lltype: {}",
            bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn));
@@ -1641,7 +1636,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                           id: ast::NodeId,
                           attrs: &[ast::Attribute]) {
     let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string());
-    debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
+    debug!("trans_fn(param_substs={:?})", param_substs);
     let _icx = push_ctxt("trans_fn");
     let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
     let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty));
@@ -1676,7 +1671,6 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                                  -> Result<'blk, 'tcx> {
 
     let ccx = bcx.fcx.ccx;
-    let tcx = ccx.tcx();
 
     let result_ty = match ctor_ty.sty {
         ty::TyBareFn(_, ref bft) => {
@@ -1685,7 +1679,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         _ => ccx.sess().bug(
             &format!("trans_enum_variant_constructor: \
                      unexpected ctor return type {}",
-                     ctor_ty.repr(tcx)))
+                     ctor_ty))
     };
 
     // Get location to store the result. If the user does not care about
@@ -1763,7 +1757,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
         _ => ccx.sess().bug(
             &format!("trans_enum_variant_or_tuple_like_struct: \
                      unexpected ctor return type {}",
-                    ty_to_string(ccx.tcx(), ctor_ty)))
+                    ctor_ty))
     };
 
     let (arena, fcx): (TypedArena<_>, FunctionContext);
@@ -2496,7 +2490,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId,
     }
 }
 
-pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>,
+pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'a, 'tcx>,
                                             ie: encoder::EncodeInlinedItem<'a>)
                                             -> encoder::EncodeParams<'a, 'tcx> {
     encoder::EncodeParams {
@@ -2632,9 +2626,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
     }
 }
 
-pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
-                         -> (ty::ctxt<'tcx>, CrateTranslation) {
-    let ty::CrateAnalysis { ty_cx: tcx, export_map, reachable, name, .. } = analysis;
+pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslation {
+    let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis;
     let krate = tcx.map.krate();
 
     let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks {
@@ -2774,7 +2767,7 @@ pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
     let formats = shared_ccx.tcx().dependency_formats.borrow().clone();
     let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
 
-    let translation = CrateTranslation {
+    CrateTranslation {
         modules: modules,
         metadata_module: metadata_module,
         link: link_meta,
@@ -2782,7 +2775,5 @@ pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
         reachable: reachable,
         crate_formats: formats,
         no_builtins: no_builtins,
-    };
-
-    (shared_ccx.take_tcx(), translation)
+    }
 }
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index 0aeb4046dc6..46f762a5195 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -54,8 +54,6 @@ use trans::type_of;
 use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
 use rustc::ast_map;
-use util::ppaux::Repr;
-use util::ppaux::ty_to_string;
 
 use syntax::abi as synabi;
 use syntax::ast;
@@ -90,7 +88,7 @@ pub struct Callee<'blk, 'tcx: 'blk> {
 fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
                      -> Callee<'blk, 'tcx> {
     let _icx = push_ctxt("trans_callee");
-    debug!("callee::trans(expr={})", expr.repr(bcx.tcx()));
+    debug!("callee::trans(expr={:?})", expr);
 
     // pick out special kinds of expressions that can be called:
     match expr.node {
@@ -118,7 +116,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
                 bcx.tcx().sess.span_bug(
                     expr.span,
                     &format!("type of callee is neither bare-fn nor closure: {}",
-                             bcx.ty_to_string(datum.ty)));
+                             datum.ty));
             }
         }
     }
@@ -135,7 +133,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
                              def: def::Def,
                              ref_expr: &ast::Expr)
                              -> Callee<'blk, 'tcx> {
-        debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
+        debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
         let expr_ty = common::node_id_type(bcx, ref_expr.id);
         match def {
             def::DefFn(did, _) if {
@@ -229,10 +227,10 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let _icx = push_ctxt("trans_fn_ref");
 
     let substs = common::node_id_substs(ccx, node, param_substs);
-    debug!("trans_fn_ref(def_id={}, node={:?}, substs={})",
-           def_id.repr(ccx.tcx()),
+    debug!("trans_fn_ref(def_id={:?}, node={:?}, substs={:?})",
+           def_id,
            node,
-           substs.repr(ccx.tcx()));
+           substs);
     trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
 }
 
@@ -292,8 +290,8 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
         None => { }
     }
 
-    debug!("trans_fn_pointer_shim(bare_fn_ty={})",
-           bare_fn_ty.repr(tcx));
+    debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
+           bare_fn_ty);
 
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
@@ -308,7 +306,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 
             _ => {
                 tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
-                                           bare_fn_ty.repr(tcx)));
+                                      bare_fn_ty));
             }
         };
     let sig = ty::erase_late_bound_regions(tcx, sig);
@@ -324,7 +322,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
                                              output: sig.output,
                                              variadic: false
                                          })}));
-    debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
+    debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
 
     //
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
@@ -402,12 +400,12 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
     let _icx = push_ctxt("trans_fn_ref_with_substs");
     let tcx = ccx.tcx();
 
-    debug!("trans_fn_ref_with_substs(def_id={}, node={:?}, \
-            param_substs={}, substs={})",
-           def_id.repr(tcx),
+    debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
+            param_substs={:?}, substs={:?})",
+           def_id,
            node,
-           param_substs.repr(tcx),
-           substs.repr(tcx));
+           param_substs,
+           substs);
 
     assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
     assert!(substs.types.all(|t| !ty::type_has_escaping_regions(*t)));
@@ -458,10 +456,10 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
                     let new_substs = tcx.mk_substs(first_subst.subst(tcx, &substs));
 
                     debug!("trans_fn_with_vtables - default method: \
-                            substs = {}, trait_subst = {}, \
-                            first_subst = {}, new_subst = {}",
-                           substs.repr(tcx), trait_ref.substs.repr(tcx),
-                           first_subst.repr(tcx), new_substs.repr(tcx));
+                            substs = {:?}, trait_subst = {:?}, \
+                            first_subst = {:?}, new_subst = {:?}",
+                           substs, trait_ref.substs,
+                           first_subst, new_substs);
 
                     (true, source_id, new_substs)
                 }
@@ -505,8 +503,8 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
         false
     };
 
-    debug!("trans_fn_ref_with_substs({}) must_monomorphise: {}",
-           def_id.repr(tcx), must_monomorphise);
+    debug!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}",
+           def_id, must_monomorphise);
 
     // Create a monomorphic version of generic functions
     if must_monomorphise {
@@ -616,7 +614,7 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                          dest: expr::Dest)
                                          -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_method_call");
-    debug!("trans_method_call(call_expr={})", call_expr.repr(bcx.tcx()));
+    debug!("trans_method_call(call_expr={:?})", call_expr);
     let method_call = MethodCall::expr(call_expr.id);
     let method_ty = match bcx.tcx().method_map.borrow().get(&method_call) {
         Some(method) => match method.origin {
@@ -1126,8 +1124,8 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let mut bcx = bcx;
     let ccx = bcx.ccx();
 
-    debug!("trans_arg_datum({})",
-           formal_arg_ty.repr(bcx.tcx()));
+    debug!("trans_arg_datum({:?})",
+           formal_arg_ty);
 
     let arg_datum_ty = arg_datum.ty;
 
@@ -1166,8 +1164,8 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
         debug!("casting actual type ({}) to match formal ({})",
                bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
-        debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty),
-                                     ty_to_string(bcx.tcx(), formal_arg_ty));
+        debug!("Rust types: {:?}; {:?}", arg_datum_ty,
+                                     formal_arg_ty);
         val = PointerCast(bcx, val, llformal_arg_ty);
     }
 
diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs
index 9133004dfef..6355a713a2c 100644
--- a/src/librustc_trans/trans/cleanup.rs
+++ b/src/librustc_trans/trans/cleanup.rs
@@ -133,7 +133,6 @@ use trans::type_::Type;
 use middle::ty::{self, Ty};
 use std::fmt;
 use syntax::ast;
-use util::ppaux::Repr;
 
 pub struct CleanupScope<'blk, 'tcx: 'blk> {
     // The id of this cleanup scope. If the id is None,
@@ -397,10 +396,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
             skip_dtor: false,
         };
 
-        debug!("schedule_drop_mem({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
+        debug!("schedule_drop_mem({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
                cleanup_scope,
                self.ccx.tn().val_to_string(val),
-               ty.repr(self.ccx.tcx()),
+               ty,
                drop.fill_on_drop,
                drop.skip_dtor);
 
@@ -423,10 +422,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
             skip_dtor: false,
         };
 
-        debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={}, fill_on_drop={}, skip_dtor={})",
+        debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={:?}, fill_on_drop={}, skip_dtor={})",
                cleanup_scope,
                self.ccx.tn().val_to_string(val),
-               ty.repr(self.ccx.tcx()),
+               ty,
                drop.fill_on_drop,
                drop.skip_dtor);
 
@@ -455,10 +454,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
             skip_dtor: true,
         };
 
-        debug!("schedule_drop_adt_contents({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
+        debug!("schedule_drop_adt_contents({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
                cleanup_scope,
                self.ccx.tn().val_to_string(val),
-               ty.repr(self.ccx.tcx()),
+               ty,
                drop.fill_on_drop,
                drop.skip_dtor);
 
@@ -484,7 +483,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
         debug!("schedule_drop_immediate({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
                cleanup_scope,
                self.ccx.tn().val_to_string(val),
-               ty.repr(self.ccx.tcx()),
+               ty,
                drop.fill_on_drop,
                drop.skip_dtor);
 
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index 27080966fcb..91b0a6c0069 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -28,7 +28,6 @@ use trans::type_of::*;
 use middle::ty::{self, ClosureTyper};
 use middle::subst::Substs;
 use session::config::FullDebugInfo;
-use util::ppaux::Repr;
 
 use syntax::abi::RustCall;
 use syntax::ast;
@@ -353,9 +352,9 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     llreffn: ValueRef)
     -> ValueRef
 {
-    debug!("trans_fn_once_adapter_shim(closure_def_id={}, substs={}, llreffn={})",
-           closure_def_id.repr(ccx.tcx()),
-           substs.repr(ccx.tcx()),
+    debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={})",
+           closure_def_id,
+           substs,
            ccx.tn().val_to_string(llreffn));
 
     let tcx = ccx.tcx();
@@ -374,8 +373,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
                                                                abi: abi,
                                                                sig: sig.clone() });
     let llref_fn_ty = ty::mk_bare_fn(tcx, None, llref_bare_fn_ty);
-    debug!("trans_fn_once_adapter_shim: llref_fn_ty={}",
-           llref_fn_ty.repr(tcx));
+    debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
+           llref_fn_ty);
 
     // Make a version of the closure type with the same arguments, but
     // with argument #0 being by value.
@@ -423,8 +422,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let input_tys = match sig.inputs[1].sty {
         ty::TyTuple(ref tys) => &**tys,
         _ => bcx.sess().bug(&format!("trans_fn_once_adapter_shim: not rust-call! \
-                                      closure_def_id={}",
-                                     closure_def_id.repr(tcx)))
+                                      closure_def_id={:?}",
+                                     closure_def_id))
     };
     let llargs: Vec<_> =
         input_tys.iter()
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 1cabeb26856..5dddf161e69 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -41,7 +41,6 @@ use middle::ty::{self, HasProjectionTypes, Ty};
 use middle::ty_fold;
 use middle::ty_fold::{TypeFolder, TypeFoldable};
 use rustc::ast_map::{PathElem, PathName};
-use util::ppaux::Repr;
 use util::nodemap::{FnvHashMap, NodeMap};
 
 use arena::TypedArena;
@@ -64,11 +63,11 @@ pub use trans::context::CrateContext;
 /// subtyping, but they are anonymized and normalized as well). This
 /// is a stronger, caching version of `ty_fold::erase_regions`.
 pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     let value1 = value.fold_with(&mut RegionEraser(cx));
-    debug!("erase_regions({}) = {}",
-           value.repr(cx), value1.repr(cx));
+    debug!("erase_regions({:?}) = {:?}",
+           value, value1);
     return value1;
 
     struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
@@ -88,7 +87,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
         }
 
         fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
-            where T : TypeFoldable<'tcx> + Repr<'tcx>
+            where T : TypeFoldable<'tcx>
         {
             let u = ty::anonymize_late_bound_regions(self.tcx(), t);
             ty_fold::super_fold_binder(self, &u)
@@ -212,7 +211,7 @@ fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>,
     // destructor (e.g. zero its memory on move).
 
     let contents = ty::type_contents(cx, ty);
-    debug!("type_needs_drop ty={} contents={:?}", ty.repr(cx), contents);
+    debug!("type_needs_drop ty={:?} contents={:?}", ty, contents);
     contents.needs_drop(cx)
 }
 
@@ -518,7 +517,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
     }
 
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+        where T : TypeFoldable<'tcx> + HasProjectionTypes
     {
         monomorphize::apply_param_substs(self.ccx.tcx(),
                                          self.param_substs,
@@ -593,10 +592,6 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
         self.tcx().map.node_to_string(id).to_string()
     }
 
-    pub fn expr_to_string(&self, e: &ast::Expr) -> String {
-        e.repr(self.tcx())
-    }
-
     pub fn def(&self, nid: ast::NodeId) -> def::Def {
         match self.tcx().def_map.borrow().get(&nid) {
             Some(v) => v.full_def(),
@@ -615,16 +610,12 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
         self.ccx().tn().type_to_string(ty)
     }
 
-    pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
-        t.repr(self.tcx())
-    }
-
     pub fn to_str(&self) -> String {
         format!("[block {:p}]", self)
     }
 
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+        where T : TypeFoldable<'tcx> + HasProjectionTypes
     {
         monomorphize::apply_param_substs(self.tcx(),
                                          self.fcx.param_substs,
@@ -994,14 +985,14 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // First check the cache.
     match ccx.trait_cache().borrow().get(&trait_ref) {
         Some(vtable) => {
-            info!("Cache hit: {}", trait_ref.repr(ccx.tcx()));
+            info!("Cache hit: {:?}", trait_ref);
             return (*vtable).clone();
         }
         None => { }
     }
 
-    debug!("trans fulfill_obligation: trait_ref={} def_id={:?}",
-           trait_ref.repr(ccx.tcx()), trait_ref.def_id());
+    debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
+           trait_ref, trait_ref.def_id());
 
     ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
     let infcx = infer::new_infer_ctxt(tcx);
@@ -1022,9 +1013,9 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // leading to an ambiguous result. So report this as an
             // overflow bug, since I believe this is the only case
             // where ambiguity can result.
-            debug!("Encountered ambiguity selecting `{}` during trans, \
+            debug!("Encountered ambiguity selecting `{:?}` during trans, \
                     presuming due to overflow",
-                   trait_ref.repr(tcx));
+                   trait_ref);
             ccx.sess().span_fatal(
                 span,
                 "reached the recursion limit during monomorphization");
@@ -1032,9 +1023,9 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         Err(e) => {
             tcx.sess.span_bug(
                 span,
-                &format!("Encountered error `{}` selecting `{}` during trans",
-                        e.repr(tcx),
-                        trait_ref.repr(tcx)))
+                &format!("Encountered error `{:?}` selecting `{:?}` during trans",
+                        e,
+                        trait_ref))
         }
     };
 
@@ -1047,7 +1038,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     });
     let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable);
 
-    info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
+    info!("Cache miss: {:?}", trait_ref);
     ccx.trait_cache().borrow_mut().insert(trait_ref,
                                           vtable.clone());
 
@@ -1062,8 +1053,8 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                predicates: Vec<ty::Predicate<'tcx>>)
                                                -> bool
 {
-    debug!("normalize_and_test_predicates(predicates={})",
-           predicates.repr(ccx.tcx()));
+    debug!("normalize_and_test_predicates(predicates={:?})",
+           predicates);
 
     let tcx = ccx.tcx();
     let infcx = infer::new_infer_ctxt(tcx);
@@ -1135,15 +1126,15 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
                                                 fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                                 result: &T)
                                                 -> T
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
     match drain_fulfillment_cx(infcx, fulfill_cx, result) {
         Ok(v) => v,
         Err(errors) => {
             infcx.tcx.sess.span_bug(
                 span,
-                &format!("Encountered errors `{}` fulfilling during trans",
-                         errors.repr(infcx.tcx)));
+                &format!("Encountered errors `{:?}` fulfilling during trans",
+                         errors));
         }
     }
 }
@@ -1159,10 +1150,10 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>,
                                        fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                        result: &T)
                                        -> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx> + Repr<'tcx>
+    where T : TypeFoldable<'tcx>
 {
-    debug!("drain_fulfillment_cx(result={})",
-           result.repr(infcx.tcx));
+    debug!("drain_fulfillment_cx(result={:?})",
+           result);
 
     // In principle, we only need to do this so long as `result`
     // contains unbound type parameters. It could be a slight
@@ -1210,7 +1201,7 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     if substs.types.any(|t| ty::type_needs_infer(*t)) {
             tcx.sess.bug(&format!("type parameters for node {:?} include inference types: {:?}",
-                                 node, substs.repr(tcx)));
+                                 node, substs));
         }
 
         monomorphize::apply_param_substs(tcx,
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index f7d1fad19a1..ad6358e0573 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -32,7 +32,6 @@ use trans::type_of;
 use middle::cast::{CastTy,IntTy};
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
-use util::ppaux::{Repr, ty_to_string};
 use util::nodemap::NodeMap;
 
 use std::iter::repeat;
@@ -66,9 +65,9 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
                     C_integral(Type::uint_from_ty(cx, t), i as u64, false)
                 }
                 _ => cx.sess().span_bug(lit.span,
-                        &format!("integer literal has type {} (expected int \
+                        &format!("integer literal has type {:?} (expected int \
                                  or usize)",
-                                ty_to_string(cx.tcx(), lit_int_ty)))
+                                lit_int_ty))
             }
         }
         ast::LitFloat(ref fs, t) => {
@@ -160,8 +159,8 @@ fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }
         }
         None => {
-            cx.sess().bug(&format!("unexpected dereferenceable type {}",
-                                   ty_to_string(cx.tcx(), ty)))
+            cx.sess().bug(&format!("unexpected dereferenceable type {:?}",
+                                   ty))
         }
     }
 }
@@ -368,8 +367,8 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             llvm::LLVMDumpValue(llconst);
             llvm::LLVMDumpValue(C_undef(llty));
         }
-        cx.sess().bug(&format!("const {} of type {} has size {} instead of {}",
-                         e.repr(cx.tcx()), ty_to_string(cx.tcx(), ety_adjusted),
+        cx.sess().bug(&format!("const {:?} of type {:?} has size {} instead of {}",
+                         e, ety_adjusted,
                          csize, tsize));
     }
     (llconst, ety_adjusted)
@@ -476,10 +475,10 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                    fn_args: FnArgMap)
                                    -> ValueRef
 {
-    debug!("const_expr_unadjusted(e={}, ety={}, param_substs={})",
-           e.repr(cx.tcx()),
-           ety.repr(cx.tcx()),
-           param_substs.repr(cx.tcx()));
+    debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
+           e,
+           ety,
+           param_substs);
 
     let map_list = |exprs: &[P<ast::Expr>]| -> Vec<ValueRef> {
         exprs.iter()
@@ -496,9 +495,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             /* Neither type is bottom, and we expect them to be unified
              * already, so the following is safe. */
             let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args);
-            debug!("const_expr_unadjusted: te1={}, ty={}",
+            debug!("const_expr_unadjusted: te1={}, ty={:?}",
                    cx.tn().val_to_string(te1),
-                   ty.repr(cx.tcx()));
+                   ty);
             let is_simd = ty::type_is_simd(cx.tcx(), ty);
             let intype = if is_simd {
                 ty::simd_type(cx.tcx(), ty)
@@ -620,13 +619,13 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                       },
                       _ => cx.sess().span_bug(base.span,
                                               &format!("index-expr base must be a vector \
-                                                       or string type, found {}",
-                                                      ty_to_string(cx.tcx(), bt)))
+                                                       or string type, found {:?}",
+                                                      bt))
                   },
                   _ => cx.sess().span_bug(base.span,
                                           &format!("index-expr base must be a vector \
-                                                   or string type, found {}",
-                                                  ty_to_string(cx.tcx(), bt)))
+                                                   or string type, found {:?}",
+                                                  bt))
               };
 
               let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
@@ -654,7 +653,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let t_cast = ety;
             let llty = type_of::type_of(cx, t_cast);
             let (v, t_expr) = const_expr(cx, &**base, param_substs, fn_args);
-            debug!("trans_const_cast({} as {})", t_expr.repr(cx.tcx()), t_cast.repr(cx.tcx()));
+            debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast);
             if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
                 return v;
             }
diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs
index 663a01e19f3..0ae69682f91 100644
--- a/src/librustc_trans/trans/context.rs
+++ b/src/librustc_trans/trans/context.rs
@@ -28,7 +28,6 @@ use middle::subst::Substs;
 use middle::ty::{self, Ty};
 use session::config::NoDebugInfo;
 use session::Session;
-use util::ppaux::Repr;
 use util::sha2::Sha256;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
 
@@ -57,7 +56,7 @@ pub struct Stats {
 /// per crate.  The data here is shared between all compilation units of the
 /// crate, so it must not contain references to any LLVM data structures
 /// (aside from metadata-related ones).
-pub struct SharedCrateContext<'tcx> {
+pub struct SharedCrateContext<'a, 'tcx: 'a> {
     local_ccxs: Vec<LocalCrateContext<'tcx>>,
 
     metadata_llmod: ModuleRef,
@@ -68,7 +67,7 @@ pub struct SharedCrateContext<'tcx> {
     item_symbols: RefCell<NodeMap<String>>,
     link_meta: LinkMeta,
     symbol_hasher: RefCell<Sha256>,
-    tcx: ty::ctxt<'tcx>,
+    tcx: &'a ty::ctxt<'tcx>,
     stats: Stats,
     check_overflow: bool,
     check_drop_flag_for_sanity: bool,
@@ -159,7 +158,7 @@ pub struct LocalCrateContext<'tcx> {
 }
 
 pub struct CrateContext<'a, 'tcx: 'a> {
-    shared: &'a SharedCrateContext<'tcx>,
+    shared: &'a SharedCrateContext<'a, 'tcx>,
     local: &'a LocalCrateContext<'tcx>,
     /// The index of `local` in `shared.local_ccxs`.  This is used in
     /// `maybe_iter(true)` to identify the original `LocalCrateContext`.
@@ -167,7 +166,7 @@ pub struct CrateContext<'a, 'tcx: 'a> {
 }
 
 pub struct CrateContextIterator<'a, 'tcx: 'a> {
-    shared: &'a SharedCrateContext<'tcx>,
+    shared: &'a SharedCrateContext<'a, 'tcx>,
     index: usize,
 }
 
@@ -192,7 +191,7 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
 
 /// The iterator produced by `CrateContext::maybe_iter`.
 pub struct CrateContextMaybeIterator<'a, 'tcx: 'a> {
-    shared: &'a SharedCrateContext<'tcx>,
+    shared: &'a SharedCrateContext<'a, 'tcx>,
     index: usize,
     single: bool,
     origin: usize,
@@ -237,17 +236,17 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR
     (llcx, llmod)
 }
 
-impl<'tcx> SharedCrateContext<'tcx> {
+impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
     pub fn new(crate_name: &str,
                local_count: usize,
-               tcx: ty::ctxt<'tcx>,
+               tcx: &'b ty::ctxt<'tcx>,
                export_map: ExportMap,
                symbol_hasher: Sha256,
                link_meta: LinkMeta,
                reachable: NodeSet,
                check_overflow: bool,
                check_drop_flag_for_sanity: bool)
-               -> SharedCrateContext<'tcx> {
+               -> SharedCrateContext<'b, 'tcx> {
         let (metadata_llcx, metadata_llmod) = unsafe {
             create_context_and_module(&tcx.sess, "metadata")
         };
@@ -397,10 +396,6 @@ impl<'tcx> SharedCrateContext<'tcx> {
     }
 
     pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
-        &self.tcx
-    }
-
-    pub fn take_tcx(self) -> ty::ctxt<'tcx> {
         self.tcx
     }
 
@@ -418,7 +413,7 @@ impl<'tcx> SharedCrateContext<'tcx> {
 }
 
 impl<'tcx> LocalCrateContext<'tcx> {
-    fn new(shared: &SharedCrateContext<'tcx>,
+    fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
            name: &str)
            -> LocalCrateContext<'tcx> {
         unsafe {
@@ -505,7 +500,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
     /// This is used in the `LocalCrateContext` constructor to allow calling
     /// functions that expect a complete `CrateContext`, even before the local
     /// portion is fully initialized and attached to the `SharedCrateContext`.
-    fn dummy_ccx<'a>(&'a self, shared: &'a SharedCrateContext<'tcx>)
+    fn dummy_ccx<'a>(&'a self, shared: &'a SharedCrateContext<'a, 'tcx>)
                      -> CrateContext<'a, 'tcx> {
         CrateContext {
             shared: shared,
@@ -516,7 +511,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
 }
 
 impl<'b, 'tcx> CrateContext<'b, 'tcx> {
-    pub fn shared(&self) -> &'b SharedCrateContext<'tcx> {
+    pub fn shared(&self) -> &'b SharedCrateContext<'b, 'tcx> {
         self.shared
     }
 
@@ -548,7 +543,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
 
 
     pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
-        &self.shared.tcx
+        self.shared.tcx
     }
 
     pub fn sess<'a>(&'a self) -> &'a Session {
@@ -770,8 +765,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
 
     pub fn report_overbig_object(&self, obj: Ty<'tcx>) -> ! {
         self.sess().fatal(
-            &format!("the type `{}` is too big for the current architecture",
-                    obj.repr(self.tcx())))
+            &format!("the type `{:?}` is too big for the current architecture",
+                    obj))
     }
 
     pub fn check_overflow(&self) -> bool {
diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs
index d203aeca0a7..ceef07207ac 100644
--- a/src/librustc_trans/trans/controlflow.rs
+++ b/src/librustc_trans/trans/controlflow.rs
@@ -24,7 +24,6 @@ use trans::debuginfo::{DebugLoc, ToDebugLoc};
 use trans::expr;
 use trans;
 use middle::ty;
-use util::ppaux::Repr;
 
 use syntax::ast;
 use syntax::ast_util;
@@ -36,14 +35,14 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                               -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_stmt");
     let fcx = cx.fcx;
-    debug!("trans_stmt({})", s.repr(cx.tcx()));
+    debug!("trans_stmt({:?})", s);
 
     if cx.unreachable.get() {
         return cx;
     }
 
     if cx.sess().asm_comments() {
-        add_span_comment(cx, s.span, &s.repr(cx.tcx()));
+        add_span_comment(cx, s.span, &format!("{:?}", s));
     }
 
     let mut bcx = cx;
@@ -151,8 +150,8 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                             els: Option<&ast::Expr>,
                             dest: expr::Dest)
                             -> Block<'blk, 'tcx> {
-    debug!("trans_if(bcx={}, if_id={}, cond={}, thn={}, dest={})",
-           bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id,
+    debug!("trans_if(bcx={}, if_id={}, cond={:?}, thn={}, dest={})",
+           bcx.to_str(), if_id, cond, thn.id,
            dest.to_string(bcx.ccx()));
     let _icx = push_ctxt("trans_if");
 
diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs
index dd32ed3bc1e..e60e4e4abe0 100644
--- a/src/librustc_trans/trans/datum.rs
+++ b/src/librustc_trans/trans/datum.rs
@@ -102,7 +102,6 @@ use trans::expr;
 use trans::tvec;
 use trans::type_of;
 use middle::ty::{self, Ty};
-use util::ppaux::ty_to_string;
 
 use std::fmt;
 use syntax::ast;
@@ -614,9 +613,9 @@ impl<'tcx, K: KindOps + fmt::Debug> Datum<'tcx, K> {
 
     #[allow(dead_code)] // useful for debugging
     pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
-        format!("Datum({}, {}, {:?})",
+        format!("Datum({}, {:?}, {:?})",
                 ccx.tn().val_to_string(self.val),
-                ty_to_string(ccx.tcx(), self.ty),
+                self.ty,
                 self.kind)
     }
 
diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs
index 5e35e5c67f3..7660f59e1d0 100644
--- a/src/librustc_trans/trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/trans/debuginfo/metadata.rs
@@ -34,7 +34,6 @@ use trans::type_::Type;
 use middle::ty::{self, Ty, ClosureTyper};
 use session::config::{self, FullDebugInfo};
 use util::nodemap::FnvHashMap;
-use util::ppaux;
 use util::common::path2cstr;
 
 use libc::{c_uint, c_longlong};
@@ -105,7 +104,7 @@ impl<'tcx> TypeMap<'tcx> {
                                        metadata: DIType) {
         if self.type_to_metadata.insert(type_, metadata).is_some() {
             cx.sess().bug(&format!("Type metadata for Ty '{}' is already in the TypeMap!",
-                                   ppaux::ty_to_string(cx.tcx(), type_)));
+                                   type_));
         }
     }
 
@@ -297,9 +296,8 @@ impl<'tcx> TypeMap<'tcx> {
                                                         &mut unique_type_id);
             },
             _ => {
-                cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
-                                      &ppaux::ty_to_string(cx.tcx(), type_),
-                                      type_.sty))
+                cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {:?}",
+                                       type_))
             }
         };
 
@@ -489,8 +487,8 @@ impl<'tcx> RecursiveTypeDescription<'tcx> {
                     if type_map.find_metadata_for_unique_id(unique_type_id).is_none() ||
                        type_map.find_metadata_for_type(unfinished_type).is_none() {
                         cx.sess().bug(&format!("Forward declaration of potentially recursive type \
-                                              '{}' was not found in TypeMap!",
-                                              ppaux::ty_to_string(cx.tcx(), unfinished_type))
+                                              '{:?}' was not found in TypeMap!",
+                                              unfinished_type)
                                       );
                     }
                 }
@@ -676,10 +674,9 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let def_id = match trait_type.sty {
         ty::TyTrait(ref data) => data.principal_def_id(),
         _ => {
-            let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type);
             cx.sess().bug(&format!("debuginfo: Unexpected trait-object type in \
-                                   trait_pointer_metadata(): {}",
-                                   &pp_type_name[..]));
+                                   trait_pointer_metadata(): {:?}",
+                                   trait_type));
         }
     };
 
@@ -841,7 +838,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                  the debuginfo::TypeMap but it \
                                                  was not. (Ty = {})",
                                                 &unique_type_id_str[..],
-                                                ppaux::ty_to_string(cx.tcx(), t));
+                                                t);
                     cx.sess().span_bug(usage_site_span, &error_message[..]);
                 }
             };
@@ -856,7 +853,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                      debuginfo::TypeMap. \
                                                      UniqueTypeId={}, Ty={}",
                             &unique_type_id_str[..],
-                            ppaux::ty_to_string(cx.tcx(), t));
+                            t);
                         cx.sess().span_bug(usage_site_span, &error_message[..]);
                     }
                 }
diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs
index 7d6c053cd1b..5ba5ecb02c0 100644
--- a/src/librustc_trans/trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/trans/debuginfo/type_names.rs
@@ -15,9 +15,9 @@ use super::namespace::crate_root_namespace;
 use trans::common::CrateContext;
 use middle::subst::{self, Substs};
 use middle::ty::{self, Ty, ClosureTyper};
+
 use syntax::ast;
 use syntax::parse::token;
-use util::ppaux;
 
 
 // Compute the name of the type as it should be stored in debuginfo. Does not do
@@ -162,7 +162,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::TyProjection(..) |
         ty::TyParam(_) => {
             cx.sess().bug(&format!("debuginfo: Trying to create type name for \
-                unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t)));
+                unexpected type: {:?}", t));
         }
     }
 
diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs
index 935925e5a8f..8bc3326d300 100644
--- a/src/librustc_trans/trans/declare.rs
+++ b/src/librustc_trans/trans/declare.rs
@@ -29,7 +29,6 @@ use trans::context::CrateContext;
 use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
-use util::ppaux::Repr;
 
 use std::ffi::CString;
 use libc::c_uint;
@@ -106,11 +105,11 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type,
 /// update the declaration and return existing ValueRef instead.
 pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
                                  fn_type: ty::Ty<'tcx>) -> ValueRef {
-    debug!("declare_rust_fn(name={:?}, fn_type={})", name,
-           fn_type.repr(ccx.tcx()));
+    debug!("declare_rust_fn(name={:?}, fn_type={:?})", name,
+           fn_type);
     let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type);
-    debug!("declare_rust_fn (after normalised associated types) fn_type={}",
-           fn_type.repr(ccx.tcx()));
+    debug!("declare_rust_fn (after normalised associated types) fn_type={:?}",
+           fn_type);
 
     let function_type; // placeholder so that the memory ownership works out ok
     let (sig, abi, env) = match fn_type.sty {
@@ -122,15 +121,15 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
             function_type = typer.closure_type(closure_did, substs);
             let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
             let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type);
-            debug!("declare_rust_fn function_type={} self_type={}",
-                   function_type.repr(ccx.tcx()), self_type.repr(ccx.tcx()));
+            debug!("declare_rust_fn function_type={:?} self_type={:?}",
+                   function_type, self_type);
             (&function_type.sig, abi::RustCall, Some(llenvironment_type))
         }
         _ => ccx.sess().bug("expected closure or fn")
     };
 
     let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig));
-    debug!("declare_rust_fn (after region erasure) sig={}", sig.repr(ccx.tcx()));
+    debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
     let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi);
     debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty));
 
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 07a8cbc38d5..48deceeeef7 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -78,7 +78,6 @@ use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
 use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
 use util::common::indenter;
-use util::ppaux::Repr;
 use trans::machine::{llsize_of, llsize_of_alloc};
 use trans::type_::Type;
 
@@ -181,7 +180,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }
     }
 
-    debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
+    debug!("trans_into() expr={:?}", expr);
 
     let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
                                                                           expr.id,
@@ -211,7 +210,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                          expr: &ast::Expr)
                          -> DatumBlock<'blk, 'tcx, Expr> {
-    debug!("trans(expr={})", bcx.expr_to_string(expr));
+    debug!("trans(expr={:?})", expr);
 
     let mut bcx = bcx;
     let fcx = bcx.fcx;
@@ -329,9 +328,9 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
             consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
                             Type::vtable_ptr(ccx))
         }
-        _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}",
-                                     source.repr(ccx.tcx()),
-                                     target.repr(ccx.tcx())))
+        _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}",
+                                     source,
+                                     target))
     }
 }
 
@@ -350,8 +349,8 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }
         Some(adj) => { adj }
     };
-    debug!("unadjusted datum for expr {}: {} adjustment={:?}",
-           expr.repr(bcx.tcx()),
+    debug!("unadjusted datum for expr {:?}: {} adjustment={:?}",
+           expr,
            datum.to_string(bcx.ccx()),
            adjustment);
     match adjustment {
@@ -501,8 +500,8 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     ty::custom_coerce_unsized_kind(bcx.tcx(), impl_def_id)
                 }
                 vtable => {
-                    bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {}",
-                                                       vtable.repr(bcx.tcx())));
+                    bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {:?}",
+                                                       vtable));
                 }
             };
 
@@ -545,9 +544,9 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 }
             }
         }
-        _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {} -> {}",
-                                     source.ty.repr(bcx.tcx()),
-                                     target.ty.repr(bcx.tcx())))
+        _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {:?} -> {:?}",
+                                     source.ty,
+                                     target.ty))
     }
     bcx
 }
@@ -575,7 +574,7 @@ fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 -> DatumBlock<'blk, 'tcx, Expr> {
     let mut bcx = bcx;
 
-    debug!("trans_unadjusted(expr={})", bcx.expr_to_string(expr));
+    debug!("trans_unadjusted(expr={:?})", expr);
     let _indenter = indenter();
 
     debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
@@ -1281,9 +1280,9 @@ pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
         _ => {
             ccx.tcx().sess.span_bug(ref_expr.span, &format!(
-                    "trans_def_fn_unadjusted invoked on: {:?} for {}",
+                    "trans_def_fn_unadjusted invoked on: {:?} for {:?}",
                     def,
-                    ref_expr.repr(ccx.tcx())));
+                    ref_expr));
         }
     }
 }
@@ -1317,7 +1316,7 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 }
             };
             debug!("take_local(nid={}, v={}, ty={})",
-                   nid, bcx.val_to_string(datum.val), bcx.ty_to_string(datum.ty));
+                   nid, bcx.val_to_string(datum.val), datum.ty);
             datum
         }
         _ => {
@@ -1354,9 +1353,9 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
             match node_id_opt {
                 None => {
                     tcx.sess.bug(&format!(
-                        "cannot get field types from the enum type {} \
+                        "cannot get field types from the enum type {:?} \
                          without a node ID",
-                        ty.repr(tcx)));
+                        ty));
                 }
                 Some(node_id) => {
                     let def = tcx.def_map.borrow().get(&node_id).unwrap().full_def();
@@ -1378,8 +1377,8 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
 
         _ => {
             tcx.sess.bug(&format!(
-                "cannot get field types from the type {}",
-                ty.repr(tcx)));
+                "cannot get field types from the type {:?}",
+                ty));
         }
     }
 }
@@ -2060,7 +2059,7 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let t_in = expr_ty_adjusted(bcx, expr);
     let t_out = node_id_type(bcx, id);
 
-    debug!("trans_cast({} as {})", t_in.repr(bcx.tcx()), t_out.repr(bcx.tcx()));
+    debug!("trans_cast({:?} as {:?})", t_in, t_out);
     let mut ll_t_in = type_of::arg_type_of(ccx, t_in);
     let ll_t_out = type_of::arg_type_of(ccx, t_out);
     // Convert the value to be cast into a ValueRef, either by-ref or
@@ -2123,9 +2122,9 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
         _ => ccx.sess().span_bug(expr.span,
                                   &format!("translating unsupported cast: \
-                                            {} -> {}",
-                                           t_in.repr(bcx.tcx()),
-                                           t_out.repr(bcx.tcx()))
+                                            {:?} -> {:?}",
+                                           t_in,
+                                           t_out)
                                  )
     };
     return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
@@ -2140,7 +2139,7 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let _icx = push_ctxt("trans_assign_op");
     let mut bcx = bcx;
 
-    debug!("trans_assign_op(expr={})", bcx.expr_to_string(expr));
+    debug!("trans_assign_op(expr={:?})", expr);
 
     // User-defined operator methods cannot be used with `+=` etc right now
     assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
@@ -2210,8 +2209,8 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           -> DatumBlock<'blk, 'tcx, Expr> {
     let ccx = bcx.ccx();
 
-    debug!("deref_once(expr={}, datum={}, method_call={:?})",
-           expr.repr(bcx.tcx()),
+    debug!("deref_once(expr={:?}, datum={}, method_call={:?})",
+           expr,
            datum.to_string(ccx),
            method_call);
 
@@ -2295,8 +2294,8 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         _ => {
             bcx.tcx().sess.span_bug(
                 expr.span,
-                &format!("deref invoked on expr of illegal type {}",
-                        datum.ty.repr(bcx.tcx())));
+                &format!("deref invoked on expr of illegal type {:?}",
+                        datum.ty));
         }
     };
 
diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs
index 9ad6df5a6ab..977d636d253 100644
--- a/src/librustc_trans/trans/foreign.rs
+++ b/src/librustc_trans/trans/foreign.rs
@@ -40,7 +40,6 @@ use syntax::parse::token;
 use syntax::ast;
 use syntax::attr;
 use syntax::print::pprust;
-use util::ppaux::Repr;
 
 ///////////////////////////////////////////////////////////////////////////
 // Type definitions
@@ -183,11 +182,11 @@ pub fn get_extern_fn(ccx: &CrateContext,
 pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                           abi: Abi, fty: Ty<'tcx>,
                                           name: &str) -> ValueRef {
-    debug!("register_foreign_item_fn(abi={}, \
-            ty={}, \
+    debug!("register_foreign_item_fn(abi={:?}, \
+            ty={:?}, \
             name={})",
-           abi.repr(ccx.tcx()),
-           fty.repr(ccx.tcx()),
+           abi,
+           fty,
            name);
 
     let cc = llvm_calling_convention(ccx, abi);
@@ -233,12 +232,11 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                      -> Block<'blk, 'tcx>
 {
     let ccx = bcx.ccx();
-    let tcx = bcx.tcx();
 
-    debug!("trans_native_call(callee_ty={}, \
+    debug!("trans_native_call(callee_ty={:?}, \
             llfn={}, \
             llretptr={})",
-           callee_ty.repr(tcx),
+           callee_ty,
            ccx.tn().val_to_string(llfn),
            ccx.tn().val_to_string(llretptr));
 
@@ -610,16 +608,16 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 assert!(f.abi != Rust && f.abi != RustIntrinsic);
             }
             _ => {
-                ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {}, \
+                ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \
                                         expected a bare fn ty",
                                        ccx.tcx().map.path_to_string(id),
-                                       t.repr(tcx)));
+                                       t));
             }
         };
 
-        debug!("build_rust_fn: path={} id={} t={}",
+        debug!("build_rust_fn: path={} id={} t={:?}",
                ccx.tcx().map.path_to_string(id),
-               id, t.repr(tcx));
+               id, t);
 
         let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
             ccx.sess().bug(&format!("symbol `{}` already defined", ps));
@@ -636,12 +634,11 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                       t: Ty<'tcx>) {
         let _icx = push_ctxt(
             "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
-        let tcx = ccx.tcx();
 
-        debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={})",
+        debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={:?})",
                ccx.tn().val_to_string(llrustfn),
                ccx.tn().val_to_string(llwrapfn),
-               t.repr(ccx.tcx()));
+               t);
 
         // Avoid all the Rust generation stuff and just generate raw
         // LLVM here.
@@ -723,10 +720,10 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     debug!("out pointer, \
                             allocad={}, \
                             llrust_ret_ty={}, \
-                            return_ty={}",
+                            return_ty={:?}",
                            ccx.tn().val_to_string(slot),
                            ccx.tn().type_to_string(llrust_ret_ty),
-                           tys.fn_sig.output.repr(tcx));
+                           tys.fn_sig.output);
                     llrust_args.push(slot);
                     return_alloca = Some(slot);
                 }
@@ -817,8 +814,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
 
         // Perform the call itself
-        debug!("calling llrustfn = {}, t = {}",
-               ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx()));
+        debug!("calling llrustfn = {}, t = {:?}",
+               ccx.tn().val_to_string(llrustfn), t);
         let attributes = attributes::from_fn_type(ccx, t);
         let llrust_ret_val = builder.call(llrustfn, &llrust_args, Some(attributes));
 
@@ -936,11 +933,11 @@ fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                        llsig.llret_ty,
                                        llsig.ret_def);
     debug!("foreign_types_for_fn_ty(\
-           ty={}, \
+           ty={:?}, \
            llsig={} -> {}, \
            fn_ty={} -> {}, \
            ret_def={}",
-           ty.repr(ccx.tcx()),
+           ty,
            ccx.tn().types_to_str(&llsig.llarg_tys),
            ccx.tn().type_to_string(llsig.llret_ty),
            ccx.tn().types_to_str(&fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>()),
diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs
index c7f5b86412c..6caf00634b6 100644
--- a/src/librustc_trans/trans/glue.rs
+++ b/src/librustc_trans/trans/glue.rs
@@ -39,8 +39,6 @@ use trans::machine::*;
 use trans::monomorphize;
 use trans::type_of::{type_of, type_of_dtor, sizing_type_of, align_of};
 use trans::type_::Type;
-use util::ppaux;
-use util::ppaux::{ty_to_short_str, Repr};
 
 use arena::TypedArena;
 use libc::c_uint;
@@ -141,7 +139,7 @@ pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 debug_loc: DebugLoc,
                                 skip_dtor: bool) -> Block<'blk, 'tcx> {
     // NB: v is an *alias* of type t here, not a direct value.
-    debug!("drop_ty_core(t={}, skip_dtor={})", t.repr(bcx.tcx()), skip_dtor);
+    debug!("drop_ty_core(t={:?}, skip_dtor={})", t, skip_dtor);
     let _icx = push_ctxt("drop_ty");
     if bcx.fcx.type_needs_drop(t) {
         let ccx = bcx.ccx();
@@ -204,21 +202,13 @@ impl<'tcx> DropGlueKind<'tcx> {
             DropGlueKind::TyContents(t) => DropGlueKind::TyContents(f(t)),
         }
     }
-
-    fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
-        let t_str = ppaux::ty_to_string(ccx.tcx(), self.ty());
-        match *self {
-            DropGlueKind::Ty(_) => format!("DropGlueKind::Ty({})", t_str),
-            DropGlueKind::TyContents(_) => format!("DropGlueKind::TyContents({})", t_str),
-        }
-    }
 }
 
 fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 g: DropGlueKind<'tcx>) -> ValueRef {
-    debug!("make drop glue for {}", g.to_string(ccx));
+    debug!("make drop glue for {:?}", g);
     let g = g.map_ty(|t| get_drop_glue_type(ccx, t));
-    debug!("drop glue type {}", g.to_string(ccx));
+    debug!("drop glue type {:?}", g);
     match ccx.drop_glues().borrow().get(&g) {
         Some(&glue) => return glue,
         _ => { }
@@ -247,7 +237,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     });
     ccx.available_drop_glues().borrow_mut().insert(g, fn_nm);
 
-    let _s = StatRecorder::new(ccx, format!("drop {}", ty_to_short_str(ccx.tcx(), t)));
+    let _s = StatRecorder::new(ccx, format!("drop {:?}", t));
 
     let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
     let (arena, fcx): (TypedArena<_>, FunctionContext);
@@ -355,7 +345,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  substs: &subst::Substs<'tcx>)
                                  -> Block<'blk, 'tcx>
 {
-    debug!("trans_struct_drop t: {}", bcx.ty_to_string(t));
+    debug!("trans_struct_drop t: {}", t);
 
     // Find and call the actual destructor
     let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t, class_did, substs);
@@ -390,7 +380,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
                                          -> (ValueRef, ValueRef) {
     debug!("calculate size of DST: {}; with lost info: {}",
-           bcx.ty_to_string(t), bcx.val_to_string(info));
+           t, bcx.val_to_string(info));
     if type_is_sized(bcx.tcx(), t) {
         let sizing_type = sizing_type_of(bcx.ccx(), t);
         let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
@@ -445,8 +435,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
             (Mul(bcx, info, C_uint(bcx.ccx(), unit_size), DebugLoc::None),
              C_uint(bcx.ccx(), unit_align))
         }
-        _ => bcx.sess().bug(&format!("Unexpected unsized type, found {}",
-                                    bcx.ty_to_string(t)))
+        _ => bcx.sess().bug(&format!("Unexpected unsized type, found {}", t))
     }
 }
 
@@ -520,8 +509,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                         // stupid and dangerous.
                         bcx.sess().warn(&format!("Ignoring drop flag in destructor for {}\
                                                  because the struct is unsized. See issue\
-                                                 #16758",
-                                                bcx.ty_to_string(t)));
+                                                 #16758", t));
                         trans_struct_drop(bcx, t, v0, dtor, did, substs)
                     }
                 }
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index 419ab1bb05d..41d150ac265 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -34,7 +34,6 @@ use middle::ty::{self, Ty};
 use syntax::abi::RustIntrinsic;
 use syntax::ast;
 use syntax::parse::token;
-use util::ppaux::{Repr, ty_to_string};
 
 pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Option<ValueRef> {
     let name = match &token::get_ident(item.ident)[..] {
@@ -102,7 +101,7 @@ pub fn check_intrinsics(ccx: &CrateContext) {
             continue;
         }
 
-        debug!("transmute_restriction: {}", transmute_restriction.repr(ccx.tcx()));
+        debug!("transmute_restriction: {:?}", transmute_restriction);
 
         assert!(!ty::type_has_params(transmute_restriction.substituted_from));
         assert!(!ty::type_has_params(transmute_restriction.substituted_to));
@@ -121,10 +120,10 @@ pub fn check_intrinsics(ccx: &CrateContext) {
                     transmute_restriction.span,
                     &format!("transmute called on types with potentially different sizes: \
                               {} (could be {} bit{}) to {} (could be {} bit{})",
-                             ty_to_string(ccx.tcx(), transmute_restriction.original_from),
+                             transmute_restriction.original_from,
                              from_type_size as usize,
                              if from_type_size == 1 {""} else {"s"},
-                             ty_to_string(ccx.tcx(), transmute_restriction.original_to),
+                             transmute_restriction.original_to,
                              to_type_size as usize,
                              if to_type_size == 1 {""} else {"s"}));
             } else {
@@ -132,10 +131,10 @@ pub fn check_intrinsics(ccx: &CrateContext) {
                     transmute_restriction.span,
                     &format!("transmute called on types with different sizes: \
                               {} ({} bit{}) to {} ({} bit{})",
-                             ty_to_string(ccx.tcx(), transmute_restriction.original_from),
+                             transmute_restriction.original_from,
                              from_type_size as usize,
                              if from_type_size == 1 {""} else {"s"},
-                             ty_to_string(ccx.tcx(), transmute_restriction.original_to),
+                             transmute_restriction.original_to,
                              to_type_size as usize,
                              if to_type_size == 1 {""} else {"s"}));
             }
@@ -405,7 +404,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
         (_, "type_name") => {
             let tp_ty = *substs.types.get(FnSpace, 0);
-            let ty_name = token::intern_and_get_ident(&ty_to_string(ccx.tcx(), tp_ty));
+            let ty_name = token::intern_and_get_ident(&tp_ty.to_string());
             C_str_slice(ccx, ty_name)
         }
         (_, "type_id") => {
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 7827771994f..eca6eecff42 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -39,7 +39,6 @@ use trans::type_::Type;
 use trans::type_of::*;
 use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
-use util::ppaux::Repr;
 
 use syntax::abi::{Rust, RustCall};
 use syntax::parse::token;
@@ -62,7 +61,7 @@ pub fn trans_impl(ccx: &CrateContext,
     let _icx = push_ctxt("meth::trans_impl");
     let tcx = ccx.tcx();
 
-    debug!("trans_impl(name={}, id={})", name.repr(tcx), id);
+    debug!("trans_impl(name={}, id={})", name, id);
 
     let mut v = TransItemVisitor { ccx: ccx };
 
@@ -136,15 +135,15 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }) => {
             let trait_ref = ty::Binder(bcx.monomorphize(trait_ref));
             let span = bcx.tcx().map.span(method_call.expr_id);
-            debug!("method_call={:?} trait_ref={} trait_ref id={:?} substs={:?}",
+            debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
                    method_call,
-                   trait_ref.repr(bcx.tcx()),
+                   trait_ref,
                    trait_ref.0.def_id,
                    trait_ref.0.substs);
             let origin = fulfill_obligation(bcx.ccx(),
                                             span,
                                             trait_ref.clone());
-            debug!("origin = {}", origin.repr(bcx.tcx()));
+            debug!("origin = {:?}", origin);
             trans_monomorphized_callee(bcx,
                                        method_call,
                                        trait_ref.def_id(),
@@ -234,7 +233,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                              rcvr_self,
                                              Vec::new()));
     let trait_substs = tcx.mk_substs(trait_substs);
-    debug!("trait_substs={}", trait_substs.repr(tcx));
+    debug!("trait_substs={:?}", trait_substs);
     let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
                                               substs: trait_substs });
     let vtbl = fulfill_obligation(ccx,
@@ -296,8 +295,8 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             immediate_rvalue(llfn, ty)
         }
         _ => {
-            tcx.sess.bug(&format!("static call to invalid vtable: {}",
-                                 vtbl.repr(tcx)));
+            tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
+                                 vtbl));
         }
     }
 }
@@ -390,8 +389,8 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         traits::VtableDefaultImpl(..) |
         traits::VtableParam(..) => {
             bcx.sess().bug(
-                &format!("resolved vtable bad vtable {} in trans",
-                        vtable.repr(bcx.tcx())));
+                &format!("resolved vtable bad vtable {:?} in trans",
+                        vtable));
         }
     }
 }
@@ -415,8 +414,8 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs);
 
-    debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx()));
-    debug!("node_substs={}", node_substs.repr(ccx.tcx()));
+    debug!("rcvr_substs={:?}", rcvr_substs);
+    debug!("node_substs={:?}", node_substs);
 
     // Break apart the type parameters from the node and type
     // parameters from the receiver.
@@ -484,7 +483,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Load the data pointer from the object.
     debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llpair={})",
-           callee_ty.repr(ccx.tcx()),
+           callee_ty,
            vtable_index,
            bcx.val_to_string(llpair));
     let llboxptr = GEPi(bcx, llpair, &[0, abi::FAT_PTR_ADDR]);
@@ -556,9 +555,9 @@ pub fn trans_object_shim<'a, 'tcx>(
     let tcx = ccx.tcx();
     let trait_id = upcast_trait_ref.def_id();
 
-    debug!("trans_object_shim(object_ty={}, upcast_trait_ref={}, method_offset_in_trait={})",
-           object_ty.repr(tcx),
-           upcast_trait_ref.repr(tcx),
+    debug!("trans_object_shim(object_ty={:?}, upcast_trait_ref={:?}, method_offset_in_trait={})",
+           object_ty,
+           upcast_trait_ref,
            method_offset_in_trait);
 
     let object_trait_ref =
@@ -567,15 +566,15 @@ pub fn trans_object_shim<'a, 'tcx>(
                 data.principal_trait_ref_with_self_ty(tcx, object_ty)
             }
             _ => {
-                tcx.sess.bug(&format!("trans_object_shim() called on non-object: {}",
-                                      object_ty.repr(tcx)));
+                tcx.sess.bug(&format!("trans_object_shim() called on non-object: {:?}",
+                                      object_ty));
             }
         };
 
     // Upcast to the trait in question and extract out the substitutions.
     let upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref);
     let object_substs = upcast_trait_ref.substs.clone().erase_regions();
-    debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx));
+    debug!("trans_object_shim: object_substs={:?}", object_substs);
 
     // Lookup the type of this method as declared in the trait and apply substitutions.
     let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) {
@@ -587,7 +586,7 @@ pub fn trans_object_shim<'a, 'tcx>(
     let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
     let fty = tcx.mk_bare_fn(fty);
     let method_ty = opaque_method_ty(tcx, fty);
-    debug!("trans_object_shim: fty={} method_ty={}", fty.repr(tcx), method_ty.repr(tcx));
+    debug!("trans_object_shim: fty={:?} method_ty={:?}", fty, method_ty);
 
     //
     let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty);
@@ -627,8 +626,8 @@ pub fn trans_object_shim<'a, 'tcx>(
                     ty::TyTuple(ref tys) => &**tys,
                     _ => {
                         bcx.sess().bug(
-                            &format!("rust-call expects a tuple not {}",
-                                     sig.inputs[1].repr(tcx)));
+                            &format!("rust-call expects a tuple not {:?}",
+                                     sig.inputs[1]));
                     }
                 }
             }
@@ -692,7 +691,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let tcx = ccx.tcx();
     let _icx = push_ctxt("meth::get_vtable");
 
-    debug!("get_vtable(trait_ref={})", trait_ref.repr(tcx));
+    debug!("get_vtable(trait_ref={:?})", trait_ref);
 
     // Check the cache.
     match ccx.vtables().borrow().get(&trait_ref) {
@@ -739,14 +738,14 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 // an object type; this cannot happen because we
                 // cannot cast an unsized type into a trait object
                 tcx.sess.bug(
-                    &format!("cannot get vtable for an object type: {}",
-                            data.repr(tcx)));
+                    &format!("cannot get vtable for an object type: {:?}",
+                            data));
             }
             traits::VtableParam(..) => {
                 tcx.sess.bug(
-                    &format!("resolved vtable for {} to bad vtable {} in trans",
-                            trait_ref.repr(tcx),
-                            vtable.repr(tcx)));
+                    &format!("resolved vtable for {:?} to bad vtable {:?} in trans",
+                            trait_ref,
+                            vtable));
             }
         }
     });
@@ -776,10 +775,10 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 {
     let tcx = ccx.tcx();
 
-    debug!("emit_vtable_methods(impl_id={}, substs={}, param_substs={})",
-           impl_id.repr(tcx),
-           substs.repr(tcx),
-           param_substs.repr(tcx));
+    debug!("emit_vtable_methods(impl_id={:?}, substs={:?}, param_substs={:?})",
+           impl_id,
+           substs,
+           param_substs);
 
     let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
         Some(t_id) => t_id.def_id,
@@ -806,8 +805,8 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // method could never be called from this object, just supply
         // null.
         .map(|trait_method_def_id| {
-            debug!("emit_vtable_methods: trait_method_def_id={}",
-                   trait_method_def_id.repr(tcx));
+            debug!("emit_vtable_methods: trait_method_def_id={:?}",
+                   trait_method_def_id);
 
             let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) {
                 ty::MethodTraitItem(m) => m,
@@ -821,8 +820,8 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 return nullptr;
             }
 
-            debug!("emit_vtable_methods: trait_method_type={}",
-                   trait_method_type.repr(tcx));
+            debug!("emit_vtable_methods: trait_method_type={:?}",
+                   trait_method_type);
 
             // The substitutions we have are on the impl, so we grab
             // the method type from the impl to substitute into.
@@ -832,8 +831,8 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 _ => ccx.sess().bug("should be a method, not other assoc item"),
             };
 
-            debug!("emit_vtable_methods: impl_method_type={}",
-                   impl_method_type.repr(tcx));
+            debug!("emit_vtable_methods: impl_method_type={:?}",
+                   impl_method_type);
 
             // If this is a default method, it's possible that it
             // relies on where clauses that do not hold for this
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index e28dd77d5e5..f4bad313baf 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -26,7 +26,6 @@ use trans::common::*;
 use trans::declare;
 use trans::foreign;
 use middle::ty::{self, HasProjectionTypes, Ty};
-use util::ppaux::Repr;
 
 use syntax::abi;
 use syntax::ast;
@@ -41,11 +40,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 ref_id: Option<ast::NodeId>)
     -> (ValueRef, Ty<'tcx>, bool) {
     debug!("monomorphic_fn(\
-            fn_id={}, \
-            real_substs={}, \
+            fn_id={:?}, \
+            real_substs={:?}, \
             ref_id={:?})",
-           fn_id.repr(ccx.tcx()),
-           psubsts.repr(ccx.tcx()),
+           fn_id,
+           psubsts,
            ref_id);
 
     assert!(psubsts.types.all(|t| {
@@ -61,7 +60,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty;
 
-    debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx()));
+    debug!("monomorphic_fn about to subst into {:?}", item_ty);
     let mono_ty = item_ty.subst(ccx.tcx(), psubsts);
 
     match ccx.monomorphized().borrow().get(&hash_id) {
@@ -74,11 +73,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 
     debug!("monomorphic_fn(\
-            fn_id={}, \
-            psubsts={}, \
+            fn_id={:?}, \
+            psubsts={:?}, \
             hash_id={:?})",
-           fn_id.repr(ccx.tcx()),
-           psubsts.repr(ccx.tcx()),
+           fn_id,
+           psubsts,
            hash_id);
 
 
@@ -99,10 +98,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
     }
 
-    debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));
+    debug!("mono_ty = {:?} (post-substitution)", mono_ty);
 
     let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
-    debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx()));
+    debug!("mono_ty = {:?} (post-normalization)", mono_ty);
 
     ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
 
@@ -303,7 +302,7 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
                                   param_substs: &Substs<'tcx>,
                                   value: &T)
                                   -> T
-    where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+    where T : TypeFoldable<'tcx> + HasProjectionTypes
 {
     let substituted = value.subst(tcx, param_substs);
     normalize_associated_type(tcx, &substituted)
@@ -314,9 +313,9 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
 /// and hence we can be sure that all associated types will be
 /// completely normalized away.
 pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
-    where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+    where T : TypeFoldable<'tcx> + HasProjectionTypes
 {
-    debug!("normalize_associated_type(t={})", value.repr(tcx));
+    debug!("normalize_associated_type(t={:?})", value);
 
     let value = erase_regions(tcx, value);
 
@@ -333,9 +332,9 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
     let traits::Normalized { value: result, obligations } =
         traits::normalize(&mut selcx, cause, &value);
 
-    debug!("normalize_associated_type: result={} obligations={}",
-           result.repr(tcx),
-           obligations.repr(tcx));
+    debug!("normalize_associated_type: result={:?} obligations={:?}",
+           result,
+           obligations);
 
     let mut fulfill_cx = traits::FulfillmentContext::new(true);
     for obligation in obligations {
diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs
index 3df6c904c7b..bba0f6d2608 100644
--- a/src/librustc_trans/trans/tvec.rs
+++ b/src/librustc_trans/trans/tvec.rs
@@ -28,7 +28,6 @@ use trans::machine::llsize_of_alloc;
 use trans::type_::Type;
 use trans::type_of;
 use middle::ty::{self, Ty};
-use util::ppaux::ty_to_string;
 
 use syntax::ast;
 use syntax::parse::token::InternedString;
@@ -42,7 +41,7 @@ struct VecTypes<'tcx> {
 impl<'tcx> VecTypes<'tcx> {
     pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
         format!("VecTypes {{unit_ty={}, llunit_ty={}}}",
-                ty_to_string(ccx.tcx(), self.unit_ty),
+                self.unit_ty,
                 ccx.tn().type_to_string(self.llunit_ty))
     }
 }
@@ -58,8 +57,8 @@ pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // to store the array of the suitable size, so all we have to do is
     // generate the content.
 
-    debug!("trans_fixed_vstore(expr={}, dest={})",
-           bcx.expr_to_string(expr), dest.to_string(bcx.ccx()));
+    debug!("trans_fixed_vstore(expr={:?}, dest={})",
+           expr, dest.to_string(bcx.ccx()));
 
     let vt = vec_types_from_expr(bcx, expr);
 
@@ -85,8 +84,8 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let ccx = fcx.ccx;
     let mut bcx = bcx;
 
-    debug!("trans_slice_vec(slice_expr={})",
-           bcx.expr_to_string(slice_expr));
+    debug!("trans_slice_vec(slice_expr={:?})",
+           slice_expr);
 
     let vec_ty = node_id_type(bcx, slice_expr.id);
 
@@ -139,8 +138,8 @@ pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  str_lit: InternedString,
                                  dest: Dest)
                                  -> Block<'blk, 'tcx> {
-    debug!("trans_lit_str(lit_expr={}, dest={})",
-           bcx.expr_to_string(lit_expr),
+    debug!("trans_lit_str(lit_expr={:?}, dest={})",
+           lit_expr,
            dest.to_string(bcx.ccx()));
 
     match dest {
@@ -167,10 +166,10 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let fcx = bcx.fcx;
     let mut bcx = bcx;
 
-    debug!("write_content(vt={}, dest={}, vstore_expr={})",
+    debug!("write_content(vt={}, dest={}, vstore_expr={:?})",
            vt.to_string(bcx.ccx()),
            dest.to_string(bcx.ccx()),
-           bcx.expr_to_string(vstore_expr));
+           vstore_expr);
 
     match content_expr.node {
         ast::ExprLit(ref lit) => {
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index 763d0581d6f..26b54142d63 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -16,8 +16,6 @@ use trans::common::*;
 use trans::foreign;
 use trans::machine;
 use middle::ty::{self, RegionEscape, Ty};
-use util::ppaux;
-use util::ppaux::Repr;
 
 use trans::type_::Type;
 
@@ -100,8 +98,8 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                  abi: abi::Abi)
                                  -> Type
 {
-    debug!("type_of_rust_fn(sig={},abi={:?})",
-           sig.repr(cx.tcx()),
+    debug!("type_of_rust_fn(sig={:?},abi={:?})",
+           sig,
            abi);
 
     let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
@@ -229,8 +227,8 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
         }
 
         ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | ty::TyError(..) => {
-            cx.sess().bug(&format!("fictitious type {} in sizing_type_of()",
-                                  ppaux::ty_to_string(cx.tcx(), t)))
+            cx.sess().bug(&format!("fictitious type {:?} in sizing_type_of()",
+                                   t))
         }
         ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => unreachable!()
     };
@@ -299,7 +297,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
         None => ()
     }
 
-    debug!("type_of {} {:?}", t.repr(cx.tcx()), t.sty);
+    debug!("type_of {:?}", t);
 
     assert!(!t.has_escaping_regions());
 
@@ -312,10 +310,10 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 
     if t != t_norm {
         let llty = in_memory_type_of(cx, t_norm);
-        debug!("--> normalized {} {:?} to {} {:?} llty={}",
-                t.repr(cx.tcx()),
+        debug!("--> normalized {:?} {:?} to {:?} {:?} llty={}",
                 t,
-                t_norm.repr(cx.tcx()),
+                t,
+                t_norm,
                 t_norm,
                 cx.tn().type_to_string(llty));
         cx.lltypes().borrow_mut().insert(t, llty);
@@ -364,8 +362,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
                       }
                       ty::TyTrait(_) => Type::vtable_ptr(cx),
                       _ => panic!("Unexpected type returned from \
-                                   struct_tail: {} for ty={}",
-                                  unsized_part.repr(cx.tcx()), ty.repr(cx.tcx()))
+                                   struct_tail: {:?} for ty={:?}",
+                                  unsized_part, ty)
                   };
                   Type::struct_(cx, &[ptr_ty, info_ty], false)
               }
@@ -419,8 +417,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TyError(..) => cx.sess().bug("type_of with TyError"),
     };
 
-    debug!("--> mapped t={} {:?} to llty={}",
-            t.repr(cx.tcx()),
+    debug!("--> mapped t={:?} {:?} to llty={}",
+            t,
             t,
             cx.tn().type_to_string(llty));
 
@@ -450,7 +448,7 @@ fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                             tps: &[Ty<'tcx>])
                             -> String {
     let base = ty::item_path_str(cx.tcx(), did);
-    let strings: Vec<String> = tps.iter().map(|t| t.repr(cx.tcx())).collect();
+    let strings: Vec<String> = tps.iter().map(|t| t.to_string()).collect();
     let tstr = if strings.is_empty() {
         base
     } else {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index cb3d5bd9bf9..8e838d991fb 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -61,7 +61,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::FnvHashSet;
-use util::ppaux::{self, Repr, UserString};
 
 use std::iter::repeat;
 use std::slice;
@@ -178,10 +177,10 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
         }
     };
 
-    debug!("ast_region_to_region(lifetime={} id={}) yields {}",
-           lifetime.repr(tcx),
+    debug!("ast_region_to_region(lifetime={:?} id={}) yields {:?}",
+           lifetime,
            lifetime.id,
-           r.repr(tcx));
+           r);
 
     r
 }
@@ -256,9 +255,9 @@ pub fn opt_ast_region_to_region<'tcx>(
         }
     };
 
-    debug!("opt_ast_region_to_region(opt_lifetime={}) yields {}",
-            opt_lifetime.repr(this.tcx()),
-            r.repr(this.tcx()));
+    debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}",
+            opt_lifetime,
+            r);
 
     r
 }
@@ -373,10 +372,10 @@ fn create_substs_for_ast_path<'tcx>(
 {
     let tcx = this.tcx();
 
-    debug!("create_substs_for_ast_path(decl_generics={}, self_ty={}, \
-           types_provided={}, region_substs={}",
-           decl_generics.repr(tcx), self_ty.repr(tcx), types_provided.repr(tcx),
-           region_substs.repr(tcx));
+    debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
+           types_provided={:?}, region_substs={:?}",
+           decl_generics, self_ty, types_provided,
+           region_substs);
 
     assert_eq!(region_substs.regions().len(TypeSpace), decl_generics.regions.len(TypeSpace));
     assert!(region_substs.types.is_empty());
@@ -441,8 +440,8 @@ fn create_substs_for_ast_path<'tcx>(
                           "the type parameter `{}` must be explicitly specified \
                            in an object type because its default value `{}` references \
                            the type `Self`",
-                          param.name.user_string(tcx),
-                          default.user_string(tcx));
+                          param.name,
+                          default);
                 substs.types.push(TypeSpace, tcx.types.err);
             } else {
                 // This is a default type parameter.
@@ -649,7 +648,7 @@ fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::D
         def::DefTrait(trait_def_id) => trait_def_id,
         _ => {
             span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
-                        path.user_string(this.tcx()));
+                        path);
         }
     }
 }
@@ -879,7 +878,7 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>(
 
     let candidate = try!(one_bound_for_assoc_type(tcx,
                                                   candidates,
-                                                  &trait_ref.user_string(tcx),
+                                                  &trait_ref.to_string(),
                                                   &token::get_name(binding.item_name),
                                                   binding.span));
 
@@ -985,19 +984,21 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
             });
             match (&ty.node, full_span) {
                 (&ast::TyRptr(None, ref mut_ty), Some(full_span)) => {
+                    let mutbl_str = if mut_ty.mutbl == ast::MutMutable { "mut " } else { "" };
                     this.tcx().sess
                         .span_suggestion(full_span, "try adding parentheses (per RFC 438):",
                                          format!("&{}({} +{})",
-                                                 ppaux::mutability_to_string(mut_ty.mutbl),
+                                                 mutbl_str,
                                                  pprust::ty_to_string(&*mut_ty.ty),
                                                  pprust::bounds_to_string(bounds)));
                 }
                 (&ast::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
+                    let mutbl_str = if mut_ty.mutbl == ast::MutMutable { "mut " } else { "" };
                     this.tcx().sess
                         .span_suggestion(full_span, "try adding parentheses (per RFC 438):",
                                          format!("&{} {}({} +{})",
                                                  pprust::lifetime_to_string(lt),
-                                                 ppaux::mutability_to_string(mut_ty.mutbl),
+                                                 mutbl_str,
                                                  pprust::ty_to_string(&*mut_ty.ty),
                                                  pprust::bounds_to_string(bounds)));
                 }
@@ -1028,8 +1029,8 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
                                                      bounds);
 
     let result = make_object_type(this, span, trait_ref, existential_bounds);
-    debug!("trait_ref_to_object_type: result={}",
-           result.repr(this.tcx()));
+    debug!("trait_ref_to_object_type: result={:?}",
+           result);
 
     result
 }
@@ -1072,7 +1073,7 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>,
     for (trait_def_id, name) in associated_types {
         span_err!(tcx.sess, span, E0191,
             "the value of the associated type `{}` (from the trait `{}`) must be specified",
-                    name.user_string(tcx),
+                    name,
                     ty::item_path_str(tcx, trait_def_id));
     }
 
@@ -1158,7 +1159,7 @@ fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>,
             span_note!(tcx.sess, span,
                        "associated type `{}` could derive from `{}`",
                        ty_param_name,
-                       bound.user_string(tcx));
+                       bound);
         }
     }
 
@@ -1181,7 +1182,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
     let tcx = this.tcx();
     let assoc_name = item_segment.identifier.name;
 
-    debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name));
+    debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
 
     check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
 
@@ -1237,7 +1238,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
         _ => {
             report_ambiguous_associated_type(tcx,
                                              span,
-                                             &ty.user_string(tcx),
+                                             &ty.to_string(),
                                              "Trait",
                                              &token::get_name(assoc_name));
             return (tcx.types.err, ty_path_def);
@@ -1294,7 +1295,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
         return tcx.types.err;
     };
 
-    debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
+    debug!("qpath_to_ty: self_type={:?}", self_ty);
 
     let trait_ref = ast_path_to_mono_trait_ref(this,
                                                rscope,
@@ -1304,7 +1305,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
                                                Some(self_ty),
                                                trait_segment);
 
-    debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
+    debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
 
     this.projected_ty(span, trait_ref, item_segment.identifier.name)
 }
@@ -1493,8 +1494,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
                           ast_ty: &ast::Ty)
                           -> Ty<'tcx>
 {
-    debug!("ast_ty_to_ty(ast_ty={})",
-           ast_ty.repr(this.tcx()));
+    debug!("ast_ty_to_ty(ast_ty={:?})",
+           ast_ty);
 
     let tcx = this.tcx();
 
@@ -1529,7 +1530,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
         }
         ast::TyRptr(ref region, ref mt) => {
             let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
-            debug!("TyRef r={}", r.repr(this.tcx()));
+            debug!("TyRef r={:?}", r);
             let rscope1 =
                 &ObjectLifetimeDefaultRscope::new(
                     rscope,
@@ -1566,8 +1567,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
                     depth: path.segments.len()
                 }
             } else {
-                tcx.sess.span_bug(ast_ty.span,
-                                  &format!("unbound path {}", ast_ty.repr(tcx)))
+                tcx.sess.span_bug(ast_ty.span, &format!("unbound path {:?}", ast_ty))
             };
             let def = path_res.base_def;
             let base_ty_end = path.segments.len() - path_res.depth;
@@ -1841,11 +1841,11 @@ fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>,
             let impl_modifiers = count_modifiers(self_info.untransformed_self_ty);
             let method_modifiers = count_modifiers(explicit_type);
 
-            debug!("determine_explicit_self_category(self_info.untransformed_self_ty={} \
-                   explicit_type={} \
+            debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \
+                   explicit_type={:?} \
                    modifiers=({},{})",
-                   self_info.untransformed_self_ty.repr(this.tcx()),
-                   explicit_type.repr(this.tcx()),
+                   self_info.untransformed_self_ty,
+                   explicit_type,
                    impl_modifiers,
                    method_modifiers);
 
@@ -1878,8 +1878,8 @@ pub fn ty_of_closure<'tcx>(
     expected_sig: Option<ty::FnSig<'tcx>>)
     -> ty::ClosureTy<'tcx>
 {
-    debug!("ty_of_closure(expected_sig={})",
-           expected_sig.repr(this.tcx()));
+    debug!("ty_of_closure(expected_sig={:?})",
+           expected_sig);
 
     // new region names that appear inside of the fn decl are bound to
     // that function type
@@ -1917,8 +1917,8 @@ pub fn ty_of_closure<'tcx>(
         ast::NoReturn(..) => ty::FnDiverging
     };
 
-    debug!("ty_of_closure: input_tys={}", input_tys.repr(this.tcx()));
-    debug!("ty_of_closure: output_ty={}", output_ty.repr(this.tcx()));
+    debug!("ty_of_closure: input_tys={:?}", input_tys);
+    debug!("ty_of_closure: output_ty={:?}", output_ty);
 
     ty::ClosureTy {
         unsafety: unsafety,
@@ -2035,10 +2035,10 @@ fn compute_object_lifetime_bound<'tcx>(
     let tcx = this.tcx();
 
     debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
-           principal_trait_ref={}, builtin_bounds={})",
+           principal_trait_ref={:?}, builtin_bounds={:?})",
            explicit_region_bounds,
-           principal_trait_ref.repr(tcx),
-           builtin_bounds.repr(tcx));
+           principal_trait_ref,
+           builtin_bounds);
 
     if explicit_region_bounds.len() > 1 {
         span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
@@ -2104,7 +2104,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
                             ast_bounds: &'a [ast::TyParamBound])
                             -> PartitionedBounds<'a>
 {
-    let mut builtin_bounds = ty::empty_builtin_bounds();
+    let mut builtin_bounds = ty::BuiltinBounds::empty();
     let mut region_bounds = Vec::new();
     let mut trait_bounds = Vec::new();
     for ast_bound in ast_bounds {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 2f1447e0714..cf086a32ae5 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -22,7 +22,6 @@ use check::{check_expr_with_lvalue_pref, LvaluePreference};
 use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
 use require_same_types;
 use util::nodemap::FnvHashMap;
-use util::ppaux::Repr;
 
 use std::cmp::{self, Ordering};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -40,9 +39,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     let fcx = pcx.fcx;
     let tcx = pcx.fcx.ccx.tcx;
 
-    debug!("check_pat(pat={},expected={})",
-           pat.repr(tcx),
-           expected.repr(tcx));
+    debug!("check_pat(pat={:?},expected={:?})",
+           pat,
+           expected);
 
     match pat.node {
         ast::PatWild(_) => {
@@ -222,7 +221,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                 }
             } else {
                 tcx.sess.span_bug(pat.span,
-                                  &format!("unbound path {}", pat.repr(tcx)))
+                                  &format!("unbound path {:?}", pat))
             };
             if let Some((opt_ty, segments, def)) =
                     resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs
index 377af080526..df9fe6b002e 100644
--- a/src/librustc_typeck/check/assoc.rs
+++ b/src/librustc_typeck/check/assoc.rs
@@ -12,10 +12,9 @@ use middle::infer::InferCtxt;
 use middle::traits::{self, FulfillmentContext, Normalized, MiscObligation,
                      SelectionContext, ObligationCause};
 use middle::ty::{self, HasProjectionTypes};
-use middle::ty_fold::{TypeFoldable, TypeFolder};
+use middle::ty_fold::TypeFoldable;
 use syntax::ast;
 use syntax::codemap::Span;
-use util::ppaux::Repr;
 
 pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                                 typer: &(ty::ClosureTyper<'tcx>+'a),
@@ -24,15 +23,15 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                                 body_id: ast::NodeId,
                                                 value: &T)
                                                 -> T
-    where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+    where T : TypeFoldable<'tcx> + HasProjectionTypes
 {
-    debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
+    debug!("normalize_associated_types_in(value={:?})", value);
     let mut selcx = SelectionContext::new(infcx, typer);
     let cause = ObligationCause::new(span, body_id, MiscObligation);
     let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
-    debug!("normalize_associated_types_in: result={} predicates={}",
-           result.repr(infcx.tcx),
-           obligations.repr(infcx.tcx));
+    debug!("normalize_associated_types_in: result={:?} predicates={:?}",
+           result,
+           obligations);
     for obligation in obligations {
         fulfillment_cx.register_predicate_obligation(infcx, obligation);
     }
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index aa2433a362a..e7271d2fa88 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -32,7 +32,6 @@ use syntax::ast;
 use syntax::codemap::Span;
 use syntax::parse::token;
 use syntax::ptr::P;
-use util::ppaux::Repr;
 
 /// Check that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
@@ -120,9 +119,9 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                       autoderefs: usize)
                                       -> Option<CallStep<'tcx>>
 {
-    debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})",
-           call_expr.repr(fcx.tcx()),
-           adjusted_ty.repr(fcx.tcx()),
+    debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
+           call_expr,
+           adjusted_ty,
            autoderefs);
 
     // If the callee is a bare function or a closure, then we're all set.
@@ -328,6 +327,7 @@ fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
 }
 
+#[derive(Debug)]
 struct CallResolution<'tcx> {
     call_expr: &'tcx ast::Expr,
     callee_expr: &'tcx ast::Expr,
@@ -337,23 +337,10 @@ struct CallResolution<'tcx> {
     closure_def_id: ast::DefId,
 }
 
-impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \
-                autoderefs={}, fn_sig={}, closure_def_id={})",
-                self.call_expr.repr(tcx),
-                self.callee_expr.repr(tcx),
-                self.adjusted_ty.repr(tcx),
-                self.autoderefs,
-                self.fn_sig.repr(tcx),
-                self.closure_def_id.repr(tcx))
-    }
-}
-
 impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
     fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
-        debug!("DeferredCallResolution::resolve() {}",
-               self.repr(fcx.tcx()));
+        debug!("DeferredCallResolution::resolve() {:?}",
+               self);
 
         // we should not be invoked until the closure kind has been
         // determined by upvar inference
@@ -375,8 +362,8 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
                     ty::no_late_bound_regions(fcx.tcx(),
                                               ty::ty_fn_sig(method_callee.ty)).unwrap();
 
-                debug!("attempt_resolution: method_callee={}",
-                       method_callee.repr(fcx.tcx()));
+                debug!("attempt_resolution: method_callee={:?}",
+                       method_callee);
 
                 for (&method_arg_ty, &self_arg_ty) in
                     method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 9fefd7ac036..9522a21b69e 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -45,7 +45,6 @@ use middle::ty::Ty;
 use syntax::ast;
 use syntax::ast::UintTy::{TyU8};
 use syntax::codemap::Span;
-use util::ppaux::Repr;
 
 /// Reifies a cast check to be checked once we have full type information for
 /// a function context.
@@ -192,8 +191,8 @@ impl<'tcx> CastCheck<'tcx> {
         self.expr_ty = structurally_resolved_type(fcx, self.span, self.expr_ty);
         self.cast_ty = structurally_resolved_type(fcx, self.span, self.cast_ty);
 
-        debug!("check_cast({}, {} as {})", self.expr.id, self.expr_ty.repr(fcx.tcx()),
-               self.cast_ty.repr(fcx.tcx()));
+        debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty,
+               self.cast_ty);
 
         if ty::type_is_error(self.expr_ty) || ty::type_is_error(self.cast_ty) {
             // No sense in giving duplicate error messages
@@ -273,8 +272,8 @@ impl<'tcx> CastCheck<'tcx> {
                               m_cast: &'tcx ty::mt<'tcx>)
                               -> Result<CastKind, CastError>
     {
-        debug!("check_ptr_ptr_cast m_expr={} m_cast={}",
-               m_expr.repr(fcx.tcx()), m_cast.repr(fcx.tcx()));
+        debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}",
+               m_expr, m_cast);
         // ptr-ptr cast. vtables must match.
 
         // Cast to sized is OK
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index cac0a86124e..10b2459b220 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -20,7 +20,6 @@ use std::cmp;
 use syntax::abi;
 use syntax::ast;
 use syntax::ast_util;
-use util::ppaux::Repr;
 
 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                    expr: &ast::Expr,
@@ -28,9 +27,9 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                    decl: &'tcx ast::FnDecl,
                                    body: &'tcx ast::Block,
                                    expected: Expectation<'tcx>) {
-    debug!("check_expr_closure(expr={},expected={})",
-           expr.repr(fcx.tcx()),
-           expected.repr(fcx.tcx()));
+    debug!("check_expr_closure(expr={:?},expected={:?})",
+           expr,
+           expected);
 
     // It's always helpful for inference if we know the kind of
     // closure sooner rather than later, so first examine the expected
@@ -50,9 +49,9 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                           expected_sig: Option<ty::FnSig<'tcx>>) {
     let expr_def_id = ast_util::local_def(expr.id);
 
-    debug!("check_closure opt_kind={:?} expected_sig={}",
+    debug!("check_closure opt_kind={:?} expected_sig={:?}",
            opt_kind,
-           expected_sig.repr(fcx.tcx()));
+           expected_sig);
 
     let mut fn_ty = astconv::ty_of_closure(
         fcx,
@@ -86,9 +85,9 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     // the `closures` table.
     fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
 
-    debug!("closure for {} --> sig={} opt_kind={:?}",
-           expr_def_id.repr(fcx.tcx()),
-           fn_ty.sig.repr(fcx.tcx()),
+    debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
+           expr_def_id,
+           fn_ty.sig,
            opt_kind);
 
     fcx.inh.closure_tys.borrow_mut().insert(expr_def_id, fn_ty);
@@ -103,8 +102,8 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
     expected_ty: Ty<'tcx>)
     -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
 {
-    debug!("deduce_expectations_from_expected_type(expected_ty={})",
-           expected_ty.repr(fcx.tcx()));
+    debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
+           expected_ty);
 
     match expected_ty.sty {
         ty::TyTrait(ref object_type) => {
@@ -138,8 +137,8 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
         .pending_obligations()
         .iter()
         .filter_map(|obligation| {
-            debug!("deduce_expectations_from_obligations: obligation.predicate={}",
-                   obligation.predicate.repr(fcx.tcx()));
+            debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
+                   obligation.predicate);
 
             match obligation.predicate {
                 // Given a Projection predicate, we can potentially infer
@@ -200,8 +199,8 @@ fn deduce_sig_from_projection<'a,'tcx>(
 {
     let tcx = fcx.tcx();
 
-    debug!("deduce_sig_from_projection({})",
-           projection.repr(tcx));
+    debug!("deduce_sig_from_projection({:?})",
+           projection);
 
     let trait_ref = projection.to_poly_trait_ref();
 
@@ -211,24 +210,24 @@ fn deduce_sig_from_projection<'a,'tcx>(
 
     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
     let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
-    debug!("deduce_sig_from_projection: arg_param_ty {}", arg_param_ty.repr(tcx));
+    debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
 
     let input_tys = match arg_param_ty.sty {
         ty::TyTuple(ref tys) => { (*tys).clone() }
         _ => { return None; }
     };
-    debug!("deduce_sig_from_projection: input_tys {}", input_tys.repr(tcx));
+    debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
 
     let ret_param_ty = projection.0.ty;
     let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
-    debug!("deduce_sig_from_projection: ret_param_ty {}", ret_param_ty.repr(tcx));
+    debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
 
     let fn_sig = ty::FnSig {
         inputs: input_tys,
         output: ty::FnConverging(ret_param_ty),
         variadic: false
     };
-    debug!("deduce_sig_from_projection: fn_sig {}", fn_sig.repr(tcx));
+    debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
 
     Some(fn_sig)
 }
@@ -240,9 +239,9 @@ fn self_type_matches_expected_vid<'a,'tcx>(
     -> Option<ty::PolyTraitRef<'tcx>>
 {
     let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
-    debug!("self_type_matches_expected_vid(trait_ref={}, self_ty={})",
-           trait_ref.repr(fcx.tcx()),
-           self_ty.repr(fcx.tcx()));
+    debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
+           trait_ref,
+           self_ty);
     match self_ty.sty {
         ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
         _ => None,
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 2c332b65a48..785202de921 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -69,7 +69,6 @@ use middle::ty::{AutoDerefRef, AdjustDerefRef};
 use middle::ty::{self, mt, Ty};
 use middle::ty_relate::RelateResult;
 use util::common::indent;
-use util::ppaux::Repr;
 
 use std::cell::RefCell;
 use std::collections::VecDeque;
@@ -104,9 +103,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
               a: Ty<'tcx>,
               b: Ty<'tcx>)
               -> CoerceResult<'tcx> {
-        debug!("Coerce.tys({} => {})",
-               a.repr(self.tcx()),
-               b.repr(self.tcx()));
+        debug!("Coerce.tys({:?} => {:?})",
+               a,
+               b);
 
         // Consider coercing the subtype to a DST
         let unsize = self.unpack_actual_value(a, |a| {
@@ -166,9 +165,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                                b: Ty<'tcx>,
                                mutbl_b: ast::Mutability)
                                -> CoerceResult<'tcx> {
-        debug!("coerce_borrowed_pointer(a={}, b={})",
-               a.repr(self.tcx()),
-               b.repr(self.tcx()));
+        debug!("coerce_borrowed_pointer(a={:?}, b={:?})",
+               a,
+               b);
 
         // If we have a parameter of type `&M T_a` and the value
         // provided is `expr`, we will be adding an implicit borrow,
@@ -238,9 +237,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                       source: Ty<'tcx>,
                       target: Ty<'tcx>)
                       -> CoerceResult<'tcx> {
-        debug!("coerce_unsized(source={}, target={})",
-               source.repr(self.tcx()),
-               target.repr(self.tcx()));
+        debug!("coerce_unsized(source={:?}, target={:?})",
+               source,
+               target);
 
         let traits = (self.tcx().lang_items.unsize_trait(),
                       self.tcx().lang_items.coerce_unsized_trait());
@@ -294,7 +293,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // inference might unify those two inner type variables later.
         let traits = [coerce_unsized_did, unsize_did];
         while let Some(obligation) = queue.pop_front() {
-            debug!("coerce_unsized resolve step: {}", obligation.repr(self.tcx()));
+            debug!("coerce_unsized resolve step: {:?}", obligation);
             let trait_ref =  match obligation.predicate {
                 ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
                     tr.clone()
@@ -336,7 +335,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             autoref: reborrow,
             unsize: Some(target)
         };
-        debug!("Success, coerced with {}", adjustment.repr(self.tcx()));
+        debug!("Success, coerced with {:?}", adjustment);
         Ok(Some(AdjustDerefRef(adjustment)))
     }
 
@@ -352,8 +351,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
          */
 
         self.unpack_actual_value(b, |b| {
-            debug!("coerce_from_fn_pointer(a={}, b={})",
-                   a.repr(self.tcx()), b.repr(self.tcx()));
+            debug!("coerce_from_fn_pointer(a={:?}, b={:?})",
+                   a, b);
 
             if let ty::TyBareFn(None, fn_ty_b) = b.sty {
                 match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
@@ -380,8 +379,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
          */
 
         self.unpack_actual_value(b, |b| {
-            debug!("coerce_from_fn_item(a={}, b={})",
-                   a.repr(self.tcx()), b.repr(self.tcx()));
+            debug!("coerce_from_fn_item(a={:?}, b={:?})",
+                   a, b);
 
             match b.sty {
                 ty::TyBareFn(None, _) => {
@@ -399,9 +398,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                          b: Ty<'tcx>,
                          mutbl_b: ast::Mutability)
                          -> CoerceResult<'tcx> {
-        debug!("coerce_unsafe_ptr(a={}, b={})",
-               a.repr(self.tcx()),
-               b.repr(self.tcx()));
+        debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
+               a,
+               b);
 
         let (is_ref, mt_a) = match a.sty {
             ty::TyRef(_, mt) => (true, mt),
@@ -436,7 +435,7 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                              a: Ty<'tcx>,
                              b: Ty<'tcx>)
                              -> RelateResult<'tcx, ()> {
-    debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
+    debug!("mk_assignty({:?} -> {:?})", a, b);
     let mut unsizing_obligations = vec![];
     let adjustment = try!(indent(|| {
         fcx.infcx().commit_if_ok(|_| {
@@ -460,7 +459,7 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 
     if let Some(adjustment) = adjustment {
-        debug!("Success, coerced with {}", adjustment.repr(fcx.tcx()));
+        debug!("Success, coerced with {:?}", adjustment);
         fcx.write_adjustment(expr.id, adjustment);
     }
     Ok(())
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index c5861be2716..7cd5e4548ec 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -13,7 +13,6 @@ use middle::infer;
 use middle::traits;
 use middle::ty::{self};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace};
-use util::ppaux::{self, Repr};
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -38,11 +37,11 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                  impl_m_body_id: ast::NodeId,
                                  trait_m: &ty::Method<'tcx>,
                                  impl_trait_ref: &ty::TraitRef<'tcx>) {
-    debug!("compare_impl_method(impl_trait_ref={})",
-           impl_trait_ref.repr(tcx));
+    debug!("compare_impl_method(impl_trait_ref={:?})",
+           impl_trait_ref);
 
-    debug!("compare_impl_method: impl_trait_ref (liberated) = {}",
-           impl_trait_ref.repr(tcx));
+    debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
+           impl_trait_ref);
 
     let infcx = infer::new_infer_ctxt(tcx);
     let mut fulfillment_cx = traits::FulfillmentContext::new(true);
@@ -63,18 +62,16 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
             span_err!(tcx.sess, impl_m_span, E0185,
                 "method `{}` has a `{}` declaration in the impl, \
                         but not in the trait",
-                        token::get_name(trait_m.name),
-                        ppaux::explicit_self_category_to_str(
-                            &impl_m.explicit_self));
+                        trait_m.name,
+                        impl_m.explicit_self);
             return;
         }
         (_, &ty::StaticExplicitSelfCategory) => {
             span_err!(tcx.sess, impl_m_span, E0186,
                 "method `{}` has a `{}` declaration in the trait, \
                         but not in the impl",
-                        token::get_name(trait_m.name),
-                        ppaux::explicit_self_category_to_str(
-                            &trait_m.explicit_self));
+                        trait_m.name,
+                        trait_m.explicit_self);
             return;
         }
         _ => {
@@ -185,8 +182,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         .subst(tcx, impl_to_skol_substs)
         .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
                      impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
-    debug!("compare_impl_method: trait_to_skol_substs={}",
-           trait_to_skol_substs.repr(tcx));
+    debug!("compare_impl_method: trait_to_skol_substs={:?}",
+           trait_to_skol_substs);
 
     // Check region bounds. FIXME(@jroesch) refactor this away when removing
     // ParamBounds.
@@ -213,8 +210,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
             impl_m_span,
             infer::HigherRankedType,
             &ty::Binder(impl_bounds));
-    debug!("compare_impl_method: impl_bounds={}",
-           impl_bounds.repr(tcx));
+    debug!("compare_impl_method: impl_bounds={:?}",
+           impl_bounds);
 
     // Normalize the associated types in the trait_bounds.
     let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs);
@@ -244,8 +241,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     let trait_param_env = traits::normalize_param_env_or_error(trait_param_env,
                                                                normalize_cause.clone());
 
-    debug!("compare_impl_method: trait_bounds={}",
-        trait_param_env.caller_bounds.repr(tcx));
+    debug!("compare_impl_method: trait_bounds={:?}",
+        trait_param_env.caller_bounds);
 
     let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env);
 
@@ -305,8 +302,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                            tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety,
                                                          abi: impl_m.fty.abi,
                                                          sig: ty::Binder(impl_sig) }));
-        debug!("compare_impl_method: impl_fty={}",
-               impl_fty.repr(tcx));
+        debug!("compare_impl_method: impl_fty={:?}",
+               impl_fty);
 
         let (trait_sig, skol_map) =
             infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
@@ -326,8 +323,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                          abi: trait_m.fty.abi,
                                                          sig: ty::Binder(trait_sig) }));
 
-        debug!("compare_impl_method: trait_fty={}",
-               trait_fty.repr(tcx));
+        debug!("compare_impl_method: trait_fty={:?}",
+               trait_fty);
 
         try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty));
 
@@ -337,13 +334,13 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     match err {
         Ok(()) => { }
         Err(terr) => {
-            debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
-                   impl_fty.repr(tcx),
-                   trait_fty.repr(tcx));
+            debug!("checking trait method for compatibility: impl ty {:?}, trait ty {:?}",
+                   impl_fty,
+                   trait_fty);
             span_err!(tcx.sess, impl_m_span, E0053,
                       "method `{}` has an incompatible type for trait: {}",
                       token::get_name(trait_m.name),
-                      ty::type_err_to_str(tcx, &terr));
+                      terr);
             return;
         }
     }
@@ -383,14 +380,14 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         let impl_params = impl_generics.regions.get_slice(subst::FnSpace);
 
         debug!("check_region_bounds_on_impl_method: \
-               trait_generics={} \
-               impl_generics={} \
-               trait_to_skol_substs={} \
-               impl_to_skol_substs={}",
-               trait_generics.repr(tcx),
-               impl_generics.repr(tcx),
-               trait_to_skol_substs.repr(tcx),
-               impl_to_skol_substs.repr(tcx));
+               trait_generics={:?} \
+               impl_generics={:?} \
+               trait_to_skol_substs={:?} \
+               impl_to_skol_substs={:?}",
+               trait_generics,
+               impl_generics,
+               trait_to_skol_substs,
+               impl_to_skol_substs);
 
         // Must have same number of early-bound lifetime parameters.
         // Unfortunately, if the user screws up the bounds, then this
@@ -418,8 +415,8 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
                                 impl_c_span: Span,
                                 trait_c: &ty::AssociatedConst<'tcx>,
                                 impl_trait_ref: &ty::TraitRef<'tcx>) {
-    debug!("compare_const_impl(impl_trait_ref={})",
-           impl_trait_ref.repr(tcx));
+    debug!("compare_const_impl(impl_trait_ref={:?})",
+           impl_trait_ref);
 
     let infcx = infer::new_infer_ctxt(tcx);
     let mut fulfillment_cx = traits::FulfillmentContext::new(true);
@@ -445,8 +442,8 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
         .subst(tcx, impl_to_skol_substs)
         .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
                      impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
-    debug!("compare_const_impl: trait_to_skol_substs={}",
-           trait_to_skol_substs.repr(tcx));
+    debug!("compare_const_impl: trait_to_skol_substs={:?}",
+           trait_to_skol_substs);
 
     // Compute skolemized form of impl and trait const tys.
     let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
@@ -463,8 +460,8 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                  impl_c_span,
                                                  0,
                                                  &impl_ty);
-        debug!("compare_const_impl: impl_ty={}",
-               impl_ty.repr(tcx));
+        debug!("compare_const_impl: impl_ty={:?}",
+               impl_ty);
 
         let trait_ty =
             assoc::normalize_associated_types_in(&infcx,
@@ -473,8 +470,8 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                  impl_c_span,
                                                  0,
                                                  &trait_ty);
-        debug!("compare_const_impl: trait_ty={}",
-               trait_ty.repr(tcx));
+        debug!("compare_const_impl: trait_ty={:?}",
+               trait_ty);
 
         infer::mk_subty(&infcx, false, origin, impl_ty, trait_ty)
     });
@@ -482,14 +479,14 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
     match err {
         Ok(()) => { }
         Err(terr) => {
-            debug!("checking associated const for compatibility: impl ty {}, trait ty {}",
-                   impl_ty.repr(tcx),
-                   trait_ty.repr(tcx));
+            debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+                   impl_ty,
+                   trait_ty);
             span_err!(tcx.sess, impl_c_span, E0326,
                       "implemented const `{}` has an incompatible type for \
                       trait: {}",
                       token::get_name(trait_c.name),
-                      ty::type_err_to_str(tcx, &terr));
+                      terr);
             return;
         }
     }
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index cd6a1226e00..392515926da 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -16,7 +16,6 @@ use middle::infer;
 use std::result::Result::{Err, Ok};
 use syntax::ast;
 use syntax::codemap::Span;
-use util::ppaux::Repr;
 
 // Requires that the two types unify, and prints an error message if
 // they don't.
@@ -59,9 +58,9 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                         expected: Ty<'tcx>,
                         expr: &ast::Expr) {
     let expr_ty = fcx.expr_ty(expr);
-    debug!("demand::coerce(expected = {}, expr_ty = {})",
-           expected.repr(fcx.ccx.tcx),
-           expr_ty.repr(fcx.ccx.tcx));
+    debug!("demand::coerce(expected = {:?}, expr_ty = {:?})",
+           expected,
+           expr_ty);
     let expr_ty = fcx.resolve_type_vars_if_possible(expr_ty);
     let expected = fcx.resolve_type_vars_if_possible(expected);
     match coercion::mk_assignty(fcx, expr, expr_ty, expected) {
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 6e6231dec32..fb17f41d88d 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -14,7 +14,6 @@ use middle::infer;
 use middle::region;
 use middle::subst::{self, Subst};
 use middle::ty::{self, Ty};
-use util::ppaux::{Repr, UserString};
 
 use syntax::ast;
 use syntax::codemap::{self, Span};
@@ -38,7 +37,7 @@ use syntax::codemap::{self, Span};
 ///
 pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ()> {
     let ty::TypeScheme { generics: ref dtor_generics,
-                         ty: ref dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did);
+                         ty: dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did);
     let dtor_predicates = ty::lookup_predicates(tcx, drop_impl_did);
     match dtor_self_type.sty {
         ty::TyEnum(self_type_did, self_to_impl_substs) |
@@ -47,7 +46,7 @@ pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(),
             try!(ensure_drop_params_and_item_params_correspond(tcx,
                                                                drop_impl_did,
                                                                dtor_generics,
-                                                               dtor_self_type,
+                                                               &dtor_self_type,
                                                                self_type_did));
 
             ensure_drop_predicates_are_implied_by_item_defn(tcx,
@@ -62,7 +61,7 @@ pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(),
             let span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
             tcx.sess.span_bug(
                 span, &format!("should have been rejected by coherence check: {}",
-                               dtor_self_type.repr(tcx)));
+                               dtor_self_type));
         }
     }
 }
@@ -212,9 +211,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
 
         if !assumptions_in_impl_context.contains(&predicate) {
             let item_span = tcx.map.span(self_type_did.node);
-            let req = predicate.user_string(tcx);
             span_err!(tcx.sess, drop_impl_span, E0367,
-                      "The requirement `{}` is added only by the Drop impl.", req);
+                      "The requirement `{}` is added only by the Drop impl.", predicate);
             tcx.sess.span_note(item_span,
                                "The same requirement must be part of \
                                 the struct/enum definition");
@@ -257,8 +255,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
                                                      typ: ty::Ty<'tcx>,
                                                      span: Span,
                                                      scope: region::CodeExtent) {
-    debug!("check_safety_of_destructor_if_necessary typ: {} scope: {:?}",
-           typ.repr(rcx.tcx()), scope);
+    debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
+           typ, scope);
 
     // types that have been traversed so far by `traverse_type_if_unseen`
     let mut breadcrumbs: Vec<Ty<'tcx>> = Vec::new();
@@ -277,8 +275,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
         Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
             let tcx = rcx.tcx();
             span_err!(tcx.sess, span, E0320,
-                      "overflow while adding drop-check rules for {}",
-                      typ.user_string(rcx.tcx()));
+                      "overflow while adding drop-check rules for {}", typ);
             match *ctxt {
                 TypeContext::Root => {
                     // no need for an additional note if the overflow
@@ -294,7 +291,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
                         ty::item_path_str(tcx, def_id),
                         variant,
                         arg_index,
-                        detected_on_typ.user_string(rcx.tcx()));
+                        detected_on_typ);
                 }
                 TypeContext::Struct { def_id, field } => {
                     span_note!(
@@ -303,7 +300,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
                         "overflowed on struct {} field {} type: {}",
                         ty::item_path_str(tcx, def_id),
                         field,
-                        detected_on_typ.user_string(rcx.tcx()));
+                        detected_on_typ);
                 }
             }
         }
@@ -372,8 +369,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
                     let tp_def = item_type.generics.types
                         .opt_get(subst::TypeSpace, 0).unwrap();
                     let new_typ = substs.type_for_def(tp_def);
-                    debug!("replacing phantom {} with {}",
-                           typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
+                    debug!("replacing phantom {:?} with {:?}",
+                           typ, new_typ);
                     (new_typ, xref_depth_orig + 1)
                 } else {
                     (typ, xref_depth_orig)
@@ -384,8 +381,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
             // definition of `Box<T>` must carry a PhantomData that
             // puts us into the previous case.
             ty::TyBox(new_typ) => {
-                debug!("replacing TyBox {} with {}",
-                       typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
+                debug!("replacing TyBox {:?} with {:?}",
+                       typ, new_typ);
                 (new_typ, xref_depth_orig + 1)
             }
 
@@ -411,7 +408,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
         debug!("iterate_over_potentially_unsafe_regions_in_type \
                 {}typ: {} scope: {:?} xref: {}",
                (0..depth).map(|_| ' ').collect::<String>(),
-               typ.repr(rcx.tcx()), scope, xref_depth);
+               typ, scope, xref_depth);
 
         // If `typ` has a destructor, then we must ensure that all
         // borrowed data reachable via `typ` must outlive the parent
@@ -467,8 +464,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
 
             match typ.sty {
                 ty::TyStruct(struct_did, substs) => {
-                    debug!("typ: {} is struct; traverse structure and not type-expression",
-                           typ.repr(rcx.tcx()));
+                    debug!("typ: {:?} is struct; traverse structure and not type-expression",
+                           typ);
                     // Don't recurse; we extract type's substructure,
                     // so do not process subparts of type expression.
                     walker.skip_current_subtree();
@@ -497,8 +494,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
                 }
 
                 ty::TyEnum(enum_did, substs) => {
-                    debug!("typ: {} is enum; traverse structure and not type-expression",
-                           typ.repr(rcx.tcx()));
+                    debug!("typ: {:?} is enum; traverse structure and not type-expression",
+                           typ);
                     // Don't recurse; we extract type's substructure,
                     // so do not process subparts of type expression.
                     walker.skip_current_subtree();
@@ -571,24 +568,24 @@ fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>,
     match dtor_kind {
         DtorKind::PureRecur => {
             has_dtor_of_interest = false;
-            debug!("typ: {} has no dtor, and thus is uninteresting",
-                   typ.repr(tcx));
+            debug!("typ: {:?} has no dtor, and thus is uninteresting",
+                   typ);
         }
         DtorKind::Unknown(bounds) => {
             match bounds.region_bound {
                 ty::ReStatic => {
-                    debug!("trait: {} has 'static bound, and thus is uninteresting",
-                           typ.repr(tcx));
+                    debug!("trait: {:?} has 'static bound, and thus is uninteresting",
+                           typ);
                     has_dtor_of_interest = false;
                 }
                 ty::ReEmpty => {
-                    debug!("trait: {} has empty region bound, and thus is uninteresting",
-                           typ.repr(tcx));
+                    debug!("trait: {:?} has empty region bound, and thus is uninteresting",
+                           typ);
                     has_dtor_of_interest = false;
                 }
                 r => {
-                    debug!("trait: {} has non-static bound: {}; assumed interesting",
-                           typ.repr(tcx), r.repr(tcx));
+                    debug!("trait: {:?} has non-static bound: {:?}; assumed interesting",
+                           typ, r);
                     has_dtor_of_interest = true;
                 }
             }
@@ -645,8 +642,8 @@ fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>,
 
                     if result {
                         has_pred_of_interest = true;
-                        debug!("typ: {} has interesting dtor due to generic preds, e.g. {}",
-                               typ.repr(tcx), pred.repr(tcx));
+                        debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}",
+                               typ, pred);
                         break 'items;
                     }
                 }
@@ -670,14 +667,14 @@ fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>,
                 has_pred_of_interest;
 
             if has_dtor_of_interest {
-                debug!("typ: {} has interesting dtor, due to \
+                debug!("typ: {:?} has interesting dtor, due to \
                         region params: {} or pred: {}",
-                       typ.repr(tcx),
+                       typ,
                        has_region_param_of_interest,
                        has_pred_of_interest);
             } else {
-                debug!("typ: {} has dtor, but it is uninteresting",
-                       typ.repr(tcx));
+                debug!("typ: {:?} has dtor, but it is uninteresting",
+                       typ);
             }
         }
     }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index bd482a4c787..fd93a2493db 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -24,7 +24,6 @@ use middle::infer::InferCtxt;
 use syntax::ast;
 use syntax::codemap::Span;
 use std::iter::repeat;
-use util::ppaux::Repr;
 
 struct ConfirmContext<'a, 'tcx:'a> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -56,10 +55,10 @@ pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                          supplied_method_types: Vec<Ty<'tcx>>)
                          -> MethodCallee<'tcx>
 {
-    debug!("confirm(unadjusted_self_ty={}, pick={}, supplied_method_types={})",
-           unadjusted_self_ty.repr(fcx.tcx()),
-           pick.repr(fcx.tcx()),
-           supplied_method_types.repr(fcx.tcx()));
+    debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
+           unadjusted_self_ty,
+           pick,
+           supplied_method_types);
 
     let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr);
     confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
@@ -93,7 +92,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         let (method_types, method_regions) =
             self.instantiate_method_substs(&pick, supplied_method_types);
         let all_substs = rcvr_substs.with_method(method_types, method_regions);
-        debug!("all_substs={}", all_substs.repr(self.tcx()));
+        debug!("all_substs={:?}", all_substs);
 
         // Create the final signature for the method, replacing late-bound regions.
         let InstantiatedMethodSig {
@@ -225,10 +224,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         this.upcast(original_poly_trait_ref.clone(), trait_def_id);
                     let upcast_trait_ref =
                         this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
-                    debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}",
-                           original_poly_trait_ref.repr(this.tcx()),
-                           upcast_trait_ref.repr(this.tcx()),
-                           trait_def_id.repr(this.tcx()));
+                    debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
+                           original_poly_trait_ref,
+                           upcast_trait_ref,
+                           trait_def_id);
                     let substs = upcast_trait_ref.substs.clone();
                     let origin = MethodTraitObject(MethodObject {
                         trait_ref: upcast_trait_ref,
@@ -322,7 +321,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                 self.tcx().sess.span_bug(
                     self.span,
                     &format!("self-type `{}` for ObjectPick never dereferenced to an object",
-                            self_ty.repr(self.tcx())))
+                            self_ty))
             }
         }
     }
@@ -376,10 +375,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             Err(_) => {
                 self.tcx().sess.span_bug(
                     self.span,
-                    &format!(
-                        "{} was a subtype of {} but now is not?",
-                        self_ty.repr(self.tcx()),
-                        method_self_ty.repr(self.tcx())));
+                    &format!("{} was a subtype of {} but now is not?",
+                             self_ty, method_self_ty));
             }
         }
     }
@@ -392,9 +389,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                               all_substs: subst::Substs<'tcx>)
                               -> InstantiatedMethodSig<'tcx>
     {
-        debug!("instantiate_method_sig(pick={}, all_substs={})",
-               pick.repr(self.tcx()),
-               all_substs.repr(self.tcx()));
+        debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
+               pick,
+               all_substs);
 
         // Instantiate the bounds on the method with the
         // type/early-bound-regions substitutions performed. There can
@@ -404,8 +401,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         let method_predicates = self.fcx.normalize_associated_types_in(self.span,
                                                                        &method_predicates);
 
-        debug!("method_predicates after subst = {}",
-               method_predicates.repr(self.tcx()));
+        debug!("method_predicates after subst = {:?}",
+               method_predicates);
 
         // Instantiate late-bound regions and substitute the trait
         // parameters into the method type to get the actual method type.
@@ -415,12 +412,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         // may reference those regions.
         let method_sig = self.replace_late_bound_regions_with_fresh_var(
             &pick.item.as_opt_method().unwrap().fty.sig);
-        debug!("late-bound lifetimes from method instantiated, method_sig={}",
-               method_sig.repr(self.tcx()));
+        debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
+               method_sig);
 
         let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
-        debug!("type scheme substituted, method_sig={}",
-               method_sig.repr(self.tcx()));
+        debug!("type scheme substituted, method_sig={:?}",
+               method_sig);
 
         InstantiatedMethodSig {
             method_sig: method_sig,
@@ -433,10 +430,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                        pick: &probe::Pick<'tcx>,
                        all_substs: &subst::Substs<'tcx>,
                        method_predicates: &ty::InstantiatedPredicates<'tcx>) {
-        debug!("add_obligations: pick={} all_substs={} method_predicates={}",
-               pick.repr(self.tcx()),
-               all_substs.repr(self.tcx()),
-               method_predicates.repr(self.tcx()));
+        debug!("add_obligations: pick={:?} all_substs={:?} method_predicates={:?}",
+               pick,
+               all_substs,
+               method_predicates);
 
         self.fcx.add_obligations_for_parameters(
             traits::ObligationCause::misc(self.span, self.fcx.body_id),
@@ -483,8 +480,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             }
         }
 
-        debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={}",
-               exprs.repr(self.tcx()));
+        debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={:?}",
+               exprs);
 
         // Fix up autoderefs and derefs.
         for (i, &expr) in exprs.iter().rev().enumerate() {
@@ -498,8 +495,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                 Some(_) | None => 0,
             };
 
-            debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}",
-                   i, expr.repr(self.tcx()), autoderef_count);
+            debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={:?} \
+                                                                  autoderef_count={}",
+                   i, expr, autoderef_count);
 
             if autoderef_count > 0 {
                 check::autoderef(self.fcx,
@@ -545,8 +543,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                                 Some(_) => {
                                     self.tcx().sess.span_bug(
                                         base_expr.span,
-                                        &format!("unexpected adjustment autoref {}",
-                                                adr.repr(self.tcx())));
+                                        &format!("unexpected adjustment autoref {:?}",
+                                                adr));
                                 }
                             },
                             None => (0, None),
@@ -647,17 +645,17 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         if upcast_trait_refs.len() != 1 {
             self.tcx().sess.span_bug(
                 self.span,
-                &format!("cannot uniquely upcast `{}` to `{}`: `{}`",
-                         source_trait_ref.repr(self.tcx()),
-                         target_trait_def_id.repr(self.tcx()),
-                         upcast_trait_refs.repr(self.tcx())));
+                &format!("cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
+                         source_trait_ref,
+                         target_trait_def_id,
+                         upcast_trait_refs));
         }
 
         upcast_trait_refs.into_iter().next().unwrap()
     }
 
     fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
-        where T : TypeFoldable<'tcx> + Repr<'tcx>
+        where T : TypeFoldable<'tcx>
     {
         self.infcx().replace_late_bound_regions_with_fresh_var(
             self.span, infer::FnCall, value).0
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index bb620c6ecd8..85a4b02cf80 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -18,7 +18,6 @@ use middle::subst;
 use middle::traits;
 use middle::ty::{self, AsPredicate, ToPolyTraitRef};
 use middle::infer;
-use util::ppaux::Repr;
 
 use syntax::ast::DefId;
 use syntax::ast;
@@ -96,11 +95,11 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                         self_expr: &'tcx ast::Expr)
                         -> Result<ty::MethodCallee<'tcx>, MethodError>
 {
-    debug!("lookup(method_name={}, self_ty={}, call_expr={}, self_expr={})",
-           method_name.repr(fcx.tcx()),
-           self_ty.repr(fcx.tcx()),
-           call_expr.repr(fcx.tcx()),
-           self_expr.repr(fcx.tcx()));
+    debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
+           method_name,
+           self_ty,
+           call_expr,
+           self_expr);
 
     let mode = probe::Mode::MethodCall;
     let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
@@ -141,11 +140,11 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                           opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
                                           -> Option<ty::MethodCallee<'tcx>>
 {
-    debug!("lookup_in_trait_adjusted(self_ty={}, self_expr={}, m_name={}, trait_def_id={})",
-           self_ty.repr(fcx.tcx()),
-           self_expr.repr(fcx.tcx()),
-           m_name.repr(fcx.tcx()),
-           trait_def_id.repr(fcx.tcx()));
+    debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, m_name={}, trait_def_id={:?})",
+           self_ty,
+           self_expr,
+           m_name,
+           trait_def_id);
 
     let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_def_id);
 
@@ -190,8 +189,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
     assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
 
-    debug!("lookup_in_trait_adjusted: method_num={} method_ty={}",
-           method_num, method_ty.repr(fcx.tcx()));
+    debug!("lookup_in_trait_adjusted: method_num={} method_ty={:?}",
+           method_num, method_ty);
 
     // Instantiate late-bound regions and substitute the trait
     // parameters into the method type to get the actual method type.
@@ -210,9 +209,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         abi: method_ty.fty.abi.clone(),
     }));
 
-    debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}",
-           fty.repr(fcx.tcx()),
-           obligation.repr(fcx.tcx()));
+    debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
+           fty,
+           obligation);
 
     // Register obligations for the parameters.  This will include the
     // `Self` parameter, which in turn has a bound of the main trait,
@@ -272,7 +271,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                 span,
                                 &format!(
                                     "trait method is &self but first arg is: {}",
-                                    transformed_self_ty.repr(fcx.tcx())));
+                                    transformed_self_ty));
                         }
                     }
                 }
@@ -296,7 +295,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         substs: trait_ref.substs.clone()
     };
 
-    debug!("callee = {}", callee.repr(fcx.tcx()));
+    debug!("callee = {:?}", callee);
 
     Some(callee)
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 915aadd722b..ecf6cad32be 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -28,7 +28,6 @@ use syntax::codemap::{Span, DUMMY_SP};
 use std::collections::HashSet;
 use std::mem;
 use std::rc::Rc;
-use util::ppaux::Repr;
 
 use self::CandidateKind::*;
 pub use self::PickKind::*;
@@ -46,18 +45,21 @@ struct ProbeContext<'a, 'tcx:'a> {
     static_candidates: Vec<CandidateSource>,
 }
 
+#[derive(Debug)]
 struct CandidateStep<'tcx> {
     self_ty: Ty<'tcx>,
     autoderefs: usize,
     unsize: bool
 }
 
+#[derive(Debug)]
 struct Candidate<'tcx> {
     xform_self_ty: Ty<'tcx>,
     item: ty::ImplOrTraitItem<'tcx>,
     kind: CandidateKind<'tcx>,
 }
 
+#[derive(Debug)]
 enum CandidateKind<'tcx> {
     InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>,
                           /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
@@ -70,6 +72,7 @@ enum CandidateKind<'tcx> {
     ProjectionCandidate(ast::DefId, ItemIndex),
 }
 
+#[derive(Debug)]
 pub struct Pick<'tcx> {
     pub item: ty::ImplOrTraitItem<'tcx>,
     pub kind: PickKind<'tcx>,
@@ -123,8 +126,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                        scope_expr_id: ast::NodeId)
                        -> PickResult<'tcx>
 {
-    debug!("probe(self_ty={}, item_name={}, scope_expr_id={})",
-           self_ty.repr(fcx.tcx()),
+    debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
+           self_ty,
            item_name,
            scope_expr_id);
 
@@ -163,9 +166,9 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             Some(simplified_steps)
         };
 
-    debug!("ProbeContext: steps for self_ty={} are {}",
-           self_ty.repr(fcx.tcx()),
-           steps.repr(fcx.tcx()));
+    debug!("ProbeContext: steps for self_ty={:?} are {:?}",
+           self_ty,
+           steps);
 
     // this creates one big transaction so that all type variables etc
     // that we create during the probe process are removed later
@@ -268,8 +271,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     }
 
     fn assemble_probe(&mut self, self_ty: Ty<'tcx>) {
-        debug!("assemble_probe: self_ty={}",
-               self_ty.repr(self.tcx()));
+        debug!("assemble_probe: self_ty={:?}",
+               self_ty);
 
         match self_ty.sty {
             ty::TyTrait(box ref data) => {
@@ -412,7 +415,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         let traits::Normalized { value: xform_self_ty, obligations } =
             traits::normalize(selcx, cause, &xform_self_ty);
         debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
-               xform_self_ty.repr(self.tcx()));
+               xform_self_ty);
 
         self.inherent_candidates.push(Candidate {
             xform_self_ty: xform_self_ty,
@@ -424,8 +427,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     fn assemble_inherent_candidates_from_object(&mut self,
                                                 self_ty: Ty<'tcx>,
                                                 data: &ty::TraitTy<'tcx>) {
-        debug!("assemble_inherent_candidates_from_object(self_ty={})",
-               self_ty.repr(self.tcx()));
+        debug!("assemble_inherent_candidates_from_object(self_ty={:?})",
+               self_ty);
 
         let tcx = self.tcx();
 
@@ -496,10 +499,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                    trait_ref.substs);
 
             if let Some(ref m) = item.as_opt_method() {
-                debug!("found match: trait_ref={} substs={} m={}",
-                       trait_ref.repr(this.tcx()),
-                       trait_ref.substs.repr(this.tcx()),
-                       m.repr(this.tcx()));
+                debug!("found match: trait_ref={:?} substs={:?} m={:?}",
+                       trait_ref,
+                       trait_ref.substs,
+                       m);
                 assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
                            trait_ref.substs.types.get_slice(subst::TypeSpace).len());
                 assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
@@ -539,7 +542,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             usize,
         ),
     {
-        debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx()));
+        debug!("elaborate_bounds(bounds={:?})", bounds);
 
         let tcx = self.tcx();
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
@@ -588,8 +591,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                                trait_def_id: ast::DefId)
                                                -> Result<(),MethodError>
     {
-        debug!("assemble_extension_candidates_for_trait(trait_def_id={})",
-               trait_def_id.repr(self.tcx()));
+        debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
+               trait_def_id);
 
         // Check whether `trait_def_id` defines a method with suitable name:
         let trait_items =
@@ -638,9 +641,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
         // FIXME(arielb1): can we use for_each_relevant_impl here?
         trait_def.for_each_impl(self.tcx(), |impl_def_id| {
-            debug!("assemble_extension_candidates_for_trait_impl: trait_def_id={} impl_def_id={}",
-                   trait_def_id.repr(self.tcx()),
-                   impl_def_id.repr(self.tcx()));
+            debug!("assemble_extension_candidates_for_trait_impl: trait_def_id={:?} \
+                                                                  impl_def_id={:?}",
+                   trait_def_id,
+                   impl_def_id);
 
             if !self.impl_can_possibly_match(impl_def_id) {
                 return;
@@ -648,14 +652,14 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
             let (_, impl_substs) = self.impl_ty_and_substs(impl_def_id);
 
-            debug!("impl_substs={}", impl_substs.repr(self.tcx()));
+            debug!("impl_substs={:?}", impl_substs);
 
             let impl_trait_ref =
                 ty::impl_trait_ref(self.tcx(), impl_def_id)
                 .unwrap() // we know this is a trait impl
                 .subst(self.tcx(), &impl_substs);
 
-            debug!("impl_trait_ref={}", impl_trait_ref.repr(self.tcx()));
+            debug!("impl_trait_ref={:?}", impl_trait_ref);
 
             // Determine the receiver type that the method itself expects.
             let xform_self_ty =
@@ -671,7 +675,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             let traits::Normalized { value: xform_self_ty, obligations } =
                 traits::normalize(selcx, cause, &xform_self_ty);
 
-            debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx()));
+            debug!("xform_self_ty={:?}", xform_self_ty);
 
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
@@ -769,31 +773,31 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                       item_index: usize)
     {
         debug!("assemble_projection_candidates(\
-               trait_def_id={}, \
-               item={}, \
+               trait_def_id={:?}, \
+               item={:?}, \
                item_index={})",
-               trait_def_id.repr(self.tcx()),
-               item.repr(self.tcx()),
+               trait_def_id,
+               item,
                item_index);
 
         for step in self.steps.iter() {
-            debug!("assemble_projection_candidates: step={}",
-                   step.repr(self.tcx()));
+            debug!("assemble_projection_candidates: step={:?}",
+                   step);
 
             let projection_trait_ref = match step.self_ty.sty {
                 ty::TyProjection(ref data) => &data.trait_ref,
                 _ => continue,
             };
 
-            debug!("assemble_projection_candidates: projection_trait_ref={}",
-                   projection_trait_ref.repr(self.tcx()));
+            debug!("assemble_projection_candidates: projection_trait_ref={:?}",
+                   projection_trait_ref);
 
             let trait_predicates = ty::lookup_predicates(self.tcx(),
                                                          projection_trait_ref.def_id);
             let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
             let predicates = bounds.predicates.into_vec();
-            debug!("assemble_projection_candidates: predicates={}",
-                   predicates.repr(self.tcx()));
+            debug!("assemble_projection_candidates: predicates={:?}",
+                   predicates);
             for poly_bound in
                 traits::elaborate_predicates(self.tcx(), predicates)
                 .filter_map(|p| p.to_opt_poly_trait_ref())
@@ -801,18 +805,18 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             {
                 let bound = self.erase_late_bound_regions(&poly_bound);
 
-                debug!("assemble_projection_candidates: projection_trait_ref={} bound={}",
-                       projection_trait_ref.repr(self.tcx()),
-                       bound.repr(self.tcx()));
+                debug!("assemble_projection_candidates: projection_trait_ref={:?} bound={:?}",
+                       projection_trait_ref,
+                       bound);
 
                 if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
                     let xform_self_ty = self.xform_self_ty(&item,
                                                            bound.self_ty(),
                                                            bound.substs);
 
-                    debug!("assemble_projection_candidates: bound={} xform_self_ty={}",
-                           bound.repr(self.tcx()),
-                           xform_self_ty.repr(self.tcx()));
+                    debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
+                           bound,
+                           xform_self_ty);
 
                     self.extension_candidates.push(Candidate {
                         xform_self_ty: xform_self_ty,
@@ -829,8 +833,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                         item: ty::ImplOrTraitItem<'tcx>,
                                         item_index: usize)
     {
-        debug!("assemble_where_clause_candidates(trait_def_id={})",
-               trait_def_id.repr(self.tcx()));
+        debug!("assemble_where_clause_candidates(trait_def_id={:?})",
+               trait_def_id);
 
         let caller_predicates = self.fcx.inh.param_env.caller_bounds.clone();
         for poly_bound in traits::elaborate_predicates(self.tcx(), caller_predicates)
@@ -842,9 +846,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                                    bound.self_ty(),
                                                    bound.substs);
 
-            debug!("assemble_where_clause_candidates: bound={} xform_self_ty={}",
-                   bound.repr(self.tcx()),
-                   xform_self_ty.repr(self.tcx()));
+            debug!("assemble_where_clause_candidates: bound={:?} xform_self_ty={:?}",
+                   bound,
+                   xform_self_ty);
 
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
@@ -910,7 +914,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     }
 
     fn pick_step(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
-        debug!("pick_step: step={}", step.repr(self.tcx()));
+        debug!("pick_step: step={:?}", step);
 
         if ty::type_is_error(step.self_ty) {
             return None;
@@ -1008,7 +1012,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                   .filter(|&probe| self.consider_probe(self_ty, probe))
                   .collect();
 
-        debug!("applicable_candidates: {}", applicable_candidates.repr(self.tcx()));
+        debug!("applicable_candidates: {:?}", applicable_candidates);
 
         if applicable_candidates.len() > 1 {
             match self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) {
@@ -1029,9 +1033,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     }
 
     fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool {
-        debug!("consider_probe: self_ty={} probe={}",
-               self_ty.repr(self.tcx()),
-               probe.repr(self.tcx()));
+        debug!("consider_probe: self_ty={:?} probe={:?}",
+               self_ty,
+               probe);
 
         self.infcx().probe(|_| {
             // First check that the self type can be related.
@@ -1062,10 +1066,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
                     // Convert the bounds into obligations.
                     let obligations =
-                        traits::predicates_for_generics(self.tcx(),
-                                                        cause.clone(),
+                        traits::predicates_for_generics(cause.clone(),
                                                         &impl_bounds);
-                    debug!("impl_obligations={}", obligations.repr(self.tcx()));
+                    debug!("impl_obligations={:?}", obligations);
 
                     // Evaluate those obligations to see if they might possibly hold.
                     obligations.iter()
@@ -1177,10 +1180,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                             substs: &subst::Substs<'tcx>)
                             -> Ty<'tcx>
     {
-        debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
-               impl_ty.repr(self.tcx()),
-               method.fty.sig.0.inputs.get(0).repr(self.tcx()),
-               substs.repr(self.tcx()));
+        debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
+               impl_ty,
+               method.fty.sig.0.inputs.get(0),
+               substs);
 
         assert!(!substs.has_escaping_regions());
 
@@ -1265,7 +1268,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     ///    and/or tracking the substitution and
     ///    so forth.
     fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T
-        where T : TypeFoldable<'tcx> + Repr<'tcx>
+        where T : TypeFoldable<'tcx>
     {
         ty::erase_late_bound_regions(self.tcx(), value)
     }
@@ -1371,59 +1374,3 @@ impl<'tcx> Candidate<'tcx> {
         }
     }
 }
-
-impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Candidate(xform_self_ty={}, kind={})",
-                self.xform_self_ty.repr(tcx),
-                self.kind.repr(tcx))
-    }
-}
-
-impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            InherentImplCandidate(ref a, ref b, ref c) =>
-                format!("InherentImplCandidate({},{},{})", a.repr(tcx), b.repr(tcx),
-                        c.repr(tcx)),
-            ObjectCandidate(a, b, c) =>
-                format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c),
-            ExtensionImplCandidate(ref a, ref b, ref c, ref d, ref e) =>
-                format!("ExtensionImplCandidate({},{},{},{},{})", a.repr(tcx), b.repr(tcx),
-                        c.repr(tcx), d, e.repr(tcx)),
-            ClosureCandidate(ref a, ref b) =>
-                format!("ClosureCandidate({},{})", a.repr(tcx), b),
-            WhereClauseCandidate(ref a, ref b) =>
-                format!("WhereClauseCandidate({},{})", a.repr(tcx), b),
-            ProjectionCandidate(ref a, ref b) =>
-                format!("ProjectionCandidate({},{})", a.repr(tcx), b),
-        }
-    }
-}
-
-impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("CandidateStep({}, autoderefs={}, unsize={})",
-                self.self_ty.repr(tcx),
-                self.autoderefs,
-                self.unsize)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for PickKind<'tcx> {
-    fn repr(&self, _tcx: &ty::ctxt) -> String {
-        format!("{:?}", self)
-    }
-}
-
-impl<'tcx> Repr<'tcx> for Pick<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Pick(item={}, autoderefs={},
-                 autoref={}, unsize={}, kind={:?})",
-                self.item.repr(tcx),
-                self.autoderefs,
-                self.autoref.repr(tcx),
-                self.unsize.repr(tcx),
-                self.kind)
-    }
-}
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 8a48ef543cc..b098fb56d4d 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -18,7 +18,6 @@ use check::{self, FnCtxt};
 use middle::ty::{self, Ty};
 use middle::def;
 use metadata::{csearch, cstore, decoder};
-use util::ppaux::UserString;
 
 use syntax::{ast, ast_util};
 use syntax::codemap::Span;
@@ -45,7 +44,6 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     match error {
         MethodError::NoMatch(static_sources, out_of_scope_traits, mode) => {
             let cx = fcx.tcx();
-            let item_ustring = item_name.user_string(cx);
 
             fcx.type_error_message(
                 span,
@@ -54,7 +52,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                              in the current scope",
                             if mode == Mode::MethodCall { "method" }
                             else { "associated item" },
-                            item_ustring,
+                            item_name,
                             actual)
                 },
                 rcvr_ty,
@@ -66,7 +64,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 if fields.iter().any(|f| f.name == item_name) {
                     cx.sess.span_note(span,
                         &format!("use `(s.{0})(...)` if you meant to call the \
-                                 function stored in the `{0}` field", item_ustring));
+                                 function stored in the `{0}` field", item_name));
                 }
             }
 
@@ -93,7 +91,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
                                invoked on this closure as we have not yet inferred what \
                                kind of closure it is",
-                               item_name.user_string(fcx.tcx()),
+                               item_name,
                                ty::item_path_str(fcx.tcx(), trait_def_id));
             let msg = if let Some(callee) = rcvr_expr {
                 format!("{}; use overloaded call notation instead (e.g., `{}()`)",
@@ -134,7 +132,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                "candidate #{} is defined in an impl{} for the type `{}`",
                                idx + 1,
                                insertion,
-                               impl_ty.user_string(fcx.tcx()));
+                               impl_ty);
                 }
                 CandidateSource::TraitSource(trait_did) => {
                     let (_, item) = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
@@ -160,7 +158,6 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                       valid_out_of_scope_traits: Vec<ast::DefId>)
 {
     let tcx = fcx.tcx();
-    let item_ustring = item_name.user_string(tcx);
 
     if !valid_out_of_scope_traits.is_empty() {
         let mut candidates = valid_out_of_scope_traits;
@@ -217,7 +214,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
              perhaps you need to implement {one_of_them}:",
             traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"},
             one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
-            name = item_ustring);
+            name = item_name);
 
         fcx.sess().fileline_help(span, &msg[..]);
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9df0d4aa56b..34df349b7a3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -106,7 +106,6 @@ use {CrateCtxt, lookup_full_def, require_same_types};
 use TypeAndSubsts;
 use lint;
 use util::common::{block_query, ErrorReported, indenter, loop_query};
-use util::ppaux::{self, Repr};
 use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
 use util::lev_distance::lev_distance;
 
@@ -193,7 +192,7 @@ type DeferredCallResolutionHandler<'tcx> = Box<DeferredCallResolution<'tcx>+'tcx
 
 /// When type-checking an expression, we propagate downward
 /// whatever type hint we are able in the form of an `Expectation`.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum Expectation<'tcx> {
     /// We know nothing about what type this expression should have.
     NoExpectation,
@@ -398,7 +397,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
                                         body_id: ast::NodeId,
                                         value: &T)
                                         -> T
-        where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
+        where T : TypeFoldable<'tcx> + HasProjectionTypes
     {
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
         assoc::normalize_associated_types_in(&self.infcx,
@@ -567,8 +566,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
             None => None
         };
         self.assign(local.span, local.id, o_ty);
-        debug!("Local variable {} is assigned type {}",
-               self.fcx.pat_to_string(&*local.pat),
+        debug!("Local variable {:?} is assigned type {}",
+               local.pat,
                self.fcx.infcx().ty_to_string(
                    self.fcx.inh.locals.borrow().get(&local.id).unwrap().clone()));
         visit::walk_local(self, local);
@@ -583,11 +582,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
                 self.fcx.require_type_is_sized(var_ty, p.span,
                                                traits::VariableType(p.id));
 
-                debug!("Pattern binding {} is assigned to {} with type {}",
+                debug!("Pattern binding {} is assigned to {} with type {:?}",
                        token::get_ident(path1.node),
                        self.fcx.infcx().ty_to_string(
                            self.fcx.inh.locals.borrow().get(&p.id).unwrap().clone()),
-                       var_ty.repr(self.fcx.tcx()));
+                       var_ty);
             }
         }
         visit::walk_pat(self, p);
@@ -641,9 +640,9 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
     let arg_tys = &fn_sig.inputs;
     let ret_ty = fn_sig.output;
 
-    debug!("check_fn(arg_tys={}, ret_ty={}, fn_id={})",
-           arg_tys.repr(tcx),
-           ret_ty.repr(tcx),
+    debug!("check_fn(arg_tys={:?}, ret_ty={:?}, fn_id={})",
+           arg_tys,
+           ret_ty,
            fn_id);
 
     // Create the function context.  This is either derived from scratch or,
@@ -669,9 +668,9 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
         fn_sig_tys.push(ret_ty);
     }
 
-    debug!("fn-sig-map: fn_id={} fn_sig_tys={}",
+    debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}",
            fn_id,
-           fn_sig_tys.repr(tcx));
+           fn_sig_tys);
 
     inherited.fn_sig_map.borrow_mut().insert(fn_id, fn_sig_tys);
 
@@ -918,12 +917,12 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                sig: &'tcx ast::MethodSig,
                                body: &'tcx ast::Block,
                                id: ast::NodeId, span: Span) {
-    debug!("check_method_body(item_generics={}, id={})",
-            item_generics.repr(ccx.tcx), id);
+    debug!("check_method_body(item_generics={:?}, id={})",
+            item_generics, id);
     let param_env = ParameterEnvironment::for_item(ccx.tcx, id);
 
     let fty = ty::node_id_to_type(ccx.tcx, id);
-    debug!("check_method_body: fty={}", fty.repr(ccx.tcx));
+    debug!("check_method_body: fty={:?}", fty);
 
     check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
 }
@@ -963,9 +962,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             _ => {
                                 span_err!(tcx.sess, impl_item.span, E0323,
                                           "item `{}` is an associated const, \
-                                          which doesn't match its trait `{}`",
+                                          which doesn't match its trait `{:?}`",
                                           token::get_name(impl_const_ty.name()),
-                                          impl_trait_ref.repr(tcx))
+                                          impl_trait_ref)
                             }
                         }
                     }
@@ -976,9 +975,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             impl_item.span,
                             &format!(
                                 "associated const `{}` is not a member of \
-                                 trait `{}`",
+                                 trait `{:?}`",
                                 token::get_name(impl_const_ty.name()),
-                                impl_trait_ref.repr(tcx)));
+                                impl_trait_ref));
                     }
                 }
             }
@@ -1009,9 +1008,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             _ => {
                                 span_err!(tcx.sess, impl_item.span, E0324,
                                           "item `{}` is an associated method, \
-                                          which doesn't match its trait `{}`",
+                                          which doesn't match its trait `{:?}`",
                                           token::get_name(impl_item_ty.name()),
-                                          impl_trait_ref.repr(tcx))
+                                          impl_trait_ref)
                             }
                         }
                     }
@@ -1020,9 +1019,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         // caught in resolve.
                         tcx.sess.span_bug(
                             impl_item.span,
-                            &format!("method `{}` is not a member of trait `{}`",
+                            &format!("method `{}` is not a member of trait `{:?}`",
                                      token::get_name(impl_item_ty.name()),
-                                     impl_trait_ref.repr(tcx)));
+                                     impl_trait_ref));
                     }
                 }
             }
@@ -1043,9 +1042,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             _ => {
                                 span_err!(tcx.sess, impl_item.span, E0325,
                                           "item `{}` is an associated type, \
-                                          which doesn't match its trait `{}`",
+                                          which doesn't match its trait `{:?}`",
                                           token::get_name(typedef_ty.name()),
-                                          impl_trait_ref.repr(tcx))
+                                          impl_trait_ref)
                             }
                         }
                     }
@@ -1056,9 +1055,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             impl_item.span,
                             &format!(
                                 "associated type `{}` is not a member of \
-                                 trait `{}`",
+                                 trait `{:?}`",
                                 token::get_name(typedef_ty.name()),
-                                impl_trait_ref.repr(tcx)));
+                                impl_trait_ref));
                     }
                 }
             }
@@ -1295,18 +1294,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// version, this version will also select obligations if it seems
     /// useful, in an effort to get more type information.
     fn resolve_type_vars_if_possible(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_type_vars_if_possible(ty={})", ty.repr(self.tcx()));
+        debug!("resolve_type_vars_if_possible(ty={:?})", ty);
 
         // No ty::infer()? Nothing needs doing.
         if !ty::type_has_ty_infer(ty) {
-            debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+            debug!("resolve_type_vars_if_possible: ty={:?}", ty);
             return ty;
         }
 
         // If `ty` is a type variable, see whether we already know what it is.
         ty = self.infcx().resolve_type_vars_if_possible(&ty);
         if !ty::type_has_ty_infer(ty) {
-            debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+            debug!("resolve_type_vars_if_possible: ty={:?}", ty);
             return ty;
         }
 
@@ -1314,7 +1313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.select_new_obligations();
         ty = self.infcx().resolve_type_vars_if_possible(&ty);
         if !ty::type_has_ty_infer(ty) {
-            debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+            debug!("resolve_type_vars_if_possible: ty={:?}", ty);
             return ty;
         }
 
@@ -1325,7 +1324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.select_obligations_where_possible();
         ty = self.infcx().resolve_type_vars_if_possible(&ty);
 
-        debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+        debug!("resolve_type_vars_if_possible: ty={:?}", ty);
         ty
     }
 
@@ -1395,16 +1394,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     #[inline]
     pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
-        debug!("write_ty({}, {}) in fcx {}",
-               node_id, ppaux::ty_to_string(self.tcx(), ty), self.tag());
+        debug!("write_ty({}, {:?}) in fcx {}",
+               node_id, ty, self.tag());
         self.inh.node_types.borrow_mut().insert(node_id, ty);
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
         if !substs.substs.is_noop() {
-            debug!("write_substs({}, {}) in fcx {}",
+            debug!("write_substs({}, {:?}) in fcx {}",
                    node_id,
-                   substs.repr(self.tcx()),
+                   substs,
                    self.tag());
 
             self.inh.item_substs.borrow_mut().insert(node_id, substs);
@@ -1427,7 +1426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn write_adjustment(&self,
                             node_id: ast::NodeId,
                             adj: ty::AutoAdjustment<'tcx>) {
-        debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx()));
+        debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj);
 
         if adj.is_identity() {
             return;
@@ -1444,14 +1443,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                   substs: &Substs<'tcx>,
                                   value: &T)
                                   -> T
-        where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
+        where T : TypeFoldable<'tcx> + HasProjectionTypes
     {
         let value = value.subst(self.tcx(), substs);
         let result = self.normalize_associated_types_in(span, &value);
-        debug!("instantiate_type_scheme(value={}, substs={}) = {}",
-               value.repr(self.tcx()),
-               substs.repr(self.tcx()),
-               result.repr(self.tcx()));
+        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}",
+               value,
+               substs,
+               result);
         result
     }
 
@@ -1470,7 +1469,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
 
     fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
-        where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
+        where T : TypeFoldable<'tcx> + HasProjectionTypes
     {
         self.inh.normalize_associated_types_in(self, span, self.body_id, value)
     }
@@ -1615,8 +1614,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn register_predicate(&self,
                               obligation: traits::PredicateObligation<'tcx>)
     {
-        debug!("register_predicate({})",
-               obligation.repr(self.tcx()));
+        debug!("register_predicate({:?})",
+               obligation);
         self.inh.fulfillment_cx
             .borrow_mut()
             .register_predicate_obligation(self.infcx(), obligation);
@@ -1633,10 +1632,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         t
     }
 
-    pub fn pat_to_string(&self, pat: &ast::Pat) -> String {
-        pat.repr(self.tcx())
-    }
-
     pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> {
         match self.inh.node_types.borrow().get(&ex.id) {
             Some(&t) => t,
@@ -1745,7 +1740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                       cause: traits::ObligationCause<'tcx>)
     {
         let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
-        fulfillment_cx.register_region_obligation(self.infcx(), ty, region, cause);
+        fulfillment_cx.register_region_obligation(ty, region, cause);
     }
 
     pub fn add_default_region_param_bounds(&self,
@@ -1784,12 +1779,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         assert!(!predicates.has_escaping_regions());
 
-        debug!("add_obligations_for_parameters(predicates={})",
-               predicates.repr(self.tcx()));
+        debug!("add_obligations_for_parameters(predicates={:?})",
+               predicates);
 
-        for obligation in traits::predicates_for_generics(self.tcx(),
-                                                          cause,
-                                                          predicates) {
+        for obligation in traits::predicates_for_generics(cause, predicates) {
             self.register_predicate(obligation);
         }
     }
@@ -1942,9 +1935,9 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
                                  -> (Ty<'tcx>, usize, Option<T>)
     where F: FnMut(Ty<'tcx>, usize) -> Option<T>,
 {
-    debug!("autoderef(base_ty={}, opt_expr={}, lvalue_pref={:?})",
-           base_ty.repr(fcx.tcx()),
-           opt_expr.repr(fcx.tcx()),
+    debug!("autoderef(base_ty={:?}, opt_expr={:?}, lvalue_pref={:?})",
+           base_ty,
+           opt_expr,
            lvalue_pref);
 
     let mut t = base_ty;
@@ -2004,8 +1997,8 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
 
     // We've reached the recursion limit, error gracefully.
     span_err!(fcx.tcx().sess, sp, E0055,
-        "reached the recursion limit while auto-dereferencing {}",
-        base_ty.repr(fcx.tcx()));
+        "reached the recursion limit while auto-dereferencing {:?}",
+        base_ty);
     (fcx.tcx().types.err, 0, None)
 }
 
@@ -2120,14 +2113,14 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                             -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
 {
     let tcx = fcx.tcx();
-    debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, \
-                           autoderefs={}, unsize={}, index_ty={})",
-           expr.repr(tcx),
-           base_expr.repr(tcx),
-           adjusted_ty.repr(tcx),
+    debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \
+                           autoderefs={}, unsize={}, index_ty={:?})",
+           expr,
+           base_expr,
+           adjusted_ty,
            autoderefs,
            unsize,
-           index_ty.repr(tcx));
+           index_ty);
 
     let input_ty = fcx.infcx().next_ty_var();
 
@@ -2606,9 +2599,9 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             None
         }
     }).unwrap_or(vec![]);
-    debug!("expected_types_for_fn_args(formal={} -> {}, expected={} -> {})",
-           formal_args.repr(fcx.tcx()), formal_ret.repr(fcx.tcx()),
-           expected_args.repr(fcx.tcx()), expected_ret.repr(fcx.tcx()));
+    debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})",
+           formal_args, formal_ret,
+           expected_args, expected_ret);
     expected_args
 }
 
@@ -2629,8 +2622,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                                         unifier: F) where
     F: FnOnce(),
 {
-    debug!(">> typechecking: expr={} expected={}",
-           expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
+    debug!(">> typechecking: expr={:?} expected={:?}",
+           expr, expected);
 
     // Checks a method call.
     fn check_method_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
@@ -2746,7 +2739,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                                                   |base_t, _| {
                 match base_t.sty {
                     ty::TyStruct(base_id, substs) => {
-                        debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
+                        debug!("struct named {:?}",  base_t);
                         let fields = ty::lookup_struct_fields(tcx, base_id);
                         fcx.lookup_field_ty(expr.span, base_id, &fields[..],
                                             field.node.name, &(*substs))
@@ -2850,7 +2843,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                     ty::TyStruct(base_id, substs) => {
                         tuple_like = ty::is_tuple_struct(tcx, base_id);
                         if tuple_like {
-                            debug!("tuple struct named {}", ppaux::ty_to_string(tcx, base_t));
+                            debug!("tuple struct named {:?}",  base_t);
                             let fields = ty::lookup_struct_fields(tcx, base_id);
                             fcx.lookup_tup_field_ty(expr.span, base_id, &fields[..],
                                                     idx.node, &(*substs))
@@ -3276,7 +3269,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                 }
             } else {
               tcx.sess.span_bug(expr.span,
-                                &format!("unbound path {}", expr.repr(tcx)))
+                                &format!("unbound path {:?}", expr))
           };
 
           if let Some((opt_ty, segments, def)) =
@@ -3607,8 +3600,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                                type_and_substs.ty) {
                 Ok(()) => {}
                 Err(type_error) => {
-                    let type_error_description =
-                        ty::type_err_to_str(tcx, &type_error);
                     span_err!(fcx.tcx().sess, path.span, E0235,
                                  "structure constructor specifies a \
                                          structure of type `{}`, but this \
@@ -3618,7 +3609,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                                          fcx.infcx()
                                             .ty_to_string(
                                                 actual_structure_type),
-                                         type_error_description);
+                                         type_error);
                     ty::note_and_explain_type_err(tcx, &type_error, path.span);
                 }
             }
@@ -3748,9 +3739,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
 
     debug!("type of expr({}) {} is...", expr.id,
            syntax::print::pprust::expr_to_string(expr));
-    debug!("... {}, expected is {}",
-           ppaux::ty_to_string(tcx, fcx.expr_ty(expr)),
-           expected.repr(tcx));
+    debug!("... {:?}, expected is {:?}",
+           fcx.expr_ty(expr),
+           expected);
 
     unifier();
 }
@@ -3909,20 +3900,6 @@ impl<'tcx> Expectation<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for Expectation<'tcx> {
-    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        match *self {
-            NoExpectation => format!("NoExpectation"),
-            ExpectHasType(t) => format!("ExpectHasType({})",
-                                        t.repr(tcx)),
-            ExpectCastableToType(t) => format!("ExpectCastableToType({})",
-                                               t.repr(tcx)),
-            ExpectRvalueLikeUnsized(t) => format!("ExpectRvalueLikeUnsized({})",
-                                                  t.repr(tcx)),
-        }
-    }
-}
-
 pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                        local: &'tcx ast::Local,
                                        init: &'tcx ast::Expr)
@@ -4197,8 +4174,8 @@ pub fn check_instantiable(tcx: &ty::ctxt,
         span_err!(tcx.sess, sp, E0073,
             "this type cannot be instantiated without an \
              instance of itself");
-        fileline_help!(tcx.sess, sp, "consider using `Option<{}>`",
-            ppaux::ty_to_string(tcx, item_ty));
+        fileline_help!(tcx.sess, sp, "consider using `Option<{:?}>`",
+             item_ty);
         false
     } else {
         true
@@ -4389,11 +4366,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                   def: def::Def,
                                   span: Span,
                                   node_id: ast::NodeId) {
-    debug!("instantiate_path(path={:?}, def={}, node_id={}, type_scheme={})",
+    debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
            segments,
-           def.repr(fcx.tcx()),
+           def,
            node_id,
-           type_scheme.repr(fcx.tcx()));
+           type_scheme);
 
     // We need to extract the type parameters supplied by the user in
     // the path `path`. Due to the current setup, this is a bit of a
@@ -4633,9 +4610,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         if fcx.mk_subty(false, infer::Misc(span), self_ty, impl_ty).is_err() {
             fcx.tcx().sess.span_bug(span,
             &format!(
-                "instantiate_path: (UFCS) {} was a subtype of {} but now is not?",
-                self_ty.repr(fcx.tcx()),
-                impl_ty.repr(fcx.tcx())));
+                "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
+                self_ty,
+                impl_ty));
         }
     }
 
@@ -4840,7 +4817,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
         assert_eq!(substs.types.len(space), desired.len());
 
-        debug!("Final substs: {}", substs.repr(fcx.tcx()));
+        debug!("Final substs: {:?}", substs);
     }
 
     fn adjust_region_parameters(
@@ -4949,8 +4926,8 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                        span: Span,
                                        tps: &OwnedSlice<ast::TyParam>,
                                        ty: Ty<'tcx>) {
-    debug!("check_bounds_are_used(n_tps={}, ty={})",
-           tps.len(), ppaux::ty_to_string(ccx.tcx, ty));
+    debug!("check_bounds_are_used(n_tps={}, ty={:?})",
+           tps.len(),  ty);
 
     // make a vector of booleans initially false, set to true when used
     if tps.is_empty() { return; }
@@ -5273,7 +5250,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
                            fty,
                            || {
                 format!("intrinsic has wrong type: expected `{}`",
-                        ppaux::ty_to_string(ccx.tcx, fty))
+                         fty)
             });
     }
 }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index b4000788d19..a5e4e0fab59 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -25,7 +25,6 @@ use middle::ty::{self, Ty};
 use syntax::ast;
 use syntax::ast_util;
 use syntax::parse::token;
-use util::ppaux::{Repr, UserString};
 
 /// Check a `a <op>= b`
 pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
@@ -51,8 +50,8 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
         span_err!(tcx.sess, lhs_expr.span, E0368,
                   "binary assignment operation `{}=` cannot be applied to types `{}` and `{}`",
                   ast_util::binop_to_string(op.node),
-                  lhs_ty.user_string(fcx.tcx()),
-                  rhs_ty.user_string(fcx.tcx()));
+                  lhs_ty,
+                  rhs_ty);
         fcx.write_error(expr.id);
     }
 
@@ -73,12 +72,12 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 {
     let tcx = fcx.ccx.tcx;
 
-    debug!("check_binop(expr.id={}, expr={}, op={:?}, lhs_expr={}, rhs_expr={})",
+    debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})",
            expr.id,
-           expr.repr(tcx),
+           expr,
            op,
-           lhs_expr.repr(tcx),
-           rhs_expr.repr(tcx));
+           lhs_expr,
+           rhs_expr);
 
     check_expr(fcx, lhs_expr);
     let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr));
@@ -180,16 +179,16 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // if this is simd, result is same as lhs, else bool
             if ty::type_is_simd(tcx, lhs_ty) {
                 let unit_ty = ty::simd_type(tcx, lhs_ty);
-                debug!("enforce_builtin_binop_types: lhs_ty={} unit_ty={}",
-                       lhs_ty.repr(tcx),
-                       unit_ty.repr(tcx));
+                debug!("enforce_builtin_binop_types: lhs_ty={:?} unit_ty={:?}",
+                       lhs_ty,
+                       unit_ty);
                 if !ty::type_is_integral(unit_ty) {
                     tcx.sess.span_err(
                         lhs_expr.span,
                         &format!("binary comparison operation `{}` not supported \
                                   for floating point SIMD vector `{}`",
                                  ast_util::binop_to_string(op.node),
-                                 lhs_ty.user_string(tcx)));
+                                 lhs_ty));
                     tcx.types.err
                 } else {
                     lhs_ty
@@ -209,9 +208,9 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                     op: ast::BinOp)
                                     -> (Ty<'tcx>, Ty<'tcx>)
 {
-    debug!("check_overloaded_binop(expr.id={}, lhs_ty={})",
+    debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?})",
            expr.id,
-           lhs_ty.repr(fcx.tcx()));
+           lhs_ty);
 
     let (name, trait_def_id) = name_and_trait_def_id(fcx, op);
 
@@ -233,7 +232,7 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
                           "binary operation `{}` cannot be applied to type `{}`",
                           ast_util::binop_to_string(op.node),
-                          lhs_ty.user_string(fcx.tcx()));
+                          lhs_ty);
             }
             fcx.tcx().types.err
         }
@@ -304,12 +303,12 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
                               lhs_expr: &'a ast::Expr)
                               -> Result<Ty<'tcx>,()>
 {
-    debug!("lookup_op_method(expr={}, lhs_ty={}, opname={:?}, trait_did={}, lhs_expr={})",
-           expr.repr(fcx.tcx()),
-           lhs_ty.repr(fcx.tcx()),
+    debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, trait_did={:?}, lhs_expr={:?})",
+           expr,
+           lhs_ty,
            opname,
-           trait_did.repr(fcx.tcx()),
-           lhs_expr.repr(fcx.tcx()));
+           trait_did,
+           lhs_expr);
 
     let method = match trait_did {
         Some(trait_did) => {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index cb4d048ab37..a96e7864fe6 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -94,7 +94,6 @@ use middle::traits;
 use middle::ty::{self, ClosureTyper, ReScope, Ty, MethodCall};
 use middle::infer::{self, GenericKind};
 use middle::pat_util;
-use util::ppaux::{ty_to_string, Repr};
 
 use std::mem;
 use syntax::{ast, ast_util};
@@ -321,8 +320,8 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
                                        .to_vec();
 
         for r_o in &region_obligations {
-            debug!("visit_region_obligations: r_o={}",
-                   r_o.repr(self.tcx()));
+            debug!("visit_region_obligations: r_o={:?}",
+                   r_o);
             let sup_type = self.resolve_type(r_o.sup_type);
             let origin = infer::RelateParamBound(r_o.cause.span, sup_type);
             type_must_outlive(self, origin, sup_type, r_o.sub_region);
@@ -348,24 +347,23 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
                            body_id: ast::NodeId,
                            span: Span) {
         debug!("relate_free_regions >>");
-        let tcx = self.tcx();
 
         for &ty in fn_sig_tys {
             let ty = self.resolve_type(ty);
-            debug!("relate_free_regions(t={})", ty.repr(tcx));
+            debug!("relate_free_regions(t={:?})", ty);
             let body_scope = CodeExtent::from_node_id(body_id);
             let body_scope = ty::ReScope(body_scope);
             let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id,
                                                         ty, body_scope, span);
 
             // Record any relations between free regions that we observe into the free-region-map.
-            self.free_region_map.relate_free_regions_from_implications(tcx, &implications);
+            self.free_region_map.relate_free_regions_from_implications(&implications);
 
             // But also record other relationships, such as `T:'x`,
             // that don't go into the free-region-map but which we use
             // here.
             for implication in implications {
-                debug!("implication: {}", implication.repr(tcx));
+                debug!("implication: {:?}", implication);
                 match implication {
                     implicator::Implication::RegionSubRegion(_,
                                                              ty::ReFree(free_a),
@@ -373,8 +371,8 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
                         self.fcx.inh.infcx.add_given(free_a, vid_b);
                     }
                     implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => {
-                        debug!("RegionSubGeneric: {} <= {}",
-                               r_a.repr(tcx), generic_b.repr(tcx));
+                        debug!("RegionSubGeneric: {:?} <= {:?}",
+                               r_a, generic_b);
 
                         self.region_bound_pairs.push((r_a, generic_b.clone()));
                     }
@@ -465,7 +463,7 @@ fn visit_local(rcx: &mut Rcx, l: &ast::Local) {
 
 fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
     let tcx = rcx.fcx.tcx();
-    debug!("regionck::visit_pat(pat={})", pat.repr(tcx));
+    debug!("regionck::visit_pat(pat={:?})", pat);
     pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| {
         // If we have a variable that contains region'd data, that
         // data will be accessible from anywhere that the variable is
@@ -502,8 +500,8 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
 }
 
 fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
-    debug!("regionck::visit_expr(e={}, repeating_scope={})",
-           expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
+    debug!("regionck::visit_expr(e={:?}, repeating_scope={})",
+           expr, rcx.repeating_scope);
 
     // No matter what, the type of each expression must outlive the
     // scope of that expression. This also guarantees basic WF.
@@ -745,9 +743,9 @@ fn constrain_cast(rcx: &mut Rcx,
                   cast_expr: &ast::Expr,
                   source_expr: &ast::Expr)
 {
-    debug!("constrain_cast(cast_expr={}, source_expr={})",
-           cast_expr.repr(rcx.tcx()),
-           source_expr.repr(rcx.tcx()));
+    debug!("constrain_cast(cast_expr={:?}, source_expr={:?})",
+           cast_expr,
+           source_expr);
 
     let source_ty = rcx.resolve_node_type(source_expr.id);
     let target_ty = rcx.resolve_node_type(cast_expr.id);
@@ -758,9 +756,9 @@ fn constrain_cast(rcx: &mut Rcx,
                            cast_expr: &ast::Expr,
                            from_ty: Ty<'tcx>,
                            to_ty: Ty<'tcx>) {
-        debug!("walk_cast(from_ty={}, to_ty={})",
-               from_ty.repr(rcx.tcx()),
-               to_ty.repr(rcx.tcx()));
+        debug!("walk_cast(from_ty={:?}, to_ty={:?})",
+               from_ty,
+               to_ty);
         match (&from_ty.sty, &to_ty.sty) {
             /*From:*/ (&ty::TyRef(from_r, ref from_mt),
             /*To:  */  &ty::TyRef(to_r, ref to_mt)) => {
@@ -808,7 +806,7 @@ fn constrain_callee(rcx: &mut Rcx,
             //
             // tcx.sess.span_bug(
             //     callee_expr.span,
-            //     format!("Calling non-function: {}", callee_ty.repr(tcx)));
+            //     format!("Calling non-function: {}", callee_ty));
         }
     }
 }
@@ -823,12 +821,11 @@ fn constrain_call<'a, I: Iterator<Item=&'a ast::Expr>>(rcx: &mut Rcx,
     //! in the type of the function. Also constrains the regions that
     //! appear in the arguments appropriately.
 
-    let tcx = rcx.fcx.tcx();
-    debug!("constrain_call(call_expr={}, \
-            receiver={}, \
+    debug!("constrain_call(call_expr={:?}, \
+            receiver={:?}, \
             implicitly_ref_args={})",
-            call_expr.repr(tcx),
-            receiver.repr(tcx),
+            call_expr,
+            receiver,
             implicitly_ref_args);
 
     // `callee_region` is the scope representing the time in which the
@@ -838,10 +835,10 @@ fn constrain_call<'a, I: Iterator<Item=&'a ast::Expr>>(rcx: &mut Rcx,
     let callee_scope = CodeExtent::from_node_id(call_expr.id);
     let callee_region = ty::ReScope(callee_scope);
 
-    debug!("callee_region={}", callee_region.repr(tcx));
+    debug!("callee_region={:?}", callee_region);
 
     for arg_expr in arg_exprs {
-        debug!("Argument: {}", arg_expr.repr(tcx));
+        debug!("Argument: {:?}", arg_expr);
 
         // ensure that any regions appearing in the argument type are
         // valid for at least the lifetime of the function:
@@ -860,7 +857,7 @@ fn constrain_call<'a, I: Iterator<Item=&'a ast::Expr>>(rcx: &mut Rcx,
 
     // as loop above, but for receiver
     if let Some(r) = receiver {
-        debug!("receiver: {}", r.repr(tcx));
+        debug!("receiver: {:?}", r);
         type_of_node_must_outlive(
             rcx, infer::CallRcvr(r.span),
             r.id, callee_region);
@@ -877,10 +874,10 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                                   derefs: usize,
                                   mut derefd_ty: Ty<'tcx>)
 {
-    debug!("constrain_autoderefs(deref_expr={}, derefs={}, derefd_ty={})",
-           deref_expr.repr(rcx.tcx()),
+    debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})",
+           deref_expr,
            derefs,
-           derefd_ty.repr(rcx.tcx()));
+           derefd_ty);
 
     let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
     for i in 0..derefs {
@@ -889,8 +886,8 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
 
         derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
             Some(method) => {
-                debug!("constrain_autoderefs: #{} is overloaded, method={}",
-                       i, method.repr(rcx.tcx()));
+                debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
+                       i, method);
 
                 // Treat overloaded autoderefs as if an AutoRef adjustment
                 // was applied on the base type, as that is always the case.
@@ -903,19 +900,19 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                     _ => {
                         rcx.tcx().sess.span_bug(
                             deref_expr.span,
-                            &format!("bad overloaded deref type {}",
-                                     method.ty.repr(rcx.tcx())))
+                            &format!("bad overloaded deref type {:?}",
+                                     method.ty))
                     }
                 };
 
                 debug!("constrain_autoderefs: receiver r={:?} m={:?}",
-                       r.repr(rcx.tcx()), m);
+                       r, m);
 
                 {
                     let mc = mc::MemCategorizationContext::new(rcx.fcx);
                     let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
                     debug!("constrain_autoderefs: self_cmt={:?}",
-                           self_cmt.repr(rcx.tcx()));
+                           self_cmt);
                     link_region(rcx, deref_expr.span, r,
                                 ty::BorrowKind::from_mutbl(m), self_cmt);
                 }
@@ -976,8 +973,8 @@ fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 't
                        .sess
                        .span_bug(span,
                                  &format!("unexpected rvalue region in rvalue \
-                                           destructor safety checking: `{}`",
-                                          region.repr(rcx.tcx())));
+                                           destructor safety checking: `{:?}`",
+                                          region));
                 }
             }
         }
@@ -1025,7 +1022,7 @@ fn type_of_node_must_outlive<'a, 'tcx>(
                            |method_call| rcx.resolve_method_type(method_call));
     debug!("constrain_regions_in_type_of_node(\
             ty={}, ty0={}, id={}, minimum_lifetime={:?})",
-           ty_to_string(tcx, ty), ty_to_string(tcx, ty0),
+            ty,  ty0,
            id, minimum_lifetime);
     type_must_outlive(rcx, origin, ty, minimum_lifetime);
 }
@@ -1034,14 +1031,14 @@ fn type_of_node_must_outlive<'a, 'tcx>(
 /// resulting pointer is linked to the lifetime of its guarantor (if any).
 fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
                 mutability: ast::Mutability, base: &ast::Expr) {
-    debug!("link_addr_of(expr={}, base={})", expr.repr(rcx.tcx()), base.repr(rcx.tcx()));
+    debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
 
     let cmt = {
         let mc = mc::MemCategorizationContext::new(rcx.fcx);
         ignore_err!(mc.cat_expr(base))
     };
 
-    debug!("link_addr_of: cmt={}", cmt.repr(rcx.tcx()));
+    debug!("link_addr_of: cmt={:?}", cmt);
 
     link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
 }
@@ -1067,7 +1064,7 @@ fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
     debug!("regionck::for_match()");
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
     let discr_cmt = ignore_err!(mc.cat_expr(discr));
-    debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
+    debug!("discr_cmt={:?}", discr_cmt);
     for arm in arms {
         for root_pat in &arm.pats {
             link_pattern(rcx, mc, discr_cmt.clone(), &**root_pat);
@@ -1085,9 +1082,9 @@ fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) {
         let arg_ty = rcx.fcx.node_ty(arg.id);
         let re_scope = ty::ReScope(body_scope);
         let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
-        debug!("arg_ty={} arg_cmt={}",
-               arg_ty.repr(rcx.tcx()),
-               arg_cmt.repr(rcx.tcx()));
+        debug!("arg_ty={:?} arg_cmt={:?}",
+               arg_ty,
+               arg_cmt);
         link_pattern(rcx, mc, arg_cmt, &*arg.pat);
     }
 }
@@ -1098,9 +1095,9 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                           mc: mc::MemCategorizationContext<FnCtxt<'a, 'tcx>>,
                           discr_cmt: mc::cmt<'tcx>,
                           root_pat: &ast::Pat) {
-    debug!("link_pattern(discr_cmt={}, root_pat={})",
-           discr_cmt.repr(rcx.tcx()),
-           root_pat.repr(rcx.tcx()));
+    debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
+           discr_cmt,
+           root_pat);
     let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
             match sub_pat.node {
                 // `ref x` pattern
@@ -1136,7 +1133,7 @@ fn link_autoref(rcx: &Rcx,
     debug!("link_autoref(autoref={:?})", autoref);
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
     let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
-    debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
+    debug!("expr_cmt={:?}", expr_cmt);
 
     match *autoref {
         ty::AutoPtr(r, m) => {
@@ -1156,9 +1153,8 @@ fn link_autoref(rcx: &Rcx,
 fn link_by_ref(rcx: &Rcx,
                expr: &ast::Expr,
                callee_scope: CodeExtent) {
-    let tcx = rcx.tcx();
-    debug!("link_by_ref(expr={}, callee_scope={:?})",
-           expr.repr(tcx), callee_scope);
+    debug!("link_by_ref(expr={:?}, callee_scope={:?})",
+           expr, callee_scope);
     let mc = mc::MemCategorizationContext::new(rcx.fcx);
     let expr_cmt = ignore_err!(mc.cat_expr(expr));
     let borrow_region = ty::ReScope(callee_scope);
@@ -1172,13 +1168,13 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                                         id: ast::NodeId,
                                         mutbl: ast::Mutability,
                                         cmt_borrowed: mc::cmt<'tcx>) {
-    debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={})",
-           id, mutbl, cmt_borrowed.repr(rcx.tcx()));
+    debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
+           id, mutbl, cmt_borrowed);
 
     let rptr_ty = rcx.resolve_node_type(id);
     if !ty::type_is_error(rptr_ty) {
         let tcx = rcx.fcx.ccx.tcx;
-        debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty));
+        debug!("rptr_ty={}",  rptr_ty);
         let r = ty::ty_region(tcx, span, rptr_ty);
         link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl),
                     cmt_borrowed);
@@ -1197,10 +1193,10 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
     let mut borrow_kind = borrow_kind;
 
     loop {
-        debug!("link_region(borrow_region={}, borrow_kind={}, borrow_cmt={})",
-               borrow_region.repr(rcx.tcx()),
-               borrow_kind.repr(rcx.tcx()),
-               borrow_cmt.repr(rcx.tcx()));
+        debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})",
+               borrow_region,
+               borrow_kind,
+               borrow_cmt);
         match borrow_cmt.cat.clone() {
             mc::cat_deref(ref_cmt, _,
                           mc::Implicit(ref_kind, ref_region)) |
@@ -1310,8 +1306,8 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                 _ => {
                     rcx.tcx().sess.span_bug(
                         span,
-                        &format!("Illegal upvar id: {}",
-                                upvar_id.repr(rcx.tcx())));
+                        &format!("Illegal upvar id: {:?}",
+                                upvar_id));
                 }
             }
         }
@@ -1326,9 +1322,9 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
         }
     };
 
-    debug!("link_reborrowed_region: {} <= {}",
-           borrow_region.repr(rcx.tcx()),
-           ref_region.repr(rcx.tcx()));
+    debug!("link_reborrowed_region: {:?} <= {:?}",
+           borrow_region,
+           ref_region);
     rcx.fcx.mk_subr(cause, *borrow_region, ref_region);
 
     // If we end up needing to recurse and establish a region link
@@ -1401,14 +1397,14 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                                ty: Ty<'tcx>,
                                region: ty::Region)
 {
-    debug!("type_must_outlive(ty={}, region={})",
-           ty.repr(rcx.tcx()),
-           region.repr(rcx.tcx()));
+    debug!("type_must_outlive(ty={:?}, region={:?})",
+           ty,
+           region);
 
     let implications = implicator::implications(rcx.fcx.infcx(), rcx.fcx, rcx.body_id,
                                                 ty, region, origin.span());
     for implication in implications {
-        debug!("implication: {}", implication.repr(rcx.tcx()));
+        debug!("implication: {:?}", implication);
         match implication {
             implicator::Implication::RegionSubRegion(None, r_a, r_b) => {
                 rcx.fcx.mk_subr(origin.clone(), r_a, r_b);
@@ -1443,8 +1439,8 @@ fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                                   region: ty::Region,
                                   def_id: ast::DefId,
                                   substs: &'tcx Substs<'tcx>) {
-    debug!("closure_must_outlive(region={}, def_id={}, substs={})",
-           region.repr(rcx.tcx()), def_id.repr(rcx.tcx()), substs.repr(rcx.tcx()));
+    debug!("closure_must_outlive(region={:?}, def_id={:?}, substs={:?})",
+           region, def_id, substs);
 
     let upvars = rcx.fcx.closure_upvars(def_id, substs).unwrap();
     for upvar in upvars {
@@ -1461,9 +1457,9 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                                   generic: &GenericKind<'tcx>) {
     let param_env = &rcx.fcx.inh.param_env;
 
-    debug!("param_must_outlive(region={}, generic={})",
-           region.repr(rcx.tcx()),
-           generic.repr(rcx.tcx()));
+    debug!("param_must_outlive(region={:?}, generic={:?})",
+           region,
+           generic);
 
     // To start, collect bounds from user:
     let mut param_bounds =
@@ -1496,9 +1492,9 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
     // well-formed, then, A must be lower-generic by `'a`, but we
     // don't know that this holds from first principles.
     for &(ref r, ref p) in &rcx.region_bound_pairs {
-        debug!("generic={} p={}",
-               generic.repr(rcx.tcx()),
-               p.repr(rcx.tcx()));
+        debug!("generic={:?} p={:?}",
+               generic,
+               p);
         if generic == p {
             param_bounds.push(*r);
         }
@@ -1521,8 +1517,8 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
     let tcx = fcx.tcx();
     let infcx = fcx.infcx();
 
-    debug!("projection_bounds(projection_ty={})",
-           projection_ty.repr(tcx));
+    debug!("projection_bounds(projection_ty={:?})",
+           projection_ty);
 
     let ty = ty::mk_projection(tcx, projection_ty.trait_ref.clone(), projection_ty.item_name);
 
@@ -1546,16 +1542,16 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
                 _ => { return None; }
             };
 
-            debug!("projection_bounds: outlives={} (1)",
-                   outlives.repr(tcx));
+            debug!("projection_bounds: outlives={:?} (1)",
+                   outlives);
 
             // apply the substitutions (and normalize any projected types)
             let outlives = fcx.instantiate_type_scheme(span,
                                                        projection_ty.trait_ref.substs,
                                                        &outlives);
 
-            debug!("projection_bounds: outlives={} (2)",
-                   outlives.repr(tcx));
+            debug!("projection_bounds: outlives={:?} (2)",
+                   outlives);
 
             let region_result = infcx.commit_if_ok(|_| {
                 let (outlives, _) =
@@ -1564,8 +1560,8 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
                         infer::AssocTypeProjection(projection_ty.item_name),
                         &outlives);
 
-                debug!("projection_bounds: outlives={} (3)",
-                       outlives.repr(tcx));
+                debug!("projection_bounds: outlives={:?} (3)",
+                       outlives);
 
                 // check whether this predicate applies to our current projection
                 match infer::mk_eqty(infcx, false, infer::Misc(span), ty, outlives.0) {
@@ -1574,8 +1570,8 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
                 }
             });
 
-            debug!("projection_bounds: region_result={}",
-                   region_result.repr(tcx));
+            debug!("projection_bounds: region_result={:?}",
+                   region_result);
 
             region_result.ok()
         })
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 10ec2225555..99e6309918c 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -51,7 +51,6 @@ use syntax::ast;
 use syntax::ast_util;
 use syntax::codemap::Span;
 use syntax::visit::{self, Visitor};
-use util::ppaux::Repr;
 
 ///////////////////////////////////////////////////////////////////////////
 // PUBLIC ENTRY POINTS
@@ -133,8 +132,8 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
         if !self.fcx.inh.closure_kinds.borrow().contains_key(&closure_def_id) {
             self.closures_with_inferred_kinds.insert(expr.id);
             self.fcx.inh.closure_kinds.borrow_mut().insert(closure_def_id, ty::FnClosureKind);
-            debug!("check_closure: adding closure_id={} to closures_with_inferred_kinds",
-                   closure_def_id.repr(self.tcx()));
+            debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds",
+                   closure_def_id);
         }
 
         ty::with_freevars(self.tcx(), expr.id, |freevars| {
@@ -178,10 +177,6 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
         AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds }
     }
 
-    fn tcx(&self) -> &'a ty::ctxt<'tcx> {
-        self.fcx.tcx()
-    }
-
     fn analyze_closure(&mut self, id: ast::NodeId, decl: &ast::FnDecl, body: &ast::Block) {
         /*!
          * Analysis starting point.
@@ -245,8 +240,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                                             cmt: mc::cmt<'tcx>,
                                             mode: euv::ConsumeMode)
     {
-        debug!("adjust_upvar_borrow_kind_for_consume(cmt={}, mode={:?})",
-               cmt.repr(self.tcx()), mode);
+        debug!("adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})",
+               cmt, mode);
 
         // we only care about moves
         match mode {
@@ -258,8 +253,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
         // for that to be legal, the upvar would have to be borrowed
         // by value instead
         let guarantor = cmt.guarantor();
-        debug!("adjust_upvar_borrow_kind_for_consume: guarantor={}",
-               guarantor.repr(self.tcx()));
+        debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
+               guarantor);
         match guarantor.cat {
             mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
             mc::cat_deref(_, _, mc::Implicit(..)) => {
@@ -296,8 +291,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
     /// to). If cmt contains any by-ref upvars, this implies that
     /// those upvars must be borrowed using an `&mut` borrow.
     fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
-        debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
-               cmt.repr(self.tcx()));
+        debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})",
+               cmt);
 
         match cmt.cat.clone() {
             mc::cat_deref(base, _, mc::Unique) |
@@ -330,8 +325,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
     }
 
     fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
-        debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
-               cmt.repr(self.tcx()));
+        debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})",
+               cmt);
 
         match cmt.cat.clone() {
             mc::cat_deref(base, _, mc::Unique) |
@@ -498,7 +493,7 @@ impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
                cmt: mc::cmt<'tcx>,
                mode: euv::ConsumeMode)
     {
-        debug!("consume(cmt={},mode={:?})", cmt.repr(self.tcx()), mode);
+        debug!("consume(cmt={:?},mode={:?})", cmt, mode);
         self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
     }
 
@@ -513,7 +508,7 @@ impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
                    cmt: mc::cmt<'tcx>,
                    mode: euv::ConsumeMode)
     {
-        debug!("consume_pat(cmt={},mode={:?})", cmt.repr(self.tcx()), mode);
+        debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode);
         self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
     }
 
@@ -525,8 +520,8 @@ impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
               bk: ty::BorrowKind,
               _loan_cause: euv::LoanCause)
     {
-        debug!("borrow(borrow_id={}, cmt={}, bk={:?})",
-               borrow_id, cmt.repr(self.tcx()), bk);
+        debug!("borrow(borrow_id={}, cmt={:?}, bk={:?})",
+               borrow_id, cmt, bk);
 
         match bk {
             ty::ImmBorrow => { }
@@ -550,8 +545,8 @@ impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
               assignee_cmt: mc::cmt<'tcx>,
               _mode: euv::MutateMode)
     {
-        debug!("mutate(assignee_cmt={})",
-               assignee_cmt.repr(self.tcx()));
+        debug!("mutate(assignee_cmt={:?})",
+               assignee_cmt);
 
         self.adjust_upvar_borrow_kind_for_mut(assignee_cmt);
     }
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index 779f48d1e1b..c048845892c 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -18,7 +18,6 @@ use middle::traits;
 use middle::ty::{self, Ty};
 use middle::ty::liberate_late_bound_regions;
 use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
-use util::ppaux::{Repr, UserString};
 
 use std::collections::HashSet;
 use syntax::ast;
@@ -350,7 +349,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                          param_name: ast::Name)
     {
         span_err!(self.tcx().sess, span, E0392,
-            "parameter `{}` is never used", param_name.user_string(self.tcx()));
+            "parameter `{}` is never used", param_name);
 
         let suggested_marker_id = self.tcx().lang_items.phantom_data();
         match suggested_marker_id {
@@ -358,7 +357,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 self.tcx().sess.fileline_help(
                     span,
                     &format!("consider removing `{}` or using a marker such as `{}`",
-                             param_name.user_string(self.tcx()),
+                             param_name,
                              ty::item_path_str(self.tcx(), def_id)));
             }
             None => {
@@ -395,7 +394,7 @@ fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
             "cannot bound type `{}`, where clause \
                 bounds may only be attached to types involving \
                 type parameters",
-                bounded_ty.repr(tcx))
+                bounded_ty)
     }
 
     fn is_ty_param(ty: ty::Ty) -> bool {
@@ -536,23 +535,23 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
     }
 
     fn fold_binder<T>(&mut self, binder: &ty::Binder<T>) -> ty::Binder<T>
-        where T : TypeFoldable<'tcx> + Repr<'tcx>
+        where T : TypeFoldable<'tcx>
     {
         self.binding_count += 1;
         let value = liberate_late_bound_regions(
             self.fcx.tcx(),
             region::DestructionScopeData::new(self.scope),
             binder);
-        debug!("BoundsChecker::fold_binder: late-bound regions replaced: {} at scope: {:?}",
-               value.repr(self.tcx()), self.scope);
+        debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}",
+               value, self.scope);
         let value = value.fold_with(self);
         self.binding_count -= 1;
         ty::Binder(value)
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("BoundsChecker t={}",
-               t.repr(self.tcx()));
+        debug!("BoundsChecker t={:?}",
+               t);
 
         match self.cache {
             Some(ref mut cache) => {
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3ecef67ed98..05cc3077fc9 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -21,7 +21,6 @@ use middle::ty_fold::{TypeFolder,TypeFoldable};
 use middle::infer;
 use write_substs_to_tcx;
 use write_ty_to_tcx;
-use util::ppaux::Repr;
 
 use std::cell::Cell;
 
@@ -169,10 +168,10 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
 
         self.visit_node_id(ResolvingPattern(p.span), p.id);
 
-        debug!("Type for pattern binding {} (id {}) resolved to {}",
+        debug!("Type for pattern binding {} (id {}) resolved to {:?}",
                pat_to_string(p),
                p.id,
-               ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
+               ty::node_id_to_type(self.tcx(), p.id));
 
         visit::walk_pat(self, p);
     }
@@ -215,9 +214,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                         ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
                 }
             };
-            debug!("Upvar capture for {} resolved to {}",
-                   upvar_id.repr(self.tcx()),
-                   new_upvar_capture.repr(self.tcx()));
+            debug!("Upvar capture for {:?} resolved to {:?}",
+                   upvar_id,
+                   new_upvar_capture);
             self.fcx.tcx().upvar_capture_map.borrow_mut().insert(*upvar_id, new_upvar_capture);
         }
     }
@@ -245,7 +244,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         let n_ty = self.fcx.node_ty(id);
         let n_ty = self.resolve(&n_ty, reason);
         write_ty_to_tcx(self.tcx(), id, n_ty);
-        debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
+        debug!("Node {} has type {:?}", id, n_ty);
 
         // Resolve any substitutions
         self.fcx.opt_node_ty_substs(id, |item_substs| {
@@ -294,9 +293,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         // Resolve any method map entry
         match self.fcx.inh.method_map.borrow_mut().remove(&method_call) {
             Some(method) => {
-                debug!("writeback::resolve_method_map_entry(call={:?}, entry={})",
+                debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
                        method_call,
-                       method.repr(self.tcx()));
+                       method);
                 let new_method = MethodCallee {
                     origin: self.resolve(&method.origin, reason),
                     ty: self.resolve(&method.ty, reason),
@@ -427,8 +426,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
         match self.infcx.fully_resolve(&t) {
             Ok(t) => t,
             Err(e) => {
-                debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
-                       t.repr(self.tcx));
+                debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable",
+                       t);
                 self.report_error(e);
                 self.tcx().types.err
             }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index cd7be46f9e0..b66c76048c6 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -44,7 +44,6 @@ use syntax::codemap::Span;
 use syntax::parse::token;
 use syntax::visit;
 use util::nodemap::{DefIdMap, FnvHashMap};
-use util::ppaux::Repr;
 
 mod orphan;
 mod overlap;
@@ -82,7 +81,7 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
             inference_context.tcx.sess.span_bug(
                 span,
                 &format!("coherence encountered unexpected type searching for base type: {}",
-                        ty.repr(inference_context.tcx)));
+                         ty));
         }
     }
 }
@@ -149,9 +148,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
 
         if let Some(trait_ref) = ty::impl_trait_ref(self.crate_context.tcx,
                                                     impl_did) {
-            debug!("(checking implementation) adding impl for trait '{}', item '{}'",
-                   trait_ref.repr(self.crate_context.tcx),
-                   token::get_ident(item.ident));
+            debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
+                   trait_ref,
+                   item.ident);
 
             enforce_trait_manually_implementable(self.crate_context.tcx,
                                                  item.span,
@@ -179,8 +178,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             trait_ref: &ty::TraitRef<'tcx>,
             all_impl_items: &mut Vec<ImplOrTraitItemId>) {
         let tcx = self.crate_context.tcx;
-        debug!("instantiate_default_methods(impl_id={:?}, trait_ref={})",
-               impl_id, trait_ref.repr(tcx));
+        debug!("instantiate_default_methods(impl_id={:?}, trait_ref={:?})",
+               impl_id, trait_ref);
 
         let impl_type_scheme = ty::lookup_item_type(tcx, impl_id);
 
@@ -190,7 +189,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             let new_id = tcx.sess.next_node_id();
             let new_did = local_def(new_id);
 
-            debug!("new_did={:?} trait_method={}", new_did, trait_method.repr(tcx));
+            debug!("new_did={:?} trait_method={:?}", new_did, trait_method);
 
             // Create substitutions for the various trait parameters.
             let new_method_ty =
@@ -203,7 +202,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                     &**trait_method,
                     Some(trait_method.def_id)));
 
-            debug!("new_method_ty={}", new_method_ty.repr(tcx));
+            debug!("new_method_ty={:?}", new_method_ty);
             all_impl_items.push(MethodTraitItemId(new_did));
 
             // construct the polytype for the method based on the
@@ -214,7 +213,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                 ty: ty::mk_bare_fn(tcx, Some(new_did),
                                    tcx.mk_bare_fn(new_method_ty.fty.clone()))
             };
-            debug!("new_polytype={}", new_polytype.repr(tcx));
+            debug!("new_polytype={:?}", new_polytype);
 
             tcx.tcache.borrow_mut().insert(new_did, new_polytype);
             tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone());
@@ -360,8 +359,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
         let copy_trait = ty::lookup_trait_def(tcx, copy_trait);
 
         copy_trait.for_each_impl(tcx, |impl_did| {
-            debug!("check_implementations_of_copy: impl_did={}",
-                   impl_did.repr(tcx));
+            debug!("check_implementations_of_copy: impl_did={:?}",
+                   impl_did);
 
             if impl_did.krate != ast::LOCAL_CRATE {
                 debug!("check_implementations_of_copy(): impl not in this \
@@ -370,16 +369,16 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             }
 
             let self_type = ty::lookup_item_type(tcx, impl_did);
-            debug!("check_implementations_of_copy: self_type={} (bound)",
-                   self_type.repr(tcx));
+            debug!("check_implementations_of_copy: self_type={:?} (bound)",
+                   self_type);
 
             let span = tcx.map.span(impl_did.node);
             let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
             let self_type = self_type.ty.subst(tcx, &param_env.free_substs);
             assert!(!self_type.has_escaping_regions());
 
-            debug!("check_implementations_of_copy: self_type={} (free)",
-                   self_type.repr(tcx));
+            debug!("check_implementations_of_copy: self_type={:?} (free)",
+                   self_type);
 
             match ty::can_type_implement_copy(&param_env, span, self_type) {
                 Ok(()) => {}
@@ -429,8 +428,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
         let trait_def = ty::lookup_trait_def(tcx, coerce_unsized_trait);
 
         trait_def.for_each_impl(tcx, |impl_did| {
-            debug!("check_implementations_of_coerce_unsized: impl_did={}",
-                   impl_did.repr(tcx));
+            debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
+                   impl_did);
 
             if impl_did.krate != ast::LOCAL_CRATE {
                 debug!("check_implementations_of_coerce_unsized(): impl not \
@@ -442,8 +441,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             let trait_ref = ty::impl_trait_ref(self.crate_context.tcx,
                                                impl_did).unwrap();
             let target = *trait_ref.substs.types.get(subst::TypeSpace, 0);
-            debug!("check_implementations_of_coerce_unsized: {} -> {} (bound)",
-                   source.repr(tcx), target.repr(tcx));
+            debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
+                   source, target);
 
             let span = tcx.map.span(impl_did.node);
             let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
@@ -451,8 +450,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             let target = target.subst(tcx, &param_env.free_substs);
             assert!(!source.has_escaping_regions());
 
-            debug!("check_implementations_of_coerce_unsized: {} -> {} (free)",
-                   source.repr(tcx), target.repr(tcx));
+            debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
+                   source, target);
 
             let infcx = new_infer_ctxt(tcx);
 
@@ -518,10 +517,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                                                 if name == token::special_names::unnamed_field {
                                                     i.to_string()
                                                 } else {
-                                                    token::get_name(name).to_string()
-                                                },
-                                                a.repr(tcx),
-                                                b.repr(tcx))
+                                                    name.to_string()
+                                                }, a, b)
                                    }).collect::<Vec<_>>().connect(", "));
                         return;
                     }
@@ -597,8 +594,8 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
 {
     let combined_substs = ty::make_substs_for_receiver_types(tcx, trait_ref, method);
 
-    debug!("subst_receiver_types_in_method_ty: combined_substs={}",
-           combined_substs.repr(tcx));
+    debug!("subst_receiver_types_in_method_ty: combined_substs={:?}",
+           combined_substs);
 
     let method_predicates = method.predicates.subst(tcx, &combined_substs);
     let mut method_generics = method.generics.subst(tcx, &combined_substs);
@@ -614,13 +611,13 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
             impl_type_scheme.generics.regions.get_slice(space).to_vec());
     }
 
-    debug!("subst_receiver_types_in_method_ty: method_generics={}",
-           method_generics.repr(tcx));
+    debug!("subst_receiver_types_in_method_ty: method_generics={:?}",
+           method_generics);
 
     let method_fty = method.fty.subst(tcx, &combined_substs);
 
-    debug!("subst_receiver_types_in_method_ty: method_ty={}",
-           method.fty.repr(tcx));
+    debug!("subst_receiver_types_in_method_ty: method_ty={:?}",
+           method.fty);
 
     ty::Method::new(
         method.name,
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index d815893524f..8376b92da3d 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -18,7 +18,6 @@ use syntax::ast;
 use syntax::ast_util;
 use syntax::codemap::Span;
 use syntax::visit;
-use util::ppaux::{Repr, UserString};
 
 pub fn check(tcx: &ty::ctxt) {
     let mut orphan = OrphanChecker { tcx: tcx };
@@ -66,7 +65,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
             ast::ItemImpl(_, _, _, None, _, _) => {
                 // For inherent impls, self type must be a nominal type
                 // defined in this crate.
-                debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx));
+                debug!("coherence2::orphan check: inherent impl {}",
+                       self.tcx.map.node_to_string(item.id));
                 let self_ty = ty::lookup_item_type(self.tcx, def_id).ty;
                 match self_ty.sty {
                     ty::TyEnum(def_id, _) |
@@ -208,7 +208,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
             }
             ast::ItemImpl(_, _, _, Some(_), _, _) => {
                 // "Trait" impl
-                debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx));
+                debug!("coherence2::orphan check: trait impl {}",
+                       self.tcx.map.node_to_string(item.id));
                 let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
                 let trait_def_id = trait_ref.def_id;
                 match traits::orphan_check(self.tcx, def_id) {
@@ -227,7 +228,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                                 "type parameter `{}` must be used as the type parameter for \
                                  some local type (e.g. `MyStruct<T>`); only traits defined in \
                                  the current crate can be implemented for a type parameter",
-                                param_ty.user_string(self.tcx));
+                                param_ty);
                         return;
                     }
                 }
@@ -265,9 +266,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                 // This final impl is legal according to the orpan
                 // rules, but it invalidates the reasoning from
                 // `two_foos` above.
-                debug!("trait_ref={} trait_def_id={} trait_has_default_impl={}",
-                       trait_ref.repr(self.tcx),
-                       trait_def_id.repr(self.tcx),
+                debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
+                       trait_ref,
+                       trait_def_id,
                        ty::trait_has_default_impl(self.tcx, trait_def_id));
                 if
                     ty::trait_has_default_impl(self.tcx, trait_def_id) &&
@@ -305,7 +306,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                                  can only be implemented for a struct/enum type, \
                                  not `{}`",
                                 ty::item_path_str(self.tcx, trait_def_id),
-                                self_ty.user_string(self.tcx)))
+                                self_ty))
                         }
                     };
 
@@ -329,7 +330,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
             }
             ast::ItemDefaultImpl(..) => {
                 // "Trait" impl
-                debug!("coherence2::orphan check: default trait impl {}", item.repr(self.tcx));
+                debug!("coherence2::orphan check: default trait impl {}",
+                       self.tcx.map.node_to_string(item.id));
                 let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
                 if trait_ref.def_id.krate != ast::LOCAL_CRATE {
                     span_err!(self.tcx.sess, item.span, E0318,
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 7564f7862fc..0e8067e7181 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -21,7 +21,6 @@ use syntax::ast_util;
 use syntax::visit;
 use syntax::codemap::Span;
 use util::nodemap::DefIdMap;
-use util::ppaux::{Repr, UserString};
 
 pub fn check(tcx: &ty::ctxt) {
     let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() };
@@ -61,8 +60,8 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
     fn check_for_overlapping_impls_of_trait(&self,
                                             trait_def: &'tcx ty::TraitDef<'tcx>)
     {
-        debug!("check_for_overlapping_impls_of_trait(trait_def={})",
-               trait_def.repr(self.tcx));
+        debug!("check_for_overlapping_impls_of_trait(trait_def={:?})",
+               trait_def);
 
         // We should already know all impls of this trait, so these
         // borrows are safe.
@@ -131,10 +130,10 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
         if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
             impl1_def_id, impl2_def_id)
         {
-            debug!("check_if_impls_overlap({}, {}, {})",
-                   trait_def_id.repr(self.tcx),
-                   impl1_def_id.repr(self.tcx),
-                   impl2_def_id.repr(self.tcx));
+            debug!("check_if_impls_overlap({:?}, {:?}, {:?})",
+                   trait_def_id,
+                   impl1_def_id,
+                   impl2_def_id);
 
             let infcx = infer::new_infer_ctxt(self.tcx);
             if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
@@ -217,7 +216,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
                                 span_err!(self.tcx.sess, item.span, E0371,
                                           "the object type `{}` automatically \
                                            implements the trait `{}`",
-                                          trait_ref.self_ty().user_string(self.tcx),
+                                          trait_ref.self_ty(),
                                           ty::item_path_str(self.tcx, trait_def_id));
                             }
                         }
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index e4926b119d5..fa39e9d0491 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -16,7 +16,6 @@ use syntax::ast::{Item, ItemImpl};
 use syntax::ast;
 use syntax::ast_util;
 use syntax::visit;
-use util::ppaux::UserString;
 
 pub fn check(tcx: &ty::ctxt) {
     let mut orphan = UnsafetyChecker { tcx: tcx };
@@ -55,14 +54,14 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
                     (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
                         span_err!(self.tcx.sess, item.span, E0199,
                                   "implementing the trait `{}` is not unsafe",
-                                  trait_ref.user_string(self.tcx));
+                                  trait_ref);
                     }
 
                     (ast::Unsafety::Unsafe,
                      ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
                         span_err!(self.tcx.sess, item.span, E0200,
                                   "the trait `{}` requires an `unsafe impl` declaration",
-                                  trait_ref.user_string(self.tcx));
+                                  trait_ref);
                     }
 
                     (ast::Unsafety::Unsafe,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index aabd33d9c1d..13d2cf25e06 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -80,8 +80,6 @@ use rscope::*;
 use rustc::ast_map;
 use util::common::{ErrorReported, memoized};
 use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux;
-use util::ppaux::{Repr,UserString};
 use write_ty_to_tcx;
 
 use std::cell::{Cell, RefCell};
@@ -256,7 +254,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
                 tcx.sess.note(
                     &format!("the cycle begins when computing the bounds \
                               for type parameter `{}`...",
-                             def.name.user_string(tcx)));
+                             def.name));
             }
         }
 
@@ -278,7 +276,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
                     tcx.sess.note(
                         &format!("...which then requires computing the bounds \
                                   for type parameter `{}`...",
-                                 def.name.user_string(tcx)));
+                                 def.name));
                 }
             }
         }
@@ -301,7 +299,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
                 tcx.sess.note(
                     &format!("...which then again requires computing the bounds \
                               for type parameter `{}`, completing the cycle.",
-                             def.name.user_string(tcx)));
+                             def.name));
             }
         }
     }
@@ -318,7 +316,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
 
         let item = match tcx.map.get(trait_id.node) {
             ast_map::NodeItem(item) => item,
-            _ => tcx.sess.bug(&format!("get_trait_def({}): not an item", trait_id.repr(tcx)))
+            _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id))
         };
 
         trait_def_of_item(self, &*item)
@@ -372,8 +370,8 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
                                trait_def_id: ast::DefId)
                                -> Result<(), ErrorReported>
     {
-        debug!("ensure_super_predicates(trait_def_id={})",
-               trait_def_id.repr(self.tcx()));
+        debug!("ensure_super_predicates(trait_def_id={:?})",
+               trait_def_id);
 
         self.ccx.ensure_super_predicates(span, trait_def_id)
     }
@@ -635,8 +633,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let fty = ty::mk_bare_fn(ccx.tcx, Some(def_id),
                              ccx.tcx.mk_bare_fn(ty_method.fty.clone()));
-    debug!("method {} (id {}) has type {}",
-            ident.repr(ccx.tcx), id, fty.repr(ccx.tcx));
+    debug!("method {} (id {}) has type {:?}",
+            ident, id, fty);
     ccx.tcx.tcache.borrow_mut().insert(def_id,TypeScheme {
         generics: ty_method.generics.clone(),
         ty: fty
@@ -645,8 +643,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     write_ty_to_tcx(ccx.tcx, id, fty);
 
-    debug!("writing method type: def_id={:?} mty={}",
-            def_id, ty_method.repr(ccx.tcx));
+    debug!("writing method type: def_id={:?} mty={:?}",
+            def_id, ty_method);
 
     ccx.tcx.impl_or_trait_items.borrow_mut().insert(def_id,
         ty::MethodTraitItem(Rc::new(ty_method)));
@@ -743,10 +741,11 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
                                  rcvr_ty_predicates: &ty::GenericPredicates<'tcx>)
     where I: Iterator<Item=(&'i ast::MethodSig, ast::NodeId, ast::Ident, ast::Visibility, Span)>
 {
-    debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={}, rcvr_ty_predicates={})",
-           untransformed_rcvr_ty.repr(ccx.tcx),
-           rcvr_ty_generics.repr(ccx.tcx),
-           rcvr_ty_predicates.repr(ccx.tcx));
+    debug!("convert_methods(untransformed_rcvr_ty={:?}, rcvr_ty_generics={:?}, \
+                            rcvr_ty_predicates={:?})",
+           untransformed_rcvr_ty,
+           rcvr_ty_generics,
+           rcvr_ty_predicates);
 
     let tcx = ccx.tcx;
     let mut seen_methods = FnvHashSet();
@@ -1140,7 +1139,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt,
 {
     let tcx = ccx.tcx;
 
-    debug!("ensure_super_predicates_step(trait_def_id={})", trait_def_id.repr(tcx));
+    debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
 
     if trait_def_id.krate != ast::LOCAL_CRATE {
         // If this trait comes from an external crate, then all of the
@@ -1192,9 +1191,9 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt,
         let superpredicates = ty::GenericPredicates {
             predicates: VecPerParamSpace::new(superbounds, vec![], vec![])
         };
-        debug!("superpredicates for trait {} = {}",
-               local_def(item.id).repr(ccx.tcx),
-               superpredicates.repr(ccx.tcx));
+        debug!("superpredicates for trait {:?} = {:?}",
+               local_def(item.id),
+               superpredicates);
 
         tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
 
@@ -1207,7 +1206,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt,
                                          .map(|tr| tr.def_id())
                                          .collect();
 
-    debug!("ensure_super_predicates_step: def_ids={}", def_ids.repr(tcx));
+    debug!("ensure_super_predicates_step: def_ids={:?}", def_ids);
 
     def_ids
 }
@@ -1533,9 +1532,8 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             scheme.generics.types.iter()
                                  .map(|t| match t.object_lifetime_default {
                                      Some(ty::ObjectLifetimeDefault::Specific(r)) =>
-                                         r.user_string(tcx),
-                                     d =>
-                                         d.repr(ccx.tcx),
+                                         r.to_string(),
+                                     d => format!("{:?}", d),
                                  })
                                  .collect::<Vec<String>>()
                                  .connect(",");
@@ -1621,8 +1619,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                    ast_generics: &ast::Generics)
                                    -> ty::Generics<'tcx>
 {
-    debug!("ty_generics_for_trait(trait_id={}, substs={})",
-           local_def(trait_id).repr(ccx.tcx), substs.repr(ccx.tcx));
+    debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})",
+           local_def(trait_id), substs);
 
     let mut generics = ty_generics_for_type_or_impl(ccx, ast_generics);
 
@@ -2201,12 +2199,12 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
                 &ty::liberate_late_bound_regions(
                     tcx, body_scope, &ty::Binder(base_type)));
 
-        debug!("required_type={} required_type_free={} \
-                base_type={} base_type_free={}",
-               required_type.repr(tcx),
-               required_type_free.repr(tcx),
-               base_type.repr(tcx),
-               base_type_free.repr(tcx));
+        debug!("required_type={:?} required_type_free={:?} \
+                base_type={:?} base_type_free={:?}",
+               required_type,
+               required_type_free,
+               base_type,
+               base_type_free);
 
         let infcx = infer::new_infer_ctxt(tcx);
         drop(::require_same_types(tcx,
@@ -2217,7 +2215,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
                                   required_type_free,
                                   || {
                 format!("mismatched self type: expected `{}`",
-                        ppaux::ty_to_string(tcx, required_type))
+                         required_type)
         }));
 
         // We could conceviably add more free-region relations here,
@@ -2236,7 +2234,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
         scope: region::DestructionScopeData,
         value: &T)
         -> T
-        where T : TypeFoldable<'tcx> + Repr<'tcx>
+        where T : TypeFoldable<'tcx>
     {
         /*!
          * Convert early-bound regions into free regions; normally this is done by
@@ -2287,7 +2285,7 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
                                      idx: index as u32,
                                      name: ty_param.ident.name };
         if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) {
-            report_unused_parameter(tcx, ty_param.span, "type", &param_ty.user_string(tcx));
+            report_unused_parameter(tcx, ty_param.span, "type", &param_ty.to_string());
         }
     }
 
@@ -2317,7 +2315,7 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
             !input_parameters.contains(&ctp::Parameter::Region(region))
         {
             report_unused_parameter(tcx, lifetime_def.lifetime.span,
-                                    "lifetime", &region.name.user_string(tcx));
+                                    "lifetime", &region.name.to_string());
         }
     }
 
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 7519cd05195..8feecd15613 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -109,8 +109,6 @@ use middle::ty::{self, Ty};
 use rustc::ast_map;
 use session::config;
 use util::common::time;
-use util::ppaux::Repr;
-use util::ppaux;
 
 use syntax::codemap::Span;
 use syntax::print::pprust::*;
@@ -149,7 +147,7 @@ pub struct CrateCtxt<'a, 'tcx: 'a> {
 
 // Functions that write types into the node type table
 fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
-    debug!("write_ty_to_tcx({}, {})", node_id, ppaux::ty_to_string(tcx, ty));
+    debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
     assert!(!ty::type_needs_infer(ty));
     tcx.node_type_insert(node_id, ty);
 }
@@ -158,9 +156,9 @@ fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
                                  node_id: ast::NodeId,
                                  item_substs: ty::ItemSubsts<'tcx>) {
     if !item_substs.is_noop() {
-        debug!("write_substs_to_tcx({}, {})",
+        debug!("write_substs_to_tcx({}, {:?})",
                node_id,
-               item_substs.repr(tcx));
+               item_substs);
 
         assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t)));
 
@@ -200,11 +198,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
     match result {
         Ok(_) => true,
         Err(ref terr) => {
-            span_err!(tcx.sess, span, E0211,
-                              "{}: {}",
-                                      msg(),
-                                      ty::type_err_to_str(tcx,
-                                                          terr));
+            span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
             ty::note_and_explain_type_err(tcx, terr, span);
             false
         }
@@ -245,15 +239,13 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
             require_same_types(tcx, None, false, main_span, main_t, se_ty,
                 || {
                     format!("main function expects type: `{}`",
-                            ppaux::ty_to_string(ccx.tcx, se_ty))
+                             se_ty)
                 });
         }
         _ => {
             tcx.sess.span_bug(main_span,
-                              &format!("main has a non-function type: found \
-                                       `{}`",
-                                      ppaux::ty_to_string(tcx,
-                                                       main_t)));
+                              &format!("main has a non-function type: found `{}`",
+                                       main_t));
         }
     }
 }
@@ -296,15 +288,14 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
             require_same_types(tcx, None, false, start_span, start_t, se_ty,
                 || {
                     format!("start function expects type: `{}`",
-                            ppaux::ty_to_string(ccx.tcx, se_ty))
+                             se_ty)
                 });
 
         }
         _ => {
             tcx.sess.span_bug(start_span,
-                              &format!("start has a non-function type: found \
-                                       `{}`",
-                                      ppaux::ty_to_string(tcx, start_t)));
+                              &format!("start has a non-function type: found `{}`",
+                                       start_t));
         }
     }
 }
diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs
index 37088701adc..1f4e1343651 100644
--- a/src/librustc_typeck/variance.rs
+++ b/src/librustc_typeck/variance.rs
@@ -278,7 +278,6 @@ use syntax::ast_util;
 use syntax::visit;
 use syntax::visit::Visitor;
 use util::nodemap::NodeMap;
-use util::ppaux::Repr;
 
 pub fn infer_variance(tcx: &ty::ctxt) {
     let krate = tcx.map.krate();
@@ -518,7 +517,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
 
 impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &ast::Item) {
-        debug!("add_inferreds for item {}", item.repr(self.tcx));
+        debug!("add_inferreds for item {}", self.tcx.map.node_to_string(item.id));
 
         match item.node {
             ast::ItemEnum(_, ref generics) |
@@ -600,8 +599,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
         let did = ast_util::local_def(item.id);
         let tcx = self.terms_cx.tcx;
 
-        debug!("visit_item item={}",
-               item.repr(tcx));
+        debug!("visit_item item={}", tcx.map.node_to_string(item.id));
 
         match item.node {
             ast::ItemEnum(ref enum_definition, _) => {
@@ -846,8 +844,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                                       generics: &ty::Generics<'tcx>,
                                       trait_ref: ty::TraitRef<'tcx>,
                                       variance: VarianceTermPtr<'a>) {
-        debug!("add_constraints_from_trait_ref: trait_ref={} variance={:?}",
-               trait_ref.repr(self.tcx()),
+        debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
+               trait_ref,
                variance);
 
         let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id);
@@ -868,8 +866,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                                generics: &ty::Generics<'tcx>,
                                ty: Ty<'tcx>,
                                variance: VarianceTermPtr<'a>) {
-        debug!("add_constraints_from_ty(ty={}, variance={:?})",
-               ty.repr(self.tcx()),
+        debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
+               ty,
                variance);
 
         match ty.sty {
@@ -982,8 +980,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             ty::TyInfer(..) => {
                 self.tcx().sess.bug(
                     &format!("unexpected type encountered in \
-                            variance inference: {}",
-                            ty.repr(self.tcx())));
+                              variance inference: {}", ty));
             }
         }
     }
@@ -998,9 +995,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                                    region_param_defs: &[ty::RegionParameterDef],
                                    substs: &subst::Substs<'tcx>,
                                    variance: VarianceTermPtr<'a>) {
-        debug!("add_constraints_from_substs(def_id={}, substs={}, variance={:?})",
-               def_id.repr(self.tcx()),
-               substs.repr(self.tcx()),
+        debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
+               def_id,
+               substs,
                variance);
 
         for p in type_param_defs {
@@ -1067,8 +1064,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.tcx()
                     .sess
                     .bug(&format!("unexpected region encountered in variance \
-                                  inference: {}",
-                                 region.repr(self.tcx())));
+                                  inference: {:?}",
+                                 region));
             }
         }
     }
@@ -1195,17 +1192,16 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
                 types: types,
                 regions: regions
             };
-            debug!("item_id={} item_variances={}",
+            debug!("item_id={} item_variances={:?}",
                     item_id,
-                    item_variances.repr(tcx));
+                    item_variances);
 
             let item_def_id = ast_util::local_def(item_id);
 
             // For unit testing: check for a special "rustc_variance"
             // attribute and report an error with various results if found.
             if ty::has_attr(tcx, item_def_id, "rustc_variance") {
-                let found = item_variances.repr(tcx);
-                span_err!(tcx.sess, tcx.map.span(item_id), E0208, "{}", &found[..]);
+                span_err!(tcx.sess, tcx.map.span(item_id), E0208, "{:?}", item_variances);
             }
 
             let newly_added = tcx.item_variance_map.borrow_mut()
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 77409f2746a..d40a9522f23 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -522,7 +522,7 @@ pub enum TyParamBound {
 impl TyParamBound {
     fn maybe_sized(cx: &DocContext) -> TyParamBound {
         use syntax::ast::TraitBoundModifier as TBM;
-        let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
+        let mut sized_bound = ty::BoundSized.clean(cx);
         if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
             *tbm = TBM::Maybe
         };
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 3183307250c..13022fd43ef 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -32,17 +32,17 @@ pub use rustc::session::config::Input;
 pub use rustc::session::search_paths::SearchPaths;
 
 /// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
-pub enum MaybeTyped<'tcx> {
-    Typed(ty::ctxt<'tcx>),
+pub enum MaybeTyped<'a, 'tcx: 'a> {
+    Typed(&'a ty::ctxt<'tcx>),
     NotTyped(session::Session)
 }
 
 pub type ExternalPaths = RefCell<Option<HashMap<ast::DefId,
                                                 (Vec<String>, clean::TypeKind)>>>;
 
-pub struct DocContext<'tcx> {
+pub struct DocContext<'a, 'tcx: 'a> {
     pub krate: &'tcx ast::Crate,
-    pub maybe_typed: MaybeTyped<'tcx>,
+    pub maybe_typed: MaybeTyped<'a, 'tcx>,
     pub input: Input,
     pub external_paths: ExternalPaths,
     pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
@@ -52,17 +52,17 @@ pub struct DocContext<'tcx> {
     pub deref_trait_did: Cell<Option<ast::DefId>>,
 }
 
-impl<'tcx> DocContext<'tcx> {
+impl<'b, 'tcx> DocContext<'b, 'tcx> {
     pub fn sess<'a>(&'a self) -> &'a session::Session {
         match self.maybe_typed {
-            Typed(ref tcx) => &tcx.sess,
+            Typed(tcx) => &tcx.sess,
             NotTyped(ref sess) => sess
         }
     }
 
     pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt<'tcx>> {
         match self.maybe_typed {
-            Typed(ref tcx) => Some(tcx),
+            Typed(tcx) => Some(tcx),
             NotTyped(_) => None
         }
     }
@@ -133,48 +133,49 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
     let arenas = ty::CtxtArenas::new();
     let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
 
-    let ty::CrateAnalysis {
-        exported_items, public_items, ty_cx, ..
-    } = driver::phase_3_run_analysis_passes(sess,
-                                            ast_map,
-                                            &arenas,
-                                            name,
-                                            resolve::MakeGlobMap::No);
-
-    let ctxt = DocContext {
-        krate: ty_cx.map.krate(),
-        maybe_typed: Typed(ty_cx),
-        input: input,
-        external_traits: RefCell::new(Some(HashMap::new())),
-        external_typarams: RefCell::new(Some(HashMap::new())),
-        external_paths: RefCell::new(Some(HashMap::new())),
-        inlined: RefCell::new(Some(HashSet::new())),
-        populated_crate_impls: RefCell::new(HashSet::new()),
-        deref_trait_did: Cell::new(None),
-    };
-    debug!("crate: {:?}", ctxt.krate);
-
-    let mut analysis = CrateAnalysis {
-        exported_items: exported_items,
-        public_items: public_items,
-        external_paths: RefCell::new(None),
-        external_typarams: RefCell::new(None),
-        inlined: RefCell::new(None),
-        deref_trait_did: None,
-    };
-
-    let krate = {
-        let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
-        v.visit(ctxt.krate);
-        v.clean(&ctxt)
-    };
-
-    let external_paths = ctxt.external_paths.borrow_mut().take();
-    *analysis.external_paths.borrow_mut() = external_paths;
-    let map = ctxt.external_typarams.borrow_mut().take();
-    *analysis.external_typarams.borrow_mut() = map;
-    let map = ctxt.inlined.borrow_mut().take();
-    *analysis.inlined.borrow_mut() = map;
-    analysis.deref_trait_did = ctxt.deref_trait_did.get();
-    (krate, analysis)
+    driver::phase_3_run_analysis_passes(sess,
+                                        ast_map,
+                                        &arenas,
+                                        name,
+                                        resolve::MakeGlobMap::No,
+                                        |tcx, analysis| {
+        let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
+
+        let ctxt = DocContext {
+            krate: tcx.map.krate(),
+            maybe_typed: Typed(tcx),
+            input: input,
+            external_traits: RefCell::new(Some(HashMap::new())),
+            external_typarams: RefCell::new(Some(HashMap::new())),
+            external_paths: RefCell::new(Some(HashMap::new())),
+            inlined: RefCell::new(Some(HashSet::new())),
+            populated_crate_impls: RefCell::new(HashSet::new()),
+            deref_trait_did: Cell::new(None),
+        };
+        debug!("crate: {:?}", ctxt.krate);
+
+        let mut analysis = CrateAnalysis {
+            exported_items: exported_items,
+            public_items: public_items,
+            external_paths: RefCell::new(None),
+            external_typarams: RefCell::new(None),
+            inlined: RefCell::new(None),
+            deref_trait_did: None,
+        };
+
+        let krate = {
+            let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
+            v.visit(ctxt.krate);
+            v.clean(&ctxt)
+        };
+
+        let external_paths = ctxt.external_paths.borrow_mut().take();
+        *analysis.external_paths.borrow_mut() = external_paths;
+        let map = ctxt.external_typarams.borrow_mut().take();
+        *analysis.external_typarams.borrow_mut() = map;
+        let map = ctxt.inlined.borrow_mut().take();
+        *analysis.inlined.borrow_mut() = map;
+        analysis.deref_trait_did = ctxt.deref_trait_did.get();
+        (krate, analysis)
+    }).1
 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index ff058fa908d..305747d1282 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -38,14 +38,14 @@ use doctree::*;
 pub struct RustdocVisitor<'a, 'tcx: 'a> {
     pub module: Module,
     pub attrs: Vec<ast::Attribute>,
-    pub cx: &'a core::DocContext<'tcx>,
+    pub cx: &'a core::DocContext<'a, 'tcx>,
     pub analysis: Option<&'a core::CrateAnalysis>,
     view_item_stack: HashSet<ast::NodeId>,
     inlining_from_glob: bool,
 }
 
 impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
-    pub fn new(cx: &'a core::DocContext<'tcx>,
+    pub fn new(cx: &'a core::DocContext<'a, 'tcx>,
                analysis: Option<&'a core::CrateAnalysis>) -> RustdocVisitor<'a, 'tcx> {
         // If the root is reexported, terminate all recursion.
         let mut stack = HashSet::new();
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 5b03b3bf038..e844b206cc0 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -63,8 +63,10 @@ use owned_slice::OwnedSlice;
 use parse::token::{InternedString, str_to_ident};
 use parse::token;
 use parse::lexer;
+use print::pprust;
 use ptr::P;
 
+use std::cell::Cell;
 use std::fmt;
 use std::rc::Rc;
 use serialize::{Encodable, Decodable, Encoder, Decoder};
@@ -200,14 +202,19 @@ impl Decodable for Ident {
 /// Function name (not all functions have names)
 pub type FnIdent = Option<Ident>;
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,
-           Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
     pub span: Span,
     pub name: Name
 }
 
+impl fmt::Debug for Lifetime {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
+    }
+}
+
 /// A lifetime definition, eg `'a: 'b+'c+'d`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct LifetimeDef {
@@ -218,7 +225,7 @@ pub struct LifetimeDef {
 /// A "Path" is essentially Rust's notion of a name; for instance:
 /// std::cmp::PartialEq  .  It's represented as a sequence of identifiers,
 /// along with a bunch of supporting information.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Path {
     pub span: Span,
     /// A `::foo` path, is relative to the crate root rather than current
@@ -228,6 +235,18 @@ pub struct Path {
     pub segments: Vec<PathSegment>,
 }
 
+impl fmt::Debug for Path {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "path({})", pprust::path_to_string(self))
+    }
+}
+
+impl fmt::Display for Path {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", pprust::path_to_string(self))
+    }
+}
+
 /// A segment of a path: an identifier, an optional lifetime, and a set of
 /// types.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -358,12 +377,25 @@ pub type CrateNum = u32;
 pub type NodeId = u32;
 
 #[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
-           RustcDecodable, Hash, Debug, Copy)]
+           RustcDecodable, Hash, Copy)]
 pub struct DefId {
     pub krate: CrateNum,
     pub node: NodeId,
 }
 
+fn default_def_id_debug(_: DefId, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) }
+
+thread_local!(pub static DEF_ID_DEBUG: Cell<fn(DefId, &mut fmt::Formatter) -> fmt::Result> =
+                Cell::new(default_def_id_debug));
+
+impl fmt::Debug for DefId {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        try!(write!(f, "DefId {{ krate: {}, node: {} }}",
+                    self.krate, self.node));
+        DEF_ID_DEBUG.with(|def_id_debug| def_id_debug.get()(*self, f))
+    }
+}
+
 impl DefId {
     /// Read the node id, asserting that this def-id is krate-local.
     pub fn local_id(&self) -> NodeId {
@@ -539,13 +571,19 @@ pub struct Block {
     pub span: Span,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Pat {
     pub id: NodeId,
     pub node: Pat_,
     pub span: Span,
 }
 
+impl fmt::Debug for Pat {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "pat({}: {})", self.id, pprust::pat_to_string(self))
+    }
+}
+
 /// A single field in a struct pattern
 ///
 /// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
@@ -682,7 +720,16 @@ pub enum UnOp {
 /// A statement
 pub type Stmt = Spanned<Stmt_>;
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+impl fmt::Debug for Stmt {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "stmt({}: {})",
+               ast_util::stmt_id(self),
+               pprust::stmt_to_string(self))
+    }
+}
+
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub enum Stmt_ {
     /// Could be an item or a local (let) binding:
     StmtDecl(P<Decl>, NodeId),
@@ -695,7 +742,6 @@ pub enum Stmt_ {
 
     StmtMac(P<Mac>, MacStmtStyle),
 }
-
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum MacStmtStyle {
     /// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
@@ -772,13 +818,19 @@ pub enum UnsafeSource {
 }
 
 /// An expression
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,)]
 pub struct Expr {
     pub id: NodeId,
     pub node: Expr_,
     pub span: Span,
 }
 
+impl fmt::Debug for Expr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "expr({}: {})", self.id, pprust::expr_to_string(self))
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Expr_ {
     /// First expr is the place; second expr is the value.
@@ -1357,13 +1409,19 @@ pub struct TypeBinding {
 
 
 // NB PartialEq method appears below.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Ty {
     pub id: NodeId,
     pub node: Ty_,
     pub span: Span,
 }
 
+impl fmt::Debug for Ty {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "type({})", pprust::ty_to_string(self))
+    }
+}
+
 /// Not represented directly in the AST, referred to by name through a ty_path.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum PrimTy {
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index ea27ed6b360..5ddcfaef9ea 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -19,7 +19,7 @@
 
 pub use self::ExpnFormat::*;
 
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::ops::{Add, Sub};
 use std::path::Path;
 use std::rc::Rc;
@@ -115,7 +115,7 @@ impl Sub for CharPos {
 /// are *absolute* positions from the beginning of the codemap, not positions
 /// relative to FileMaps. Methods on the CodeMap can be used to relate spans back
 /// to the original source.
-#[derive(Clone, Copy, Debug, Hash)]
+#[derive(Clone, Copy, Hash)]
 pub struct Span {
     pub lo: BytePos,
     pub hi: BytePos,
@@ -164,6 +164,20 @@ impl Decodable for Span {
     }
 }
 
+fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
+    write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}",
+           span.lo, span.hi, span.expn_id)
+}
+
+thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
+                Cell::new(default_span_debug));
+
+impl fmt::Debug for Span {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f))
+    }
+}
+
 pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
     respan(mk_sp(lo, hi), t)
 }
diff --git a/src/test/compile-fail/object-lifetime-default.rs b/src/test/compile-fail/object-lifetime-default.rs
index ac03c085b7b..b71eadd6d08 100644
--- a/src/test/compile-fail/object-lifetime-default.rs
+++ b/src/test/compile-fail/object-lifetime-default.rs
@@ -29,6 +29,6 @@ struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b
 struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b
 
 #[rustc_object_lifetime_default]
-struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous
+struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Some(Ambiguous)
 
 fn main() { }
diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs
index 5c15a56c6ef..8af3844e62e 100644
--- a/src/test/run-make/execution-engine/test.rs
+++ b/src/test/run-make/execution-engine/test.rs
@@ -221,25 +221,26 @@ fn compile_program(input: &str, sysroot: PathBuf)
         let arenas = ty::CtxtArenas::new();
         let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
 
-        let analysis = driver::phase_3_run_analysis_passes(
-            sess, ast_map, &arenas, id, MakeGlobMap::No);
+        driver::phase_3_run_analysis_passes(
+            sess, ast_map, &arenas, id, MakeGlobMap::No, |tcx, analysis| {
 
-        let (tcx, trans) = driver::phase_4_translate_to_llvm(analysis);
+            let trans = driver::phase_4_translate_to_llvm(tcx, analysis);
 
-        let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
+            let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
 
-        // Collect crates used in the session.
-        // Reverse order finds dependencies first.
-        let deps = crates.into_iter().rev()
-            .filter_map(|(_, p)| p).collect();
+            // Collect crates used in the session.
+            // Reverse order finds dependencies first.
+            let deps = crates.into_iter().rev()
+                .filter_map(|(_, p)| p).collect();
 
-        assert_eq!(trans.modules.len(), 1);
-        let llmod = trans.modules[0].llmod;
+            assert_eq!(trans.modules.len(), 1);
+            let llmod = trans.modules[0].llmod;
 
-        // Workaround because raw pointers do not impl Send
-        let modp = llmod as usize;
+            // Workaround because raw pointers do not impl Send
+            let modp = llmod as usize;
 
-        (modp, deps)
+            (modp, deps)
+        }).1
     }).unwrap();
 
     match handle.join() {