about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2017-08-10 16:10:04 +0200
committerMichael Woerister <michaelwoerister@posteo>2017-08-11 12:17:07 +0200
commit1f54df1101cabc4663906a5b8b6ca99bab6267a3 (patch)
treeaab690ab10fb69acdb3d68dd3169dbbdc6f24dfe
parentbdfd78db8ad4f5520414f346fdfbfb5449d5be48 (diff)
Encapsulate sub-table access in TypeckTables and validate keys on each access.
-rw-r--r--src/librustc/ich/impls_ty.rs68
-rw-r--r--src/librustc/infer/mod.rs11
-rw-r--r--src/librustc/middle/dead.rs6
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs8
-rw-r--r--src/librustc/middle/mem_categorization.rs14
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/traits/error_reporting.rs3
-rw-r--r--src/librustc/ty/context.rs355
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs8
-rw-r--r--src/librustc_const_eval/check_match.rs15
-rw-r--r--src/librustc_const_eval/pattern.rs4
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_lint/unused.rs3
-rw-r--r--src/librustc_mir/build/mod.rs3
-rw-r--r--src/librustc_mir/hair/cx/expr.rs11
-rw-r--r--src/librustc_passes/consts.rs6
-rw-r--r--src/librustc_privacy/lib.rs8
-rw-r--r--src/librustc_save_analysis/lib.rs4
-rw-r--r--src/librustc_typeck/check/_match.rs10
-rw-r--r--src/librustc_typeck/check/cast.rs9
-rw-r--r--src/librustc_typeck/check/closure.rs5
-rw-r--r--src/librustc_typeck/check/coercion.rs2
-rw-r--r--src/librustc_typeck/check/method/confirm.rs10
-rw-r--r--src/librustc_typeck/check/method/probe.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs54
-rw-r--r--src/librustc_typeck/check/op.rs10
-rw-r--r--src/librustc_typeck/check/regionck.rs23
-rw-r--r--src/librustc_typeck/check/upvar.rs12
-rw-r--r--src/librustc_typeck/check/writeback.rs103
-rw-r--r--src/librustc_typeck/collect.rs4
31 files changed, 463 insertions, 316 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 279e62c6311..45b2a4a1e96 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -11,8 +11,7 @@
 //! This module contains `HashStable` implementations for various data types
 //! from rustc::ty in no particular order.
 
-use hir::def_id::DefId;
-use ich::{self, StableHashingContext, NodeIdHashingMode};
+use ich::StableHashingContext;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
 use std::hash as std_hash;
@@ -612,71 +611,6 @@ impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> {
     ty
 });
 
-
-impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
-for ty::TypeckTables<'gcx> {
-    fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
-                                          hasher: &mut StableHasher<W>) {
-        let ty::TypeckTables {
-            local_id_root,
-            ref type_dependent_defs,
-            ref node_types,
-            ref node_substs,
-            ref adjustments,
-            ref pat_binding_modes,
-            ref upvar_capture_map,
-            ref closure_tys,
-            ref closure_kinds,
-            ref liberated_fn_sigs,
-            ref fru_field_types,
-
-            ref cast_kinds,
-
-            ref used_trait_imports,
-            tainted_by_errors,
-            ref free_region_map,
-        } = *self;
-
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            ich::hash_stable_itemlocalmap(hcx, hasher, type_dependent_defs);
-            ich::hash_stable_itemlocalmap(hcx, hasher, node_types);
-            ich::hash_stable_itemlocalmap(hcx, hasher, node_substs);
-            ich::hash_stable_itemlocalmap(hcx, hasher, adjustments);
-            ich::hash_stable_itemlocalmap(hcx, hasher, pat_binding_modes);
-            ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
-                let ty::UpvarId {
-                    var_id,
-                    closure_expr_id
-                } = *up_var_id;
-
-                let var_def_id = DefId {
-                    krate: local_id_root.krate,
-                    index: var_id,
-                };
-                let closure_def_id = DefId {
-                    krate: local_id_root.krate,
-                    index: closure_expr_id,
-                };
-                (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id))
-            });
-
-            ich::hash_stable_itemlocalmap(hcx, hasher, closure_tys);
-            ich::hash_stable_itemlocalmap(hcx, hasher, closure_kinds);
-            ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs);
-            ich::hash_stable_itemlocalmap(hcx, hasher, fru_field_types);
-            ich::hash_stable_itemlocalmap(hcx, hasher, cast_kinds);
-
-            ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| {
-                hcx.def_path_hash(*def_id)
-            });
-
-            tainted_by_errors.hash_stable(hcx, hasher);
-            free_region_map.hash_stable(hcx, hasher);
-        })
-    }
-}
-
 impl_stable_hash_for!(enum ty::fast_reject::SimplifiedType {
     BoolSimplifiedType,
     CharSimplifiedType,
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 727b0af2f54..1a8d570bde0 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1331,11 +1331,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         if let Some(tables) = self.in_progress_tables {
             if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
-                let tables = tables.borrow();
                 let hir_id = self.tcx.hir.node_to_hir_id(id);
-                tables.validate_hir_id(hir_id);
-                return tables.closure_kinds
-                             .get(&hir_id.local_id)
+                return tables.borrow()
+                             .closure_kinds()
+                             .get(hir_id)
                              .cloned()
                              .map(|(kind, _)| kind);
             }
@@ -1355,10 +1354,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
         if let Some(tables) = self.in_progress_tables {
             if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
-                let tables = tables.borrow();
                 let hir_id = self.tcx.hir.node_to_hir_id(id);
-                tables.validate_hir_id(hir_id);
-                if let Some(&ty) = tables.closure_tys.get(&hir_id.local_id) {
+                if let Some(&ty) = tables.borrow().closure_tys().get(hir_id) {
                     return ty;
                 }
             }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 0cca5690c01..0081555095b 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -94,8 +94,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn lookup_and_handle_method(&mut self, id: hir::ItemLocalId) {
-        self.check_def_id(self.tables.type_dependent_defs[&id].def_id());
+    fn lookup_and_handle_method(&mut self, id: hir::HirId) {
+        self.check_def_id(self.tables.type_dependent_defs()[id].def_id());
     }
 
     fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
@@ -241,7 +241,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
                 self.handle_definition(def);
             }
             hir::ExprMethodCall(..) => {
-                self.lookup_and_handle_method(expr.hir_id.local_id);
+                self.lookup_and_handle_method(expr.hir_id);
             }
             hir::ExprField(ref lhs, ref name) => {
                 self.handle_field_access(&lhs, name.node);
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index e8ecf9c21cd..6b7280cf0ac 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -166,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprMethodCall(..) => {
-                let def_id = self.tables.type_dependent_defs[&expr.hir_id.local_id].def_id();
+                let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id();
                 let sig = self.tcx.fn_sig(def_id);
                 debug!("effect: method call case, signature is {:?}",
                         sig);
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 73800fe7f08..324f9a6e906 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -537,7 +537,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             }
             ty::TyError => { }
             _ => {
-                let def_id = self.mc.tables.type_dependent_defs[&call.hir_id.local_id].def_id();
+                let def_id = self.mc.tables.type_dependent_defs()[call.hir_id].def_id();
                 match OverloadedCallType::from_method_id(self.tcx(), def_id) {
                     FnMutOverloadedCall => {
                         let call_scope_r = self.tcx().node_scope_region(call.id);
@@ -797,8 +797,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                pat);
         return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
             if let PatKind::Binding(..) = pat.node {
-                self.mc.tables.validate_hir_id(pat.hir_id);
-                let bm = *self.mc.tables.pat_binding_modes.get(&pat.hir_id.local_id)
+                let bm = *self.mc.tables.pat_binding_modes().get(pat.hir_id)
                                                           .expect("missing binding mode");
                 match bm {
                     ty::BindByReference(..) =>
@@ -824,8 +823,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
             if let PatKind::Binding(_, def_id, ..) = pat.node {
                 debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
-                mc.tables.validate_hir_id(pat.hir_id);
-                let bm = *mc.tables.pat_binding_modes.get(&pat.hir_id.local_id)
+                let bm = *mc.tables.pat_binding_modes().get(pat.hir_id)
                                                      .expect("missing binding mode");
 
                 // pat_ty: the type of the binding being produced.
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 08231a9ba1b..1f3f9fce854 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -334,10 +334,8 @@ impl MutabilityCategory {
         let ret = match tcx.hir.get(id) {
             hir_map::NodeLocal(p) => match p.node {
                 PatKind::Binding(..) => {
-
-                    tables.validate_hir_id(p.hir_id);
-                    let bm = *tables.pat_binding_modes
-                                    .get(&p.hir_id.local_id)
+                    let bm = *tables.pat_binding_modes()
+                                    .get(p.hir_id)
                                     .expect("missing binding mode");
                     if bm == ty::BindByValue(hir::MutMutable) {
                         McDeclared
@@ -485,10 +483,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // fundamental fix to this conflated use of the node id.
         let ret_ty = match pat.node {
             PatKind::Binding(..) => {
-                self.tables.validate_hir_id(pat.hir_id);
                 let bm = *self.tables
-                              .pat_binding_modes
-                              .get(&pat.hir_id.local_id)
+                              .pat_binding_modes()
+                              .get(pat.hir_id)
                               .expect("missing binding mode");
 
                 if let ty::BindByReference(_) = bm {
@@ -698,7 +695,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                  -> McResult<cmt<'tcx>>
     {
         let fn_hir_id = self.tcx.hir.node_to_hir_id(fn_node_id);
-        self.tables.validate_hir_id(fn_hir_id);
 
         // An upvar can have up to 3 components. We translate first to a
         // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the
@@ -723,7 +719,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // FnMut          | copied -> &'env mut  | upvar -> &'env mut -> &'up bk
         // FnOnce         | copied               | upvar -> &'up bk
 
-        let kind = match self.tables.closure_kinds.get(&fn_hir_id.local_id) {
+        let kind = match self.tables.closure_kinds().get(fn_hir_id) {
             Some(&(kind, _)) => kind,
             None => span_bug!(span, "missing closure kind")
         };
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 98f82a51267..bd9a413ca61 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -110,7 +110,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
                 Some(self.tables.qpath_def(qpath, expr.hir_id))
             }
             hir::ExprMethodCall(..) => {
-                Some(self.tables.type_dependent_defs[&expr.hir_id.local_id])
+                Some(self.tables.type_dependent_defs()[expr.hir_id])
             }
             _ => None
         };
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 8c4054254d0..c5b0f11b823 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -684,8 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         if let Some(tables) = self.in_progress_tables {
                             let tables = tables.borrow();
                             let closure_hir_id = self.tcx.hir.node_to_hir_id(node_id);
-                            tables.validate_hir_id(closure_hir_id);
-                            match tables.closure_kinds.get(&closure_hir_id.local_id) {
+                            match tables.closure_kinds().get(closure_hir_id) {
                                 Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => {
                                     err.span_note(span, &format!(
                                         "closure is `FnOnce` because it moves the \
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 77964f6845b..ac851f182a0 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -20,6 +20,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use hir::map as hir_map;
 use hir::map::DefPathHash;
 use lint::{self, Lint};
+use ich::{self, StableHashingContext, NodeIdHashingMode};
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
 use middle::resolve_lifetime;
@@ -45,19 +46,22 @@ use ty::BindingMode;
 use util::nodemap::{NodeMap, NodeSet, DefIdSet, ItemLocalMap};
 use util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
 
 use arena::{TypedArena, DroplessArena};
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
 use std::cmp::Ordering;
+use std::collections::hash_map::{self, Entry};
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::ops::Deref;
 use std::iter;
 use std::rc::Rc;
 use syntax::abi;
-use syntax::ast::{self, Name};
+use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::codemap::MultiSpan;
 use syntax::symbol::{Symbol, keywords};
@@ -207,6 +211,91 @@ pub struct CommonTypes<'tcx> {
     pub re_erased: Region<'tcx>,
 }
 
+pub struct LocalTableInContext<'a, V: 'a> {
+    local_id_root: DefId,
+    data: &'a ItemLocalMap<V>
+}
+
+/// Validate that the given HirId (respectively its `local_id` part) can be
+/// safely used as a key in the tables of a TypeckTable. For that to be
+/// the case, the HirId must have the same `owner` as all the other IDs in
+/// this table (signified by `local_id_root`). Otherwise the HirId
+/// would be in a different frame of reference and using its `local_id`
+/// would result in lookup errors, or worse, in silently wrong data being
+/// stored/returned.
+fn validate_hir_id_for_typeck_tables(table_id_root: DefId, hir_id: hir::HirId) {
+    #[cfg(debug_assertions)]
+    {
+        if table_id_root.is_local() {
+            if hir_id.owner != table_id_root.index {
+                ty::tls::with(|tcx| {
+                    let node_id = tcx.hir
+                                     .definitions()
+                                     .find_node_for_hir_id(hir_id);
+
+                    bug!("node {} with HirId::owner {:?} cannot be placed in \
+                          TypeckTables with local_id_root {:?}",
+                          tcx.hir.node_to_string(node_id),
+                          DefId::local(hir_id.owner),
+                          table_id_root)
+                });
+            }
+        }
+    }
+}
+
+impl<'a, V> LocalTableInContext<'a, V> {
+    pub fn contains_key(&self, id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
+        self.data.contains_key(&id.local_id)
+    }
+
+    pub fn get(&self, id: hir::HirId) -> Option<&V> {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
+        self.data.get(&id.local_id)
+    }
+
+    pub fn iter(&self) -> hash_map::Iter<hir::ItemLocalId, V> {
+        self.data.iter()
+    }
+}
+
+impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
+    type Output = V;
+
+    fn index(&self, key: hir::HirId) -> &V {
+        self.get(key).expect("LocalTableInContext: key not found")
+    }
+}
+
+pub struct LocalTableInContextMut<'a, V: 'a> {
+    local_id_root: DefId,
+    data: &'a mut ItemLocalMap<V>
+}
+
+impl<'a, V> LocalTableInContextMut<'a, V> {
+
+    pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
+        self.data.get_mut(&id.local_id)
+    }
+
+    pub fn entry(&mut self, id: hir::HirId) -> Entry<hir::ItemLocalId, V> {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
+        self.data.entry(id.local_id)
+    }
+
+    pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
+        self.data.insert(id.local_id, val)
+    }
+
+    pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
+        self.data.remove(&id.local_id)
+    }
+}
+
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct TypeckTables<'tcx> {
     /// The HirId::owner all ItemLocalIds in this table are relative to.
@@ -214,50 +303,50 @@ pub struct TypeckTables<'tcx> {
 
     /// Resolved definitions for `<T>::X` associated paths and
     /// method calls, including those of overloaded operators.
-    pub type_dependent_defs: ItemLocalMap<Def>,
+    type_dependent_defs: ItemLocalMap<Def>,
 
     /// Stores the types for various nodes in the AST.  Note that this table
     /// is not guaranteed to be populated until after typeck.  See
     /// typeck::check::fn_ctxt for details.
-    pub node_types: ItemLocalMap<Ty<'tcx>>,
+    node_types: ItemLocalMap<Ty<'tcx>>,
 
     /// Stores the type parameters which were substituted to obtain the type
     /// of this node.  This only applies to nodes that refer to entities
     /// parameterized by type parameters, such as generic fns, types, or
     /// other items.
-    pub node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
+    node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
 
-    pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+    adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
     // Stores the actual binding mode for all instances of hir::BindingAnnotation.
-    pub pat_binding_modes: ItemLocalMap<BindingMode>,
+    pat_binding_modes: ItemLocalMap<BindingMode>,
 
     /// Borrows
     pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
 
     /// Records the type of each closure.
-    pub closure_tys: ItemLocalMap<ty::PolyFnSig<'tcx>>,
+    closure_tys: ItemLocalMap<ty::PolyFnSig<'tcx>>,
 
     /// Records the kind of each closure and the span and name of the variable
     /// that caused the closure to be this kind.
-    pub closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
+    closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
 
     /// For each fn, records the "liberated" types of its arguments
     /// and return type. Liberated means that all bound regions
     /// (including late-bound regions) are replaced with free
     /// equivalents. This table is not used in trans (since regions
     /// are erased there) and hence is not serialized to metadata.
-    pub liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
+    liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
 
     /// For each FRU expression, record the normalized types of the fields
     /// of the struct - this is needed because it is non-trivial to
     /// normalize while preserving regions. This table is used only in
     /// MIR construction and hence is not serialized to metadata.
-    pub fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
+    fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
 
     /// Maps a cast expression to its kind. This is keyed on the
     /// *from* expression of the cast, not the cast itself.
-    pub cast_kinds: ItemLocalMap<ty::cast::CastKind>,
+    cast_kinds: ItemLocalMap<ty::cast::CastKind>,
 
     /// Set of trait imports actually used in the method resolution.
     /// This is used for warning unused imports.
@@ -288,7 +377,6 @@ impl<'tcx> TypeckTables<'tcx> {
             liberated_fn_sigs: ItemLocalMap(),
             fru_field_types: ItemLocalMap(),
             cast_kinds: ItemLocalMap(),
-            lints: lint::LintTable::new(),
             used_trait_imports: DefIdSet(),
             tainted_by_errors: false,
             free_region_map: FreeRegionMap::new(),
@@ -300,12 +388,40 @@ impl<'tcx> TypeckTables<'tcx> {
         match *qpath {
             hir::QPath::Resolved(_, ref path) => path.def,
             hir::QPath::TypeRelative(..) => {
-                self.validate_hir_id(id);
+                validate_hir_id_for_typeck_tables(self.local_id_root, id);
                 self.type_dependent_defs.get(&id.local_id).cloned().unwrap_or(Def::Err)
             }
         }
     }
 
+    pub fn type_dependent_defs(&self) -> LocalTableInContext<Def> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.type_dependent_defs
+        }
+    }
+
+    pub fn type_dependent_defs_mut(&mut self) -> LocalTableInContextMut<Def> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.type_dependent_defs
+        }
+    }
+
+    pub fn node_types(&self) -> LocalTableInContext<Ty<'tcx>> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.node_types
+        }
+    }
+
+    pub fn node_types_mut(&mut self) -> LocalTableInContextMut<Ty<'tcx>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.node_types
+        }
+    }
+
     pub fn node_id_to_type(&self, id: hir::HirId) -> Ty<'tcx> {
         match self.node_id_to_type_opt(id) {
             Some(ty) => ty,
@@ -320,15 +436,27 @@ impl<'tcx> TypeckTables<'tcx> {
     }
 
     pub fn node_id_to_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
-        self.validate_hir_id(id);
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
         self.node_types.get(&id.local_id).cloned()
     }
 
+    pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<&'tcx Substs<'tcx>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.node_substs
+        }
+    }
+
     pub fn node_substs(&self, id: hir::HirId) -> &'tcx Substs<'tcx> {
-        self.validate_hir_id(id);
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
         self.node_substs.get(&id.local_id).cloned().unwrap_or(Substs::empty())
     }
 
+    pub fn node_substs_opt(&self, id: hir::HirId) -> Option<&'tcx Substs<'tcx>> {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id);
+        self.node_substs.get(&id.local_id).cloned()
+    }
+
     // 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> {
@@ -357,9 +485,24 @@ impl<'tcx> TypeckTables<'tcx> {
         self.node_id_to_type_opt(expr.hir_id)
     }
 
+    pub fn adjustments(&self) -> LocalTableInContext<Vec<ty::adjustment::Adjustment<'tcx>>> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.adjustments
+        }
+    }
+
+    pub fn adjustments_mut(&mut self)
+                           -> LocalTableInContextMut<Vec<ty::adjustment::Adjustment<'tcx>>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.adjustments
+        }
+    }
+
     pub fn expr_adjustments(&self, expr: &hir::Expr)
                             -> &[ty::adjustment::Adjustment<'tcx>] {
-        self.validate_hir_id(expr.hir_id);
+        validate_hir_id_for_typeck_tables(self.local_id_root, expr.hir_id);
         self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
     }
 
@@ -385,50 +528,168 @@ impl<'tcx> TypeckTables<'tcx> {
             return false;
         }
 
-        self.validate_hir_id(expr.hir_id);
-        match self.type_dependent_defs.get(&expr.hir_id.local_id) {
+        match self.type_dependent_defs().get(expr.hir_id) {
             Some(&Def::Method(_)) => true,
             _ => false
         }
     }
 
+    pub fn pat_binding_modes(&self) -> LocalTableInContext<BindingMode> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.pat_binding_modes
+        }
+    }
+
+    pub fn pat_binding_modes_mut(&mut self)
+                           -> LocalTableInContextMut<BindingMode> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.pat_binding_modes
+        }
+    }
+
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
         self.upvar_capture_map[&upvar_id]
     }
 
-    /// Validate that the given HirId (respectively its `local_id` part) can be
-    /// safely used as a key in the tables of this TypeckTable. For that to be
-    /// the case, the HirId must have the same `owner` as all the other IDs in
-    /// this table (signified by the `local_id_root` field). Otherwise the HirId
-    /// would be in a different frame of reference and using its `local_id`
-    /// would result in lookup errors, or worse, in silently wrong data being
-    /// stored/returned.
-    ///
-    /// Therefore it is advised to call this method anytime before using a given
-    /// HirId::local_id as a key.
-    #[inline]
-    pub fn validate_hir_id(&self, hir_id: hir::HirId) {
-        #[cfg(debug_assertions)]
-        {
-            if self.local_id_root.is_local() {
-                if hir_id.owner != self.local_id_root.index {
-                    ty::tls::with(|tcx| {
-                        let node_id = tcx.hir
-                                         .definitions()
-                                         .find_node_for_hir_id(hir_id);
-
-                        bug!("node {} with HirId::owner {:?} cannot be placed in \
-                              TypeckTables with local_id_root {:?}",
-                              tcx.hir.node_to_string(node_id),
-                              DefId::local(hir_id.owner),
-                              self.local_id_root)
-                    });
-                }
-            }
+    pub fn closure_tys(&self) -> LocalTableInContext<ty::PolyFnSig<'tcx>> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.closure_tys
+        }
+    }
+
+    pub fn closure_tys_mut(&mut self)
+                           -> LocalTableInContextMut<ty::PolyFnSig<'tcx>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.closure_tys
+        }
+    }
+
+    pub fn closure_kinds(&self) -> LocalTableInContext<(ty::ClosureKind,
+                                                        Option<(Span, ast::Name)>)> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.closure_kinds
+        }
+    }
+
+    pub fn closure_kinds_mut(&mut self)
+            -> LocalTableInContextMut<(ty::ClosureKind, Option<(Span, ast::Name)>)> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.closure_kinds
+        }
+    }
+
+    pub fn liberated_fn_sigs(&self) -> LocalTableInContext<ty::FnSig<'tcx>> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.liberated_fn_sigs
+        }
+    }
+
+    pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<ty::FnSig<'tcx>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.liberated_fn_sigs
+        }
+    }
+
+    pub fn fru_field_types(&self) -> LocalTableInContext<Vec<Ty<'tcx>>> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.fru_field_types
+        }
+    }
+
+    pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<Vec<Ty<'tcx>>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.fru_field_types
+        }
+    }
+
+    pub fn cast_kinds(&self) -> LocalTableInContext<ty::cast::CastKind> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.cast_kinds
+        }
+    }
+
+    pub fn cast_kinds_mut(&mut self) -> LocalTableInContextMut<ty::cast::CastKind> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.cast_kinds
         }
     }
 }
 
+impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for TypeckTables<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::TypeckTables {
+            local_id_root,
+            ref type_dependent_defs,
+            ref node_types,
+            ref node_substs,
+            ref adjustments,
+            ref pat_binding_modes,
+            ref upvar_capture_map,
+            ref closure_tys,
+            ref closure_kinds,
+            ref liberated_fn_sigs,
+            ref fru_field_types,
+
+            ref cast_kinds,
+
+            ref used_trait_imports,
+            tainted_by_errors,
+            ref free_region_map,
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            ich::hash_stable_itemlocalmap(hcx, hasher, type_dependent_defs);
+            ich::hash_stable_itemlocalmap(hcx, hasher, node_types);
+            ich::hash_stable_itemlocalmap(hcx, hasher, node_substs);
+            ich::hash_stable_itemlocalmap(hcx, hasher, adjustments);
+            ich::hash_stable_itemlocalmap(hcx, hasher, pat_binding_modes);
+            ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
+                let ty::UpvarId {
+                    var_id,
+                    closure_expr_id
+                } = *up_var_id;
+
+                let var_def_id = DefId {
+                    krate: local_id_root.krate,
+                    index: var_id,
+                };
+                let closure_def_id = DefId {
+                    krate: local_id_root.krate,
+                    index: closure_expr_id,
+                };
+                (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id))
+            });
+
+            ich::hash_stable_itemlocalmap(hcx, hasher, closure_tys);
+            ich::hash_stable_itemlocalmap(hcx, hasher, closure_kinds);
+            ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs);
+            ich::hash_stable_itemlocalmap(hcx, hasher, fru_field_types);
+            ich::hash_stable_itemlocalmap(hcx, hasher, cast_kinds);
+
+            ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| {
+                hcx.def_path_hash(*def_id)
+            });
+
+            tainted_by_errors.hash_stable(hcx, hasher);
+            free_region_map.hash_stable(hcx, hasher);
+        })
+    }
+}
+
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
         let mk = |sty| interners.intern_ty(sty, None);
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 07981cc67fc..412af05f5bd 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -600,9 +600,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     ty::TypeVariants::TyClosure(id, _) => {
                         let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
                         let hir_id = self.tcx.hir.node_to_hir_id(node_id);
-                        self.tables.validate_hir_id(hir_id);
                         if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) =
-                            self.tables.closure_kinds.get(&hir_id.local_id)
+                            self.tables.closure_kinds().get(hir_id)
                         {
                             err.span_note(span, &format!(
                                 "closure cannot be invoked more than once because \
@@ -904,10 +903,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
         match pat.node {
             hir::PatKind::Binding(..) => {
-                self.tables.validate_hir_id(pat.hir_id);
                 *self.tables
-                     .pat_binding_modes
-                     .get(&pat.hir_id.local_id)
+                     .pat_binding_modes()
+                     .get(pat.hir_id)
                      .expect("missing binding mode")
             }
             _ => bug!("local is not a binding: {:?}", pat)
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index a990670f08b..ea7deef4724 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -269,10 +269,9 @@ 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(_, _, name, None) = p.node {
-            cx.tables.validate_hir_id(p.hir_id);
             let bm = *cx.tables
-                        .pat_binding_modes
-                        .get(&p.hir_id.local_id)
+                        .pat_binding_modes()
+                        .get(p.hir_id)
                         .expect("missing binding mode");
 
             if bm != ty::BindByValue(hir::MutImmutable) {
@@ -464,10 +463,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
     for pat in pats {
         pat.each_binding(|_, id, span, _path| {
             let hir_id = cx.tcx.hir.node_to_hir_id(id);
-            cx.tables.validate_hir_id(hir_id);
             let bm = *cx.tables
-                        .pat_binding_modes
-                        .get(&hir_id.local_id)
+                        .pat_binding_modes()
+                        .get(hir_id)
                         .expect("missing binding mode");
             if let ty::BindByReference(..) = bm {
                 by_ref_span = Some(span);
@@ -501,10 +499,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
     for pat in pats {
         pat.walk(|p| {
             if let PatKind::Binding(_, _, _, ref sub) = p.node {
-                cx.tables.validate_hir_id(p.hir_id);
                 let bm = *cx.tables
-                            .pat_binding_modes
-                            .get(&p.hir_id.local_id)
+                            .pat_binding_modes()
+                            .get(p.hir_id)
                             .expect("missing binding mode");
                 match bm {
                     ty::BindByValue(..) => {
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 924193786c1..d151e817040 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -381,8 +381,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                     ty::TyRef(r, _) => Some(r),
                     _ => None,
                 };
-                let bm = *self.tables.pat_binding_modes.get(&pat.hir_id.local_id)
-                                                       .expect("missing binding mode");
+                let bm = *self.tables.pat_binding_modes().get(pat.hir_id)
+                                                         .expect("missing binding mode");
                 let (mutability, mode) = match bm {
                     ty::BindByValue(hir::MutMutable) =>
                         (Mutability::Mut, BindingMode::ByValue),
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 56c0fa7b2ad..cef35be59cd 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -935,7 +935,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             // Check for method calls and overloaded operators.
             if cx.tables.is_method_call(expr) {
                 let hir_id = cx.tcx.hir.definitions().node_to_hir_id(id);
-                let def_id = cx.tables.type_dependent_defs[&hir_id.local_id].def_id();
+                let def_id = cx.tables.type_dependent_defs()[hir_id].def_id();
                 let substs = cx.tables.node_substs(hir_id);
                 if method_call_refers_to_method(cx, method, def_id, substs, id) {
                     return true;
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index f8f91e6c29d..65973d99c54 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -46,8 +46,7 @@ impl UnusedMut {
         for p in pats {
             p.each_binding(|_, id, span, path1| {
                 let hir_id = cx.tcx.hir.node_to_hir_id(id);
-                cx.tables.validate_hir_id(hir_id);
-                let bm = match cx.tables.pat_binding_modes.get(&hir_id.local_id) {
+                let bm = match cx.tables.pat_binding_modes().get(hir_id) {
                     Some(&bm) => bm,
                     None => span_bug!(span, "missing binding mode"),
                 };
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index d029e2f10e8..14392ae70e4 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -91,8 +91,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
             // fetch the fully liberated fn signature (that is, all bound
             // types/lifetimes replaced)
             let fn_hir_id = tcx.hir.node_to_hir_id(id);
-            cx.tables().validate_hir_id(fn_hir_id);
-            let fn_sig = cx.tables().liberated_fn_sigs[&fn_hir_id.local_id].clone();
+            let fn_sig = cx.tables().liberated_fn_sigs()[fn_hir_id].clone();
 
             let ty = tcx.type_of(tcx.hir.local_def_id(id));
             let mut abi = fn_sig.abi;
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 11da73187b3..5b3e4b1ddc3 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -387,11 +387,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                 substs: substs,
                                 fields: field_refs,
                                 base: base.as_ref().map(|base| {
-                                    cx.tables().validate_hir_id(expr.hir_id);
                                     FruInfo {
                                         base: base.to_ref(),
                                         field_types: cx.tables()
-                                                       .fru_field_types[&expr.hir_id.local_id]
+                                                       .fru_field_types()[expr.hir_id]
                                                        .clone(),
                                     }
                                 }),
@@ -551,10 +550,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprCast(ref source, _) => {
             // Check to see if this cast is a "coercion cast", where the cast is actually done
             // using a coercion (or is a no-op).
-            cx.tables().validate_hir_id(source.hir_id);
             if let Some(&TyCastKind::CoercionCast) = cx.tables()
-                                                       .cast_kinds
-                                                       .get(&source.hir_id.local_id) {
+                                                       .cast_kinds()
+                                                       .get(source.hir_id) {
                 // Convert the lexpr to a vexpr.
                 ExprKind::Use { source: source.to_ref() }
             } else {
@@ -586,8 +584,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  -> Expr<'tcx> {
     let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
     let (def_id, substs) = custom_callee.unwrap_or_else(|| {
-        cx.tables().validate_hir_id(expr.hir_id);
-        (cx.tables().type_dependent_defs[&expr.hir_id.local_id].def_id(),
+        (cx.tables().type_dependent_defs()[expr.hir_id].def_id(),
          cx.tables().node_substs(expr.hir_id))
     });
     Expr {
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 4a2925175c2..a390448f43a 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -320,8 +320,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         }
         hir::ExprCast(ref from, _) => {
             debug!("Checking const cast(id={})", from.id);
-            v.tables.validate_hir_id(from.hir_id);
-            match v.tables.cast_kinds.get(&from.hir_id.local_id) {
+            match v.tables.cast_kinds().get(from.hir_id) {
                 None => span_bug!(e.span, "no kind for cast"),
                 Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
                     v.promotable = false;
@@ -388,8 +387,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprMethodCall(..) => {
-            v.tables.validate_hir_id(e.hir_id);
-            let def_id = v.tables.type_dependent_defs[&e.hir_id.local_id].def_id();
+            let def_id = v.tables.type_dependent_defs()[e.hir_id].def_id();
             match v.tcx.associated_item(def_id).container {
                 ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty),
                 ty::TraitContainer(_) => v.promotable = false
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 1c5e528d887..6f8c6a5ed3b 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -649,7 +649,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
         if self.tables.node_substs(id).visit_with(self) {
             return true;
         }
-        if let Some(adjustments) = self.tables.adjustments.get(&id.local_id) {
+        if let Some(adjustments) = self.tables.adjustments().get(id) {
             for adjustment in adjustments {
                 if adjustment.target.visit_with(self) {
                     return true;
@@ -748,8 +748,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
             }
             hir::ExprMethodCall(_, span, _) => {
                 // Method calls have to be checked specially.
-                self.tables.validate_hir_id(expr.hir_id);
-                let def_id = self.tables.type_dependent_defs[&expr.hir_id.local_id].def_id();
+                let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id();
                 self.span = span;
                 if self.tcx.type_of(def_id).visit_with(self) {
                     return;
@@ -766,8 +765,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
         // we have to check it additionally.
         if let hir::QPath::TypeRelative(..) = *qpath {
             let hir_id = self.tcx.hir.node_to_hir_id(id);
-            self.tables.validate_hir_id(hir_id);
-            if let Some(def) = self.tables.type_dependent_defs.get(&hir_id.local_id).cloned() {
+            if let Some(def) = self.tables.type_dependent_defs().get(hir_id).cloned() {
                 if let Some(assoc_item) = self.tcx.opt_associated_item(def.def_id()) {
                     if let ty::ImplContainer(impl_def_id) = assoc_item.container {
                         if self.tcx.type_of(impl_def_id).visit_with(self) {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index d46d8624a12..8baea0fd83d 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -550,8 +550,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 }
             }
             ast::ExprKind::MethodCall(..) => {
-                let local_id = self.tcx.hir.definitions().node_to_hir_id(expr.id).local_id;
-                let method_id = self.tables.type_dependent_defs[&local_id].def_id();
+                let expr_hir_id = self.tcx.hir.definitions().node_to_hir_id(expr.id);
+                let method_id = self.tables.type_dependent_defs()[expr_hir_id].def_id();
                 let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
                     ty::ImplContainer(_) => (Some(method_id), None),
                     ty::TraitContainer(_) => (None, Some(method_id)),
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 3a616dadc42..b49b9377e8c 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -118,11 +118,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // identical to what could be scraped from the HIR, but this will change with
                 // default binding modes (#42640).
                 let bm = ty::BindingMode::convert(ba);
-                {
-                    let mut inh_tables = self.inh.tables.borrow_mut();
-                    inh_tables.validate_hir_id(pat.hir_id);
-                    inh_tables.pat_binding_modes.insert(pat.hir_id.local_id, bm);
-                }
+                self.inh
+                    .tables
+                    .borrow_mut()
+                    .pat_binding_modes_mut()
+                    .insert(pat.hir_id, bm);
                 let typ = self.local_ty(pat.span, pat.id);
                 match bm {
                     ty::BindByReference(mutbl) => {
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 2be427eee1b..b18b11f3d90 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -330,16 +330,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
         } else if self.try_coercion_cast(fcx) {
             self.trivial_cast_lint(fcx);
             debug!(" -> CoercionCast");
-            let mut tables = fcx.tables.borrow_mut();
-            tables.validate_hir_id(self.expr.hir_id);
-            tables.cast_kinds.insert(self.expr.hir_id.local_id, CastKind::CoercionCast);
+            fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id,
+                                                            CastKind::CoercionCast);
         } else {
             match self.do_check(fcx) {
                 Ok(k) => {
                     debug!(" -> {:?}", k);
-                    let mut tables = fcx.tables.borrow_mut();
-                    tables.validate_hir_id(self.expr.hir_id);
-                    tables.cast_kinds.insert(self.expr.hir_id.local_id, k);
+                    fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id, k);
                 }
                 Err(e) => self.report_cast_error(fcx, e),
             };
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 8bf58d866ef..61795a7e623 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -104,11 +104,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         {
             let mut tables = self.tables.borrow_mut();
-            tables.validate_hir_id(expr.hir_id);
-            tables.closure_tys.insert(expr.hir_id.local_id, sig);
+            tables.closure_tys_mut().insert(expr.hir_id, sig);
             match opt_kind {
                 Some(kind) => {
-                    tables.closure_kinds.insert(expr.hir_id.local_id, (kind, None));
+                    tables.closure_kinds_mut().insert(expr.hir_id, (kind, None));
                 }
                 None => {}
             }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 428938eae82..53f3d811fae 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -844,7 +844,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // First try to coerce the new expression to the type of the previous ones,
         // but only if the new expression has no coercion already applied to it.
         let mut first_error = None;
-        if !self.tables.borrow().adjustments.contains_key(&new.hir_id.local_id) {
+        if !self.tables.borrow().adjustments().contains_key(new.hir_id) {
             let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
             match result {
                 Ok(ok) => {
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 0294dab17d5..355e6cdbbe0 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -451,8 +451,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             // tables borrowed during (`deref_mut`) method resolution.
             let previous_adjustments = self.tables
                                            .borrow_mut()
-                                           .adjustments
-                                           .remove(&expr.hir_id.local_id);
+                                           .adjustments_mut()
+                                           .remove(expr.hir_id);
             if let Some(mut adjustments) = previous_adjustments {
                 let pref = LvaluePreference::PreferMutLvalue;
                 for adjustment in &mut adjustments {
@@ -469,7 +469,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     }
                     source = adjustment.target;
                 }
-                self.tables.borrow_mut().adjustments.insert(expr.hir_id.local_id, adjustments);
+                self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
             }
 
             match expr.node {
@@ -529,8 +529,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         let base_expr_ty = self.node_ty(base_expr.hir_id);
         if let Some(adjustments) = self.tables
                                        .borrow_mut()
-                                       .adjustments
-                                       .get_mut(&base_expr.hir_id.local_id) {
+                                       .adjustments_mut()
+                                       .get_mut(base_expr.hir_id) {
             let mut source = base_expr_ty;
             for adjustment in &mut adjustments[..] {
                 if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index fc8f4f32440..5de4a35bdc7 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -829,9 +829,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             };
 
             let closure_kind = {
-                let tables = self.tables.borrow();
-                tables.validate_hir_id(closure_id);
-                match tables.closure_kinds.get(&closure_id.local_id) {
+                match self.tables.borrow().closure_kinds().get(closure_id) {
                     Some(&(k, _)) => k,
                     None => {
                         return Err(MethodError::ClosureAmbiguity(trait_def_id));
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 60930d8184a..483b5bb1020 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -744,7 +744,7 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           -> ty::ClosureKind {
     let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
     let hir_id = tcx.hir.node_to_hir_id(node_id);
-    tcx.typeck_tables_of(def_id).closure_kinds[&hir_id.local_id].0
+    tcx.typeck_tables_of(def_id).closure_kinds()[hir_id].0
 }
 
 fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1028,12 +1028,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
         fcx.write_ty(arg.hir_id, arg_ty);
     }
 
-    {
-        let mut inh_tables = inherited.tables.borrow_mut();
-        let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id);
-        inh_tables.validate_hir_id(fn_hir_id);
-        inh_tables.liberated_fn_sigs.insert(fn_hir_id.local_id, fn_sig);
-    }
+    let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id);
+    inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_hir_id, fn_sig);
 
     fcx.check_return_expr(&body.value);
 
@@ -1816,11 +1812,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
         debug!("write_ty({:?}, {:?}) in fcx {}",
                id, self.resolve_type_vars_if_possible(&ty), self.tag());
-        {
-            let mut tables = self.tables.borrow_mut();
-            tables.validate_hir_id(id);
-            tables.node_types.insert(id.local_id, ty);
-        }
+        self.tables.borrow_mut().node_types_mut().insert(id, ty);
 
         if ty.references_error() {
             self.has_errors.set(true);
@@ -1833,11 +1825,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn write_method_call(&self,
                              hir_id: hir::HirId,
                              method: MethodCallee<'tcx>) {
-        {
-            let mut tables = self.tables.borrow_mut();
-            tables.validate_hir_id(hir_id);
-            tables.type_dependent_defs.insert(hir_id.local_id, Def::Method(method.def_id));
-        }
+        self.tables
+            .borrow_mut()
+            .type_dependent_defs_mut()
+            .insert(hir_id, Def::Method(method.def_id));
         self.write_substs(hir_id, method.substs);
     }
 
@@ -1848,9 +1839,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                    substs,
                    self.tag());
 
-            let mut tables = self.tables.borrow_mut();
-            tables.validate_hir_id(node_id);
-            tables.node_substs.insert(node_id.local_id, substs);
+            self.tables.borrow_mut().node_substs_mut().insert(node_id, substs);
         }
     }
 
@@ -1861,9 +1850,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             return;
         }
 
-        let mut tables = self.tables.borrow_mut();
-        tables.validate_hir_id(expr.hir_id);
-        match tables.adjustments.entry(expr.hir_id.local_id) {
+        match self.tables.borrow_mut().adjustments_mut().entry(expr.hir_id) {
             Entry::Vacant(entry) => { entry.insert(adj); },
             Entry::Occupied(mut entry) => {
                 debug!(" - composing on top of {:?}", entry.get());
@@ -2017,9 +2004,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
-        let tables = self.tables.borrow();
-        tables.validate_hir_id(id);
-        match tables.node_types.get(&id.local_id) {
+        match self.tables.borrow().node_types().get(id) {
             Some(&t) => t,
             None if self.err_count_since_creation() != 0 => self.tcx.types.err,
             None => {
@@ -2682,7 +2667,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // While we don't allow *arbitrary* coercions here, we *do* allow
         // coercions from ! to `expected`.
         if ty.is_never() {
-            assert!(!self.tables.borrow().adjustments.contains_key(&expr.hir_id.local_id),
+            assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id),
                     "expression with never type wound up being adjusted");
             let adj_ty = self.next_diverging_ty_var(
                 TypeVariableOrigin::AdjustmentType(expr.span));
@@ -3408,9 +3393,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
                     }).collect();
 
-                    let mut tables = self.tables.borrow_mut();
-                    tables.validate_hir_id(expr.hir_id);
-                    tables.fru_field_types.insert(expr.hir_id.local_id, fru_field_types);
+                    self.tables
+                        .borrow_mut()
+                        .fru_field_types_mut()
+                        .insert(expr.hir_id, fru_field_types);
                 }
                 _ => {
                     span_err!(self.tcx.sess, base_expr.span, E0436,
@@ -4043,9 +4029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 // Write back the new resolution.
                 let hir_id = self.tcx.hir.node_to_hir_id(node_id);
-                let mut tables = self.tables.borrow_mut();
-                tables.validate_hir_id(hir_id);
-                tables.type_dependent_defs.insert(hir_id.local_id, def);
+                self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def);
 
                 (def, ty)
             }
@@ -4087,9 +4071,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Write back the new resolution.
         let hir_id = self.tcx.hir.node_to_hir_id(node_id);
-        let mut tables = self.tables.borrow_mut();
-        tables.validate_hir_id(hir_id);
-        tables.type_dependent_defs.insert(hir_id.local_id, def);
+        self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def);
         (def, Some(ty), slice::ref_slice(&**item_segment))
     }
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index f2104b8dbae..a4e1fdaf39e 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -210,10 +210,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         // some cases applied on the RHS, on top of which we need
                         // to autoref, which is not allowed by apply_adjustments.
                         // self.apply_adjustments(rhs_expr, vec![autoref]);
-                        let mut tables = self.tables.borrow_mut();
-                        tables.validate_hir_id(rhs_expr.hir_id);
-                        tables.adjustments.entry(rhs_expr.hir_id.local_id)
-                            .or_insert(vec![]).push(autoref);
+                        self.tables
+                            .borrow_mut()
+                            .adjustments_mut()
+                            .entry(rhs_expr.hir_id)
+                            .or_insert(vec![])
+                            .push(autoref);
                     }
                 }
                 self.write_method_call(expr.hir_id, method);
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index c9c8f3363ce..b187075a36d 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -309,10 +309,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         let old_call_site_scope = self.set_call_site_scope(Some(call_site));
 
         let fn_sig = {
-            let tables = self.tables.borrow();
             let fn_hir_id = self.tcx.hir.node_to_hir_id(id);
-            tables.validate_hir_id(fn_hir_id);
-            match tables.liberated_fn_sigs.get(&fn_hir_id.local_id) {
+            match self.tables.borrow().liberated_fn_sigs().get(fn_hir_id) {
                 Some(f) => f.clone(),
                 None => {
                     bug!("No fn-sig entry for id={}", id);
@@ -1121,14 +1119,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // report errors later on in the writeback phase.
         let ty0 = self.resolve_node_type(hir_id);
 
-        let ty = {
-            let tables = self.tables.borrow();
-            tables.validate_hir_id(hir_id);
-            tables.adjustments
-                  .get(&hir_id.local_id)
-                  .and_then(|adj| adj.last())
-                  .map_or(ty0, |adj| adj.target)
-        };
+        let ty = self.tables
+                     .borrow()
+                     .adjustments()
+                     .get(hir_id)
+                     .and_then(|adj| adj.last())
+                     .map_or(ty0, |adj| adj.target);
         let ty = self.resolve_type(ty);
         debug!("constrain_regions_in_type_of_node(\
                 ty={}, ty0={}, id={:?}, minimum_lifetime={:?})",
@@ -1207,9 +1203,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                 match sub_pat.node {
                     // `ref x` pattern
                     PatKind::Binding(..) => {
-                        mc.tables.validate_hir_id(sub_pat.hir_id);
-                        let bm = *mc.tables.pat_binding_modes.get(&sub_pat.hir_id.local_id)
-                                                             .expect("missing binding mode");
+                        let bm = *mc.tables.pat_binding_modes().get(sub_pat.hir_id)
+                                                               .expect("missing binding mode");
                         if let ty::BindByReference(mutbl) = bm {
                             self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id,
                                                             mutbl, sub_cmt);
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 111f224c3d1..6db5c5b1cb0 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -103,8 +103,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let infer_kind = match self.tables
                                    .borrow_mut()
-                                   .closure_kinds
-                                   .entry(closure_hir_id.local_id) {
+                                   .closure_kinds_mut()
+                                   .entry(closure_hir_id) {
             Entry::Occupied(_) => false,
             Entry::Vacant(entry) => {
                 debug!("check_closure: adding closure {:?} as Fn", closure_node_id);
@@ -162,8 +162,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                             .remove(&closure_def_id.index) {
                     self.tables
                         .borrow_mut()
-                        .closure_kinds
-                        .insert(closure_hir_id.local_id, kind);
+                        .closure_kinds_mut()
+                        .insert(closure_hir_id, kind);
                 }
             }
             self.tables.borrow_mut().upvar_capture_map.extend(
@@ -482,9 +482,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
         let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned()
             .or_else(|| {
                 let closure_id = self.fcx.tcx.hir.def_index_to_hir_id(closure_id);
-                let fcx_tables = self.fcx.tables.borrow();
-                fcx_tables.validate_hir_id(closure_id);
-                fcx_tables.closure_kinds.get(&closure_id.local_id).cloned()
+                self.fcx.tables.borrow().closure_kinds().get(closure_id).cloned()
             });
 
         if let Some((existing_kind, _)) = closure_kind {
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 515bbe49c39..0e7083b72f5 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -93,8 +93,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) {
         debug!("write_ty_to_tables({:?}, {:?})", hir_id,  ty);
         assert!(!ty.needs_infer());
-        self.tables.validate_hir_id(hir_id);
-        self.tables.node_types.insert(hir_id.local_id, ty);
+        self.tables.node_types_mut().insert(hir_id, ty);
     }
 
     // Hacky hack: During type-checking, we treat *all* operators
@@ -110,9 +109,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
                 if inner_ty.is_scalar() {
                     let mut tables = self.fcx.tables.borrow_mut();
-                    tables.validate_hir_id(e.hir_id);
-                    tables.type_dependent_defs.remove(&e.hir_id.local_id);
-                    tables.node_substs.remove(&e.hir_id.local_id);
+                    tables.type_dependent_defs_mut().remove(e.hir_id);
+                    tables.node_substs_mut().remove(e.hir_id);
                 }
             }
             hir::ExprBinary(ref op, ref lhs, ref rhs) |
@@ -125,19 +123,19 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
                 if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
                     let mut tables = self.fcx.tables.borrow_mut();
-                    tables.validate_hir_id(e.hir_id);
-                    tables.type_dependent_defs.remove(&e.hir_id.local_id);
-                    tables.node_substs.remove(&e.hir_id.local_id);
+                    tables.type_dependent_defs_mut().remove(e.hir_id);
+                    tables.node_substs_mut().remove(e.hir_id);
 
                     match e.node {
                         hir::ExprBinary(..) => {
                             if !op.node.is_by_value() {
-                                tables.adjustments.get_mut(&lhs.hir_id.local_id).map(|a| a.pop());
-                                tables.adjustments.get_mut(&rhs.hir_id.local_id).map(|a| a.pop());
+                                let mut adjustments = tables.adjustments_mut();
+                                adjustments.get_mut(lhs.hir_id).map(|a| a.pop());
+                                adjustments.get_mut(rhs.hir_id).map(|a| a.pop());
                             }
                         },
                         hir::ExprAssignOp(..) => {
-                            tables.adjustments.get_mut(&lhs.hir_id.local_id).map(|a| a.pop());
+                            tables.adjustments_mut().get_mut(lhs.hir_id).map(|a| a.pop());
                         },
                         _ => {},
                     }
@@ -186,14 +184,13 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     fn visit_pat(&mut self, p: &'gcx hir::Pat) {
         match p.node {
             hir::PatKind::Binding(..) => {
-                let bm = {
-                    let fcx_tables = self.fcx.tables.borrow();
-                    fcx_tables.validate_hir_id(p.hir_id);
-                    *fcx_tables.pat_binding_modes.get(&p.hir_id.local_id)
-                                                 .expect("missing binding mode")
-                };
-                self.tables.validate_hir_id(p.hir_id);
-                self.tables.pat_binding_modes.insert(p.hir_id.local_id, bm);
+                let bm = *self.fcx
+                              .tables
+                              .borrow()
+                              .pat_binding_modes()
+                              .get(p.hir_id)
+                              .expect("missing binding mode");
+                self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
             }
             _ => {}
         };
@@ -233,23 +230,36 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         let fcx_tables = self.fcx.tables.borrow();
         debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
 
-        for (&id, closure_ty) in fcx_tables.closure_tys.iter() {
+        for (&id, closure_ty) in fcx_tables.closure_tys().iter() {
             let hir_id = hir::HirId {
                 owner: fcx_tables.local_id_root.index,
                 local_id: id,
             };
             let closure_ty = self.resolve(closure_ty, &hir_id);
-            self.tables.closure_tys.insert(id, closure_ty);
+            self.tables.closure_tys_mut().insert(hir_id, closure_ty);
         }
 
-        for (&id, &closure_kind) in fcx_tables.closure_kinds.iter() {
-            self.tables.closure_kinds.insert(id, closure_kind);
+        for (&id, &closure_kind) in fcx_tables.closure_kinds().iter() {
+            let hir_id = hir::HirId {
+                owner: fcx_tables.local_id_root.index,
+                local_id: id,
+            };
+            self.tables.closure_kinds_mut().insert(hir_id, closure_kind);
         }
     }
 
     fn visit_cast_types(&mut self) {
-        self.tables.cast_kinds.extend(
-            self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value)));
+        let fcx_tables = self.fcx.tables.borrow();
+        let fcx_cast_kinds = fcx_tables.cast_kinds();
+        let mut self_cast_kinds = self.tables.cast_kinds_mut();
+
+        for (&local_id, &cast_kind) in fcx_cast_kinds.iter() {
+            let hir_id = hir::HirId {
+                owner: fcx_tables.local_id_root.index,
+                local_id,
+            };
+            self_cast_kinds.insert(hir_id, cast_kind);
+        }
     }
 
     fn visit_free_region_map(&mut self) {
@@ -293,20 +303,18 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             });
 
             let hir_id = self.tcx().hir.node_to_hir_id(node_id);
-            self.tables.validate_hir_id(hir_id);
-            self.tables.node_types.insert(hir_id.local_id, outside_ty);
+            self.tables.node_types_mut().insert(hir_id, outside_ty);
         }
     }
 
     fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) {
-        {
-            let mut fcx_tables = self.fcx.tables.borrow_mut();
-            fcx_tables.validate_hir_id(hir_id);
-            // Export associated path extensions and method resultions.
-            if let Some(def) = fcx_tables.type_dependent_defs.remove(&hir_id.local_id) {
-                self.tables.validate_hir_id(hir_id);
-                self.tables.type_dependent_defs.insert(hir_id.local_id, def);
-            }
+        // Export associated path extensions and method resultions.
+        if let Some(def) = self.fcx
+                               .tables
+                               .borrow_mut()
+                               .type_dependent_defs_mut()
+                               .remove(hir_id) {
+            self.tables.type_dependent_defs_mut().insert(hir_id, def);
         }
 
         // Resolve any borrowings for the node with id `node_id`
@@ -319,20 +327,20 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         debug!("Node {:?} has type {:?}", hir_id, n_ty);
 
         // Resolve any substitutions
-        if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&hir_id.local_id) {
+        if let Some(substs) = self.fcx.tables.borrow().node_substs_opt(hir_id) {
             let substs = self.resolve(&substs, &span);
             debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs);
             assert!(!substs.needs_infer());
-            self.tables.node_substs.insert(hir_id.local_id, substs);
+            self.tables.node_substs_mut().insert(hir_id, substs);
         }
     }
 
     fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
-        let adjustment = {
-            let mut fcx_tables = self.fcx.tables.borrow_mut();
-            fcx_tables.validate_hir_id(hir_id);
-            fcx_tables.adjustments.remove(&hir_id.local_id)
-        };
+        let adjustment = self.fcx
+                             .tables
+                             .borrow_mut()
+                             .adjustments_mut()
+                             .remove(hir_id);
         match adjustment {
             None => {
                 debug!("No adjustments for node {:?}", hir_id);
@@ -341,8 +349,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             Some(adjustment) => {
                 let resolved_adjustment = self.resolve(&adjustment, &span);
                 debug!("Adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
-                self.tables.validate_hir_id(hir_id);
-                self.tables.adjustments.insert(hir_id.local_id, resolved_adjustment);
+                self.tables.adjustments_mut().insert(hir_id, resolved_adjustment);
             }
         }
     }
@@ -351,13 +358,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         let fcx_tables = self.fcx.tables.borrow();
         debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
 
-        for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs.iter() {
+        for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs().iter() {
             let hir_id = hir::HirId {
                 owner: fcx_tables.local_id_root.index,
                 local_id,
             };
             let fn_sig = self.resolve(fn_sig, &hir_id);
-            self.tables.liberated_fn_sigs.insert(local_id, fn_sig.clone());
+            self.tables.liberated_fn_sigs_mut().insert(hir_id, fn_sig.clone());
         }
     }
 
@@ -365,13 +372,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         let fcx_tables = self.fcx.tables.borrow();
         debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
 
-        for (&local_id, ftys) in fcx_tables.fru_field_types.iter() {
+        for (&local_id, ftys) in fcx_tables.fru_field_types().iter() {
             let hir_id = hir::HirId {
                 owner: fcx_tables.local_id_root.index,
                 local_id,
             };
             let ftys = self.resolve(ftys, &hir_id);
-            self.tables.fru_field_types.insert(local_id, ftys);
+            self.tables.fru_field_types_mut().insert(hir_id, ftys);
         }
     }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 30188a7cbdc..91b41eb33a1 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1240,9 +1240,7 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         NodeExpr(&hir::Expr { node: hir::ExprClosure(..), hir_id, .. }) => {
-            let tables = tcx.typeck_tables_of(def_id);
-            tables.validate_hir_id(hir_id);
-            tables.closure_tys[&hir_id.local_id]
+            tcx.typeck_tables_of(def_id).closure_tys()[hir_id]
         }
 
         x => {