about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/cfg/construct.rs8
-rw-r--r--src/librustc/infer/mod.rs26
-rw-r--r--src/librustc/middle/dead.rs12
-rw-r--r--src/librustc/middle/effect.rs10
-rw-r--r--src/librustc/middle/expr_use_visitor.rs55
-rw-r--r--src/librustc/middle/intrinsicck.rs2
-rw-r--r--src/librustc/middle/liveness.rs14
-rw-r--r--src/librustc/middle/mem_categorization.rs26
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/stability.rs10
-rw-r--r--src/librustc/ty/adjustment.rs289
-rw-r--r--src/librustc/ty/context.rs82
-rw-r--r--src/librustc/ty/fold.rs4
-rw-r--r--src/librustc/ty/mod.rs89
-rw-r--r--src/librustc/ty/structural_impls.rs24
-rw-r--r--src/librustc/util/ppaux.rs27
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs2
-rw-r--r--src/librustc_const_eval/check_match.rs6
-rw-r--r--src/librustc_const_eval/eval.rs14
-rw-r--r--src/librustc_const_eval/pattern.rs17
-rw-r--r--src/librustc_driver/pretty.rs2
-rw-r--r--src/librustc_lint/builtin.rs42
-rw-r--r--src/librustc_lint/types.rs12
-rw-r--r--src/librustc_lint/unused.rs11
-rw-r--r--src/librustc_metadata/astencode.rs8
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_mir/build/mod.rs6
-rw-r--r--src/librustc_mir/hair/cx/block.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs117
-rw-r--r--src/librustc_mir/mir_map.rs4
-rw-r--r--src/librustc_passes/consts.rs31
-rw-r--r--src/librustc_privacy/lib.rs8
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs13
-rw-r--r--src/librustc_save_analysis/lib.rs10
-rw-r--r--src/librustc_trans/callee.rs2
-rw-r--r--src/librustc_trans/collector.rs5
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs2
-rw-r--r--src/librustc_typeck/astconv.rs2
-rw-r--r--src/librustc_typeck/check/callee.rs2
-rw-r--r--src/librustc_typeck/check/coercion.rs125
-rw-r--r--src/librustc_typeck/check/method/confirm.rs136
-rw-r--r--src/librustc_typeck/check/method/mod.rs28
-rw-r--r--src/librustc_typeck/check/mod.rs58
-rw-r--r--src/librustc_typeck/check/regionck.rs38
-rw-r--r--src/librustc_typeck/check/wfcheck.rs6
-rw-r--r--src/librustc_typeck/check/writeback.rs38
-rw-r--r--src/librustc_typeck/lib.rs4
47 files changed, 631 insertions, 802 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 1b2976b7435..a2fc6e044e7 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -311,11 +311,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             hir::ExprIndex(ref l, ref r) |
-            hir::ExprBinary(_, ref l, ref r) if self.tcx.is_method_call(expr.id) => {
+            hir::ExprBinary(_, ref l, ref r) if self.tcx.tables().is_method_call(expr.id) => {
                 self.call(expr, pred, &l, Some(&**r).into_iter())
             }
 
-            hir::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => {
+            hir::ExprUnary(_, ref e) if self.tcx.tables().is_method_call(expr.id) => {
                 self.call(expr, pred, &e, None::<hir::Expr>.iter())
             }
 
@@ -372,9 +372,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             func_or_rcvr: &hir::Expr,
             args: I) -> CFGIndex {
         let method_call = ty::MethodCall::expr(call_expr.id);
-        let fn_ty = match self.tcx.tables.borrow().method_map.get(&method_call) {
+        let fn_ty = match self.tcx.tables().method_map.get(&method_call) {
             Some(method) => method.ty,
-            None => self.tcx.expr_ty_adjusted(func_or_rcvr)
+            None => self.tcx.tables().expr_ty_adjusted(func_or_rcvr)
         };
 
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 35802aef593..bbcd87d9cab 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1266,26 +1266,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.region_vars.new_bound(debruijn)
     }
 
-    /// Apply `adjustment` to the type of `expr`
-    pub fn adjust_expr_ty(&self,
-                          expr: &hir::Expr,
-                          adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
-                          -> Ty<'tcx>
-    {
-        let raw_ty = self.expr_ty(expr);
-        let raw_ty = self.shallow_resolve(raw_ty);
-        let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
-        raw_ty.adjust(self.tcx,
-                      expr.span,
-                      expr.id,
-                      adjustment,
-                      |method_call| self.tables
-                                        .borrow()
-                                        .method_map
-                                        .get(&method_call)
-                                        .map(|method| resolve_ty(method.ty)))
-    }
-
     /// True if errors have been reported since this infcx was
     /// created.  This is sometimes used as a heuristic to skip
     /// reporting errors that often occur as a result of earlier
@@ -1622,7 +1602,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
-        let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id));
+        let ty = self.tables.borrow().expr_ty_adjusted(expr);
         self.resolve_type_vars_or_error(&ty)
     }
 
@@ -1666,9 +1646,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             .map(|method| method.def_id)
     }
 
-    pub fn adjustments(&self) -> Ref<NodeMap<adjustment::AutoAdjustment<'tcx>>> {
+    pub fn adjustments(&self) -> Ref<NodeMap<adjustment::Adjustment<'tcx>>> {
         fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
-                                        -> &'a NodeMap<adjustment::AutoAdjustment<'tcx>> {
+                                        -> &'a NodeMap<adjustment::Adjustment<'tcx>> {
             &tables.adjustments
         }
 
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index dc634b08784..4212b1fb05e 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -92,7 +92,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         match def {
             Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_)
             if self.tcx.trait_of_item(def.def_id()).is_some() => {
-                if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) {
+                if let Some(substs) = self.tcx.tables().item_substs.get(&id) {
                     if let ty::TyAdt(tyid, _) = substs.substs.type_at(0).sty {
                         self.check_def_id(tyid.did);
                     }
@@ -123,12 +123,12 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
     fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
         let method_call = ty::MethodCall::expr(id);
-        let method = self.tcx.tables.borrow().method_map[&method_call];
+        let method = self.tcx.tables().method_map[&method_call];
         self.check_def_id(method.def_id);
     }
 
     fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
-        match self.tcx.expr_ty_adjusted(lhs).sty {
+        match self.tcx.tables().expr_ty_adjusted(lhs).sty {
             ty::TyAdt(def, _) => {
                 self.insert_def_id(def.struct_variant().field_named(name).did);
             }
@@ -137,7 +137,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) {
-        match self.tcx.expr_ty_adjusted(lhs).sty {
+        match self.tcx.tables().expr_ty_adjusted(lhs).sty {
             ty::TyAdt(def, _) => {
                 self.insert_def_id(def.struct_variant().fields[idx].did);
             }
@@ -148,7 +148,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
     fn handle_field_pattern_match(&mut self, lhs: &hir::Pat,
                                   pats: &[codemap::Spanned<hir::FieldPat>]) {
-        let variant = match self.tcx.node_id_to_type(lhs.id).sty {
+        let variant = match self.tcx.tables().node_id_to_type(lhs.id).sty {
             ty::TyAdt(adt, _) => {
                 adt.variant_of_def(self.tcx.expect_def(lhs.id))
             }
@@ -433,7 +433,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
     }
 
     fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool {
-        let field_type = self.tcx.node_id_to_type(field.id);
+        let field_type = self.tcx.tables().node_id_to_type(field.id);
         let is_marker_field = match field_type.ty_to_def_id() {
             Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)),
             _ => false
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 2a75b6620fd..8ca3c75eaa4 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -159,7 +159,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
         match expr.node {
             hir::ExprMethodCall(..) => {
                 let method_call = MethodCall::expr(expr.id);
-                let base_type = self.tcx.tables.borrow().method_map[&method_call].ty;
+                let base_type = self.tcx.tables().method_map[&method_call].ty;
                 debug!("effect: method call case, base type is {:?}",
                         base_type);
                 if type_is_unsafe_function(base_type) {
@@ -168,7 +168,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                 }
             }
             hir::ExprCall(ref base, _) => {
-                let base_type = self.tcx.expr_ty_adjusted(base);
+                let base_type = self.tcx.tables().expr_ty_adjusted(base);
                 debug!("effect: call case, base type is {:?}",
                         base_type);
                 if type_is_unsafe_function(base_type) {
@@ -176,7 +176,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                 }
             }
             hir::ExprUnary(hir::UnDeref, ref base) => {
-                let base_type = self.tcx.expr_ty_adjusted(base);
+                let base_type = self.tcx.tables().expr_ty_adjusted(base);
                 debug!("effect: unary case, base type is {:?}",
                         base_type);
                 if let ty::TyRawPtr(_) = base_type.sty {
@@ -200,7 +200,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                 }
             }
             hir::ExprField(ref base_expr, field) => {
-                if let ty::TyAdt(adt, ..) = self.tcx.expr_ty_adjusted(base_expr).sty {
+                if let ty::TyAdt(adt, ..) = self.tcx.tables().expr_ty_adjusted(base_expr).sty {
                     if adt.is_union() {
                         self.require_unsafe(field.span, "access to union field");
                     }
@@ -214,7 +214,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
 
     fn visit_pat(&mut self, pat: &hir::Pat) {
         if let PatKind::Struct(_, ref fields, _) = pat.node {
-            if let ty::TyAdt(adt, ..) = self.tcx.pat_ty(pat).sty {
+            if let ty::TyAdt(adt, ..) = self.tcx.tables().pat_ty(pat).sty {
                 if adt.is_union() {
                     for field in fields {
                         self.require_unsafe(field.span, "matching on union field");
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index c37b6df369d..0543d1303a5 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -720,11 +720,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         //NOTE(@jroesch): mixed RefCell borrow causes crash
         let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone());
         if let Some(adjustment) = adj {
-            match adjustment {
-                adjustment::AdjustNeverToAny(..) |
-                adjustment::AdjustReifyFnPointer |
-                adjustment::AdjustUnsafeFnPointer |
-                adjustment::AdjustMutToConstPointer => {
+            match adjustment.kind {
+                adjustment::Adjust::NeverToAny |
+                adjustment::Adjust::ReifyFnPointer |
+                adjustment::Adjust::UnsafeFnPointer |
+                adjustment::Adjust::MutToConstPointer => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
                     debug!("walk_adjustment: trivial adjustment");
@@ -732,8 +732,21 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                         return_if_err!(self.mc.cat_expr_unadjusted(expr));
                     self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
                 }
-                adjustment::AdjustDerefRef(ref adj) => {
-                    self.walk_autoderefref(expr, adj);
+                adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
+                    debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
+
+                    self.walk_autoderefs(expr, autoderefs);
+
+                    let cmt_derefd =
+                        return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs));
+
+                    let cmt_refd =
+                        self.walk_autoref(expr, cmt_derefd, autoref);
+
+                    if unsize {
+                        // Unsizing consumes the thin pointer and produces a fat one.
+                        self.delegate_consume(expr.id, expr.span, cmt_refd);
+                    }
                 }
             }
         }
@@ -770,28 +783,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn walk_autoderefref(&mut self,
-                         expr: &hir::Expr,
-                         adj: &adjustment::AutoDerefRef<'tcx>) {
-        debug!("walk_autoderefref expr={:?} adj={:?}",
-               expr,
-               adj);
-
-        self.walk_autoderefs(expr, adj.autoderefs);
-
-        let cmt_derefd =
-            return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs));
-
-        let cmt_refd =
-            self.walk_autoref(expr, cmt_derefd, adj.autoref);
-
-        if adj.unsize.is_some() {
-            // Unsizing consumes the thin pointer and produces a fat one.
-            self.delegate_consume(expr.id, expr.span, cmt_refd);
-        }
-    }
-
-
     /// Walks the autoref `opt_autoref` applied to the autoderef'd
     /// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
     /// after all relevant autoderefs have occurred. Because AutoRefs
@@ -803,7 +794,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     fn walk_autoref(&mut self,
                     expr: &hir::Expr,
                     cmt_base: mc::cmt<'tcx>,
-                    opt_autoref: Option<adjustment::AutoRef<'tcx>>)
+                    opt_autoref: Option<adjustment::AutoBorrow<'tcx>>)
                     -> mc::cmt<'tcx>
     {
         debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
@@ -822,7 +813,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         };
 
         match *autoref {
-            adjustment::AutoPtr(r, m) => {
+            adjustment::AutoBorrow::Ref(r, m) => {
                 self.delegate.borrow(expr.id,
                                      expr.span,
                                      cmt_base,
@@ -831,7 +822,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                                      AutoRef);
             }
 
-            adjustment::AutoUnsafe(m) => {
+            adjustment::AutoBorrow::RawPtr(m) => {
                 debug!("walk_autoref: expr.id={} cmt_base={:?}",
                        expr.id,
                        cmt_base);
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 1acd0fb0f79..57503398cfe 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -163,7 +163,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
         if let hir::ExprPath(..) = expr.node {
             match self.infcx.tcx.expect_def(expr.id) {
                 Def::Fn(did) if self.def_id_is_transmute(did) => {
-                    let typ = self.infcx.tcx.node_id_to_type(expr.id);
+                    let typ = self.infcx.tcx.tables().node_id_to_type(expr.id);
                     match typ.sty {
                         ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
                             let from = bare_fn_ty.sig.0.inputs[0];
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 79396b9ca4d..46bea00cca3 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1081,7 +1081,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprAssignOp(_, ref l, ref r) => {
             // an overloaded assign op is like a method call
-            if self.ir.tcx.is_method_call(expr.id) {
+            if self.ir.tcx.tables().is_method_call(expr.id) {
                 let succ = self.propagate_through_expr(&l, succ);
                 self.propagate_through_expr(&r, succ)
             } else {
@@ -1113,8 +1113,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprCall(ref f, ref args) => {
             // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let diverges = !self.ir.tcx.is_method_call(expr.id) &&
-                self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_never();
+            let diverges = !self.ir.tcx.tables().is_method_call(expr.id) &&
+                self.ir.tcx.tables().expr_ty_adjusted(&f).fn_ret().0.is_never();
             let succ = if diverges {
                 self.s.exit_ln
             } else {
@@ -1126,7 +1126,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprMethodCall(.., ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
-            let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
+            let method_ty = self.ir.tcx.tables().method_map[&method_call].ty;
             // FIXME(canndrew): This is_never should really be an is_uninhabited
             let succ = if method_ty.fn_ret().0.is_never() {
                 self.s.exit_ln
@@ -1409,7 +1409,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       }
 
       hir::ExprAssignOp(_, ref l, _) => {
-        if !this.ir.tcx.is_method_call(expr.id) {
+        if !this.ir.tcx.tables().is_method_call(expr.id) {
             this.check_lvalue(&l);
         }
 
@@ -1459,7 +1459,7 @@ fn check_fn(_v: &Liveness,
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn fn_ret(&self, id: NodeId) -> ty::Binder<Ty<'tcx>> {
-        let fn_ty = self.ir.tcx.node_id_to_type(id);
+        let fn_ty = self.ir.tcx.tables().node_id_to_type(id);
         match fn_ty.sty {
             ty::TyClosure(closure_def_id, substs) =>
                 self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
@@ -1502,7 +1502,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                     None if !body.stmts.is_empty() =>
                         match body.stmts.last().unwrap().node {
                             hir::StmtSemi(ref e, _) => {
-                                self.ir.tcx.expr_ty(&e) == fn_ret
+                                self.ir.tcx.tables().expr_ty(&e) == fn_ret
                             },
                             _ => false
                         },
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 9214138d210..e3ed13e1e40 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -354,11 +354,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     }
 
     fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
-        let unadjusted_ty = self.expr_ty(expr)?;
-        Ok(unadjusted_ty.adjust(
-            self.tcx(), expr.span, expr.id,
-            self.infcx.adjustments().get(&expr.id),
-            |method_call| self.infcx.node_method_ty(method_call)))
+        self.infcx.expr_ty_adjusted(expr)
     }
 
     fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
@@ -396,19 +392,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
 
             Some(adjustment) => {
-                match *adjustment {
-                    adjustment::AdjustDerefRef(
-                        adjustment::AutoDerefRef {
-                            autoref: None, unsize: None, autoderefs, ..}) => {
+                match adjustment.kind {
+                    adjustment::Adjust::DerefRef {
+                        autoderefs,
+                        autoref: None,
+                        unsize: false
+                    } => {
                         // Equivalent to *expr or something similar.
                         self.cat_expr_autoderefd(expr, autoderefs)
                     }
 
-                    adjustment::AdjustNeverToAny(..) |
-                    adjustment::AdjustReifyFnPointer |
-                    adjustment::AdjustUnsafeFnPointer |
-                    adjustment::AdjustMutToConstPointer |
-                    adjustment::AdjustDerefRef(_) => {
+                    adjustment::Adjust::NeverToAny |
+                    adjustment::Adjust::ReifyFnPointer |
+                    adjustment::Adjust::UnsafeFnPointer |
+                    adjustment::Adjust::MutToConstPointer |
+                    adjustment::Adjust::DerefRef {..} => {
                         debug!("cat_expr({:?}): {:?}",
                                adjustment,
                                expr);
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index a476d0f6f30..1a50d7aa0ad 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -116,7 +116,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
             }
             hir::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
+                let def_id = self.tcx.tables().method_map[&method_call].def_id;
 
                 // Mark the trait item (and, possibly, its default impl) as reachable
                 // Or mark inherent impl item as reachable
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 5192575972b..fd17e378787 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -555,11 +555,11 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
         hir::ExprMethodCall(i, ..) => {
             span = i.span;
             let method_call = ty::MethodCall::expr(e.id);
-            tcx.tables.borrow().method_map[&method_call].def_id
+            tcx.tables().method_map[&method_call].def_id
         }
         hir::ExprField(ref base_e, ref field) => {
             span = field.span;
-            match tcx.expr_ty_adjusted(base_e).sty {
+            match tcx.tables().expr_ty_adjusted(base_e).sty {
                 ty::TyAdt(def, _) => {
                     def.struct_variant().field_named(field.node).did
                 }
@@ -569,7 +569,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
         }
         hir::ExprTupField(ref base_e, ref field) => {
             span = field.span;
-            match tcx.expr_ty_adjusted(base_e).sty {
+            match tcx.tables().expr_ty_adjusted(base_e).sty {
                 ty::TyAdt(def, _) => {
                     def.struct_variant().fields[field.node].did
                 }
@@ -580,7 +580,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
             }
         }
         hir::ExprStruct(_, ref expr_fields, _) => {
-            match tcx.expr_ty(e).sty {
+            match tcx.tables().expr_ty(e).sty {
                 ty::TyAdt(adt, ..) => match adt.adt_kind() {
                     AdtKind::Struct | AdtKind::Union => {
                         // check the stability of each field that appears
@@ -637,7 +637,7 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
     debug!("check_pat(pat = {:?})", pat);
     if is_internal(tcx, pat.span) { return; }
 
-    let v = match tcx.pat_ty_opt(pat).map(|ty| &ty.sty) {
+    let v = match tcx.tables().pat_ty_opt(pat).map(|ty| &ty.sty) {
         Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(),
         _ => return,
     };
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index cfe370343ae..333a5c74cb4 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -8,10 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::AutoAdjustment::*;
-pub use self::AutoRef::*;
-
-use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeAndMut};
 use ty::LvaluePreference::{NoPreference};
 
 use syntax::ast;
@@ -20,116 +17,122 @@ use syntax_pos::Span;
 use hir;
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub enum AutoAdjustment<'tcx> {
-    AdjustNeverToAny(Ty<'tcx>), // go from ! to any type
-    AdjustReifyFnPointer,       // go from a fn-item type to a fn-pointer type
-    AdjustUnsafeFnPointer,      // go from a safe fn pointer to an unsafe fn pointer
-    AdjustMutToConstPointer,    // go from a mut raw pointer to a const raw pointer
-    AdjustDerefRef(AutoDerefRef<'tcx>),
+pub struct Adjustment<'tcx> {
+    pub kind: Adjust<'tcx>,
+    pub target: Ty<'tcx>
 }
 
-/// Represents coercing a pointer to a different kind of pointer - where 'kind'
-/// here means either or both of raw vs borrowed vs unique and fat vs thin.
-///
-/// We transform pointers by following the following steps in order:
-/// 1. Deref the pointer `self.autoderefs` times (may be 0).
-/// 2. If `autoref` is `Some(_)`, then take the address and produce either a
-///    `&` or `*` pointer.
-/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
-///    which will do things like convert thin pointers to fat
-///    pointers, or convert structs containing thin pointers to
-///    structs containing fat pointers, or convert between fat
-///    pointers.  We don't store the details of how the transform is
-///    done (in fact, we don't know that, because it might depend on
-///    the precise type parameters). We just store the target
-///    type. Trans figures out what has to be done at monomorphization
-///    time based on the precise source/target type at hand.
-///
-/// To make that more concrete, here are some common scenarios:
-///
-/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
-/// Here the pointer will be dereferenced N times (where a dereference can
-/// happen to raw or borrowed pointers or any smart pointer which implements
-/// Deref, including Box<_>). The number of dereferences is given by
-/// `autoderefs`.  It can then be auto-referenced zero or one times, indicated
-/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
-/// None.
-///
-/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
-/// with a thin pointer, deref a number of times, unsize the underlying data,
-/// then autoref. The 'unsize' phase may change a fixed length array to a
-/// dynamically sized one, a concrete object to a trait object, or statically
-/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
-/// represented by:
-///
-/// ```
-/// AutoDerefRef {
-///     autoderefs: 1,          // &[i32; 4] -> [i32; 4]
-///     autoref: Some(AutoPtr), // [i32] -> &[i32]
-///     unsize: Some([i32]),    // [i32; 4] -> [i32]
-/// }
-/// ```
-///
-/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
-/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
-/// The autoderef and -ref are the same as in the above example, but the type
-/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
-/// the underlying conversions from `[i32; 4]` to `[i32]`.
-///
-/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case.  In
-/// that case, we have the pointer we need coming in, so there are no
-/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
-/// At some point, of course, `Box` should move out of the compiler, in which
-/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
-/// Box<[i32]> is represented by:
-///
-/// ```
-/// AutoDerefRef {
-///     autoderefs: 0,
-///     autoref: None,
-///     unsize: Some(Box<[i32]>),
-/// }
-/// ```
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub struct AutoDerefRef<'tcx> {
-    /// Step 1. Apply a number of dereferences, producing an lvalue.
-    pub autoderefs: usize,
-
-    /// Step 2. Optionally produce a pointer/reference from the value.
-    pub autoref: Option<AutoRef<'tcx>>,
-
-    /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
-    /// `&[T]`. The stored type is the target pointer type. Note that
-    /// the source could be a thin or fat pointer.
-    pub unsize: Option<Ty<'tcx>>,
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+pub enum Adjust<'tcx> {
+    /// Go from ! to any type.
+    NeverToAny,
+
+    /// Go from a fn-item type to a fn-pointer type.
+    ReifyFnPointer,
+
+    /// Go from a safe fn pointer to an unsafe fn pointer.
+    UnsafeFnPointer,
+
+    /// Go from a mut raw pointer to a const raw pointer.
+    MutToConstPointer,
+
+    /// Represents coercing a pointer to a different kind of pointer - where 'kind'
+    /// here means either or both of raw vs borrowed vs unique and fat vs thin.
+    ///
+    /// We transform pointers by following the following steps in order:
+    /// 1. Deref the pointer `self.autoderefs` times (may be 0).
+    /// 2. If `autoref` is `Some(_)`, then take the address and produce either a
+    ///    `&` or `*` pointer.
+    /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
+    ///    which will do things like convert thin pointers to fat
+    ///    pointers, or convert structs containing thin pointers to
+    ///    structs containing fat pointers, or convert between fat
+    ///    pointers.  We don't store the details of how the transform is
+    ///    done (in fact, we don't know that, because it might depend on
+    ///    the precise type parameters). We just store the target
+    ///    type. Trans figures out what has to be done at monomorphization
+    ///    time based on the precise source/target type at hand.
+    ///
+    /// To make that more concrete, here are some common scenarios:
+    ///
+    /// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
+    /// Here the pointer will be dereferenced N times (where a dereference can
+    /// happen to raw or borrowed pointers or any smart pointer which implements
+    /// Deref, including Box<_>). The number of dereferences is given by
+    /// `autoderefs`.  It can then be auto-referenced zero or one times, indicated
+    /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
+    /// None.
+    ///
+    /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
+    /// with a thin pointer, deref a number of times, unsize the underlying data,
+    /// then autoref. The 'unsize' phase may change a fixed length array to a
+    /// dynamically sized one, a concrete object to a trait object, or statically
+    /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
+    /// represented by:
+    ///
+    /// ```
+    /// Adjust::DerefRef {
+    ///     autoderefs: 1,          // &[i32; 4] -> [i32; 4]
+    ///     autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32]
+    ///     unsize: Some([i32]),    // [i32; 4] -> [i32]
+    /// }
+    /// ```
+    ///
+    /// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
+    /// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
+    /// The autoderef and -ref are the same as in the above example, but the type
+    /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
+    /// the underlying conversions from `[i32; 4]` to `[i32]`.
+    ///
+    /// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case.  In
+    /// that case, we have the pointer we need coming in, so there are no
+    /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
+    /// At some point, of course, `Box` should move out of the compiler, in which
+    /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
+    /// Box<[i32]> is represented by:
+    ///
+    /// ```
+    /// Adjust::DerefRef {
+    ///     autoderefs: 0,
+    ///     autoref: None,
+    ///     unsize: Some(Box<[i32]>),
+    /// }
+    /// ```
+    DerefRef {
+        /// Step 1. Apply a number of dereferences, producing an lvalue.
+        autoderefs: usize,
+
+        /// Step 2. Optionally produce a pointer/reference from the value.
+        autoref: Option<AutoBorrow<'tcx>>,
+
+        /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
+        /// `&[T]`. Note that the source could be a thin or fat pointer.
+        unsize: bool,
+    }
 }
 
-impl<'tcx> AutoAdjustment<'tcx> {
+impl<'tcx> Adjustment<'tcx> {
     pub fn is_identity(&self) -> bool {
-        match *self {
-            AdjustNeverToAny(ty) => ty.is_never(),
-            AdjustReifyFnPointer |
-            AdjustUnsafeFnPointer |
-            AdjustMutToConstPointer => false,
-            AdjustDerefRef(ref r) => r.is_identity(),
+        match self.kind {
+            Adjust::NeverToAny => self.target.is_never(),
+
+            Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true,
+
+            Adjust::ReifyFnPointer |
+            Adjust::UnsafeFnPointer |
+            Adjust::MutToConstPointer |
+            Adjust::DerefRef {..} => false,
         }
     }
 }
-impl<'tcx> AutoDerefRef<'tcx> {
-    pub fn is_identity(&self) -> bool {
-        self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none()
-    }
-}
-
 
 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
-pub enum AutoRef<'tcx> {
+pub enum AutoBorrow<'tcx> {
     /// Convert from T to &T.
-    AutoPtr(&'tcx ty::Region, hir::Mutability),
+    Ref(&'tcx ty::Region, hir::Mutability),
 
     /// Convert from T to *T.
-    /// Value to thin pointer.
-    AutoUnsafe(hir::Mutability),
+    RawPtr(hir::Mutability),
 }
 
 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
@@ -139,84 +142,6 @@ pub enum CustomCoerceUnsized {
 }
 
 impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
-    /// See `expr_ty_adjusted`
-    pub fn adjust<F>(&'tcx self,
-                     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                     span: Span,
-                     expr_id: ast::NodeId,
-                     adjustment: Option<&AutoAdjustment<'tcx>>,
-                     mut method_type: F)
-                     -> Ty<'tcx> where
-        F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
-    {
-        if let ty::TyError = self.sty {
-            return self;
-        }
-
-        return match adjustment {
-            Some(adjustment) => {
-                match *adjustment {
-                    AdjustNeverToAny(ref ty) => ty,
-
-                    AdjustReifyFnPointer => {
-                        match self.sty {
-                            ty::TyFnDef(.., f) => tcx.mk_fn_ptr(f),
-                            _ => {
-                                bug!("AdjustReifyFnPointer adjustment on non-fn-item: {:?}",
-                                     self);
-                            }
-                        }
-                    }
-
-                    AdjustUnsafeFnPointer => {
-                        match self.sty {
-                            ty::TyFnPtr(b) => tcx.safe_to_unsafe_fn_ty(b),
-                            ref b => {
-                                bug!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: {:?}",
-                                     b);
-                            }
-                        }
-                    }
-
-                    AdjustMutToConstPointer => {
-                        match self.sty {
-                            ty::TyRawPtr(mt) => tcx.mk_ptr(ty::TypeAndMut {
-                                ty: mt.ty,
-                                mutbl: hir::MutImmutable
-                            }),
-                            ref b => {
-                                bug!("AdjustMutToConstPointer on non-raw-ptr: {:?}",
-                                     b);
-                            }
-                        }
-                    }
-
-                    AdjustDerefRef(ref adj) => {
-                        let mut adjusted_ty = self;
-
-                        if !adjusted_ty.references_error() {
-                            for i in 0..adj.autoderefs {
-                                adjusted_ty =
-                                    adjusted_ty.adjust_for_autoderef(tcx,
-                                                                     expr_id,
-                                                                     span,
-                                                                     i as u32,
-                                                                     &mut method_type);
-                            }
-                        }
-
-                        if let Some(target) = adj.unsize {
-                            target
-                        } else {
-                            adjusted_ty.adjust_for_autoref(tcx, adj.autoref)
-                        }
-                    }
-                }
-            }
-            None => self
-        };
-    }
-
     pub fn adjust_for_autoderef<F>(&'tcx self,
                                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                    expr_id: ast::NodeId,
@@ -247,14 +172,14 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
     }
 
     pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                              autoref: Option<AutoRef<'tcx>>)
+                              autoref: Option<AutoBorrow<'tcx>>)
                               -> Ty<'tcx> {
         match autoref {
             None => self,
-            Some(AutoPtr(r, m)) => {
+            Some(AutoBorrow::Ref(r, m)) => {
                 tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
             }
-            Some(AutoUnsafe(m)) => {
+            Some(AutoBorrow::RawPtr(m)) => {
                 tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
             }
         }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 62cc78141db..7e5e10435d5 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -41,7 +41,7 @@ use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 use arena::TypedArena;
 use std::borrow::Borrow;
-use std::cell::{Cell, RefCell, Ref};
+use std::cell::{Cell, RefCell};
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::ops::Deref;
@@ -212,7 +212,7 @@ pub struct Tables<'tcx> {
     /// other items.
     pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
 
-    pub adjustments: NodeMap<ty::adjustment::AutoAdjustment<'tcx>>,
+    pub adjustments: NodeMap<ty::adjustment::Adjustment<'tcx>>,
 
     pub method_map: ty::MethodMap<'tcx>,
 
@@ -255,6 +255,76 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
             fru_field_types: NodeMap()
         }
     }
+
+    pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> {
+        match self.node_id_to_type_opt(id) {
+            Some(ty) => ty,
+            None => {
+                bug!("node_id_to_type: no type for node `{}`",
+                     tls::with(|tcx| tcx.map.node_to_string(id)))
+            }
+        }
+    }
+
+    pub fn node_id_to_type_opt(&self, id: NodeId) -> Option<Ty<'tcx>> {
+        self.node_types.get(&id).cloned()
+    }
+
+    pub fn node_id_item_substs(&self, id: NodeId) -> Option<&'tcx Substs<'tcx>> {
+        self.item_substs.get(&id).map(|ts| ts.substs)
+    }
+
+    // Returns the type of a pattern as a monotype. Like @expr_ty, this function
+    // doesn't provide type parameter substitutions.
+    pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> {
+        self.node_id_to_type(pat.id)
+    }
+
+    pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option<Ty<'tcx>> {
+        self.node_id_to_type_opt(pat.id)
+    }
+
+    // Returns the type of an expression as a monotype.
+    //
+    // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
+    // some cases, we insert `Adjustment` annotations such as auto-deref or
+    // auto-ref.  The type returned by this function does not consider such
+    // adjustments.  See `expr_ty_adjusted()` instead.
+    //
+    // NB (2): This type doesn't provide type parameter substitutions; e.g. if you
+    // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize"
+    // instead of "fn(ty) -> T with T = isize".
+    pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> {
+        self.node_id_to_type(expr.id)
+    }
+
+    pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
+        self.node_id_to_type_opt(expr.id)
+    }
+
+    /// Returns the type of `expr`, considering any `Adjustment`
+    /// entry recorded for that expression.
+    pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> {
+        self.adjustments.get(&expr.id)
+            .map_or_else(|| self.expr_ty(expr), |adj| adj.target)
+    }
+
+    pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option<Ty<'tcx>> {
+        self.adjustments.get(&expr.id)
+            .map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
+    }
+
+    pub fn is_method_call(&self, expr_id: NodeId) -> bool {
+        self.method_map.contains_key(&ty::MethodCall::expr(expr_id))
+    }
+
+    pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool {
+        self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs))
+    }
+
+    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
+        Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone())
+    }
 }
 
 impl<'tcx> CommonTypes<'tcx> {
@@ -599,14 +669,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
     }
 
-    pub fn node_types(self) -> Ref<'a, NodeMap<Ty<'tcx>>> {
-        fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap<Ty<'tcx>> {
-            &tables.node_types
-        }
-
-        Ref::map(self.tables.borrow(), projection)
-    }
-
     pub fn node_type_insert(self, id: NodeId, ty: Ty<'gcx>) {
         self.tables.borrow_mut().node_types.insert(id, ty);
     }
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index ae0a4a0e6bd..b79ebdb14f5 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -176,8 +176,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
         r.super_fold_with(self)
     }
 
-    fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>)
-                    -> adjustment::AutoRef<'tcx> {
+    fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>)
+                    -> adjustment::AutoBorrow<'tcx> {
         ar.super_fold_with(self)
     }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 588857e557c..2c15f08e898 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2120,80 +2120,8 @@ impl BorrowKind {
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn node_id_to_type(self, id: NodeId) -> Ty<'gcx> {
-        match self.node_id_to_type_opt(id) {
-           Some(ty) => ty,
-           None => bug!("node_id_to_type: no type for node `{}`",
-                        self.map.node_to_string(id))
-        }
-    }
-
-    pub fn node_id_to_type_opt(self, id: NodeId) -> Option<Ty<'gcx>> {
-        self.tables.borrow().node_types.get(&id).cloned()
-    }
-
-    pub fn node_id_item_substs(self, id: NodeId) -> ItemSubsts<'gcx> {
-        match self.tables.borrow().item_substs.get(&id) {
-            None => ItemSubsts {
-                substs: self.global_tcx().intern_substs(&[])
-            },
-            Some(ts) => ts.clone(),
-        }
-    }
-
-    // Returns the type of a pattern as a monotype. Like @expr_ty, this function
-    // doesn't provide type parameter substitutions.
-    pub fn pat_ty(self, pat: &hir::Pat) -> Ty<'gcx> {
-        self.node_id_to_type(pat.id)
-    }
-    pub fn pat_ty_opt(self, pat: &hir::Pat) -> Option<Ty<'gcx>> {
-        self.node_id_to_type_opt(pat.id)
-    }
-
-    // Returns the type of an expression as a monotype.
-    //
-    // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
-    // some cases, we insert `AutoAdjustment` annotations such as auto-deref or
-    // auto-ref.  The type returned by this function does not consider such
-    // adjustments.  See `expr_ty_adjusted()` instead.
-    //
-    // NB (2): This type doesn't provide type parameter substitutions; e.g. if you
-    // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize"
-    // instead of "fn(ty) -> T with T = isize".
-    pub fn expr_ty(self, expr: &hir::Expr) -> Ty<'gcx> {
-        self.node_id_to_type(expr.id)
-    }
-
-    pub fn expr_ty_opt(self, expr: &hir::Expr) -> Option<Ty<'gcx>> {
-        self.node_id_to_type_opt(expr.id)
-    }
-
-    /// Returns the type of `expr`, considering any `AutoAdjustment`
-    /// entry recorded for that expression.
-    ///
-    /// It would almost certainly be better to store the adjusted ty in with
-    /// the `AutoAdjustment`, but I opted not to do this because it would
-    /// require serializing and deserializing the type and, although that's not
-    /// hard to do, I just hate that code so much I didn't want to touch it
-    /// unless it was to fix it properly, which seemed a distraction from the
-    /// thread at hand! -nmatsakis
-    pub fn expr_ty_adjusted(self, expr: &hir::Expr) -> Ty<'gcx> {
-        self.expr_ty(expr)
-            .adjust(self.global_tcx(), expr.span, expr.id,
-                    self.tables.borrow().adjustments.get(&expr.id),
-                    |method_call| {
-            self.tables.borrow().method_map.get(&method_call).map(|method| method.ty)
-        })
-    }
-
-    pub fn expr_ty_adjusted_opt(self, expr: &hir::Expr) -> Option<Ty<'gcx>> {
-        self.expr_ty_opt(expr).map(|t| t.adjust(self.global_tcx(),
-                                                expr.span,
-                                                expr.id,
-                                                self.tables.borrow().adjustments.get(&expr.id),
-                                                |method_call| {
-            self.tables.borrow().method_map.get(&method_call).map(|method| method.ty)
-        }))
+    pub fn tables(self) -> Ref<'a, Tables<'gcx>> {
+        self.tables.borrow()
     }
 
     pub fn expr_span(self, id: NodeId) -> Span {
@@ -2908,19 +2836,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_region(ty::ReScope(self.region_maps.node_extent(id)))
     }
 
-    pub fn is_method_call(self, expr_id: NodeId) -> bool {
-        self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id))
-    }
-
-    pub fn is_overloaded_autoderef(self, expr_id: NodeId, autoderefs: u32) -> bool {
-        self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id,
-                                                                            autoderefs))
-    }
-
-    pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
-        Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
-    }
-
     pub fn visit_all_items_in_krate<V,F>(self,
                                          dep_node_fn: F,
                                          visitor: &mut V)
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 3165edebf1a..9ca911837b5 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -218,15 +218,15 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoRef<'a> {
-    type Lifted = ty::adjustment::AutoRef<'tcx>;
+impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> {
+    type Lifted = ty::adjustment::AutoBorrow<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         match *self {
-            ty::adjustment::AutoPtr(r, m) => {
-                tcx.lift(&r).map(|r| ty::adjustment::AutoPtr(r, m))
+            ty::adjustment::AutoBorrow::Ref(r, m) => {
+                tcx.lift(&r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m))
             }
-            ty::adjustment::AutoUnsafe(m) => {
-                Some(ty::adjustment::AutoUnsafe(m))
+            ty::adjustment::AutoBorrow::RawPtr(m) => {
+                Some(ty::adjustment::AutoBorrow::RawPtr(m))
             }
         }
     }
@@ -676,13 +676,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
-            ty::adjustment::AutoPtr(ref r, m) => {
-                ty::adjustment::AutoPtr(r.fold_with(folder), m)
+            ty::adjustment::AutoBorrow::Ref(ref r, m) => {
+                ty::adjustment::AutoBorrow::Ref(r.fold_with(folder), m)
             }
-            ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m)
+            ty::adjustment::AutoBorrow::RawPtr(m) => ty::adjustment::AutoBorrow::RawPtr(m)
         }
     }
 
@@ -692,8 +692,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
-            ty::adjustment::AutoPtr(r, _m) => r.visit_with(visitor),
-            ty::adjustment::AutoUnsafe(_m) => false,
+            ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor),
+            ty::adjustment::AutoBorrow::RawPtr(_m) => false,
         }
     }
 }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 954e3b1fc13..31304fb7b49 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -447,32 +447,9 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
+impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::adjustment::AdjustNeverToAny(ref target) => {
-                write!(f, "AdjustNeverToAny({:?})", target)
-            }
-            ty::adjustment::AdjustReifyFnPointer => {
-                write!(f, "AdjustReifyFnPointer")
-            }
-            ty::adjustment::AdjustUnsafeFnPointer => {
-                write!(f, "AdjustUnsafeFnPointer")
-            }
-            ty::adjustment::AdjustMutToConstPointer => {
-                write!(f, "AdjustMutToConstPointer")
-            }
-            ty::adjustment::AdjustDerefRef(ref data) => {
-                write!(f, "{:?}", data)
-            }
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
-               self.autoderefs, self.unsize, self.autoref)
+        write!(f, "{:?} -> {}", self.kind, self.target)
     }
 }
 
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 9bdc6887f6d..51574868f9b 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -37,7 +37,7 @@ pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                              decl_id: ast::NodeId,
                              _decl_span: Span,
                              var_id: ast::NodeId) {
-    let ty = bccx.tcx.node_id_to_type(var_id);
+    let ty = bccx.tcx.tables().node_id_to_type(var_id);
     let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty));
     move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
 }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 9aa1ac62f55..615aca90db8 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -201,7 +201,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 
             // Finally, check if the whole match expression is exhaustive.
             // Check for empty enum, because is_useful only works on inhabited types.
-            let pat_ty = self.tcx.node_id_to_type(scrut.id);
+            let pat_ty = self.tcx.tables().node_id_to_type(scrut.id);
             if inlined_arms.is_empty() {
                 if !pat_ty.is_uninhabited(self.tcx) {
                     // We know the type is inhabited, so this must be wrong
@@ -262,7 +262,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
     pat.walk(|p| {
         if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node {
-            let pat_ty = cx.tcx.pat_ty(p);
+            let pat_ty = cx.tcx.tables().pat_ty(p);
             if let ty::TyAdt(edef, _) = pat_ty.sty {
                 if edef.is_enum() {
                     if let Def::Local(..) = cx.tcx.expect_def(p.id) {
@@ -486,7 +486,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
     for pat in pats {
         pat.walk(|p| {
             if let PatKind::Binding(hir::BindByValue(..), _, ref sub) = p.node {
-                let pat_ty = cx.tcx.node_id_to_type(p.id);
+                let pat_ty = cx.tcx.tables().node_id_to_type(p.id);
                 if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
                     check_move(p, sub.as_ref().map(|p| &**p));
                 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c02cca0da72..1f66d714068 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -246,7 +246,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                    pat_id: ast::NodeId,
                                    span: Span)
                                    -> Result<P<hir::Pat>, DefId> {
-    let pat_ty = tcx.expr_ty(expr);
+    let pat_ty = tcx.tables().expr_ty(expr);
     debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
     match pat_ty.sty {
         ty::TyFloat(_) => {
@@ -329,7 +329,8 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 Def::StructCtor(_, CtorKind::Const) |
                 Def::VariantCtor(_, CtorKind::Const) => PatKind::Path(None, path.clone()),
                 Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                    let substs = Some(tcx.node_id_item_substs(expr.id).substs);
+                    let substs = Some(tcx.tables().node_id_item_substs(expr.id)
+                        .unwrap_or_else(|| tcx.intern_substs(&[])));
                     let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
                     return const_expr_to_pat(tcx, expr, pat_id, span);
                 },
@@ -606,7 +607,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let ety = match ty_hint {
         ExprTypeChecked => {
             // After type-checking, expr_ty is guaranteed to succeed.
-            Some(tcx.expr_ty(e))
+            Some(tcx.tables().expr_ty(e))
         }
         UncheckedExprHint(ty) => {
             // Use the type hint; it's not guaranteed to be right, but it's
@@ -617,7 +618,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // This expression might not be type-checked, and we have no hint.
             // Try to query the context for a type anyway; we might get lucky
             // (for example, if the expression was imported from another crate).
-            tcx.expr_ty_opt(e)
+            tcx.tables().expr_ty_opt(e)
         }
     };
     let result = match e.node {
@@ -759,7 +760,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let base_hint = if let ExprTypeChecked = ty_hint {
             ExprTypeChecked
         } else {
-            match tcx.expr_ty_opt(&base) {
+            match tcx.tables().expr_ty_opt(&base) {
                 Some(t) => UncheckedExprHint(t),
                 None => ty_hint
             }
@@ -798,7 +799,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
                   let substs = if let ExprTypeChecked = ty_hint {
-                      Some(tcx.node_id_item_substs(e.id).substs)
+                      Some(tcx.tables().node_id_item_substs(e.id)
+                        .unwrap_or_else(|| tcx.intern_substs(&[])))
                   } else {
                       None
                   };
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 946a3974747..10b2a7625ca 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -128,7 +128,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
     }
 
     pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
-        let mut ty = self.tcx.node_id_to_type(pat.id);
+        let mut ty = self.tcx.tables().node_id_to_type(pat.id);
 
         let kind = match pat.node {
             PatKind::Wild => PatternKind::Wild,
@@ -167,8 +167,9 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 match self.tcx.expect_def(pat.id) {
                     Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                         let tcx = self.tcx.global_tcx();
-                        let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
-                        match eval::lookup_const_by_id(tcx, def_id, substs) {
+                        let substs = tcx.tables().node_id_item_substs(pat.id)
+                            .unwrap_or_else(|| tcx.intern_substs(&[]));
+                        match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
                             Some((const_expr, _const_ty)) => {
                                 match eval::const_expr_to_pat(
                                     tcx, const_expr, pat.id, pat.span)
@@ -197,7 +198,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::Slice(ref prefix, ref slice, ref suffix) => {
-                let ty = self.tcx.node_id_to_type(pat.id);
+                let ty = self.tcx.tables().node_id_to_type(pat.id);
                 match ty.sty {
                     ty::TyRef(_, mt) =>
                         PatternKind::Deref {
@@ -222,7 +223,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::Tuple(ref subpatterns, ddpos) => {
-                match self.tcx.node_id_to_type(pat.id).sty {
+                match self.tcx.tables().node_id_to_type(pat.id).sty {
                     ty::TyTuple(ref tys) => {
                         let subpatterns =
                             subpatterns.iter()
@@ -243,7 +244,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             PatKind::Binding(bm, ref ident, ref sub) => {
                 let def_id = self.tcx.expect_def(pat.id).def_id();
                 let id = self.tcx.map.as_local_node_id(def_id).unwrap();
-                let var_ty = self.tcx.node_id_to_type(pat.id);
+                let var_ty = self.tcx.tables().node_id_to_type(pat.id);
                 let region = match var_ty.sty {
                     ty::TyRef(r, _) => Some(r),
                     _ => None,
@@ -280,7 +281,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::TupleStruct(_, ref subpatterns, ddpos) => {
-                let pat_ty = self.tcx.node_id_to_type(pat.id);
+                let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
                 let adt_def = match pat_ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
@@ -299,7 +300,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::Struct(_, ref fields, _) => {
-                let pat_ty = self.tcx.node_id_to_type(pat.id);
+                let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
                 let adt_def = match pat_ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 289a7348cc8..b4ab9da92e9 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -501,7 +501,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
                 pp::space(&mut s.s)?;
                 pp::word(&mut s.s, "as")?;
                 pp::space(&mut s.s)?;
-                pp::word(&mut s.s, &self.tcx.expr_ty(expr).to_string())?;
+                pp::word(&mut s.s, &self.tcx.tables().expr_ty(expr).to_string())?;
                 s.pclose()
             }
             _ => Ok(()),
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index a28109c1471..28dc71fd59b 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -34,7 +34,6 @@ use middle::stability;
 use rustc::cfg;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::adjustment;
 use rustc::traits::{self, Reveal};
 use rustc::hir::map as hir_map;
 use util::nodemap::NodeSet;
@@ -118,7 +117,9 @@ impl LateLintPass for BoxPointers {
             hir::ItemTy(..) |
             hir::ItemEnum(..) |
             hir::ItemStruct(..) |
-            hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)),
+            hir::ItemUnion(..) => {
+                self.check_heap_type(cx, it.span, cx.tcx.tables().node_id_to_type(it.id))
+            }
             _ => (),
         }
 
@@ -129,7 +130,7 @@ impl LateLintPass for BoxPointers {
                 for struct_field in struct_def.fields() {
                     self.check_heap_type(cx,
                                          struct_field.span,
-                                         cx.tcx.node_id_to_type(struct_field.id));
+                                         cx.tcx.tables().node_id_to_type(struct_field.id));
                 }
             }
             _ => (),
@@ -137,7 +138,7 @@ impl LateLintPass for BoxPointers {
     }
 
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
-        let ty = cx.tcx.node_id_to_type(e.id);
+        let ty = cx.tcx.tables().node_id_to_type(e.id);
         self.check_heap_type(cx, e.span, ty);
     }
 }
@@ -585,7 +586,7 @@ impl LateLintPass for MissingDebugImplementations {
             let mut impls = NodeSet();
             debug_def.for_each_impl(cx.tcx, |d| {
                 if let Some(n) = cx.tcx.map.as_local_node_id(d) {
-                    if let Some(ty_def) = cx.tcx.node_id_to_type(n).ty_to_def_id() {
+                    if let Some(ty_def) = cx.tcx.tables().node_id_to_type(n).ty_to_def_id() {
                         if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) {
                             impls.insert(node_id);
                         }
@@ -939,8 +940,10 @@ impl LateLintPass for UnconditionalRecursion {
                                                 method: &ty::Method,
                                                 id: ast::NodeId)
                                                 -> bool {
+            use rustc::ty::adjustment::*;
+
             // Check for method calls and overloaded operators.
-            let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
+            let opt_m = tcx.tables().method_map.get(&ty::MethodCall::expr(id)).cloned();
             if let Some(m) = opt_m {
                 if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
                     return true;
@@ -948,15 +951,12 @@ impl LateLintPass for UnconditionalRecursion {
             }
 
             // Check for overloaded autoderef method calls.
-            let opt_adj = tcx.tables.borrow().adjustments.get(&id).cloned();
-            if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
-                for i in 0..adj.autoderefs {
+            let opt_adj = tcx.tables().adjustments.get(&id).cloned();
+            if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj {
+                for i in 0..autoderefs {
                     let method_call = ty::MethodCall::autoderef(id, i as u32);
-                    if let Some(m) = tcx.tables
-                        .borrow()
-                        .method_map
-                        .get(&method_call)
-                        .cloned() {
+                    if let Some(m) = tcx.tables().method_map.get(&method_call)
+                                                            .cloned() {
                         if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
                             return true;
                         }
@@ -971,12 +971,10 @@ impl LateLintPass for UnconditionalRecursion {
                     // it doesn't necessarily have a definition.
                     match tcx.expect_def_or_none(callee.id) {
                         Some(Def::Method(def_id)) => {
-                            let item_substs = tcx.node_id_item_substs(callee.id);
-                            method_call_refers_to_method(tcx,
-                                                         method,
-                                                         def_id,
-                                                         &item_substs.substs,
-                                                         id)
+                            let substs = tcx.tables().node_id_item_substs(callee.id)
+                                .unwrap_or_else(|| tcx.intern_substs(&[]));
+                            method_call_refers_to_method(
+                                tcx, method, def_id, substs, id)
                         }
                         _ => false,
                     }
@@ -1213,7 +1211,7 @@ impl LateLintPass for MutableTransmutes {
                 if !def_id_is_transmute(cx, did) {
                     return None;
                 }
-                let typ = cx.tcx.node_id_to_type(expr.id);
+                let typ = cx.tcx.tables().node_id_to_type(expr.id);
                 match typ.sty {
                     ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
                         let from = bare_fn.sig.0.inputs[0];
@@ -1284,7 +1282,7 @@ impl LateLintPass for UnionsWithDropFields {
         if let hir::ItemUnion(ref vdata, _) = item.node {
             let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
             for field in vdata.fields() {
-                let field_ty = ctx.tcx.node_id_to_type(field.id);
+                let field_ty = ctx.tcx.tables().node_id_to_type(field.id);
                 if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) {
                     ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
                                   field.span,
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 9464bf30b69..b04759955a9 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -113,14 +113,14 @@ impl LateLintPass for TypeLimits {
                             forbid_unsigned_negation(cx, e.span);
                         }
                         ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
-                            if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
+                            if let ty::TyUint(_) = cx.tcx.tables().node_id_to_type(e.id).sty {
                                 forbid_unsigned_negation(cx, e.span);
                             }
                         }
                         _ => (),
                     }
                 } else {
-                    let t = cx.tcx.node_id_to_type(expr.id);
+                    let t = cx.tcx.tables().node_id_to_type(expr.id);
                     if let ty::TyUint(_) = t.sty {
                         forbid_unsigned_negation(cx, e.span);
                     }
@@ -138,7 +138,7 @@ impl LateLintPass for TypeLimits {
                 }
 
                 if binop.node.is_shift() {
-                    let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
+                    let opt_ty_bits = match cx.tcx.tables().node_id_to_type(l.id).sty {
                         ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
                         ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
                         _ => None,
@@ -171,7 +171,7 @@ impl LateLintPass for TypeLimits {
                 }
             }
             hir::ExprLit(ref lit) => {
-                match cx.tcx.node_id_to_type(e.id).sty {
+                match cx.tcx.tables().node_id_to_type(e.id).sty {
                     ty::TyInt(t) => {
                         match lit.node {
                             ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
@@ -324,7 +324,7 @@ impl LateLintPass for TypeLimits {
             // Normalize the binop so that the literal is always on the RHS in
             // the comparison
             let norm_binop = if swap { rev_binop(binop) } else { binop };
-            match tcx.node_id_to_type(expr.id).sty {
+            match tcx.tables().node_id_to_type(expr.id).sty {
                 ty::TyInt(int_ty) => {
                     let (min, max) = int_ty_range(int_ty);
                     let lit_val: i64 = match lit.node {
@@ -740,7 +740,7 @@ impl LateLintPass for VariantSizeDifferences {
         if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
             if gens.ty_params.is_empty() {
                 // sizes only make sense for non-generic types
-                let t = cx.tcx.node_id_to_type(it.id);
+                let t = cx.tcx.tables().node_id_to_type(it.id);
                 let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
                     let ty = cx.tcx.erase_regions(&t);
                     ty.layout(&infcx)
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index a29ff18ab53..15430a5c9f9 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -140,7 +140,7 @@ impl LateLintPass for UnusedResults {
             return;
         }
 
-        let t = cx.tcx.expr_ty(&expr);
+        let t = cx.tcx.tables().expr_ty(&expr);
         let warned = match t.sty {
             ty::TyTuple(ref tys) if tys.is_empty() => return,
             ty::TyNever => return,
@@ -441,16 +441,15 @@ impl LateLintPass for UnusedAllocation {
             _ => return,
         }
 
-        if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
-            if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) =
-                *adjustment {
+        if let Some(adjustment) = cx.tcx.tables().adjustments.get(&e.id) {
+            if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind {
                 match autoref {
-                    &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
+                    Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => {
                         cx.span_lint(UNUSED_ALLOCATION,
                                      e.span,
                                      "unnecessary allocation, use & instead");
                     }
-                    &Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
+                    Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => {
                         cx.span_lint(UNUSED_ALLOCATION,
                                      e.span,
                                      "unnecessary allocation, use &mut instead");
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index f001f851319..e009955b92e 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -38,7 +38,7 @@ enum TableEntry<'tcx> {
     Def(Def),
     NodeType(Ty<'tcx>),
     ItemSubsts(ty::ItemSubsts<'tcx>),
-    Adjustment(ty::adjustment::AutoAdjustment<'tcx>),
+    Adjustment(ty::adjustment::Adjustment<'tcx>),
     ConstQualif(ConstQualif),
 }
 
@@ -94,9 +94,9 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx>
         };
 
         encode(tcx.expect_def_or_none(id).map(TableEntry::Def));
-        encode(tcx.node_types().get(&id).cloned().map(TableEntry::NodeType));
-        encode(tcx.tables.borrow().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
-        encode(tcx.tables.borrow().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
+        encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType));
+        encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
+        encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
         encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif));
     }
 }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index e8734e42757..fdb117ef81b 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1016,7 +1016,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         let data = ClosureData {
             kind: tcx.closure_kind(def_id),
-            ty: self.lazy(&tcx.tables.borrow().closure_tys[&def_id]),
+            ty: self.lazy(&tcx.tables().closure_tys[&def_id]),
         };
 
         Entry {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index d6fcc79a9a2..b37dd8dd0a9 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -191,7 +191,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     assert_eq!(block, builder.return_block());
 
     let mut spread_arg = None;
-    match tcx.node_id_to_type(fn_id).sty {
+    match tcx.tables().node_id_to_type(fn_id).sty {
         ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
             // RustCall pseudo-ABI untuples the last argument.
             spread_arg = Some(Local::new(arguments.len()));
@@ -203,7 +203,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
         freevars.iter().map(|fv| {
             let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap();
-            let by_ref = tcx.upvar_capture(ty::UpvarId {
+            let by_ref = tcx.tables().upvar_capture(ty::UpvarId {
                 var_id: var_id,
                 closure_expr_id: fn_id
             }).map_or(false, |capture| match capture {
@@ -233,7 +233,7 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
                                        ast_expr: &'tcx hir::Expr)
                                        -> (Mir<'tcx>, ScopeAuxiliaryVec) {
     let tcx = hir.tcx();
-    let ty = tcx.expr_ty_adjusted(ast_expr);
+    let ty = tcx.tables().expr_ty_adjusted(ast_expr);
     let span = tcx.map.span(item_id);
     let mut builder = Builder::new(hir, span, 0, ty);
 
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index ec1136368c1..cb69de2cb3c 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -77,7 +77,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    block: &'tcx hir::Block)
                                    -> ExprRef<'tcx> {
-    let block_ty = cx.tcx.node_id_to_type(block.id);
+    let block_ty = cx.tcx.tables().node_id_to_type(block.id);
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id);
     let expr = Expr {
         ty: block_ty,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 1b324ac3132..ba0d3b49a6c 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -35,15 +35,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
         let mut expr = make_mirror_unadjusted(cx, self);
+        let adj = cx.tcx.tables().adjustments.get(&self.id).cloned();
 
         debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
-               expr, cx.tcx.tables.borrow().adjustments.get(&self.id));
+               expr, adj);
 
         // Now apply adjustments, if any.
-        match cx.tcx.tables.borrow().adjustments.get(&self.id) {
+        match adj.map(|adj| (adj.kind, adj.target)) {
             None => {}
-            Some(&ty::adjustment::AdjustReifyFnPointer) => {
-                let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
+            Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
                     ty: adjusted_ty,
@@ -51,8 +51,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
                 };
             }
-            Some(&ty::adjustment::AdjustUnsafeFnPointer) => {
-                let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
+            Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
                     ty: adjusted_ty,
@@ -60,7 +59,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
                 };
             }
-            Some(&ty::adjustment::AdjustNeverToAny(adjusted_ty)) => {
+            Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
                     ty: adjusted_ty,
@@ -68,8 +67,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     kind: ExprKind::NeverToAny { source: expr.to_ref() },
                 };
             }
-            Some(&ty::adjustment::AdjustMutToConstPointer) => {
-                let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
+            Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
                     ty: adjusted_ty,
@@ -77,8 +75,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     kind: ExprKind::Cast { source: expr.to_ref() },
                 };
             }
-            Some(&ty::adjustment::AdjustDerefRef(ref adj)) => {
-                for i in 0..adj.autoderefs {
+            Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize },
+                  adjusted_ty)) => {
+                for i in 0..autoderefs {
                     let i = i as u32;
                     let adjusted_ty =
                         expr.ty.adjust_for_autoderef(
@@ -86,11 +85,11 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                             self.id,
                             self.span,
                             i,
-                            |mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty));
+                            |mc| cx.tcx.tables().method_map.get(&mc).map(|m| m.ty));
                     debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty);
                     let method_key = ty::MethodCall::autoderef(self.id, i);
                     let meth_ty =
-                        cx.tcx.tables.borrow().method_map.get(&method_key).map(|m| m.ty);
+                        cx.tcx.tables().method_map.get(&method_key).map(|m| m.ty);
                     let kind = if let Some(meth_ty) = meth_ty {
                         debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
 
@@ -128,10 +127,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     };
                 }
 
-                if let Some(autoref) = adj.autoref {
+                if let Some(autoref) = autoref {
                     let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
                     match autoref {
-                        ty::adjustment::AutoPtr(r, m) => {
+                        ty::adjustment::AutoBorrow::Ref(r, m) => {
                             expr = Expr {
                                 temp_lifetime: temp_lifetime,
                                 ty: adjusted_ty,
@@ -143,7 +142,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                                 },
                             };
                         }
-                        ty::adjustment::AutoUnsafe(m) => {
+                        ty::adjustment::AutoBorrow::RawPtr(m) => {
                             // Convert this to a suitable `&foo` and
                             // then an unsafe coercion. Limit the region to be just this
                             // expression.
@@ -169,10 +168,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     }
                 }
 
-                if let Some(target) = adj.unsize {
+                if unsize {
                     expr = Expr {
                         temp_lifetime: temp_lifetime,
-                        ty: target,
+                        ty: adjusted_ty,
                         span: self.span,
                         kind: ExprKind::Unsize { source: expr.to_ref() },
                     };
@@ -212,7 +211,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
 fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                           expr: &'tcx hir::Expr)
                                           -> Expr<'tcx> {
-    let expr_ty = cx.tcx.expr_ty(expr);
+    let expr_ty = cx.tcx.tables().expr_ty(expr);
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
 
     let kind = match expr.node {
@@ -231,7 +230,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprCall(ref fun, ref args) => {
-            if cx.tcx.is_method_call(expr.id) {
+            if cx.tcx.tables().is_method_call(expr.id) {
                 // The callee is something implementing Fn, FnMut, or FnOnce.
                 // Find the actual method implementation being called and
                 // build the appropriate UFCS call expression with the
@@ -282,7 +281,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     })
                 } else { None };
                 if let Some((adt_def, index)) = adt_data {
-                    let substs = cx.tcx.node_id_item_substs(fun.id).substs;
+                    let substs = cx.tcx.tables().node_id_item_substs(fun.id)
+                        .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
                     let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef {
                         name: Field::new(idx),
                         expr: e.to_ref()
@@ -296,7 +296,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     }
                 } else {
                     ExprKind::Call {
-                        ty: cx.tcx.node_id_to_type(fun.id),
+                        ty: cx.tcx.tables().node_id_to_type(fun.id),
                         fun: fun.to_ref(),
                         args: args.to_ref(),
                     }
@@ -328,7 +328,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            if cx.tcx.is_method_call(expr.id) {
+            if cx.tcx.tables().is_method_call(expr.id) {
                 let pass_args = if op.node.is_by_value() {
                     PassArgs::ByValue
                 } else {
@@ -350,7 +350,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         },
 
         hir::ExprBinary(op, ref lhs, ref rhs) => {
-            if cx.tcx.is_method_call(expr.id) {
+            if cx.tcx.tables().is_method_call(expr.id) {
                 let pass_args = if op.node.is_by_value() {
                     PassArgs::ByValue
                 } else {
@@ -406,7 +406,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprIndex(ref lhs, ref index) => {
-            if cx.tcx.is_method_call(expr.id) {
+            if cx.tcx.tables().is_method_call(expr.id) {
                 overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
                                   PassArgs::ByValue, lhs.to_ref(), vec![index])
             } else {
@@ -418,7 +418,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
-            if cx.tcx.is_method_call(expr.id) {
+            if cx.tcx.tables().is_method_call(expr.id) {
                 overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
                                   PassArgs::ByValue, arg.to_ref(), vec![])
             } else {
@@ -427,7 +427,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
-            if cx.tcx.is_method_call(expr.id) {
+            if cx.tcx.tables().is_method_call(expr.id) {
                 overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
                                     PassArgs::ByValue, arg.to_ref(), vec![])
             } else {
@@ -439,7 +439,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
-            if cx.tcx.is_method_call(expr.id) {
+            if cx.tcx.tables().is_method_call(expr.id) {
                 overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
                                     PassArgs::ByValue, arg.to_ref(), vec![])
             } else {
@@ -470,10 +470,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             base: base.as_ref().map(|base| {
                                 FruInfo {
                                     base: base.to_ref(),
-                                    field_types: cx.tcx.tables
-                                        .borrow()
-                                        .fru_field_types[&expr.id]
-                                        .clone()
+                                    field_types:
+                                        cx.tcx.tables().fru_field_types[&expr.id].clone()
                                 }
                             })
                         }
@@ -512,7 +510,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprClosure(..) => {
-            let closure_ty = cx.tcx.expr_ty(expr);
+            let closure_ty = cx.tcx.tables().expr_ty(expr);
             let (def_id, substs) = match closure_ty.sty {
                 ty::TyClosure(def_id, substs) => (def_id, substs),
                 _ => {
@@ -551,7 +549,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat {
             value: v.to_ref(),
             count: TypedConstVal {
-                ty: cx.tcx.expr_ty(c),
+                ty: cx.tcx.tables().expr_ty(c),
                 span: c.span,
                 value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) {
                     ConstVal::Integral(ConstInt::Usize(u)) => u,
@@ -579,7 +577,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             ExprKind::Loop { condition: None,
                              body: block::to_expr_ref(cx, body) },
         hir::ExprField(ref source, name) => {
-            let index = match cx.tcx.expr_ty_adjusted(source).sty {
+            let index = match cx.tcx.tables().expr_ty_adjusted(source).sty {
                 ty::TyAdt(adt_def, _) =>
                     adt_def.variants[0].index_of_field_named(name.node),
                 ref ty =>
@@ -631,8 +629,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  expr: &hir::Expr,
                                  method_call: ty::MethodCall)
                                  -> Expr<'tcx> {
-    let tables = cx.tcx.tables.borrow();
-    let callee = &tables.method_map[&method_call];
+    let callee = cx.tcx.tables().method_map[&method_call];
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
     Expr {
         temp_lifetime: temp_lifetime,
@@ -666,8 +663,8 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      expr: &'tcx hir::Expr)
                                      -> ExprKind<'tcx> {
-    let substs = cx.tcx.node_id_item_substs(expr.id).substs;
-    // Otherwise there may be def_map borrow conflicts
+    let substs = cx.tcx.tables().node_id_item_substs(expr.id)
+        .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
     let def = cx.tcx.expect_def(expr.id);
     let def_id = match def {
         // A regular function, constructor function or a constant.
@@ -677,18 +674,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::Const(def_id) | Def::AssociatedConst(def_id) => def_id,
 
         Def::StructCtor(def_id, CtorKind::Const) |
-        Def::VariantCtor(def_id, CtorKind::Const) => match cx.tcx.node_id_to_type(expr.id).sty {
-            // A unit struct/variant which is used as a value.
-            // We return a completely different ExprKind here to account for this special case.
-            ty::TyAdt(adt_def, substs) => return ExprKind::Adt {
-                adt_def: adt_def,
-                variant_index: adt_def.variant_index_with_id(def_id),
-                substs: substs,
-                fields: vec![],
-                base: None,
-            },
-            ref sty => bug!("unexpected sty: {:?}", sty)
-        },
+        Def::VariantCtor(def_id, CtorKind::Const) => {
+            match cx.tcx.tables().node_id_to_type(expr.id).sty {
+                // A unit struct/variant which is used as a value.
+                // We return a completely different ExprKind here to account for this special case.
+                ty::TyAdt(adt_def, substs) => return ExprKind::Adt {
+                    adt_def: adt_def,
+                    variant_index: adt_def.variant_index_with_id(def_id),
+                    substs: substs,
+                    fields: vec![],
+                    base: None,
+                },
+                ref sty => bug!("unexpected sty: {:?}", sty)
+            }
+        }
 
         Def::Static(node_id, _) => return ExprKind::StaticRef {
             id: node_id,
@@ -720,7 +719,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::Upvar(def_id, index, closure_expr_id) => {
             let id_var = cx.tcx.map.as_local_node_id(def_id).unwrap();
             debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
-            let var_ty = cx.tcx.node_id_to_type(id_var);
+            let var_ty = cx.tcx.tables().node_id_to_type(id_var);
 
             let body_id = match cx.tcx.map.find(closure_expr_id) {
                 Some(map::NodeExpr(expr)) => {
@@ -737,7 +736,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             };
 
             // FIXME free regions in closures are not right
-            let closure_ty = cx.tcx.node_id_to_type(closure_expr_id);
+            let closure_ty = cx.tcx.tables().node_id_to_type(closure_expr_id);
 
             // FIXME we're just hard-coding the idea that the
             // signature will be &self or &mut self and hence will
@@ -809,7 +808,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 var_id: id_var,
                 closure_expr_id: closure_expr_id,
             };
-            let upvar_capture = match cx.tcx.upvar_capture(upvar_id) {
+            let upvar_capture = match cx.tcx.tables().upvar_capture(upvar_id) {
                 Some(c) => c,
                 None => {
                     span_bug!(
@@ -893,7 +892,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             argrefs.extend(
                 args.iter()
                     .map(|arg| {
-                        let arg_ty = cx.tcx.expr_ty_adjusted(arg);
+                        let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg);
                         let adjusted_ty =
                             cx.tcx.mk_ref(region,
                                        ty::TypeAndMut { ty: arg_ty,
@@ -931,9 +930,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     // line up (this is because `*x` and `x[y]` represent lvalues):
 
     // to find the type &T of the content returned by the method;
-    let tables = cx.tcx.tables.borrow();
-    let callee = &tables.method_map[&method_call];
-    let ref_ty = callee.ty.fn_ret();
+    let ref_ty = cx.tcx.tables().method_map[&method_call].ty.fn_ret();
     let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
     // callees always have all late-bound regions fully instantiated,
 
@@ -962,9 +959,9 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         var_id: id_var,
         closure_expr_id: closure_expr.id,
     };
-    let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap();
+    let upvar_capture = cx.tcx.tables().upvar_capture(upvar_id).unwrap();
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id);
-    let var_ty = cx.tcx.node_id_to_type(id_var);
+    let var_ty = cx.tcx.tables().node_id_to_type(id_var);
     let captured_var = Expr {
         temp_lifetime: temp_lifetime,
         ty: var_ty,
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index b0e2d6e73d3..0ffc59fe6bf 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -214,7 +214,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
                 id: ast::NodeId) {
         // fetch the fully liberated fn signature (that is, all bound
         // types/lifetimes replaced)
-        let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) {
+        let fn_sig = match self.tcx.tables().liberated_fn_sigs.get(&id) {
             Some(f) => f.clone(),
             None => {
                 span_bug!(span, "no liberated fn sig for {:?}", id);
@@ -248,7 +248,7 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              closure_expr_id: ast::NodeId,
                              body_id: ast::NodeId)
                              -> Ty<'tcx> {
-    let closure_ty = tcx.node_id_to_type(closure_expr_id);
+    let closure_ty = tcx.tables().node_id_to_type(closure_expr_id);
 
     // We're just hard-coding the idea that the signature will be
     // &self or &mut self and hence will have a bound region with
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 8ad4d7f57a6..f23539e88f7 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -319,7 +319,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
         let mut outer = self.qualif;
         self.qualif = ConstQualif::empty();
 
-        let node_ty = self.tcx.node_id_to_type(ex.id);
+        let node_ty = self.tcx.tables().node_id_to_type(ex.id);
         check_expr(self, ex, node_ty);
         check_adjustments(self, ex);
 
@@ -449,14 +449,14 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
     match e.node {
         hir::ExprUnary(..) |
         hir::ExprBinary(..) |
-        hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
+        hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
             v.add_qualif(ConstQualif::NOT_CONST);
         }
         hir::ExprBox(_) => {
             v.add_qualif(ConstQualif::NOT_CONST);
         }
         hir::ExprUnary(op, ref inner) => {
-            match v.tcx.node_id_to_type(inner.id).sty {
+            match v.tcx.tables().node_id_to_type(inner.id).sty {
                 ty::TyRawPtr(_) => {
                     assert!(op == hir::UnDeref);
 
@@ -466,7 +466,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprBinary(op, ref lhs, _) => {
-            match v.tcx.node_id_to_type(lhs.id).sty {
+            match v.tcx.tables().node_id_to_type(lhs.id).sty {
                 ty::TyRawPtr(_) => {
                     assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
                             op.node == hir::BiLe || op.node == hir::BiLt ||
@@ -503,7 +503,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                     }
                 }
                 Def::Const(did) | Def::AssociatedConst(did) => {
-                    let substs = Some(v.tcx.node_id_item_substs(e.id).substs);
+                    let substs = Some(v.tcx.tables().node_id_item_substs(e.id)
+                        .unwrap_or_else(|| v.tcx.intern_substs(&[])));
                     if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
                         let inner = v.global_expr(Mode::Const, expr);
                         v.add_qualif(inner);
@@ -555,7 +556,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprMethodCall(..) => {
-            let method = v.tcx.tables.borrow().method_map[&method_call];
+            let method = v.tcx.tables().method_map[&method_call];
             let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
                 ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
                 ty::TraitContainer(_) => false
@@ -565,7 +566,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprStruct(..) => {
-            if let ty::TyAdt(adt, ..) = v.tcx.expr_ty(e).sty {
+            if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
                 // unsafe_cell_type doesn't necessarily exist with no_core
                 if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
                     v.add_qualif(ConstQualif::MUTABLE_MEM);
@@ -624,16 +625,18 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
 
 /// Check the adjustments of an expression
 fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
-    match v.tcx.tables.borrow().adjustments.get(&e.id) {
+    use rustc::ty::adjustment::*;
+
+    match v.tcx.tables().adjustments.get(&e.id).map(|adj| adj.kind) {
         None |
-        Some(&ty::adjustment::AdjustNeverToAny(..)) |
-        Some(&ty::adjustment::AdjustReifyFnPointer) |
-        Some(&ty::adjustment::AdjustUnsafeFnPointer) |
-        Some(&ty::adjustment::AdjustMutToConstPointer) => {}
+        Some(Adjust::NeverToAny) |
+        Some(Adjust::ReifyFnPointer) |
+        Some(Adjust::UnsafeFnPointer) |
+        Some(Adjust::MutToConstPointer) => {}
 
-        Some(&ty::adjustment::AdjustDerefRef(ty::adjustment::AutoDerefRef { autoderefs, .. })) => {
+        Some(Adjust::DerefRef { autoderefs, .. }) => {
             if (0..autoderefs as u32)
-                .any(|autoderef| v.tcx.is_overloaded_autoderef(e.id, autoderef)) {
+                .any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
                 v.add_qualif(ConstQualif::NOT_CONST);
             }
         }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 77b3e76fc54..8fdfecd4a58 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -430,11 +430,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
         match expr.node {
             hir::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                let method = self.tcx.tables.borrow().method_map[&method_call];
+                let method = self.tcx.tables().method_map[&method_call];
                 self.check_method(expr.span, method.def_id);
             }
             hir::ExprStruct(_, ref expr_fields, _) => {
-                let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
+                let adt = self.tcx.tables().expr_ty(expr).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
@@ -495,14 +495,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
 
         match pattern.node {
             PatKind::Struct(_, ref fields, _) => {
-                let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap();
+                let adt = self.tcx.tables().pat_ty(pattern).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id));
                 for field in fields {
                     self.check_field(field.span, adt, variant.field_named(field.node.name));
                 }
             }
             PatKind::TupleStruct(_, ref fields, ddpos) => {
-                match self.tcx.pat_ty(pattern).sty {
+                match self.tcx.tables().pat_ty(pattern).sty {
                     // enum fields have no privacy at this time
                     ty::TyAdt(def, _) if !def.is_enum() => {
                         let expected_len = def.struct_variant().fields.len();
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 8a628289b7f..db4788c3cea 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -356,7 +356,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             collector.visit_pat(&arg.pat);
             let span_utils = self.span.clone();
             for &(id, ref p, ..) in &collector.collected_paths {
-                let typ = self.tcx.node_types().get(&id).unwrap().to_string();
+                let typ = self.tcx.tables().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?)
                 let sub_span = span_utils.span_for_last_ident(p.span);
@@ -988,7 +988,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         match p.node {
             PatKind::Struct(ref path, ref fields, _) => {
                 visit::walk_path(self, path);
-                let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap();
+                let adt = self.tcx.tables().node_id_to_type(p.id).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(p.id));
 
                 for &Spanned { node: ref field, span } in fields {
@@ -1023,8 +1023,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 ast::Mutability::Immutable => value.to_string(),
                 _ => String::new(),
             };
-            let types = self.tcx.node_types();
-            let typ = match types.get(&id) {
+            let typ = match self.tcx.tables().node_types.get(&id) {
                 Some(typ) => {
                     let typ = typ.to_string();
                     if !value.is_empty() {
@@ -1355,7 +1354,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
             }
             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
                 let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id);
-                let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap();
+                let adt = self.tcx.tables().expr_ty(&hir_expr).ty_adt_def().unwrap();
                 let def = self.tcx.expect_def(hir_expr.id);
                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
             }
@@ -1381,7 +1380,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                         return;
                     }
                 };
-                let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
+                let ty = &self.tcx.tables().expr_ty_adjusted(&hir_node).sty;
                 match *ty {
                     ty::TyAdt(def, _) => {
                         let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
@@ -1468,7 +1467,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                     } else {
                         "<mutable>".to_string()
                     };
-                    let typ = self.tcx.node_types()
+                    let typ = self.tcx.tables().node_types
                                   .get(&id).map(|t| t.to_string()).unwrap_or(String::new());
                     value.push_str(": ");
                     value.push_str(&typ);
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 15c74f2ed6a..7e008f74162 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -286,7 +286,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                           scope: NodeId) -> Option<VariableData> {
         if let Some(ident) = field.ident {
             let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
-            let typ = self.tcx.node_types().get(&field.id).unwrap().to_string();
+            let typ = self.tcx.tables().node_types.get(&field.id).unwrap().to_string();
             let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
             filter!(self.span_utils, sub_span, field.span, None);
             Some(VariableData {
@@ -418,7 +418,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
         let hir_node = self.tcx.map.expect_expr(expr.id);
-        let ty = self.tcx.expr_ty_adjusted_opt(&hir_node);
+        let ty = self.tcx.tables().expr_ty_adjusted_opt(&hir_node);
         if ty.is_none() || ty.unwrap().sty == ty::TyError {
             return None;
         }
@@ -432,7 +432,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         return None;
                     }
                 };
-                match self.tcx.expr_ty_adjusted(&hir_node).sty {
+                match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
                     ty::TyAdt(def, _) if !def.is_enum() => {
                         let f = def.struct_variant().field_named(ident.node.name);
                         let sub_span = self.span_utils.span_for_last_ident(expr.span);
@@ -451,7 +451,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 }
             }
             ast::ExprKind::Struct(ref path, ..) => {
-                match self.tcx.expr_ty_adjusted(&hir_node).sty {
+                match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
                     ty::TyAdt(def, _) if !def.is_enum() => {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
                         filter!(self.span_utils, sub_span, path.span, None);
@@ -472,7 +472,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
             ast::ExprKind::MethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
+                let method_id = self.tcx.tables().method_map[&method_call].def_id;
                 let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() {
                     ty::ImplContainer(_) => (Some(method_id), None),
                     ty::TraitContainer(_) => (None, Some(method_id)),
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index cd81d114eb7..ffb13a833a5 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -74,7 +74,7 @@ impl<'tcx> Callee<'tcx> {
     pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
                              method_call: ty::MethodCall)
                              -> Callee<'tcx> {
-        let method = bcx.tcx().tables.borrow().method_map[&method_call];
+        let method = bcx.tcx().tables().method_map[&method_call];
         Callee::method(bcx, method)
     }
 
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 8348da9f7b7..a439d415ede 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -1082,10 +1082,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
             hir::ItemStruct(_, ref generics) |
             hir::ItemUnion(_, ref generics) => {
                 if !generics.is_parameterized() {
-                    let ty = {
-                        let tables = self.scx.tcx().tables.borrow();
-                        tables.node_types[&item.id]
-                    };
+                    let ty = self.scx.tcx().tables().node_types[&item.id];
 
                     if self.mode == TransItemCollectionMode::Eager {
                         debug!("RootCollector: ADT drop-glue for {}",
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 863aecc8244..4bb34850e08 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1765,7 +1765,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     };
 
     let is_local_to_unit = is_node_local_to_unit(cx, node_id);
-    let variable_type = tcx.erase_regions(&tcx.node_id_to_type(node_id));
+    let variable_type = tcx.erase_regions(&tcx.tables().node_id_to_type(node_id));
     let type_metadata = type_metadata(cx, variable_type, span);
     let var_name = tcx.item_name(node_def_id).to_string();
     let linkage_name = mangled_name_of_item(cx, node_def_id, "");
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1aa502fc443..c93f1c6c8e6 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1549,7 +1549,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
                 tcx.prohibit_type_params(base_segments);
                 let impl_id = tcx.map.as_local_node_id(def_id).unwrap();
-                let ty = tcx.node_id_to_type(impl_id);
+                let ty = tcx.tables().node_id_to_type(impl_id);
                 if let Some(free_substs) = self.get_free_substs() {
                     ty.subst(tcx, free_substs)
                 } else {
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index c5a21d7dd91..3cf64fa439d 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // If the callee is a bare function or a closure, then we're all set.
         match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty {
             ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-                self.write_autoderef_adjustment(callee_expr.id, autoderefs);
+                self.write_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty);
                 return Some(CallStep::Builtin);
             }
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index ccc944813ff..16493412d69 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -65,10 +65,7 @@ use check::FnCtxt;
 use rustc::hir;
 use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
 use rustc::traits::{self, ObligationCause};
-use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
-use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
-use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
-use rustc::ty::adjustment::AdjustNeverToAny;
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
@@ -93,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
     }
 }
 
-type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>;
+type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>;
 
 fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
                        to_mutbl: hir::Mutability)
@@ -144,12 +141,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
     /// Synthesize an identity adjustment.
     fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
-        Ok((ty,
-            AdjustDerefRef(AutoDerefRef {
-                autoderefs: 0,
-                autoref: None,
-                unsize: None,
-            })))
+        Ok((ty, Adjust::DerefRef {
+            autoderefs: 0,
+            autoref: None,
+            unsize: false,
+        }))
     }
 
     fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx>
@@ -166,7 +162,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
         }
 
         if a.is_never() {
-            return Ok((b, AdjustNeverToAny(b)));
+            return Ok((b, Adjust::NeverToAny));
         }
 
         // Consider coercing the subtype to a DST
@@ -396,17 +392,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             ty::TyRef(r_borrow, _) => r_borrow,
             _ => span_bug!(span, "expected a ref type, got {:?}", ty),
         };
-        let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl));
+        let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl));
         debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
                ty,
                autoderefs,
                autoref);
-        Ok((ty,
-            AdjustDerefRef(AutoDerefRef {
-                autoderefs: autoderefs,
-                autoref: autoref,
-                unsize: None,
-            })))
+        Ok((ty, Adjust::DerefRef {
+            autoderefs: autoderefs,
+            autoref: autoref,
+            unsize: false,
+        }))
     }
 
 
@@ -437,11 +432,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
                 let coercion = Coercion(self.origin.span());
                 let r_borrow = self.next_region_var(coercion);
-                (mt_a.ty, Some(AutoPtr(r_borrow, mt_b.mutbl)))
+                (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)))
             }
             (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
-                (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
+                (mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl)))
             }
             _ => (source, None),
         };
@@ -497,13 +492,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
         *self.unsizing_obligations.borrow_mut() = leftover_predicates;
 
-        let adjustment = AutoDerefRef {
+        let adjustment = Adjust::DerefRef {
             autoderefs: if reborrow.is_some() { 1 } else { 0 },
             autoref: reborrow,
-            unsize: Some(target),
+            unsize: true,
         };
         debug!("Success, coerced with {:?}", adjustment);
-        Ok((target, AdjustDerefRef(adjustment)))
+        Ok((target, adjustment))
     }
 
     fn coerce_from_safe_fn(&self,
@@ -516,7 +511,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
                 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
                     let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
                     return self.unify_and_identity(unsafe_a, b)
-                        .map(|(ty, _)| (ty, AdjustUnsafeFnPointer));
+                        .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer));
                 }
                 _ => {}
             }
@@ -555,7 +550,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             ty::TyFnPtr(_) => {
                 let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
                 self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b)
-                    .map(|(ty, _)| (ty, AdjustReifyFnPointer))
+                    .map(|(ty, _)| (ty, Adjust::ReifyFnPointer))
             }
             _ => self.unify_and_identity(a, b),
         }
@@ -585,17 +580,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
         coerce_mutbls(mt_a.mutbl, mutbl_b)?;
 
         // Although references and unsafe ptrs have the same
-        // representation, we still register an AutoDerefRef so that
+        // representation, we still register an Adjust::DerefRef so that
         // regionck knows that the region for `a` must be valid here.
         Ok((ty,
             if is_ref {
-                AdjustDerefRef(AutoDerefRef {
+                Adjust::DerefRef {
                     autoderefs: 1,
-                    autoref: Some(AutoUnsafe(mutbl_b)),
-                    unsize: None,
-                })
+                    autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
+                    unsize: false,
+                }
             } else if mt_a.mutbl != mutbl_b {
-                AdjustMutToConstPointer
+                Adjust::MutToConstPointer
             } else {
                 noop
             }))
@@ -606,24 +601,25 @@ fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>,
                                    exprs: &E,
                                    a: Ty<'tcx>,
                                    b: Ty<'tcx>)
-                                   -> CoerceResult<'tcx>
+                                   -> RelateResult<'tcx, Adjustment<'tcx>>
     where E: Fn() -> I,
           I: IntoIterator<Item = &'b hir::Expr>
 {
 
-    let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?;
+    let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?;
 
     let fcx = coerce.fcx;
-    if let AdjustDerefRef(auto) = adjustment {
-        if auto.unsize.is_some() {
-            let mut obligations = coerce.unsizing_obligations.borrow_mut();
-            for obligation in obligations.drain(..) {
-                fcx.register_predicate(obligation);
-            }
+    if let Adjust::DerefRef { unsize: true, .. } = adjust {
+        let mut obligations = coerce.unsizing_obligations.borrow_mut();
+        for obligation in obligations.drain(..) {
+            fcx.register_predicate(obligation);
         }
     }
 
-    Ok((ty, adjustment))
+    Ok(Adjustment {
+        kind: adjust,
+        target: ty
+    })
 }
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
@@ -641,17 +637,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
         self.commit_if_ok(|_| {
-            let (ty, adjustment) = apply(&mut coerce, &|| Some(expr), source, target)?;
+            let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?;
             if !adjustment.is_identity() {
                 debug!("Success, coerced with {:?}", adjustment);
                 match self.tables.borrow().adjustments.get(&expr.id) {
                     None |
-                    Some(&AdjustNeverToAny(..)) => (),
+                    Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (),
                     _ => bug!("expr already has an adjustment on it!"),
                 };
                 self.write_adjustment(expr.id, adjustment);
             }
-            Ok(ty)
+            Ok(adjustment.target)
         })
     }
 
@@ -705,12 +701,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 // Reify both sides and return the reified fn pointer type.
+                let fn_ptr = self.tcx.mk_fn_ptr(fty);
                 for expr in exprs().into_iter().chain(Some(new)) {
                     // No adjustments can produce a fn item, so this should never trip.
                     assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
-                    self.write_adjustment(expr.id, AdjustReifyFnPointer);
+                    self.write_adjustment(expr.id, Adjustment {
+                        kind: Adjust::ReifyFnPointer,
+                        target: fn_ptr
+                    });
                 }
-                return Ok(self.tcx.mk_fn_ptr(fty));
+                return Ok(fn_ptr);
             }
             _ => {}
         }
@@ -724,11 +724,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if !self.tables.borrow().adjustments.contains_key(&new.id) {
             let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty));
             match result {
-                Ok((ty, adjustment)) => {
+                Ok(adjustment) => {
                     if !adjustment.is_identity() {
                         self.write_adjustment(new.id, adjustment);
                     }
-                    return Ok(ty);
+                    return Ok(adjustment.target);
                 }
                 Err(e) => first_error = Some(e),
             }
@@ -738,10 +738,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // This requires ensuring there are no coercions applied to *any* of the
         // previous expressions, other than noop reborrows (ignoring lifetimes).
         for expr in exprs() {
-            let noop = match self.tables.borrow().adjustments.get(&expr.id) {
-                Some(&AdjustDerefRef(AutoDerefRef { autoderefs: 1,
-                                                    autoref: Some(AutoPtr(_, mutbl_adj)),
-                                                    unsize: None })) => {
+            let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) {
+                Some(Adjust::DerefRef {
+                    autoderefs: 1,
+                    autoref: Some(AutoBorrow::Ref(_, mutbl_adj)),
+                    unsize: false
+                }) => {
                     match self.node_ty(expr.id).sty {
                         ty::TyRef(_, mt_orig) => {
                             // Reborrow that we can safely ignore.
@@ -750,7 +752,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         _ => false,
                     }
                 }
-                Some(&AdjustNeverToAny(_)) => true,
+                Some(Adjust::NeverToAny) => true,
                 Some(_) => false,
                 None => true,
             };
@@ -783,18 +785,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     })
                 }
             }
-            Ok((ty, adjustment)) => {
+            Ok(adjustment) => {
                 if !adjustment.is_identity() {
+                    let mut tables = self.tables.borrow_mut();
                     for expr in exprs() {
-                        let previous = self.tables.borrow().adjustments.get(&expr.id).cloned();
-                        if let Some(AdjustNeverToAny(_)) = previous {
-                            self.write_adjustment(expr.id, AdjustNeverToAny(ty));
-                        } else {
-                            self.write_adjustment(expr.id, adjustment);
+                        if let Some(&mut Adjustment {
+                            kind: Adjust::NeverToAny,
+                            ref mut target
+                        }) = tables.adjustments.get_mut(&expr.id) {
+                            *target = adjustment.target;
+                            continue;
                         }
+                        tables.adjustments.insert(expr.id, adjustment);
                     }
                 }
-                Ok(ty)
+                Ok(adjustment.target)
             }
         }
     }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 722089cd50c..f88bb355d12 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -15,7 +15,7 @@ use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
-use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::fold::TypeFoldable;
 use rustc::infer::{self, InferOk, TypeOrigin};
 use syntax_pos::Span;
@@ -140,20 +140,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                       unadjusted_self_ty: Ty<'tcx>,
                       pick: &probe::Pick<'tcx>)
                       -> Ty<'tcx> {
-        let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
+        let autoref = if let Some(mutbl) = pick.autoref {
             let region = self.next_region_var(infer::Autoref(self.span));
-            let autoref = AutoPtr(region, mutbl);
-            (Some(autoref),
-             pick.unsize.map(|target| target.adjust_for_autoref(self.tcx, Some(autoref))))
+            Some(AutoBorrow::Ref(region, mutbl))
         } else {
             // No unsizing should be performed without autoref (at
             // least during method dispach). This is because we
             // currently only unsize `[T;N]` to `[T]`, and naturally
             // that must occur being a reference.
             assert!(pick.unsize.is_none());
-            (None, None)
+            None
         };
 
+
         // Commit the autoderefs by calling `autoderef` again, but this
         // time writing the results into the various tables.
         let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
@@ -163,19 +162,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         autoderef.unambiguous_final_ty();
         autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr));
 
+        let target = pick.unsize.unwrap_or(autoderefd_ty);
+        let target = target.adjust_for_autoref(self.tcx, autoref);
+
         // Write out the final adjustment.
-        self.write_adjustment(self.self_expr.id,
-                              AdjustDerefRef(AutoDerefRef {
-                                  autoderefs: pick.autoderefs,
-                                  autoref: autoref,
-                                  unsize: unsize,
-                              }));
-
-        if let Some(target) = unsize {
-            target
-        } else {
-            autoderefd_ty.adjust_for_autoref(self.tcx, autoref)
-        }
+        self.write_adjustment(self.self_expr.id, Adjustment {
+            kind: Adjust::DerefRef {
+                autoderefs: pick.autoderefs,
+                autoref: autoref,
+                unsize: pick.unsize.is_some(),
+            },
+            target: target
+        });
+
+        target
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -463,29 +463,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
         // Fix up autoderefs and derefs.
         for (i, &expr) in exprs.iter().rev().enumerate() {
+            debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr);
+
             // Count autoderefs.
-            let autoderef_count = match self.tables
-                .borrow()
-                .adjustments
-                .get(&expr.id) {
-                Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
-                Some(_) | None => 0,
-            };
-
-            debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \
-                                                      autoderef_count={}",
-                   i,
-                   expr,
-                   autoderef_count);
-
-            if autoderef_count > 0 {
-                let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
-                autoderef.nth(autoderef_count).unwrap_or_else(|| {
-                    span_bug!(expr.span,
-                              "expr was deref-able {} times but now isn't?",
-                              autoderef_count);
-                });
-                autoderef.finalize(PreferMutLvalue, Some(expr));
+            let adjustment = self.tables.borrow().adjustments.get(&expr.id).cloned();
+            match adjustment {
+                Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => {
+                    if autoderefs > 0 {
+                        let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
+                        autoderef.nth(autoderefs).unwrap_or_else(|| {
+                            span_bug!(expr.span,
+                                      "expr was deref-able {} times but now isn't?",
+                                      autoderefs);
+                        });
+                        autoderef.finalize(PreferMutLvalue, Some(expr));
+                    }
+                }
+                Some(_) | None => {}
             }
 
             // Don't retry the first one or we might infinite loop!
@@ -503,45 +497,55 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     // ought to recode this routine so it doesn't
                     // (ab)use the normal type checking paths.
                     let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned();
-                    let (autoderefs, unsize) = match adj {
-                        Some(AdjustDerefRef(adr)) => {
-                            match adr.autoref {
+                    let (autoderefs, unsize, adjusted_base_ty) = match adj {
+                        Some(Adjustment {
+                            kind: Adjust::DerefRef { autoderefs, autoref, unsize },
+                            target
+                        }) => {
+                            match autoref {
                                 None => {
-                                    assert!(adr.unsize.is_none());
-                                    (adr.autoderefs, None)
-                                }
-                                Some(AutoPtr(..)) => {
-                                    (adr.autoderefs,
-                                     adr.unsize.map(|target| {
-                                         target.builtin_deref(false, NoPreference)
-                                             .expect("fixup: AutoPtr is not &T")
-                                             .ty
-                                     }))
+                                    assert!(!unsize);
                                 }
+                                Some(AutoBorrow::Ref(..)) => {}
                                 Some(_) => {
                                     span_bug!(base_expr.span,
                                               "unexpected adjustment autoref {:?}",
-                                              adr);
+                                              adj);
                                 }
                             }
+
+                            (autoderefs, unsize, if unsize {
+                                target.builtin_deref(false, NoPreference)
+                                      .expect("fixup: AutoBorrow::Ref is not &T")
+                                      .ty
+                            } else {
+                                let ty = self.node_ty(base_expr.id);
+                                let mut ty = self.shallow_resolve(ty);
+                                let mut method_type = |method_call: ty::MethodCall| {
+                                    self.tables.borrow().method_map.get(&method_call).map(|m| {
+                                        self.resolve_type_vars_if_possible(&m.ty)
+                                    })
+                                };
+
+                                if !ty.references_error() {
+                                    for i in 0..autoderefs {
+                                        ty = ty.adjust_for_autoderef(self.tcx,
+                                                                     base_expr.id,
+                                                                     base_expr.span,
+                                                                     i as u32,
+                                                                     &mut method_type);
+                                    }
+                                }
+
+                                ty
+                            })
                         }
-                        None => (0, None),
+                        None => (0, false, self.node_ty(base_expr.id)),
                         Some(_) => {
                             span_bug!(base_expr.span, "unexpected adjustment type");
                         }
                     };
 
-                    let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
-                        (target, true)
-                    } else {
-                        (self.adjust_expr_ty(base_expr,
-                                             Some(&AdjustDerefRef(AutoDerefRef {
-                                                 autoderefs: autoderefs,
-                                                 autoref: None,
-                                                 unsize: None,
-                                             }))),
-                         false)
-                    };
                     let index_expr_ty = self.node_ty(index_expr.id);
 
                     let result = self.try_index_step(ty::MethodCall::expr(expr.id),
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index f084b85a45f..2df562f9ade 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -16,7 +16,7 @@ use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
-use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::infer;
 
 use syntax::ast;
@@ -294,11 +294,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        unsize,
                        method_ty.explicit_self);
 
-                match method_ty.explicit_self {
+                let autoref = match method_ty.explicit_self {
                     ty::ExplicitSelfCategory::ByValue => {
                         // Trait method is fn(self), no transformation needed.
                         assert!(!unsize);
-                        self.write_autoderef_adjustment(self_expr.id, autoderefs);
+                        None
                     }
 
                     ty::ExplicitSelfCategory::ByReference(..) => {
@@ -306,16 +306,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         // autoref. Pull the region etc out of the type of first argument.
                         match transformed_self_ty.sty {
                             ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
-                                self.write_adjustment(self_expr.id,
-                                                      AdjustDerefRef(AutoDerefRef {
-                                                          autoderefs: autoderefs,
-                                                          autoref: Some(AutoPtr(region, mutbl)),
-                                                          unsize: if unsize {
-                                                              Some(transformed_self_ty)
-                                                          } else {
-                                                              None
-                                                          },
-                                                      }));
+                                Some(AutoBorrow::Ref(region, mutbl))
                             }
 
                             _ => {
@@ -331,7 +322,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   "unexpected explicit self type in operator method: {:?}",
                                   method_ty.explicit_self);
                     }
-                }
+                };
+
+                self.write_adjustment(self_expr.id, Adjustment {
+                    kind: Adjust::DerefRef {
+                        autoderefs: autoderefs,
+                        autoref: autoref,
+                        unsize: unsize
+                    },
+                    target: transformed_self_ty
+                });
             }
         }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4e0f455e362..60e7858467b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -777,7 +777,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         check_union(ccx, it.id, it.span);
       }
       hir::ItemTy(_, ref generics) => {
-        let pty_ty = ccx.tcx.node_id_to_type(it.id);
+        let pty_ty = ccx.tcx.tables().node_id_to_type(it.id);
         check_bounds_are_used(ccx, generics, pty_ty);
       }
       hir::ItemForeignMod(ref m) => {
@@ -1205,7 +1205,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  sp: Span,
                                  item_id: ast::NodeId)
                                  -> bool {
-    let rty = tcx.node_id_to_type(item_id);
+    let rty = tcx.tables().node_id_to_type(item_id);
 
     // Check that it is possible to represent this type. This call identifies
     // (1) types that contain themselves and (2) types that contain a different
@@ -1224,7 +1224,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) {
-    let t = tcx.node_id_to_type(id);
+    let t = tcx.tables().node_id_to_type(id);
     match t.sty {
         ty::TyAdt(def, substs) if def.is_struct() => {
             let fields = &def.struct_variant().fields;
@@ -1581,20 +1581,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn write_autoderef_adjustment(&self,
                                       node_id: ast::NodeId,
-                                      derefs: usize) {
-        self.write_adjustment(
-            node_id,
-            adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
+                                      derefs: usize,
+                                      adjusted_ty: Ty<'tcx>) {
+        self.write_adjustment(node_id, adjustment::Adjustment {
+            kind: adjustment::Adjust::DerefRef {
                 autoderefs: derefs,
                 autoref: None,
-                unsize: None
-            })
-        );
+                unsize: false
+            },
+            target: adjusted_ty
+        });
     }
 
     pub fn write_adjustment(&self,
                             node_id: ast::NodeId,
-                            adj: adjustment::AutoAdjustment<'tcx>) {
+                            adj: adjustment::Adjustment<'tcx>) {
         debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj);
 
         if adj.is_identity() {
@@ -1760,21 +1761,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         t
     }
 
-    /// Apply `adjustment` to the type of `expr`
-    pub fn adjust_expr_ty(&self,
-                          expr: &hir::Expr,
-                          adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
-                          -> Ty<'tcx>
-    {
-        let raw_ty = self.node_ty(expr.id);
-        let raw_ty = self.shallow_resolve(raw_ty);
-        let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
-        raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| {
-            self.tables.borrow().method_map.get(&method_call)
-                                        .map(|method| resolve_ty(method.ty))
-        })
-    }
-
     pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
         match self.tables.borrow().node_types.get(&id) {
             Some(&t) => t,
@@ -2311,7 +2297,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 debug!("try_index_step: success, using built-in indexing");
                 // If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
                 assert!(!unsize);
-                self.write_autoderef_adjustment(base_expr.id, autoderefs);
+                self.write_autoderef_adjustment(base_expr.id, autoderefs, adjusted_ty);
                 return Some((tcx.types.usize, ty));
             }
             _ => {}
@@ -2867,9 +2853,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 // In case we did perform an adjustment, we have to update
                 // the type of the block, because old trans still uses it.
-                let adj = self.tables.borrow().adjustments.get(&then.id).cloned();
-                if res.is_ok() && adj.is_some() {
-                    self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref()));
+                if res.is_ok() {
+                    let adj = self.tables.borrow().adjustments.get(&then.id).cloned();
+                    if let Some(adj) = adj {
+                        self.write_ty(then_blk.id, adj.target);
+                    }
                 }
 
                 res
@@ -2930,7 +2918,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                             autoderef.finalize(lvalue_pref, Some(base));
-                            self.write_autoderef_adjustment(base.id, autoderefs);
+                            self.write_autoderef_adjustment(base.id, autoderefs, base_t);
                             return field_ty;
                         }
                         private_candidate = Some((base_def.did, field_ty));
@@ -3048,7 +3036,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(field_ty) = field {
                 autoderef.finalize(lvalue_pref, Some(base));
-                self.write_autoderef_adjustment(base.id, autoderefs);
+                self.write_autoderef_adjustment(base.id, autoderefs, base_t);
                 return field_ty;
             }
         }
@@ -3358,8 +3346,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if ty.is_never() {
             if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) {
                 let adj_ty = self.next_diverging_ty_var();
-                let adj = adjustment::AdjustNeverToAny(adj_ty);
-                self.write_adjustment(expr.id, adj);
+                self.write_adjustment(expr.id, adjustment::Adjustment {
+                    kind: adjustment::Adjust::NeverToAny,
+                    target: adj_ty
+                });
                 return adj_ty;
             }
         }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 9bfe80dba9d..6f6538254c4 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -259,23 +259,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         self.resolve_type(t)
     }
 
-    fn resolve_method_type(&self, method_call: MethodCall) -> Option<Ty<'tcx>> {
-        let method_ty = self.tables.borrow().method_map
-                            .get(&method_call).map(|method| method.ty);
-        method_ty.map(|method_ty| self.resolve_type(method_ty))
-    }
-
     /// Try to resolve the type for the given node.
     pub fn resolve_expr_type_adjusted(&mut self, expr: &hir::Expr) -> Ty<'tcx> {
-        let ty_unadjusted = self.resolve_node_type(expr.id);
-        if ty_unadjusted.references_error() {
-            ty_unadjusted
-        } else {
-            ty_unadjusted.adjust(
-                self.tcx, expr.span, expr.id,
-                self.tables.borrow().adjustments.get(&expr.id),
-                |method_call| self.resolve_method_type(method_call))
-        }
+        let ty = self.tables.borrow().expr_ty_adjusted(expr);
+        self.resolve_type(ty)
     }
 
     fn visit_fn_body(&mut self,
@@ -553,10 +540,8 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
         let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
         if let Some(adjustment) = adjustment {
             debug!("adjustment={:?}", adjustment);
-            match adjustment {
-                adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
-                    autoderefs, ref autoref, ..
-                }) => {
+            match adjustment.kind {
+                adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => {
                     let expr_ty = self.resolve_node_type(expr.id);
                     self.constrain_autoderefs(expr, autoderefs, expr_ty);
                     if let Some(ref autoref) = *autoref {
@@ -946,7 +931,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     let origin = infer::ParameterOrigin::OverloadedDeref;
                     self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
 
-                    // Treat overloaded autoderefs as if an AutoRef adjustment
+                    // Treat overloaded autoderefs as if an AutoBorrow adjustment
                     // was applied on the base type, as that is always the case.
                     let fn_sig = method.ty.fn_sig();
                     let fn_sig = // late-bound regions should have been instantiated
@@ -1060,15 +1045,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         id: ast::NodeId,
         minimum_lifetime: &'tcx ty::Region)
     {
-        let tcx = self.tcx;
-
         // Try to resolve the type.  If we encounter an error, then typeck
         // is going to fail anyway, so just stop here and let typeck
         // report errors later on in the writeback phase.
         let ty0 = self.resolve_node_type(id);
-        let ty = ty0.adjust(tcx, origin.span(), id,
-                            self.tables.borrow().adjustments.get(&id),
-                            |method_call| self.resolve_method_type(method_call));
+        let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target);
+        let ty = self.resolve_type(ty);
         debug!("constrain_regions_in_type_of_node(\
                 ty={}, ty0={}, id={}, minimum_lifetime={:?})",
                 ty,  ty0,
@@ -1165,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn link_autoref(&self,
                     expr: &hir::Expr,
                     autoderefs: usize,
-                    autoref: &adjustment::AutoRef<'tcx>)
+                    autoref: &adjustment::AutoBorrow<'tcx>)
     {
         debug!("link_autoref(autoref={:?})", autoref);
         let mc = mc::MemCategorizationContext::new(self);
@@ -1173,12 +1155,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         debug!("expr_cmt={:?}", expr_cmt);
 
         match *autoref {
-            adjustment::AutoPtr(r, m) => {
+            adjustment::AutoBorrow::Ref(r, m) => {
                 self.link_region(expr.span, r,
                                  ty::BorrowKind::from_mutbl(m), expr_cmt);
             }
 
-            adjustment::AutoUnsafe(m) => {
+            adjustment::AutoBorrow::RawPtr(m) => {
                 let r = self.tcx.node_scope_region(expr.id);
                 self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
             }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index e3634cfe5f5..be1f2e35679 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -416,7 +416,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                     }
                 }
                 None => {
-                    let self_ty = fcx.tcx.node_id_to_type(item.id);
+                    let self_ty = fcx.tcx.tables().node_id_to_type(item.id);
                     let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty);
                     fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone());
                 }
@@ -519,7 +519,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                                      item: &hir::Item,
                                      ast_generics: &hir::Generics)
     {
-        let ty = self.tcx().node_id_to_type(item.id);
+        let ty = self.tcx().tables().node_id_to_type(item.id);
         if self.tcx().has_error_field(ty) {
             return;
         }
@@ -649,7 +649,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let fields =
             struct_def.fields().iter()
             .map(|field| {
-                let field_ty = self.tcx.node_id_to_type(field.id);
+                let field_ty = self.tcx.tables().node_id_to_type(field.id);
                 let field_ty = self.instantiate_type_scheme(field.span,
                                                             &self.parameter_environment
                                                                  .free_substs,
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 8685f703a59..5ef3e869960 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -229,7 +229,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         debug!("Type for pattern binding {} (id {}) resolved to {:?}",
                pat_to_string(p),
                p.id,
-               self.tcx().node_id_to_type(p.id));
+               self.tcx().tables().node_id_to_type(p.id));
 
         intravisit::walk_pat(self, p);
     }
@@ -381,36 +381,40 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             }
 
             Some(adjustment) => {
-                let resolved_adjustment = match adjustment {
-                    adjustment::AdjustNeverToAny(ty) => {
-                        adjustment::AdjustNeverToAny(self.resolve(&ty, reason))
+                let resolved_adjustment = match adjustment.kind {
+                    adjustment::Adjust::NeverToAny => {
+                        adjustment::Adjust::NeverToAny
                     }
 
-                    adjustment::AdjustReifyFnPointer => {
-                        adjustment::AdjustReifyFnPointer
+                    adjustment::Adjust::ReifyFnPointer => {
+                        adjustment::Adjust::ReifyFnPointer
                     }
 
-                    adjustment::AdjustMutToConstPointer => {
-                        adjustment::AdjustMutToConstPointer
+                    adjustment::Adjust::MutToConstPointer => {
+                        adjustment::Adjust::MutToConstPointer
                     }
 
-                    adjustment::AdjustUnsafeFnPointer => {
-                        adjustment::AdjustUnsafeFnPointer
+                    adjustment::Adjust::UnsafeFnPointer => {
+                        adjustment::Adjust::UnsafeFnPointer
                     }
 
-                    adjustment::AdjustDerefRef(adj) => {
-                        for autoderef in 0..adj.autoderefs {
+                    adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => {
+                        for autoderef in 0..autoderefs {
                             let method_call = MethodCall::autoderef(id, autoderef as u32);
                             self.visit_method_map_entry(reason, method_call);
                         }
 
-                        adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
-                            autoderefs: adj.autoderefs,
-                            autoref: self.resolve(&adj.autoref, reason),
-                            unsize: self.resolve(&adj.unsize, reason),
-                        })
+                        adjustment::Adjust::DerefRef {
+                            autoderefs: autoderefs,
+                            autoref: self.resolve(&autoref, reason),
+                            unsize: unsize,
+                        }
                     }
                 };
+                let resolved_adjustment = adjustment::Adjustment {
+                    kind: resolved_adjustment,
+                    target: self.resolve(&adjustment.target, reason)
+                };
                 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
                 self.tcx().tables.borrow_mut().adjustments.insert(
                     id, resolved_adjustment);
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index d636baca248..671274a4057 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -211,7 +211,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                     main_id: ast::NodeId,
                     main_span: Span) {
     let tcx = ccx.tcx;
-    let main_t = tcx.node_id_to_type(main_id);
+    let main_t = tcx.tables().node_id_to_type(main_id);
     match main_t.sty {
         ty::TyFnDef(..) => {
             match tcx.map.find(main_id) {
@@ -263,7 +263,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                      start_id: ast::NodeId,
                      start_span: Span) {
     let tcx = ccx.tcx;
-    let start_t = tcx.node_id_to_type(start_id);
+    let start_t = tcx.tables().node_id_to_type(start_id);
     match start_t.sty {
         ty::TyFnDef(..) => {
             match tcx.map.find(start_id) {