about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-02-14 11:32:00 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-02-25 18:35:25 +0200
commitba11640179bbde334b525146d3a164999412cc73 (patch)
tree7335fd5d4cccc29807bc5dcbf780647d1f92ebbe
parent9c3c306800313a119d236e607209e831187e7501 (diff)
downloadrust-ba11640179bbde334b525146d3a164999412cc73.tar.gz
rust-ba11640179bbde334b525146d3a164999412cc73.zip
rustc_typeck: hook up collect and item/body check to on-demand.
-rw-r--r--src/librustc/middle/dead.rs7
-rw-r--r--src/librustc/mir/tcx.rs4
-rw-r--r--src/librustc/traits/fulfill.rs139
-rw-r--r--src/librustc/traits/mod.rs1
-rw-r--r--src/librustc/traits/select.rs11
-rw-r--r--src/librustc/traits/structural_impls.rs27
-rw-r--r--src/librustc/ty/context.rs22
-rw-r--r--src/librustc/ty/layout.rs9
-rw-r--r--src/librustc/ty/maps.rs84
-rw-r--r--src/librustc/ty/mod.rs104
-rw-r--r--src/librustc/ty/sty.rs2
-rw-r--r--src/librustc/ty/util.rs15
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs4
-rw-r--r--src/librustc_const_eval/eval.rs6
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs6
-rw-r--r--src/librustc_lint/types.rs56
-rw-r--r--src/librustc_metadata/cstore_impl.rs1
-rw-r--r--src/librustc_metadata/decoder.rs15
-rw-r--r--src/librustc_metadata/encoder.rs4
-rw-r--r--src/librustc_mir/build/matches/test.rs4
-rw-r--r--src/librustc_typeck/astconv.rs88
-rw-r--r--src/librustc_typeck/check/method/mod.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs306
-rw-r--r--src/librustc_typeck/check/writeback.rs54
-rw-r--r--src/librustc_typeck/check_unused.rs3
-rw-r--r--src/librustc_typeck/collect.rs791
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/libsyntax/attr.rs23
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs2
-rw-r--r--src/test/compile-fail/cycle-trait-default-type-trait.rs1
-rw-r--r--src/test/compile-fail/impl-trait/auto-trait-leak.rs17
-rw-r--r--src/test/compile-fail/impl-trait/equality.rs17
-rw-r--r--src/test/compile-fail/resolve-self-in-impl.rs2
-rw-r--r--src/test/incremental/hashes/enum_defs.rs5
-rw-r--r--src/test/run-pass/impl-trait/auto-trait-leak.rs13
-rw-r--r--src/test/run-pass/impl-trait/equality.rs13
36 files changed, 773 insertions, 1088 deletions
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 592e4cb9235..cc6d6e88dee 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -159,10 +159,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             hir_map::NodeItem(item) => {
                 match item.node {
                     hir::ItemStruct(..) | hir::ItemUnion(..) => {
-                        self.struct_has_extern_repr = item.attrs.iter().any(|attr| {
-                            attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
-                                .contains(&attr::ReprExtern)
-                        });
+                        let def_id = self.tcx.hir.local_def_id(item.id);
+                        let def = self.tcx.lookup_adt_def(def_id);
+                        self.struct_has_extern_repr = def.repr.c;
 
                         intravisit::walk_item(self, &item);
                     }
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 527f1152770..50a80305bee 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -173,9 +173,7 @@ impl<'tcx> Rvalue<'tcx> {
             Rvalue::Discriminant(ref lval) => {
                 let ty = lval.ty(mir, tcx).to_ty(tcx);
                 if let ty::TyAdt(adt_def, _) = ty.sty {
-                    let repr_hints = tcx.lookup_repr_hints(adt_def.did);
-                    let repr_type = tcx.enum_repr_type(repr_hints.get(0));
-                    Some(repr_type.to_ty(tcx))
+                    Some(adt_def.repr.discr_type().to_ty(tcx))
                 } else {
                     // Undefined behaviour, bug for now; may want to return something for
                     // the `discriminant` intrinsic later.
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index c31ab2372b6..b87d1846437 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -11,11 +11,9 @@
 use dep_graph::DepGraph;
 use infer::{InferCtxt, InferOk};
 use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
-use ty::subst::Subst;
 use rustc_data_structures::obligation_forest::{ObligationForest, Error};
 use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
 use std::marker::PhantomData;
-use std::mem;
 use syntax::ast;
 use util::nodemap::{FxHashSet, NodeMap};
 use hir::def_id::DefId;
@@ -23,9 +21,8 @@ use hir::def_id::DefId;
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
 use super::CodeSelectionError;
-use super::{FulfillmentError, FulfillmentErrorCode, SelectionError};
-use super::{ObligationCause, BuiltinDerivedObligation};
-use super::{PredicateObligation, TraitObligation, Obligation};
+use super::{FulfillmentError, FulfillmentErrorCode};
+use super::{ObligationCause, PredicateObligation, Obligation};
 use super::project;
 use super::select::SelectionContext;
 use super::Unimplemented;
@@ -82,10 +79,6 @@ pub struct FulfillmentContext<'tcx> {
     // obligations (otherwise, it's easy to fail to walk to a
     // particular node-id).
     region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
-
-    // A list of obligations that need to be deferred to
-    // a later time for them to be properly fulfilled.
-    deferred_obligations: Vec<DeferredObligation<'tcx>>,
 }
 
 #[derive(Clone)]
@@ -101,100 +94,12 @@ pub struct PendingPredicateObligation<'tcx> {
     pub stalled_on: Vec<Ty<'tcx>>,
 }
 
-/// An obligation which cannot be fulfilled in the context
-/// it was registered in, such as auto trait obligations on
-/// `impl Trait`, which require the concrete type to be
-/// available, only guaranteed after finishing type-checking.
-#[derive(Clone, Debug)]
-pub struct DeferredObligation<'tcx> {
-    pub predicate: ty::PolyTraitPredicate<'tcx>,
-    pub cause: ObligationCause<'tcx>
-}
-
-impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
-    /// If possible, create a `DeferredObligation` from
-    /// a trait predicate which had failed selection,
-    /// but could succeed later.
-    pub fn from_select_error(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                             obligation: &TraitObligation<'tcx>,
-                             selection_err: &SelectionError<'tcx>)
-                             -> Option<DeferredObligation<'tcx>> {
-        if let Unimplemented = *selection_err {
-            if DeferredObligation::must_defer(tcx, &obligation.predicate) {
-                return Some(DeferredObligation {
-                    predicate: obligation.predicate.clone(),
-                    cause: obligation.cause.clone()
-                });
-            }
-        }
-
-        None
-    }
-
-    /// Returns true if the given trait predicate can be
-    /// fulfilled at a later time.
-    pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                      predicate: &ty::PolyTraitPredicate<'tcx>)
-                      -> bool {
-        // Auto trait obligations on `impl Trait`.
-        if tcx.trait_has_default_impl(predicate.def_id()) {
-            let substs = predicate.skip_binder().trait_ref.substs;
-            if substs.types().count() == 1 && substs.regions().next().is_none() {
-                if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
-                    return true;
-                }
-            }
-        }
-
-        false
-    }
-
-    /// If possible, return the nested obligations required
-    /// to fulfill this obligation.
-    pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                      -> Option<Vec<PredicateObligation<'tcx>>> {
-        if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty {
-            let ty = if def_id.is_local() {
-                tcx.maps.ty.borrow().get(&def_id).cloned()
-            } else {
-                Some(tcx.item_type(def_id))
-            };
-            // We can resolve the `impl Trait` to its concrete type.
-            if let Some(concrete_ty) = ty.subst(tcx, substs) {
-                let predicate = ty::TraitRef {
-                    def_id: self.predicate.def_id(),
-                    substs: tcx.mk_substs_trait(concrete_ty, &[])
-                }.to_predicate();
-
-                let original_obligation = Obligation::new(self.cause.clone(),
-                                                          self.predicate.clone());
-                let cause = original_obligation.derived_cause(BuiltinDerivedObligation);
-                return Some(vec![Obligation::new(cause, predicate)]);
-            }
-        }
-
-        None
-    }
-
-    /// Return the `PredicateObligation` this was created from.
-    pub fn to_obligation(&self) -> PredicateObligation<'tcx> {
-        let predicate = ty::Predicate::Trait(self.predicate.clone());
-        Obligation::new(self.cause.clone(), predicate)
-    }
-
-    /// Return an error as if this obligation had failed.
-    pub fn to_error(&self) -> FulfillmentError<'tcx> {
-        FulfillmentError::new(self.to_obligation(), CodeSelectionError(Unimplemented))
-    }
-}
-
 impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             region_obligations: NodeMap(),
-            deferred_obligations: vec![],
         }
     }
 
@@ -294,16 +199,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     {
         self.select_where_possible(infcx)?;
 
-        // Fail all of the deferred obligations that haven't
-        // been otherwise removed from the context.
-        let deferred_errors = self.deferred_obligations.iter()
-                                  .map(|d| d.to_error());
-
         let errors: Vec<_> =
             self.predicates.to_errors(CodeAmbiguity)
                            .into_iter()
                            .map(|e| to_fulfillment_error(e))
-                           .chain(deferred_errors)
                            .collect();
         if errors.is_empty() {
             Ok(())
@@ -324,10 +223,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
         self.predicates.pending_obligations()
     }
 
-    pub fn take_deferred_obligations(&mut self) -> Vec<DeferredObligation<'tcx>> {
-        mem::replace(&mut self.deferred_obligations, vec![])
-    }
-
     /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
     /// only attempts to select obligations that haven't been seen before.
     fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
@@ -343,7 +238,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
             let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
                 selcx: selcx,
                 region_obligations: &mut self.region_obligations,
-                deferred_obligations: &mut self.deferred_obligations
             });
             debug!("select: outcome={:?}", outcome);
 
@@ -378,7 +272,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
 struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
     region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
-    deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
 }
 
 impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
@@ -391,8 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
     {
         process_predicate(self.selcx,
                           obligation,
-                          self.region_obligations,
-                          self.deferred_obligations)
+                          self.region_obligations)
             .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
                 obligation: o,
                 stalled_on: vec![]
@@ -432,8 +324,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
 fn process_predicate<'a, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
     pending_obligation: &mut PendingPredicateObligation<'tcx>,
-    region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
-    deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
+    region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
     -> Result<Option<Vec<PredicateObligation<'tcx>>>,
               FulfillmentErrorCode<'tcx>>
 {
@@ -502,21 +393,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                     info!("selecting trait `{:?}` at depth {} yielded Err",
                           data, obligation.recursion_depth);
 
-                    let defer = DeferredObligation::from_select_error(selcx.tcx(),
-                                                                      &trait_obligation,
-                                                                      &selection_err);
-                    if let Some(deferred_obligation) = defer {
-                        if let Some(nested) = deferred_obligation.try_select(selcx.tcx()) {
-                            Ok(Some(nested))
-                        } else {
-                            // Pretend that the obligation succeeded,
-                            // but record it for later.
-                            deferred_obligations.push(deferred_obligation);
-                            Ok(Some(vec![]))
-                        }
-                    } else {
-                        Err(CodeSelectionError(selection_err))
-                    }
+                    Err(CodeSelectionError(selection_err))
                 }
             }
         }
@@ -714,12 +591,6 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> {
             // already has the required read edges, so we don't need
             // to add any more edges here.
             if data.is_global() {
-                // Don't cache predicates which were fulfilled
-                // by deferring them for later fulfillment.
-                if DeferredObligation::must_defer(tcx, data) {
-                    return;
-                }
-
                 if let Some(data) = tcx.lift_to_global(data) {
                     if self.set.insert(data.clone()) {
                         debug!("add_if_global: global predicate `{:?}` added", data);
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 58ab713ef27..117e16da26c 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -31,7 +31,6 @@ pub use self::coherence::orphan_check;
 pub use self::coherence::overlapping_impls;
 pub use self::coherence::OrphanCheckErr;
 pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
-pub use self::fulfill::DeferredObligation;
 pub use self::project::MismatchedProjectionTypes;
 pub use self::project::{normalize, normalize_projection_type, Normalized};
 pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index e12ebb6d515..4c4ace0d8ba 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1478,8 +1478,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     // `assemble_candidates_from_object_ty`.
                 }
                 ty::TyParam(..) |
-                ty::TyProjection(..) |
-                ty::TyAnon(..) => {
+                ty::TyProjection(..) => {
                     // In these cases, we don't know what the actual
                     // type is.  Therefore, we cannot break it down
                     // into its constituent types. So we don't
@@ -1902,7 +1901,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             ty::TyDynamic(..) |
             ty::TyParam(..) |
             ty::TyProjection(..) |
-            ty::TyAnon(..) |
             ty::TyInfer(ty::TyVar(_)) |
             ty::TyInfer(ty::FreshTy(_)) |
             ty::TyInfer(ty::FreshIntTy(_)) |
@@ -1947,6 +1945,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     .map(|f| f.ty(self.tcx(), substs))
                     .collect()
             }
+
+            ty::TyAnon(def_id, substs) => {
+                // We can resolve the `impl Trait` to its concrete type,
+                // which enforces a DAG between the functions requiring
+                // the auto trait bounds in question.
+                vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)]
+            }
         }
     }
 
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index dedb126d7ff..717c171db2a 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -269,20 +269,6 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for traits::DeferredObligation<'a> {
-    type Lifted = traits::DeferredObligation<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.predicate).and_then(|predicate| {
-            tcx.lift(&self.cause).map(|cause| {
-                traits::DeferredObligation {
-                    predicate: predicate,
-                    cause: cause
-                }
-            })
-        })
-    }
-}
-
 // For trans only.
 impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
     type Lifted = traits::Vtable<'tcx, ()>;
@@ -589,16 +575,3 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> {
         self.code.visit_with(visitor)
     }
 }
-
-impl<'tcx> TypeFoldable<'tcx> for traits::DeferredObligation<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::DeferredObligation {
-            predicate: self.predicate.fold_with(folder),
-            cause: self.cause.fold_with(folder)
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.predicate.visit_with(visitor) || self.cause.visit_with(visitor)
-    }
-}
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index f1945fd57ef..318c866a59f 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -38,7 +38,6 @@ use ty::TypeVariants::*;
 use ty::layout::{Layout, TargetDataLayout};
 use ty::inhabitedness::DefIdForest;
 use ty::maps;
-use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -50,7 +49,6 @@ use std::cell::{Cell, RefCell};
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::ops::Deref;
-use std::rc::Rc;
 use std::iter;
 use std::cmp::Ordering;
 use syntax::abi;
@@ -242,6 +240,10 @@ pub struct TypeckTables<'tcx> {
 
     /// Lints for the body of this fn generated by typeck.
     pub lints: lint::LintTable,
+
+    /// Set of trait imports actually used in the method resolution.
+    /// This is used for warning unused imports.
+    pub used_trait_imports: DefIdSet,
 }
 
 impl<'tcx> TypeckTables<'tcx> {
@@ -259,6 +261,7 @@ impl<'tcx> TypeckTables<'tcx> {
             fru_field_types: NodeMap(),
             cast_kinds: NodeMap(),
             lints: lint::LintTable::new(),
+            used_trait_imports: DefIdSet(),
         }
     }
 
@@ -531,11 +534,6 @@ pub struct GlobalCtxt<'tcx> {
     /// shouldn't taint the common path (hence the RefCell).
     pub all_traits: RefCell<Option<Vec<DefId>>>,
 
-    /// Obligations which will have to be checked at the end of
-    /// type-checking, after all functions have been inferred.
-    /// The key is the NodeId of the item the obligations were from.
-    pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
-
     /// HIR Ty -> Ty lowering cache.
     pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
 }
@@ -734,7 +732,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             derive_macros: RefCell::new(NodeMap()),
             stability_interner: RefCell::new(FxHashSet()),
             all_traits: RefCell::new(None),
-            deferred_obligations: RefCell::new(NodeMap()),
             ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        }, f)
     }
@@ -1449,15 +1446,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     {
         self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
     }
-
-    /// Obtain the representation annotation for a struct definition.
-    pub fn lookup_repr_hints(self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
-        self.maps.repr_hints.memoize(did, || {
-            Rc::new(self.get_attrs(did).iter().flat_map(|meta| {
-                attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
-            }).collect())
-        })
-    }
 }
 
 pub trait InternAs<T: ?Sized, R> {
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 5829ae195c9..3773796e47d 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1147,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> Layout {
             }
 
             // SIMD vector types.
-            ty::TyAdt(def, ..) if def.is_simd() => {
+            ty::TyAdt(def, ..) if def.repr.simd => {
                 let element = ty.simd_type(tcx);
                 match *element.layout(infcx)? {
                     Scalar { value, .. } => {
@@ -1227,9 +1227,8 @@ impl<'a, 'gcx, 'tcx> Layout {
                     let fields = def.variants[0].fields.iter().map(|field| {
                         field.ty(tcx, substs).layout(infcx)
                     }).collect::<Result<Vec<_>, _>>()?;
-                    let packed = tcx.lookup_packed(def.did);
                     let layout = if def.is_union() {
-                        let mut un = Union::new(dl, packed);
+                        let mut un = Union::new(dl, def.repr.packed);
                         un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
                         UntaggedUnion { variants: un }
                     } else {
@@ -1353,9 +1352,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     return Err(LayoutError::SizeOverflow(ty));
                 }
 
-                let repr_hints = tcx.lookup_repr_hints(def.did);
-                let repr_type = tcx.enum_repr_type(repr_hints.get(0));
-                let typeck_ity = Integer::from_attr(dl, repr_type);
+                let typeck_ity = Integer::from_attr(dl, def.repr.discr_type());
                 if typeck_ity < min_ity {
                     // It is a bug if Layout decided on a greater discriminant size than typeck for
                     // some reason at this point (based on values discriminant can take on). Mostly
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 6958df093d0..ce4d1f5ec97 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -14,28 +14,33 @@ use middle::const_val::ConstVal;
 use mir;
 use ty::{self, Ty, TyCtxt};
 use util::common::MemoizationMap;
-use util::nodemap::DefIdSet;
 
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::cell::RefCell;
 use std::rc::Rc;
-use syntax::attr;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 trait Key {
     fn map_crate(&self) -> CrateNum;
+    fn default_span(&self, tcx: TyCtxt) -> Span;
 }
 
 impl Key for DefId {
     fn map_crate(&self) -> CrateNum {
         self.krate
     }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        tcx.def_span(*self)
+    }
 }
 
 impl Key for (DefId, DefId) {
     fn map_crate(&self) -> CrateNum {
         self.0.krate
     }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.1.default_span(tcx)
+    }
 }
 
 trait Value<'tcx>: Sized {
@@ -83,7 +88,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         err.emit();
     }
 
-    pub fn cycle_check<F, R>(self, span: Span, query: Query, compute: F) -> R
+    fn cycle_check<F, R>(self, span: Span, query: Query, compute: F) -> R
         where F: FnOnce() -> R
     {
         {
@@ -104,23 +109,28 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-impl Query {
-    fn describe(&self, tcx: TyCtxt) -> String {
-        match *self {
-            Query::ty(def_id) => {
-                format!("processing `{}`", tcx.item_path_str(def_id))
-            }
-            Query::super_predicates(def_id) => {
-                format!("computing the supertraits of `{}`",
-                        tcx.item_path_str(def_id))
-            }
-            Query::type_param_predicates((_, def_id)) => {
-                let id = tcx.hir.as_local_node_id(def_id).unwrap();
-                format!("computing the bounds for type parameter `{}`",
-                        tcx.hir.ty_param_name(id))
-            }
-            _ => bug!("unexpected `{:?}`", self)
-        }
+trait QueryDescription: DepTrackingMapConfig {
+    fn describe(tcx: TyCtxt, key: Self::Key) -> String;
+}
+
+impl<M: DepTrackingMapConfig<Key=DefId>> QueryDescription for M {
+    default fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+        format!("processing `{}`", tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::super_predicates<'tcx> {
+    fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+        format!("computing the supertraits of `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
+    fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String {
+        let id = tcx.hir.as_local_node_id(def_id).unwrap();
+        format!("computing the bounds for type parameter `{}`",
+                tcx.hir.ty_param_name(id))
     }
 }
 
@@ -152,6 +162,14 @@ macro_rules! define_maps {
             $($(#[$attr])* $name($K)),*
         }
 
+        impl Query {
+            pub fn describe(&self, tcx: TyCtxt) -> String {
+                match *self {
+                    $(Query::$name(key) => queries::$name::describe(tcx, key)),*
+                }
+            }
+        }
+
         pub mod queries {
             use std::marker::PhantomData;
 
@@ -186,11 +204,22 @@ macro_rules! define_maps {
             }
         }
 
-        impl<$tcx> Maps<$tcx> {
+        impl<'a, $tcx, 'lcx> Maps<$tcx> {
             $($(#[$attr])*
-              pub fn $name<'a, 'lcx>(&self, tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> $V {
+              pub fn $name(&self,
+                           tcx: TyCtxt<'a, $tcx, 'lcx>,
+                           mut span: Span,
+                           key: $K) -> $V {
                 self.$name.memoize(key, || {
-                    (self.providers[key.map_crate()].$name)(tcx.global_tcx(), key)
+                    // FIXME(eddyb) Get more valid Span's on queries.
+                    if span == DUMMY_SP {
+                        span = key.default_span(tcx);
+                    }
+
+                    tcx.cycle_check(span, Query::$name(key), || {
+                        let provider = self.providers[key.map_crate()].$name;
+                        provider(tcx.global_tcx(), key)
+                    })
                 })
             })*
         }
@@ -246,9 +275,6 @@ define_maps! { <'tcx>
     /// Methods in these implementations don't need to be exported.
     pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>,
 
-    /// Caches the representation hints for struct definitions.
-    pub repr_hints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>>,
-
     /// Maps from the def-id of a function/method or const/static
     /// to its MIR. Mutation is done at an item granularity to
     /// allow MIR optimization passes to function and still
@@ -272,10 +298,6 @@ define_maps! { <'tcx>
 
     pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
 
-    /// Set of trait imports actually used in the method resolution.
-    /// This is used for warning unused imports.
-    pub used_trait_imports: UsedTraitImports(DefId) -> DefIdSet,
-
     /// Results of evaluating monomorphic constants embedded in
     /// other items, such as enum variant explicit discriminants.
     pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()>
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 01be4288146..357d12bc4dd 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1296,10 +1296,9 @@ bitflags! {
         const IS_DTORCK           = 1 << 1, // is this a dtorck type?
         const IS_DTORCK_VALID     = 1 << 2,
         const IS_PHANTOM_DATA     = 1 << 3,
-        const IS_SIMD             = 1 << 4,
-        const IS_FUNDAMENTAL      = 1 << 5,
-        const IS_UNION            = 1 << 6,
-        const IS_BOX              = 1 << 7,
+        const IS_FUNDAMENTAL      = 1 << 4,
+        const IS_UNION            = 1 << 5,
+        const IS_BOX              = 1 << 6,
     }
 }
 
@@ -1384,18 +1383,29 @@ pub struct ReprOptions {
 impl ReprOptions {
     pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         let mut ret = ReprOptions::default();
-        let attrs = tcx.lookup_repr_hints(did);
-        for r in attrs.iter() {
-            match *r {
-                attr::ReprExtern => ret.c = true,
-                attr::ReprPacked => ret.packed = true,
-                attr::ReprSimd => ret.simd = true,
-                attr::ReprInt(i) => ret.int = Some(i),
-                attr::ReprAny => (),
+
+        for attr in tcx.get_attrs(did).iter() {
+            for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
+                match r {
+                    attr::ReprExtern => ret.c = true,
+                    attr::ReprPacked => ret.packed = true,
+                    attr::ReprSimd => ret.simd = true,
+                    attr::ReprInt(i) => ret.int = Some(i),
+                }
             }
         }
+
+        // FIXME(eddyb) This is deprecated and should be removed.
+        if tcx.has_attr(did, "simd") {
+            ret.simd = true;
+        }
+
         ret
     }
+
+    pub fn discr_type(&self) -> attr::IntType {
+        self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is))
+    }
 }
 
 impl<'a, 'gcx, 'tcx> AdtDef {
@@ -1409,9 +1419,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         if attr::contains_name(&attrs, "fundamental") {
             flags = flags | AdtFlags::IS_FUNDAMENTAL;
         }
-        if tcx.lookup_simd(did) {
-            flags = flags | AdtFlags::IS_SIMD;
-        }
         if Some(did) == tcx.lang_items.phantom_data() {
             flags = flags | AdtFlags::IS_PHANTOM_DATA;
         }
@@ -1500,11 +1507,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
     }
 
-    #[inline]
-    pub fn is_simd(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_SIMD)
-    }
-
     /// Returns true if this is PhantomData<T>.
     #[inline]
     pub fn is_phantom_data(&self) -> bool {
@@ -1584,8 +1586,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
 
     pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                          -> impl Iterator<Item=ConstInt> + 'a {
-        let repr_hints = tcx.lookup_repr_hints(self.did);
-        let repr_type = tcx.enum_repr_type(repr_hints.get(0));
+        let repr_type = self.repr.discr_type();
         let initial = repr_type.initial_discriminant(tcx.global_tcx());
         let mut prev_discr = None::<ConstInt>;
         self.variants.iter().map(move |v| {
@@ -1946,25 +1947,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> {
-        self.maps.typeck_tables.memoize(def_id, || {
-            if def_id.is_local() {
-                // Closures' tables come from their outermost function,
-                // as they are part of the same "inference environment".
-                let outer_def_id = self.closure_base_def_id(def_id);
-                if outer_def_id != def_id {
-                    return self.item_tables(outer_def_id);
-                }
-
-                bug!("No def'n found for {:?} in tcx.tables", def_id);
-            }
-
-            // Cross-crate side-tables only exist alongside serialized HIR.
-            self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
-                self.maps.typeck_tables.borrow()[&def_id]
-            }).unwrap_or_else(|| {
-                bug!("tcx.item_tables({:?}): missing from metadata", def_id)
-            })
-        })
+        self.maps.typeck_tables(self, DUMMY_SP, def_id)
     }
 
     pub fn expr_span(self, id: NodeId) -> Span {
@@ -2072,12 +2055,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
-        self.maps.custom_coerce_unsized_kind(self, did)
+        self.maps.custom_coerce_unsized_kind(self, DUMMY_SP, did)
     }
 
     pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
         if !def_id.is_local() {
-            return self.maps.associated_item(self, def_id);
+            return self.maps.associated_item(self, DUMMY_SP, def_id);
         }
 
         self.maps.associated_item.memoize(def_id, || {
@@ -2182,7 +2165,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
         if !def_id.is_local() {
-            return self.maps.associated_item_def_ids(self, def_id);
+            return self.maps.associated_item_def_ids(self, DUMMY_SP, def_id);
         }
 
         self.maps.associated_item_def_ids.memoize(def_id, || {
@@ -2217,7 +2200,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns the trait-ref corresponding to a given impl, or None if it is
     /// an inherent impl.
     pub fn impl_trait_ref(self, id: DefId) -> Option<TraitRef<'gcx>> {
-        self.maps.impl_trait_ref(self, id)
+        self.maps.impl_trait_ref(self, DUMMY_SP, id)
     }
 
     // Returns `ty::VariantDef` if `def` refers to a struct,
@@ -2296,37 +2279,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     // If the given item is in an external crate, looks up its type and adds it to
     // the type cache. Returns the type parameters and type.
     pub fn item_type(self, did: DefId) -> Ty<'gcx> {
-        self.maps.ty(self, did)
+        self.maps.ty(self, DUMMY_SP, did)
     }
 
     /// Given the did of a trait, returns its canonical trait ref.
     pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef {
-        self.maps.trait_def(self, did)
+        self.maps.trait_def(self, DUMMY_SP, did)
     }
 
     /// Given the did of an ADT, return a reference to its definition.
     pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef {
-        self.maps.adt_def(self, did)
+        self.maps.adt_def(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its generics.
     pub fn item_generics(self, did: DefId) -> &'gcx Generics {
-        self.maps.generics(self, did)
+        self.maps.generics(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its full set of predicates.
     pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
-        self.maps.predicates(self, did)
+        self.maps.predicates(self, DUMMY_SP, did)
     }
 
     /// Given the did of a trait, returns its superpredicates.
     pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
-        self.maps.super_predicates(self, did)
+        self.maps.super_predicates(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its MIR, borrowed immutably.
     pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
-        self.maps.mir(self, did).borrow()
+        self.maps.mir(self, DUMMY_SP, did).borrow()
     }
 
     /// If `type_needs_drop` returns true, then `ty` is definitely
@@ -2377,19 +2360,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.get_attrs(did).iter().any(|item| item.check_name(attr))
     }
 
-    /// Determine whether an item is annotated with `#[repr(packed)]`
-    pub fn lookup_packed(self, did: DefId) -> bool {
-        self.lookup_repr_hints(did).contains(&attr::ReprPacked)
-    }
-
-    /// Determine whether an item is annotated with `#[simd]`
-    pub fn lookup_simd(self, did: DefId) -> bool {
-        self.has_attr(did, "simd")
-            || self.lookup_repr_hints(did).contains(&attr::ReprSimd)
-    }
-
     pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> {
-        self.maps.variances(self, item_id)
+        self.maps.variances(self, DUMMY_SP, item_id)
     }
 
     pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
@@ -2464,11 +2436,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
-        self.maps.closure_kind(self, def_id)
+        self.maps.closure_kind(self, DUMMY_SP, def_id)
     }
 
     pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
-        self.maps.closure_type(self, def_id)
+        self.maps.closure_type(self, DUMMY_SP, def_id)
     }
 
     /// Given the def_id of an impl, return the def_id of the trait it implements.
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 3d6c1da8830..aa2990679b6 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1077,7 +1077,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     #[inline]
     pub fn is_simd(&self) -> bool {
         match self.sty {
-            TyAdt(def, _) => def.is_simd(),
+            TyAdt(def, _) => def.repr.simd,
             _ => false
         }
     }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index bda76550f34..d1c22651a9e 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -232,21 +232,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Returns the IntType representation.
-    /// This used to ensure `int_ty` doesn't contain `usize` and `isize`
-    /// by converting them to their actual types. That doesn't happen anymore.
-    pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
-        match opt_hint {
-            // Feed in the given type
-            Some(&attr::ReprInt(int_t)) => int_t,
-            // ... but provide sensible default if none provided
-            //
-            // NB. Historically `fn enum_variants` generate i64 here, while
-            // rustc_typeck::check would generate isize.
-            _ => SignedInt(ast::IntTy::Is),
-        }
-    }
-
     /// Returns the deeply last field of nested structures, or the same type,
     /// if not a structure at all. Corresponds to the only possible unsized
     /// field, and its type can be used to determine unsizing strategy.
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index c64b25032c9..f8c0044774a 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -677,9 +677,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 // Additionally, we do not want to switch on the
                 // discriminant after it is free-ed, because that
                 // way lies only trouble.
-                let repr_hints = self.tcx.lookup_repr_hints(adt.did);
-                let repr_type = self.tcx.enum_repr_type(repr_hints.get(0));
-                let discr_ty = repr_type.to_ty(self.tcx);
+                let discr_ty = adt.repr.discr_type().to_ty(self.tcx);
                 let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
                 let switch_block = self.patch.new_block(BasicBlockData {
                     statements: vec![
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 967705c7481..eadb49a0731 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -902,8 +902,7 @@ fn infer<'a, 'tcx>(i: ConstInt,
         (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
 
         (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
-            let hints = tcx.lookup_repr_hints(adt.did);
-            let int_ty = tcx.enum_repr_type(hints.iter().next());
+            let int_ty = adt.repr.discr_type();
             infer(i, tcx, &int_ty.to_ty(tcx).sty)
         },
         (_, i) => Err(BadType(ConstVal::Integral(i))),
@@ -1093,8 +1092,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
                 },
                 None => Ok(Integral(Infer(n as u128))),
                 Some(&ty::TyAdt(adt, _)) => {
-                    let hints = tcx.lookup_repr_hints(adt.did);
-                    let int_ty = tcx.enum_repr_type(hints.iter().next());
+                    let int_ty = adt.repr.discr_type();
                     infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
                 },
                 Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index a0bcb54af32..156f8b9e7c4 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -257,6 +257,12 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
 impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.check_item(item.id, item.span);
+
+        if let hir::ItemEnum(ref def, _) = item.node {
+            for v in &def.variants {
+                self.check_item(v.node.data.id(), v.span);
+            }
+        }
     }
 
     fn visit_trait_item(&mut self, item: &hir::TraitItem) {
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index dd7f751338d..3301a98968e 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -381,6 +381,17 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     false
 }
 
+fn is_ffi_safe(ty: attr::IntType) -> bool {
+    match ty {
+        attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) |
+        attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) |
+        attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) |
+        attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) |
+        attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true,
+        attr::SignedInt(ast::IntTy::Is) | attr::UnsignedInt(ast::UintTy::Us) => false
+    }
+}
+
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the given type is "ffi-safe" (has a stable, well-defined
     /// representation which can be exported to C code).
@@ -406,7 +417,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
                 match def.adt_kind() {
                     AdtKind::Struct => {
-                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                        if !def.repr.c {
                             return FfiUnsafe("found struct without foreign-function-safe \
                                               representation annotation in foreign module, \
                                               consider adding a #[repr(C)] attribute to the type");
@@ -440,7 +451,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if all_phantom { FfiPhantom } else { FfiSafe }
                     }
                     AdtKind::Union => {
-                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                        if !def.repr.c {
                             return FfiUnsafe("found union without foreign-function-safe \
                                               representation annotation in foreign module, \
                                               consider adding a #[repr(C)] attribute to the type");
@@ -479,35 +490,28 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
                         // Check for a repr() attribute to specify the size of the
                         // discriminant.
-                        let repr_hints = cx.lookup_repr_hints(def.did);
-                        match &repr_hints[..] {
-                            &[] => {
-                                // Special-case types like `Option<extern fn()>`.
-                                if !is_repr_nullable_ptr(cx, def, substs) {
-                                    return FfiUnsafe("found enum without foreign-function-safe \
-                                                      representation annotation in foreign \
-                                                      module, consider adding a #[repr(...)] \
-                                                      attribute to the type");
-                                }
+                        if !def.repr.c && def.repr.int.is_none() {
+                            // Special-case types like `Option<extern fn()>`.
+                            if !is_repr_nullable_ptr(cx, def, substs) {
+                                return FfiUnsafe("found enum without foreign-function-safe \
+                                                  representation annotation in foreign \
+                                                  module, consider adding a #[repr(...)] \
+                                                  attribute to the type");
                             }
-                            &[ref hint] => {
-                                if !hint.is_ffi_safe() {
-                                    // FIXME: This shouldn't be reachable: we should check
-                                    // this earlier.
-                                    return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
-                                }
-
-                                // Enum with an explicitly sized discriminant; either
-                                // a C-style enum or a discriminated union.
+                        }
 
-                                // The layout of enum variants is implicitly repr(C).
-                                // FIXME: Is that correct?
-                            }
-                            _ => {
+                        if let Some(int_ty) = def.repr.int {
+                            if !is_ffi_safe(int_ty) {
                                 // FIXME: This shouldn't be reachable: we should check
                                 // this earlier.
-                                return FfiUnsafe("enum has too many #[repr(...)] attributes");
+                                return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
                             }
+
+                            // Enum with an explicitly sized discriminant; either
+                            // a C-style enum or a discriminated union.
+
+                            // The layout of enum variants is implicitly repr(C).
+                            // FIXME: Is that correct?
                         }
 
                         // Check the contained variants.
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 770591bc17a..fc7b50f11da 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -101,6 +101,7 @@ provide! { <'tcx> tcx, def_id, cdata
 
         mir
     }
+    typeck_tables => { cdata.item_body_tables(def_id.index, tcx) }
     closure_kind => { cdata.closure_kind(def_id.index) }
     closure_type => { cdata.closure_ty(def_id.index, tcx) }
 }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 0e92c492e4b..e81d752fde0 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -780,16 +780,19 @@ impl<'a, 'tcx> CrateMetadata {
         if self.is_proc_macro(id) { return None; }
         self.entry(id).ast.map(|ast| {
             let def_id = self.local_def_id(id);
-            let ast = ast.decode(self);
-
-            let tables = ast.tables.decode((self, tcx));
-            tcx.maps.typeck_tables.borrow_mut().insert(def_id, tcx.alloc_tables(tables));
-
-            let body = ast.body.decode((self, tcx));
+            let body = ast.decode(self).body.decode(self);
             tcx.hir.intern_inlined_body(def_id, body)
         })
     }
 
+    pub fn item_body_tables(&self,
+                            id: DefIndex,
+                            tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                            -> &'tcx ty::TypeckTables<'tcx> {
+        let ast = self.entry(id).ast.unwrap().decode(self);
+        tcx.alloc_tables(ast.tables.decode((self, tcx)))
+    }
+
     pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
         self.entry(id).ast.into_iter().flat_map(|ast| {
             ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index ed1cff31f2f..f5fd7a152a8 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -36,7 +36,7 @@ use syntax::ast::{self, CRATE_NODE_ID};
 use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
-use syntax_pos;
+use syntax_pos::{self, DUMMY_SP};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -264,7 +264,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             discr: variant.discr,
             evaluated_discr: match variant.discr {
                 ty::VariantDiscr::Explicit(def_id) => {
-                    tcx.maps.monomorphic_const_eval.borrow()[&def_id].clone().ok()
+                    tcx.maps.monomorphic_const_eval(tcx, DUMMY_SP, def_id).ok()
                 }
                 ty::VariantDiscr::Relative(_) => None
             },
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 3256bdf9c25..fa8d7ffccde 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -209,9 +209,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
                        num_enum_variants, values, variants);
-                let repr_hints = tcx.lookup_repr_hints(adt_def.did);
-                let repr_type = tcx.enum_repr_type(repr_hints.get(0));
-                let discr_ty = repr_type.to_ty(tcx);
+                let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
                 let discr = self.temp(discr_ty);
                 self.cfg.push_assign(block, source_info, &discr,
                                      Rvalue::Discriminant(lvalue.clone()));
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 54a2c40322e..2d373ca7473 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -11,17 +11,6 @@
 //! Conversion from AST representation of types to the ty.rs
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
-//!
-//! The parameterization of `ast_ty_to_ty()` is because it behaves
-//! somewhat differently during the collect and check phases,
-//! particularly with respect to looking up the types of top-level
-//! items.  In the collect phase, the crate context is used as the
-//! `AstConv` instance; in this phase, the `get_item_type()`
-//! function triggers a recursive call to `type_of_item()`
-//! (note that `ast_ty_to_ty()` will detect recursive types and report
-//! an error).  In the check phase, when the FnCtxt is used as the
-//! `AstConv`, `get_item_type()` just looks up the item type in
-//! `tcx.types` (using `TyCtxt::item_type`).
 
 use rustc_const_eval::eval_length;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -51,18 +40,10 @@ pub trait AstConv<'gcx, 'tcx> {
     /// A cache used for the result of `ast_ty_to_ty_cache`
     fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>;
 
-    /// Identify the type for an item, like a type alias, fn, or struct.
-    fn get_item_type(&self, span: Span, id: DefId) -> Ty<'tcx>;
-
-    /// Ensure that the super-predicates for the trait with the given
-    /// id are available and also for the transitive set of
-    /// super-predicates.
-    fn ensure_super_predicates(&self, span: Span, id: DefId);
-
     /// Returns the set of bounds in scope for the type parameter with
     /// the given id.
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-                                 -> Vec<ty::Predicate<'tcx>>;
+                                 -> ty::GenericPredicates<'tcx>;
 
     /// Return an (optional) substitution to convert bound type parameters that
     /// are in scope into free ones. This function should only return Some
@@ -262,7 +243,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
         let default_needs_object_self = |p: &ty::TypeParameterDef| {
             if is_object && p.has_default {
-                if self.get_item_type(span, p.def_id).has_self_ty() {
+                if tcx.maps.ty(tcx, span, p.def_id).has_self_ty() {
                     // There is no suitable inference default for a type parameter
                     // that references self, in an object type.
                     return true;
@@ -329,7 +310,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     tcx.types.err
                 } else {
                     // This is a default type parameter.
-                    self.get_item_type(span, def.def_id).subst_spanned(tcx, substs, Some(span))
+                    tcx.maps.ty(tcx, span, def.def_id).subst_spanned(tcx, substs, Some(span))
                 }
             } else {
                 // We've already errored above about the mismatch.
@@ -591,8 +572,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         // Otherwise, we have to walk through the supertraits to find
         // those that do.
-        self.ensure_super_predicates(binding.span, trait_ref.def_id());
-
         let candidates =
             traits::supertraits(tcx, trait_ref.clone())
             .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
@@ -620,7 +599,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         -> Ty<'tcx>
     {
         let substs = self.ast_path_substs_for_ty(span, did, item_segment);
-        self.get_item_type(span, did).subst(self.tcx(), substs)
+        self.tcx().maps.ty(self.tcx(), span, did).subst(self.tcx(), substs)
     }
 
     /// Transform a PolyTraitRef into a PolyExistentialTraitRef by
@@ -677,9 +656,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             })
         });
 
-        // ensure the super predicates
-        self.ensure_super_predicates(span, principal.def_id());
-
         // check that there are no gross object safety violations,
         // most importantly, that the supertraits don't contain Self,
         // to avoid ICE-s.
@@ -776,12 +752,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let tcx = self.tcx();
 
         let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id)
-            .into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect();
-
-        // Ensure the super predicates.
-        for b in &bounds {
-            self.ensure_super_predicates(span, b.def_id());
-        }
+            .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect();
 
         // Check that there is exactly one way to find an associated type with the
         // correct name.
@@ -880,28 +851,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             (_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
                 // `Self` in an impl of a trait - we have a concrete self type and a
                 // trait reference.
-                // FIXME: Self type is not always computed when we are here because type parameter
-                // bounds may affect Self type and have to be converted before it.
-                let trait_ref = if impl_def_id.is_local() {
-                    tcx.maps.impl_trait_ref.borrow().get(&impl_def_id)
-                       .cloned().and_then(|x| x)
-                } else {
-                    tcx.impl_trait_ref(impl_def_id)
-                };
-                let trait_ref = if let Some(trait_ref) = trait_ref {
-                    trait_ref
-                } else {
-                    tcx.sess.span_err(span, "`Self` type is used before it's determined");
-                    return (tcx.types.err, Def::Err);
+                let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
+                    Some(trait_ref) => trait_ref,
+                    None => {
+                        // A cycle error occurred, most likely.
+                        return (tcx.types.err, Def::Err);
+                    }
                 };
+
                 let trait_ref = if let Some(free_substs) = self.get_free_substs() {
                     trait_ref.subst(tcx, free_substs)
                 } else {
                     trait_ref
                 };
 
-                self.ensure_super_predicates(span, trait_ref.def_id);
-
                 let candidates =
                     traits::supertraits(tcx, ty::Binder(trait_ref))
                     .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
@@ -1022,7 +985,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 assert_eq!(opt_self_ty, None);
                 tcx.prohibit_type_params(&path.segments);
 
-                let ty = self.get_item_type(span, def_id);
+                let ty = tcx.maps.ty(tcx, span, def_id);
                 if let Some(free_substs) = self.get_free_substs() {
                     ty.subst(tcx, free_substs)
                 } else {
@@ -1137,9 +1100,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyTraitObject(ref bounds, ref lifetime) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
             }
-            hir::TyImplTrait(ref bounds) => {
-                use collect::{compute_bounds, SizedByDefault};
-
+            hir::TyImplTrait(_) => {
                 // Figure out if we can allow an `impl Trait` here, by walking up
                 // to a `fn` or inherent `impl` method, going only through `Ty`
                 // or `TraitRef` nodes (as nothing else should be in types) and
@@ -1179,22 +1140,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // Create the anonymized type.
                 if allow {
                     let def_id = tcx.hir.local_def_id(ast_ty.id);
-                    tcx.item_generics(def_id);
-                    let substs = Substs::identity_for_item(tcx, def_id);
-                    let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs);
-
-                    // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
-                    let bounds = compute_bounds(self, ty, bounds,
-                                                SizedByDefault::Yes,
-                                                ast_ty.span);
-                    let predicates = bounds.predicates(tcx, ty);
-                    let predicates = tcx.lift_to_global(&predicates).unwrap();
-                    tcx.maps.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
-                        parent: None,
-                        predicates: predicates
-                    });
-
-                    ty
+                    tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
                 } else {
                     span_err!(tcx.sess, ast_ty.span, E0562,
                               "`impl Trait` not allowed outside of function \
@@ -1353,10 +1299,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         debug!("compute_opt_region_bound(existential_predicates={:?})",
                existential_predicates);
 
-        if let Some(principal) = existential_predicates.principal() {
-            self.ensure_super_predicates(span, principal.def_id());
-        }
-
         // No explicit region bound specified. Therefore, examine trait
         // bounds and see if we can derive region bounds from those.
         let derived_region_bounds =
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 62438d87d18..4085a171bbe 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -139,7 +139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.used_trait_imports.borrow_mut().insert(import_def_id);
+            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
         }
 
         self.tcx.check_stability(pick.item.def_id, call_expr.id, span);
@@ -333,7 +333,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.used_trait_imports.borrow_mut().insert(import_def_id);
+            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
         }
 
         let def = pick.item.def();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c6d3af547eb..68d8280d397 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -95,13 +95,14 @@ use rustc::ty::{self, Ty, TyCtxt, Visibility};
 use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
+use rustc::ty::maps::Providers;
 use rustc::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
 use session::{Session, CompileResult};
 use TypeAndSubsts;
 use lint;
 use util::common::{ErrorReported, indenter};
-use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};
+use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
@@ -109,7 +110,6 @@ use std::mem::replace;
 use std::ops::{self, Deref};
 use syntax::abi::Abi;
 use syntax::ast;
-use syntax::attr;
 use syntax::codemap::{self, original_sp, Spanned};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
@@ -174,16 +174,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // associated fresh inference variable. Writeback resolves these
     // variables to get the concrete type, which can be used to
     // deanonymize TyAnon, after typeck is done with all functions.
-    anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
-
-    // Obligations which will have to be checked at the end of
-    // type-checking, after all functions have been inferred.
-    deferred_obligations: RefCell<Vec<traits::DeferredObligation<'tcx>>>,
-
-    // a set of trait import def-ids that we use during method
-    // resolution; during writeback, this is written into
-    // `tcx.used_trait_imports` for this item def-id
-    used_trait_imports: RefCell<FxHashSet<DefId>>,
+    anon_types: RefCell<NodeMap<Ty<'tcx>>>,
 }
 
 impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@@ -507,9 +498,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
             locals: RefCell::new(NodeMap()),
             deferred_call_resolutions: RefCell::new(DefIdMap()),
             deferred_cast_checks: RefCell::new(Vec::new()),
-            anon_types: RefCell::new(DefIdMap()),
-            deferred_obligations: RefCell::new(Vec::new()),
-            used_trait_imports: RefCell::new(DefIdSet()),
+            anon_types: RefCell::new(NodeMap()),
         }
     }
 
@@ -545,7 +534,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         match t.node {
             hir::TyArray(_, length) => {
-                check_const_with_type(self.tcx, length, self.tcx.types.usize, length.node_id);
+                self.tcx.item_tables(self.tcx.hir.local_def_id(length.node_id));
             }
             _ => {}
         }
@@ -556,7 +545,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx hir::Expr) {
         match e.node {
             hir::ExprRepeat(_, count) => {
-                check_const_with_type(self.tcx, count, self.tcx.types.usize, count.node_id);
+                self.tcx.item_tables(self.tcx.hir.local_def_id(count.node_id));
             }
             _ => {}
         }
@@ -568,8 +557,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemFn(ref decl, .., body_id) => {
-                check_bare_fn(self.tcx, &decl, body_id, item.id, item.span);
+            hir::ItemFn(..) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(item.id));
             }
             _ => { }
         }
@@ -577,11 +566,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
-            hir::TraitItemKind::Const(_, Some(expr)) => {
-                check_const(self.tcx, expr, trait_item.id)
-            }
-            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
-                check_bare_fn(self.tcx, &sig.decl, body_id, trait_item.id, trait_item.span);
+            hir::TraitItemKind::Const(_, Some(_)) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id));
             }
             hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
             hir::TraitItemKind::Const(_, None) |
@@ -593,11 +580,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         match impl_item.node {
-            hir::ImplItemKind::Const(_, expr) => {
-                check_const(self.tcx, expr, impl_item.id)
-            }
-            hir::ImplItemKind::Method(ref sig, body_id) => {
-                check_bare_fn(self.tcx, &sig.decl, body_id, impl_item.id, impl_item.span);
+            hir::ImplItemKind::Const(..) |
+            hir::ImplItemKind::Method(..) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id));
             }
             hir::ImplItemKind::Type(_) => {
                 // Nothing to do here.
@@ -625,26 +610,6 @@ pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
     tcx.sess.track_errors(|| {
         let mut visit = CheckItemBodiesVisitor { tcx: tcx };
         tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
-
-        // Process deferred obligations, now that all functions
-        // bodies have been fully inferred.
-        for (&item_id, obligations) in tcx.deferred_obligations.borrow().iter() {
-            // Use the same DepNode as for the body of the original function/item.
-            let def_id = tcx.hir.local_def_id(item_id);
-            let _task = tcx.dep_graph.in_task(DepNode::TypeckTables(def_id));
-
-            let param_env = ParameterEnvironment::for_item(tcx, item_id);
-            tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
-                let mut fulfillment_cx = traits::FulfillmentContext::new();
-                for obligation in obligations.iter().map(|o| o.to_obligation()) {
-                    fulfillment_cx.register_predicate_obligation(&infcx, obligation);
-                }
-
-                if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) {
-                    infcx.report_fulfillment_errors(&errors);
-                }
-            });
-        }
     })
 }
 
@@ -668,38 +633,145 @@ pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
     })
 }
 
-fn check_bare_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           decl: &'tcx hir::FnDecl,
-                           body_id: hir::BodyId,
-                           fn_id: ast::NodeId,
-                           span: Span) {
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        typeck_tables,
+        closure_type,
+        closure_kind,
+        ..*providers
+    };
+}
+
+fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          def_id: DefId)
+                          -> ty::PolyFnSig<'tcx> {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    tcx.item_tables(def_id).closure_tys[&node_id]
+}
+
+fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          def_id: DefId)
+                          -> ty::ClosureKind {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    tcx.item_tables(def_id).closure_kinds[&node_id]
+}
+
+fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> &'tcx ty::TypeckTables<'tcx> {
+    // Closures' tables come from their outermost function,
+    // as they are part of the same "inference environment".
+    let outer_def_id = tcx.closure_base_def_id(def_id);
+    if outer_def_id != def_id {
+        return tcx.item_tables(outer_def_id);
+    }
+
+    let id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let span = tcx.hir.span(id);
+    let unsupported = || {
+        span_bug!(span, "can't type-check body of {:?}", def_id);
+    };
+
+    // Figure out what primary body this item has.
+    let mut fn_decl = None;
+    let body_id = match tcx.hir.get(id) {
+        hir::map::NodeItem(item) => {
+            match item.node {
+                hir::ItemConst(_, body) |
+                hir::ItemStatic(_, _, body) => body,
+                hir::ItemFn(ref decl, .., body) => {
+                    fn_decl = Some(decl);
+                    body
+                }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeTraitItem(item) => {
+            match item.node {
+                hir::TraitItemKind::Const(_, Some(body)) => body,
+                hir::TraitItemKind::Method(ref sig,
+                    hir::TraitMethod::Provided(body)) => {
+                        fn_decl = Some(&sig.decl);
+                        body
+                    }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeImplItem(item) => {
+            match item.node {
+                hir::ImplItemKind::Const(_, body) => body,
+                hir::ImplItemKind::Method(ref sig, body) => {
+                    fn_decl = Some(&sig.decl);
+                    body
+                }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeExpr(expr) => {
+            // FIXME(eddyb) Closures should have separate
+            // function definition IDs and expression IDs.
+            // Type-checking should not let closures get
+            // this far in a constant position.
+            // Assume that everything other than closures
+            // is a constant "initializer" expression.
+            match expr.node {
+                hir::ExprClosure(..) => {
+                    // We should've bailed out above for closures.
+                    span_bug!(expr.span, "unexpected closure")
+                }
+                _ => hir::BodyId { node_id: expr.id }
+            }
+        }
+        _ => unsupported()
+    };
     let body = tcx.hir.body(body_id);
 
-    let fn_sig = tcx.item_type(tcx.hir.local_def_id(fn_id)).fn_sig();
+    Inherited::build(tcx, id).enter(|inh| {
+        let fcx = if let Some(decl) = fn_decl {
+            let fn_sig = tcx.item_type(def_id).fn_sig();
+
+            check_abi(tcx, span, fn_sig.abi());
 
-    check_abi(tcx, span, fn_sig.abi());
+            // Compute the fty from point of view of inside fn.
+            let fn_scope = inh.tcx.region_maps.call_site_extent(id, body_id.node_id);
+            let fn_sig =
+                fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
+            let fn_sig =
+                inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
+            let fn_sig =
+                inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
 
-    Inherited::build(tcx, fn_id).enter(|inh| {
-        // Compute the fty from point of view of inside fn.
-        let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
-        let fn_sig =
-            fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
-        let fn_sig =
-            inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
-        let fn_sig =
-            inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+            check_fn(&inh, fn_sig, decl, id, body)
+        } else {
+            let expected_type = tcx.item_type(def_id);
+            let fcx = FnCtxt::new(&inh, None, body.value.id);
+            fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
 
-        let fcx = check_fn(&inh, fn_sig, decl, fn_id, body);
+            // Gather locals in statics (because of block expressions).
+            // This is technically unnecessary because locals in static items are forbidden,
+            // but prevents type checking from blowing up before const checking can properly
+            // emit an error.
+            GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
+
+            fcx.check_expr_coercable_to_type(&body.value, expected_type);
+
+            fcx
+        };
 
         fcx.select_all_obligations_and_apply_defaults();
         fcx.closure_analyze(body);
         fcx.select_obligations_where_possible();
         fcx.check_casts();
-        fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
+        fcx.select_all_obligations_or_error();
 
-        fcx.regionck_fn(fn_id, body);
-        fcx.resolve_type_vars_in_body(body);
-    });
+        if fn_decl.is_some() {
+            fcx.regionck_fn(id, body);
+        } else {
+            fcx.regionck_expr(body);
+        }
+
+        fcx.resolve_type_vars_in_body(body)
+    })
 }
 
 fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) {
@@ -772,7 +844,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
                 _: hir::BodyId, _: Span, _: ast::NodeId) { }
 }
 
-/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
+/// Helper used for fns and closures. Does the grungy work of checking a function
 /// body and returns the function context used for that purpose, since in the case of a fn item
 /// there is still a bit more to do.
 ///
@@ -835,7 +907,7 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let def_id = tcx.hir.local_def_id(id);
     check_representable(tcx, span, def_id);
 
-    if tcx.lookup_simd(def_id) {
+    if tcx.lookup_adt_def(def_id).repr.simd {
         check_simd(tcx, span, def_id);
     }
 }
@@ -853,8 +925,10 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
-      hir::ItemStatic(.., e) |
-      hir::ItemConst(_, e) => check_const(tcx, e, it.id),
+      hir::ItemStatic(..) |
+      hir::ItemConst(..) => {
+        tcx.item_tables(tcx.hir.local_def_id(it.id));
+      }
       hir::ItemEnum(ref enum_definition, _) => {
         check_enum_variants(tcx,
                             it.span,
@@ -1197,42 +1271,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-/// Checks a constant with a given type.
-fn check_const_with_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   body: hir::BodyId,
-                                   expected_type: Ty<'tcx>,
-                                   id: ast::NodeId) {
-    let body = tcx.hir.body(body);
-    Inherited::build(tcx, id).enter(|inh| {
-        let fcx = FnCtxt::new(&inh, None, body.value.id);
-        fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
-        // Gather locals in statics (because of block expressions).
-        // This is technically unnecessary because locals in static items are forbidden,
-        // but prevents type checking from blowing up before const checking can properly
-        // emit an error.
-        GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
-
-        fcx.check_expr_coercable_to_type(&body.value, expected_type);
-
-        fcx.select_all_obligations_and_apply_defaults();
-        fcx.closure_analyze(body);
-        fcx.select_obligations_where_possible();
-        fcx.check_casts();
-        fcx.select_all_obligations_or_error();
-
-        fcx.regionck_expr(body);
-        fcx.resolve_type_vars_in_body(body);
-    });
-}
-
-fn check_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                         body: hir::BodyId,
-                         id: ast::NodeId) {
-    let decl_ty = tcx.item_type(tcx.hir.local_def_id(id));
-    check_const_with_type(tcx, body, decl_ty, id);
-}
-
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
@@ -1293,9 +1331,9 @@ pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      vs: &'tcx [hir::Variant],
                                      id: ast::NodeId) {
     let def_id = tcx.hir.local_def_id(id);
-    let hint = *tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
+    let def = tcx.lookup_adt_def(def_id);
 
-    if hint != attr::ReprAny && vs.is_empty() {
+    if vs.is_empty() && tcx.has_attr(def_id, "repr") {
         struct_span_err!(
             tcx.sess, sp, E0084,
             "unsupported representation for zero-variant enum")
@@ -1303,7 +1341,7 @@ pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             .emit();
     }
 
-    let repr_type_ty = tcx.enum_repr_type(Some(&hint)).to_ty(tcx);
+    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
     if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
         if !tcx.sess.features.borrow().i128_type {
             emit_feature_err(&tcx.sess.parse_sess,
@@ -1313,13 +1351,10 @@ pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     for v in vs {
         if let Some(e) = v.node.disr_expr {
-            check_const_with_type(tcx, e, repr_type_ty, e.node_id);
+            tcx.item_tables(tcx.hir.local_def_id(e.node_id));
         }
     }
 
-    let def_id = tcx.hir.local_def_id(id);
-
-    let def = tcx.lookup_adt_def(def_id);
     let mut disr_vals: Vec<ConstInt> = Vec::new();
     for (discr, v) in def.discriminants(tcx).zip(vs) {
         // Check for duplicate discriminant values
@@ -1353,20 +1388,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         &self.ast_ty_to_ty_cache
     }
 
-    fn get_item_type(&self, _: Span, id: DefId) -> Ty<'tcx> {
-        self.tcx().item_type(id)
-    }
-
-    fn ensure_super_predicates(&self, _: Span, _: DefId) {
-        // all super predicates are ensured during collect pass
-    }
-
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
         Some(&self.parameter_environment.free_substs)
     }
 
     fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
-                                 -> Vec<ty::Predicate<'tcx>>
+                                 -> ty::GenericPredicates<'tcx>
     {
         let tcx = self.tcx;
         let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
@@ -1374,14 +1401,17 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         let item_def_id = tcx.hir.local_def_id(item_id);
         let generics = tcx.item_generics(item_def_id);
         let index = generics.type_param_to_index[&def_id.index];
-        self.parameter_environment.caller_bounds.iter().filter(|predicate| {
-            match **predicate {
-                ty::Predicate::Trait(ref data) => {
-                    data.0.self_ty().is_param(index)
+        ty::GenericPredicates {
+            parent: None,
+            predicates: self.parameter_environment.caller_bounds.iter().filter(|predicate| {
+                match **predicate {
+                    ty::Predicate::Trait(ref data) => {
+                        data.0.self_ty().is_param(index)
+                    }
+                    _ => false
                 }
-                _ => false
-            }
-        }).cloned().collect()
+            }).cloned().collect()
+        }
     }
 
     fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
@@ -1666,12 +1696,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if let ty::TyAnon(def_id, substs) = ty.sty {
                 // Use the same type variable if the exact same TyAnon appears more
                 // than once in the return type (e.g. if it's pased to a type alias).
-                if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
+                let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                if let Some(ty_var) = self.anon_types.borrow().get(&id) {
                     return ty_var;
                 }
                 let span = self.tcx.def_span(def_id);
                 let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
-                self.anon_types.borrow_mut().insert(def_id, ty_var);
+                self.anon_types.borrow_mut().insert(id, ty_var);
 
                 let item_predicates = self.tcx.item_predicates(def_id);
                 let bounds = item_predicates.instantiate(self.tcx, substs);
@@ -2206,11 +2237,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
 
-        // Steal the deferred obligations before the fulfillment
-        // context can turn all of them into errors.
-        let obligations = fulfillment_cx.take_deferred_obligations();
-        self.deferred_obligations.borrow_mut().extend(obligations);
-
         match fulfillment_cx.select_all_or_error(self) {
             Ok(()) => { }
             Err(errors) => { self.report_fulfillment_errors(&errors); }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index f7f004fbaef..4f0cfa8d014 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -14,7 +14,6 @@
 use self::ResolveReason::*;
 
 use check::FnCtxt;
-use hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{TypeFolder,TypeFoldable};
@@ -34,7 +33,8 @@ use rustc::hir;
 // Entry point
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) {
+    pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
+                                     -> &'gcx ty::TypeckTables<'gcx> {
         assert_eq!(self.writeback_errors.get(), false);
 
         let item_id = self.tcx.hir.body_owner(body.id());
@@ -50,18 +50,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         wbcx.visit_liberated_fn_sigs();
         wbcx.visit_fru_field_types();
         wbcx.visit_anon_types();
-        wbcx.visit_deferred_obligations(item_id);
         wbcx.visit_type_nodes();
         wbcx.visit_cast_types();
         wbcx.visit_lints();
 
-        let tables = self.tcx.alloc_tables(wbcx.tables);
-        self.tcx.maps.typeck_tables.borrow_mut().insert(item_def_id, tables);
-
-        let used_trait_imports = mem::replace(&mut *self.used_trait_imports.borrow_mut(),
+        let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
                                               DefIdSet());
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
-        self.tcx.maps.used_trait_imports.borrow_mut().insert(item_def_id, used_trait_imports);
+        wbcx.tables.used_trait_imports = used_trait_imports;
+
+        self.tcx.alloc_tables(wbcx.tables)
     }
 }
 
@@ -282,20 +280,18 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
     }
 
-    fn visit_closures(&self) {
+    fn visit_closures(&mut self) {
         if self.fcx.writeback_errors.get() {
             return
         }
 
         for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
             let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
-            let def_id = self.tcx().hir.local_def_id(id);
-            self.tcx().maps.closure_type.borrow_mut().insert(def_id, closure_ty);
+            self.tables.closure_tys.insert(id, closure_ty);
         }
 
         for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
-            let def_id = self.tcx().hir.local_def_id(id);
-            self.tcx().maps.closure_kind.borrow_mut().insert(def_id, closure_kind);
+            self.tables.closure_kinds.insert(id, closure_kind);
         }
     }
 
@@ -316,14 +312,14 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
     }
 
-    fn visit_anon_types(&self) {
+    fn visit_anon_types(&mut self) {
         if self.fcx.writeback_errors.get() {
             return
         }
 
         let gcx = self.tcx().global_tcx();
-        for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
-            let reason = ResolvingAnonTy(def_id);
+        for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
+            let reason = ResolvingAnonTy(node_id);
             let inside_ty = self.resolve(&concrete_ty, reason);
 
             // Convert the type from the function into a type valid outside
@@ -361,7 +357,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                 }
             });
 
-            gcx.maps.ty.borrow_mut().insert(def_id, outside_ty);
+            self.tables.node_types.insert(node_id, outside_ty);
         }
     }
 
@@ -483,19 +479,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
     }
 
-    fn visit_deferred_obligations(&mut self, item_id: ast::NodeId) {
-        let deferred_obligations = self.fcx.deferred_obligations.borrow();
-        let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
-            let reason = ResolvingDeferredObligation(obligation.cause.span);
-            self.resolve(obligation, reason)
-        }).collect();
-
-        if !obligations.is_empty() {
-            assert!(self.fcx.tcx.deferred_obligations.borrow_mut()
-                                .insert(item_id, obligations).is_none());
-        }
-    }
-
     fn visit_type_nodes(&self) {
         for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() {
             let ty = self.resolve(ty, ResolvingTyNode(id));
@@ -528,8 +511,7 @@ enum ResolveReason {
     ResolvingClosure(ast::NodeId),
     ResolvingFnSig(ast::NodeId),
     ResolvingFieldTypes(ast::NodeId),
-    ResolvingAnonTy(DefId),
-    ResolvingDeferredObligation(Span),
+    ResolvingAnonTy(ast::NodeId),
     ResolvingTyNode(ast::NodeId),
 }
 
@@ -545,13 +527,10 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
             ResolvingClosure(id) |
             ResolvingFnSig(id) |
             ResolvingFieldTypes(id) |
-            ResolvingTyNode(id) => {
+            ResolvingTyNode(id) |
+            ResolvingAnonTy(id) => {
                 tcx.hir.span(id)
             }
-            ResolvingAnonTy(did) => {
-                tcx.def_span(did)
-            }
-            ResolvingDeferredObligation(span) => span
         }
     }
 }
@@ -626,7 +605,6 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
 
                 ResolvingFnSig(_) |
                 ResolvingFieldTypes(_) |
-                ResolvingDeferredObligation(_) |
                 ResolvingTyNode(_) => {
                     // any failures here should also fail when
                     // resolving the patterns, closure types, or
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 0f992f75fce..3791079dc81 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -70,7 +70,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         let item_def_id = tcx.hir.local_def_id(item_id);
 
         // this will have been written by the main typeck pass
-        if let Some(imports) = tcx.maps.used_trait_imports.borrow().get(&item_def_id) {
+        if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) {
+            let imports = &tables.used_trait_imports;
             debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
             used_trait_imports.extend(imports);
         } else {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 68e42f5b27a..2a95f5f5d08 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -47,10 +47,6 @@ item, we may need to compute the *type scheme* or *trait definition*
 for other items.
 
 There are some shortcomings in this design:
-
-- Before walking the set of supertraits for a given trait, you must
-  call `ensure_super_predicates` on that trait def-id. Otherwise,
-  `item_super_predicates` will result in ICEs.
 - Because the item generics include defaults, cycles through type
   parameter defaults are illegal even if those defaults are never
   employed. This is not necessarily a bug.
@@ -66,7 +62,7 @@ use middle::resolve_lifetime as rl;
 use rustc_const_eval::EvalHint::UncheckedExprHint;
 use rustc_const_eval::{ConstContext, report_const_eval_err};
 use rustc::ty::subst::Substs;
-use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions};
+use rustc::ty::{ToPredicate, ReprOptions};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
 use rustc::ty::util::IntTypeExt;
@@ -80,6 +76,7 @@ use std::cell::RefCell;
 use std::collections::BTreeMap;
 
 use syntax::{abi, ast, attr};
+use syntax::codemap::Spanned;
 use syntax::symbol::{Symbol, keywords};
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -98,9 +95,14 @@ pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
+        ty,
         generics,
+        predicates,
+        super_predicates,
+        type_param_predicates,
         trait_def,
         adt_def,
+        impl_trait_ref,
         ..*providers
     };
 }
@@ -190,7 +192,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
         for param in &generics.ty_params {
             if param.default.is_some() {
                 let def_id = self.tcx.hir.local_def_id(param.id);
-                type_of_def_id(self.tcx, def_id);
+                self.tcx.item_type(def_id);
             }
         }
         intravisit::walk_generics(self, generics);
@@ -200,7 +202,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
         if let hir::ExprClosure(..) = expr.node {
             let def_id = self.tcx.hir.local_def_id(expr.id);
             self.tcx.item_generics(def_id);
-            type_of_def_id(self.tcx, def_id);
+            self.tcx.item_type(def_id);
         }
         intravisit::walk_expr(self, expr);
     }
@@ -209,6 +211,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
         if let hir::TyImplTrait(..) = ty.node {
             let def_id = self.tcx.hir.local_def_id(ty.id);
             self.tcx.item_generics(def_id);
+            self.tcx.item_predicates(def_id);
         }
         intravisit::walk_ty(self, ty);
     }
@@ -254,42 +257,12 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         &self.tcx.ast_ty_to_ty_cache
     }
 
-    fn get_item_type(&self, span: Span, id: DefId) -> Ty<'tcx> {
-        self.tcx.cycle_check(span, ty::maps::Query::ty(id), || {
-            type_of_def_id(self.tcx, id)
-        })
-    }
-
-    /// Ensure that the (transitive) super predicates for
-    /// `trait_def_id` are available. This will report a cycle error
-    /// if a trait `X` (transitively) extends itself in some form.
-    fn ensure_super_predicates(&self,
-                               span: Span,
-                               trait_def_id: DefId) {
-        if !trait_def_id.is_local() {
-            // If this trait comes from an external crate, then all of the
-            // supertraits it may depend on also must come from external
-            // crates, and hence all of them already have their
-            // super-predicates "converted" (and available from crate
-            // meta-data), so there is no need to transitively test them.
-            return;
-        }
-
-        self.tcx.maps.super_predicates.memoize(trait_def_id, || {
-            self.tcx.cycle_check(span, ty::maps::Query::super_predicates(trait_def_id), || {
-                super_predicates(self.tcx, trait_def_id)
-            })
-        });
-    }
-
     fn get_type_parameter_bounds(&self,
                                  span: Span,
                                  def_id: DefId)
-                                 -> Vec<ty::Predicate<'tcx>>
+                                 -> ty::GenericPredicates<'tcx>
     {
-        self.tcx.cycle_check(span,
-            ty::maps::Query::type_param_predicates((self.item_def_id, def_id)),
-            || get_type_parameter_bounds(self.tcx, self.item_def_id, def_id))
+        self.tcx.maps.type_param_predicates(self.tcx, span, (self.item_def_id, def_id))
     }
 
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
@@ -343,89 +316,91 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
     }
 }
 
-    fn get_type_parameter_bounds<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                           item_def_id: DefId,
-                                           def_id: DefId)
-                                           -> Vec<ty::Predicate<'tcx>>
-    {
-        use rustc::hir::map::*;
-        use rustc::hir::*;
-
-        // In the AST, bounds can derive from two places. Either
-        // written inline like `<T:Foo>` or in a where clause like
-        // `where T:Foo`.
-
-        let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
-        let param_owner = tcx.hir.ty_param_owner(param_id);
-        let param_owner_def_id = tcx.hir.local_def_id(param_owner);
-        let generics = tcx.item_generics(param_owner_def_id);
-        let index = generics.type_param_to_index[&def_id.index];
-        let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id));
-
-        // Don't look for bounds where the type parameter isn't in scope.
-        let parent = if item_def_id == param_owner_def_id {
-            None
-        } else {
-            tcx.item_generics(item_def_id).parent
-        };
+fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   (item_def_id, def_id): (DefId, DefId))
+                                   -> ty::GenericPredicates<'tcx> {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
 
-        let mut results = parent.map_or(vec![], |parent| {
-            let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id)
-        });
+    // In the AST, bounds can derive from two places. Either
+    // written inline like `<T:Foo>` or in a where clause like
+    // `where T:Foo`.
 
-        let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap();
-        let ast_generics = match tcx.hir.get(item_node_id) {
-            NodeTraitItem(item) => {
-                match item.node {
-                    TraitItemKind::Method(ref sig, _) => &sig.generics,
-                    _ => return results
-                }
+    let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let param_owner = tcx.hir.ty_param_owner(param_id);
+    let param_owner_def_id = tcx.hir.local_def_id(param_owner);
+    let generics = tcx.item_generics(param_owner_def_id);
+    let index = generics.type_param_to_index[&def_id.index];
+    let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id));
+
+    // Don't look for bounds where the type parameter isn't in scope.
+    let parent = if item_def_id == param_owner_def_id {
+        None
+    } else {
+        tcx.item_generics(item_def_id).parent
+    };
+
+    let mut result = parent.map_or(ty::GenericPredicates {
+        parent: None,
+        predicates: vec![]
+    }, |parent| {
+        let icx = ItemCtxt::new(tcx, parent);
+        icx.get_type_parameter_bounds(DUMMY_SP, def_id)
+    });
+
+    let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap();
+    let ast_generics = match tcx.hir.get(item_node_id) {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => return result
             }
+        }
 
-            NodeImplItem(item) => {
-                match item.node {
-                    ImplItemKind::Method(ref sig, _) => &sig.generics,
-                    _ => return results
-                }
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => return result
             }
+        }
 
-            NodeItem(item) => {
-                match item.node {
-                    ItemFn(.., ref generics, _) |
-                    ItemImpl(_, _, ref generics, ..) |
-                    ItemTy(_, ref generics) |
-                    ItemEnum(_, ref generics) |
-                    ItemStruct(_, ref generics) |
-                    ItemUnion(_, ref generics) => generics,
-                    ItemTrait(_, ref generics, ..) => {
-                        // Implied `Self: Trait` and supertrait bounds.
-                        if param_id == item_node_id {
-                            results.push(ty::TraitRef {
-                                def_id: item_def_id,
-                                substs: Substs::identity_for_item(tcx, item_def_id)
-                            }.to_predicate());
-                        }
-                        generics
+        NodeItem(item) => {
+            match item.node {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) |
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => generics,
+                ItemTrait(_, ref generics, ..) => {
+                    // Implied `Self: Trait` and supertrait bounds.
+                    if param_id == item_node_id {
+                        result.predicates.push(ty::TraitRef {
+                            def_id: item_def_id,
+                            substs: Substs::identity_for_item(tcx, item_def_id)
+                        }.to_predicate());
                     }
-                    _ => return results
+                    generics
                 }
+                _ => return result
             }
+        }
 
-            NodeForeignItem(item) => {
-                match item.node {
-                    ForeignItemFn(_, _, ref generics) => generics,
-                    _ => return results
-                }
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemFn(_, _, ref generics) => generics,
+                _ => return result
             }
+        }
 
-            _ => return results
-        };
+        _ => return result
+    };
 
-        let icx = ItemCtxt::new(tcx, item_def_id);
-        results.extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
-        results
-    }
+    let icx = ItemCtxt::new(tcx, item_def_id);
+    result.predicates.extend(
+        icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
+    result
+}
 
 impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
     /// Find bounds from hir::Generics. This requires scanning through the
@@ -483,63 +458,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn convert_field<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           field: &hir::StructField,
-                           ty_f: &'tcx ty::FieldDef)
-{
-    tcx.item_generics(ty_f.did);
-    let tt = ItemCtxt::new(tcx, ty_f.did).to_ty(&field.ty);
-    tcx.maps.ty.borrow_mut().insert(ty_f.did, tt);
-    tcx.maps.predicates.borrow_mut().insert(ty_f.did, ty::GenericPredicates {
-        parent: Some(tcx.hir.get_parent_did(field.id)),
-        predicates: vec![]
-    });
-}
-
-fn convert_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            id: ast::NodeId,
-                            sig: &hir::MethodSig) {
-    let def_id = tcx.hir.local_def_id(id);
-
-    let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), sig.unsafety, sig.abi, &sig.decl);
-    let substs = Substs::identity_for_item(tcx, def_id);
-    let fty = tcx.mk_fn_def(def_id, substs, fty);
-    tcx.maps.ty.borrow_mut().insert(def_id, fty);
-
-    ty_generic_predicates(tcx, def_id, &sig.generics);
-}
-
-fn convert_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                      container: AssociatedItemContainer,
-                                      id: ast::NodeId,
-                                      ty: ty::Ty<'tcx>)
-{
-    let predicates = ty::GenericPredicates {
-        parent: Some(container.id()),
-        predicates: vec![]
-    };
-    let def_id = tcx.hir.local_def_id(id);
-    tcx.maps.predicates.borrow_mut().insert(def_id, predicates);
-    tcx.maps.ty.borrow_mut().insert(def_id, ty);
-}
-
-fn convert_associated_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     container: AssociatedItemContainer,
-                                     id: ast::NodeId,
-                                     ty: Option<Ty<'tcx>>)
-{
-    let predicates = ty::GenericPredicates {
-        parent: Some(container.id()),
-        predicates: vec![]
-    };
-    let def_id = tcx.hir.local_def_id(id);
-    tcx.maps.predicates.borrow_mut().insert(def_id, predicates);
-
-    if let Some(ty) = ty {
-        tcx.maps.ty.borrow_mut().insert(def_id, ty);
-    }
-}
-
 fn ensure_no_ty_param_bounds(tcx: TyCtxt,
                              span: Span,
                              generics: &hir::Generics,
@@ -582,195 +500,125 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt,
 fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
     debug!("convert: item {} with id {}", it.name, it.id);
     let def_id = tcx.hir.local_def_id(it.id);
-    let icx = ItemCtxt::new(tcx, def_id);
     match it.node {
         // These don't define types.
         hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => {
         }
         hir::ItemForeignMod(ref foreign_mod) => {
             for item in &foreign_mod.items {
-                convert_foreign_item(tcx, item);
+                let def_id = tcx.hir.local_def_id(item.id);
+                tcx.item_generics(def_id);
+                tcx.item_type(def_id);
+                tcx.item_predicates(def_id);
             }
         }
         hir::ItemEnum(ref enum_definition, _) => {
             tcx.item_generics(def_id);
-            predicates_of_item(tcx, it);
-            let ty = type_of_def_id(tcx, def_id);
-            convert_enum_variant_types(tcx,
-                                       tcx.lookup_adt_def(tcx.hir.local_def_id(it.id)),
-                                       ty,
-                                       &enum_definition.variants);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
+            convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
         },
-        hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
-            let trait_ref =
-                AstConv::instantiate_mono_trait_ref(&icx,
-                                                    ast_trait_ref,
-                                                    tcx.mk_self_type());
-
-            tcx.record_trait_has_default_impl(trait_ref.def_id);
-
-            tcx.maps.impl_trait_ref.borrow_mut().insert(tcx.hir.local_def_id(it.id),
-                                                         Some(trait_ref));
+        hir::ItemDefaultImpl(..) => {
+            if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
+                tcx.record_trait_has_default_impl(trait_ref.def_id);
+            }
         }
-        hir::ItemImpl(.., ref opt_trait_ref, _, _) => {
+        hir::ItemImpl(..) => {
             tcx.item_generics(def_id);
-            let selfty = type_of_def_id(tcx, def_id);
-
-            let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
-                AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
-            });
-            tcx.maps.impl_trait_ref.borrow_mut().insert(def_id, trait_ref);
-
-            predicates_of_item(tcx, it);
+            tcx.item_type(def_id);
+            tcx.impl_trait_ref(def_id);
+            tcx.item_predicates(def_id);
         },
         hir::ItemTrait(..) => {
             tcx.item_generics(def_id);
             tcx.lookup_trait_def(def_id);
-            icx.ensure_super_predicates(it.span, def_id);
-            predicates_of_item(tcx, it);
+            tcx.maps.super_predicates(tcx, it.span, def_id);
+            tcx.item_predicates(def_id);
         },
         hir::ItemStruct(ref struct_def, _) |
         hir::ItemUnion(ref struct_def, _) => {
             tcx.item_generics(def_id);
-            predicates_of_item(tcx, it);
-            let ty = type_of_def_id(tcx, def_id);
-
-            let variant = tcx.lookup_adt_def(def_id).struct_variant();
-
-            for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) {
-                convert_field(tcx, f, ty_f)
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
+
+            for f in struct_def.fields() {
+                let def_id = tcx.hir.local_def_id(f.id);
+                tcx.item_generics(def_id);
+                tcx.item_type(def_id);
+                tcx.item_predicates(def_id);
             }
 
             if !struct_def.is_struct() {
-                convert_variant_ctor(tcx, struct_def.id(), variant, ty);
+                convert_variant_ctor(tcx, struct_def.id());
             }
         },
         hir::ItemTy(_, ref generics) => {
             ensure_no_ty_param_bounds(tcx, it.span, generics, "type");
             tcx.item_generics(def_id);
-            predicates_of_item(tcx, it);
-            type_of_def_id(tcx, def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         },
         _ => {
             tcx.item_generics(def_id);
-            predicates_of_item(tcx, it);
-            type_of_def_id(tcx, def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         },
     }
 }
 
 fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) {
-    // we can lookup details about the trait because items are visited
-    // before trait-items
-    let trait_def_id = tcx.hir.get_parent_did(trait_item.id);
-
     let def_id = tcx.hir.local_def_id(trait_item.id);
+    tcx.item_generics(def_id);
+
     match trait_item.node {
-        hir::TraitItemKind::Const(ref ty, _) => {
-            tcx.item_generics(def_id);
-            let ty = ItemCtxt::new(tcx, def_id).to_ty(&ty);
-            convert_associated_const(tcx,
-                                     TraitContainer(trait_def_id),
-                                     trait_item.id,
-                                     ty);
+        hir::TraitItemKind::Const(..) |
+        hir::TraitItemKind::Type(_, Some(_)) |
+        hir::TraitItemKind::Method(..) => {
+            tcx.item_type(def_id);
         }
 
-        hir::TraitItemKind::Type(_, ref opt_ty) => {
-            tcx.item_generics(def_id);
-
-            let typ = opt_ty.as_ref().map(|ty| ItemCtxt::new(tcx, def_id).to_ty(&ty));
-
-            convert_associated_type(tcx, TraitContainer(trait_def_id), trait_item.id, typ);
-        }
+        hir::TraitItemKind::Type(_, None) => {}
+    };
 
-        hir::TraitItemKind::Method(ref sig, _) => {
-            convert_method(tcx, trait_item.id, sig);
-        }
-    }
+    tcx.item_predicates(def_id);
 }
 
 fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) {
-    // we can lookup details about the impl because items are visited
-    // before impl-items
-    let impl_def_id = tcx.hir.get_parent_did(impl_item.id);
-
     let def_id = tcx.hir.local_def_id(impl_item.id);
-    match impl_item.node {
-        hir::ImplItemKind::Const(ref ty, _) => {
-            tcx.item_generics(def_id);
-            let ty = ItemCtxt::new(tcx, def_id).to_ty(&ty);
-            convert_associated_const(tcx,
-                                     ImplContainer(impl_def_id),
-                                     impl_item.id,
-                                     ty);
-        }
-
-        hir::ImplItemKind::Type(ref ty) => {
-            tcx.item_generics(def_id);
-
-            if tcx.impl_trait_ref(impl_def_id).is_none() {
-                span_err!(tcx.sess, impl_item.span, E0202,
-                          "associated types are not allowed in inherent impls");
-            }
-
-            let typ = ItemCtxt::new(tcx, def_id).to_ty(ty);
-
-            convert_associated_type(tcx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
-        }
-
-        hir::ImplItemKind::Method(ref sig, _) => {
-            convert_method(tcx, impl_item.id, sig);
-        }
-    }
+    tcx.item_generics(def_id);
+    tcx.item_type(def_id);
+    tcx.item_predicates(def_id);
 }
 
 fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  ctor_id: ast::NodeId,
-                                  variant: &'tcx ty::VariantDef,
-                                  ty: Ty<'tcx>) {
+                                  ctor_id: ast::NodeId) {
     let def_id = tcx.hir.local_def_id(ctor_id);
     tcx.item_generics(def_id);
-    let ctor_ty = match variant.ctor_kind {
-        CtorKind::Fictive | CtorKind::Const => ty,
-        CtorKind::Fn => {
-            let inputs = variant.fields.iter().map(|field| tcx.item_type(field.did));
-            let substs = Substs::identity_for_item(tcx, def_id);
-            tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
-                inputs,
-                ty,
-                false,
-                hir::Unsafety::Normal,
-                abi::Abi::Rust
-            )))
-        }
-    };
-    tcx.maps.ty.borrow_mut().insert(def_id, ctor_ty);
-    tcx.maps.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
-        parent: Some(tcx.hir.get_parent_did(ctor_id)),
-        predicates: vec![]
-    });
+    tcx.item_type(def_id);
+    tcx.item_predicates(def_id);
 }
 
 fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        def: &'tcx ty::AdtDef,
-                                        ty: Ty<'tcx>,
+                                        def_id: DefId,
                                         variants: &[hir::Variant]) {
-    let repr_hints = tcx.lookup_repr_hints(def.did);
-    let repr_type = tcx.enum_repr_type(repr_hints.get(0));
+    let def = tcx.lookup_adt_def(def_id);
+    let repr_type = def.repr.discr_type();
     let initial = repr_type.initial_discriminant(tcx);
     let mut prev_discr = None::<ConstInt>;
 
     // fill the discriminant values and field types
-    for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) {
+    for variant in variants {
         let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
         prev_discr = Some(if let Some(e) = variant.node.disr_expr {
-            let result = evaluate_disr_expr(tcx, repr_type, e);
-
             let expr_did = tcx.hir.local_def_id(e.node_id);
-            tcx.maps.monomorphic_const_eval.borrow_mut()
-               .insert(expr_did, result.map(ConstVal::Integral));
+            let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
+                evaluate_disr_expr(tcx, repr_type, e).map(ConstVal::Integral)
+            });
 
-            result.ok()
+            match result {
+                Ok(ConstVal::Integral(x)) => Some(x),
+                _ => None
+            }
         } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
             Some(discr)
         } else {
@@ -784,13 +632,16 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             None
         }.unwrap_or(wrapped_discr));
 
-        for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) {
-            convert_field(tcx, f, ty_f)
+        for f in variant.node.data.fields() {
+            let def_id = tcx.hir.local_def_id(f.id);
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         }
 
         // Convert the ctor, if any. This also registers the variant as
         // an item.
-        convert_variant_ctor(tcx, variant.node.data.id(), ty_variant, ty);
+        convert_variant_ctor(tcx, variant.node.data.id());
     }
 }
 
@@ -985,7 +836,7 @@ fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Now require that immediate supertraits are converted,
     // which will, in turn, reach indirect supertraits.
     for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) {
-        icx.ensure_super_predicates(item.span, bound.def_id());
+        tcx.maps.super_predicates(tcx, item.span, bound.def_id());
     }
 
     ty::GenericPredicates {
@@ -1212,121 +1063,179 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     })
 }
 
-fn type_of_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            def_id: DefId)
-                            -> Ty<'tcx> {
-    let node_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-        id
-    } else {
-        return tcx.item_type(def_id);
-    };
-    tcx.maps.ty.memoize(def_id, || {
-        use rustc::hir::map::*;
-        use rustc::hir::*;
+fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                def_id: DefId)
+                -> Ty<'tcx> {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
 
-        // Alway bring in generics, as computing the type needs them.
-        tcx.item_generics(def_id);
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
 
-        let icx = ItemCtxt::new(tcx, def_id);
+    let icx = ItemCtxt::new(tcx, def_id);
 
-        match tcx.hir.get(node_id) {
-            NodeItem(item) => {
-                match item.node {
-                    ItemStatic(ref t, ..) | ItemConst(ref t, _) |
-                    ItemTy(ref t, _) | ItemImpl(.., ref t, _) => {
-                        icx.to_ty(t)
-                    }
-                    ItemFn(ref decl, unsafety, _, abi, _, _) => {
-                        let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl);
-                        let substs = Substs::identity_for_item(tcx, def_id);
-                        tcx.mk_fn_def(def_id, substs, tofd)
-                    }
-                    ItemEnum(..) |
-                    ItemStruct(..) |
-                    ItemUnion(..) => {
-                        let def = tcx.lookup_adt_def(def_id);
-                        let substs = Substs::identity_for_item(tcx, def_id);
-                        tcx.mk_adt(def, substs)
-                    }
-                    ItemDefaultImpl(..) |
-                    ItemTrait(..) |
-                    ItemMod(..) |
-                    ItemForeignMod(..) |
-                    ItemExternCrate(..) |
-                    ItemUse(..) => {
-                        span_bug!(
-                            item.span,
-                            "compute_type_of_item: unexpected item type: {:?}",
-                            item.node);
-                    }
+    match tcx.hir.get(node_id) {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => {
+                    let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, fty)
+                }
+                TraitItemKind::Const(ref ty, _) |
+                TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
+                TraitItemKind::Type(_, None) => {
+                    span_bug!(item.span, "associated type missing default");
                 }
             }
-            NodeForeignItem(foreign_item) => {
-                let abi = tcx.hir.get_foreign_abi(node_id);
+        }
 
-                match foreign_item.node {
-                    ForeignItemFn(ref fn_decl, _, _) => {
-                        compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => {
+                    let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, fty)
+                }
+                ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
+                ImplItemKind::Type(ref ty) => {
+                    if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
+                        span_err!(tcx.sess, item.span, E0202,
+                                  "associated types are not allowed in inherent impls");
                     }
-                    ForeignItemStatic(ref t, _) => icx.to_ty(t)
+
+                    icx.to_ty(ty)
                 }
             }
-            NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
-                tcx.mk_closure(def_id, Substs::for_item(
-                    tcx, def_id,
-                    |def, _| {
-                        let region = def.to_early_bound_region_data();
-                        tcx.mk_region(ty::ReEarlyBound(region))
-                    },
-                    |def, _| tcx.mk_param_from_def(def)
-                ))
+        }
+
+        NodeItem(item) => {
+            match item.node {
+                ItemStatic(ref t, ..) | ItemConst(ref t, _) |
+                ItemTy(ref t, _) | ItemImpl(.., ref t, _) => {
+                    icx.to_ty(t)
+                }
+                ItemFn(ref decl, unsafety, _, abi, _, _) => {
+                    let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, tofd)
+                }
+                ItemEnum(..) |
+                ItemStruct(..) |
+                ItemUnion(..) => {
+                    let def = tcx.lookup_adt_def(def_id);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_adt(def, substs)
+                }
+                ItemDefaultImpl(..) |
+                ItemTrait(..) |
+                ItemMod(..) |
+                ItemForeignMod(..) |
+                ItemExternCrate(..) |
+                ItemUse(..) => {
+                    span_bug!(
+                        item.span,
+                        "compute_type_of_item: unexpected item type: {:?}",
+                        item.node);
+                }
             }
-            NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => {
-                icx.to_ty(ty)
+        }
+
+        NodeForeignItem(foreign_item) => {
+            let abi = tcx.hir.get_foreign_abi(node_id);
+
+            match foreign_item.node {
+                ForeignItemFn(ref fn_decl, _, _) => {
+                    compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+                }
+                ForeignItemStatic(ref t, _) => icx.to_ty(t)
             }
-            x => {
-                bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+        }
+
+        NodeStructCtor(&ref def) |
+        NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => {
+            let ty = tcx.item_type(tcx.hir.get_parent_did(node_id));
+            match *def {
+                VariantData::Unit(..) | VariantData::Struct(..) => ty,
+                VariantData::Tuple(ref fields, _) => {
+                    let inputs = fields.iter().map(|f| {
+                        tcx.item_type(tcx.hir.local_def_id(f.id))
+                    });
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
+                        inputs,
+                        ty,
+                        false,
+                        hir::Unsafety::Normal,
+                        abi::Abi::Rust
+                    )))
+                }
             }
         }
-    })
-}
 
-fn predicates_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
-    let def_id = tcx.hir.local_def_id(it.id);
+        NodeField(field) => icx.to_ty(&field.ty),
 
-    let no_generics = hir::Generics::empty();
-    let generics = match it.node {
-        hir::ItemFn(.., ref generics, _) |
-        hir::ItemTy(_, ref generics) |
-        hir::ItemEnum(_, ref generics) |
-        hir::ItemStruct(_, ref generics) |
-        hir::ItemUnion(_, ref generics) |
-        hir::ItemTrait(_, ref generics, _, _) |
-        hir::ItemImpl(_, _, ref generics, ..) => generics,
-        _ => &no_generics
-    };
+        NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+            tcx.mk_closure(def_id, Substs::for_item(
+                tcx, def_id,
+                |def, _| {
+                    let region = def.to_early_bound_region_data();
+                    tcx.mk_region(ty::ReEarlyBound(region))
+                },
+                |def, _| tcx.mk_param_from_def(def)
+            ))
+        }
 
-    ty_generic_predicates(tcx, def_id, generics);
-}
+        NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
+            NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
+            NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
+                if body.node_id == node_id => tcx.types.usize,
 
-fn convert_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  it: &hir::ForeignItem)
-{
-    // For reasons I cannot fully articulate, I do so hate the AST
-    // map, and I regard each time that I use it as a personal and
-    // moral failing, but at the moment it seems like the only
-    // convenient way to extract the ABI. - ndm
-    let def_id = tcx.hir.local_def_id(it.id);
-    tcx.item_generics(def_id);
-    type_of_def_id(tcx, def_id);
+            NodeVariant(&Spanned { node: Variant_ { disr_expr: Some(e), .. }, .. })
+                if e.node_id == node_id => {
+                    tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id))
+                        .repr.discr_type().to_ty(tcx)
+                }
 
-    let no_generics = hir::Generics::empty();
-    let generics = match it.node {
-        hir::ForeignItemFn(_, _, ref generics) => generics,
-        hir::ForeignItemStatic(..) => &no_generics
-    };
+            x => {
+                bug!("unexpected expr parent in type_of_def_id(): {:?}", x);
+            }
+        },
+
+        NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => {
+            icx.to_ty(ty)
+        }
+
+        NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => {
+            let owner = tcx.hir.get_parent_did(node_id);
+            tcx.item_tables(owner).node_id_to_type(node_id)
+        }
 
-    ty_generic_predicates(tcx, def_id, generics);
+        x => {
+            bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+        }
+    }
+}
+
+fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            def_id: DefId)
+                            -> Option<ty::TraitRef<'tcx>> {
+    let icx = ItemCtxt::new(tcx, def_id);
+
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    match tcx.hir.expect_item(node_id).node {
+        hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
+            Some(AstConv::instantiate_mono_trait_ref(&icx,
+                                                     ast_trait_ref,
+                                                     tcx.mk_self_type()))
+        }
+        hir::ItemImpl(.., ref opt_trait_ref, _, _) => {
+            opt_trait_ref.as_ref().map(|ast_trait_ref| {
+                let selfty = tcx.item_type(def_id);
+                AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+            })
+        }
+        _ => bug!()
+    }
 }
 
 // Is it marked with ?Sized
@@ -1389,37 +1298,87 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
         .filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id))
 }
 
-fn ty_generic_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   def_id: DefId,
-                                   ast_generics: &hir::Generics) {
+fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        def_id: DefId)
+                        -> ty::GenericPredicates<'tcx> {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
+
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let node = tcx.hir.get(node_id);
+
+    let mut is_trait = None;
+
     let icx = ItemCtxt::new(tcx, def_id);
-    let generics = tcx.item_generics(def_id);
-    let parent_count = generics.parent_count() as u32;
-    let has_own_self = generics.has_self && parent_count == 0;
+    let no_generics = hir::Generics::empty();
+    let ast_generics = match node {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
+        }
 
-    let mut predicates = vec![];
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
+        }
 
-    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
-    let (is_trait, is_impl) = match tcx.hir.get(node_id) {
-        hir::map::NodeItem(item) => {
+        NodeItem(item) => {
             match item.node {
-                hir::ItemTrait(.., ref items) => {
-                    (Some((ty::TraitRef {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) |
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => {
+                    generics
+                }
+
+                ItemTrait(_, ref generics, .., ref items) => {
+                    is_trait = Some((ty::TraitRef {
                         def_id: def_id,
                         substs: Substs::identity_for_item(tcx, def_id)
-                    }, items)), None)
-                }
-                hir::ItemImpl(..) => {
-                    let self_ty = type_of_def_id(tcx, def_id);
-                    let trait_ref = tcx.impl_trait_ref(def_id);
-                    (None, Some((self_ty, trait_ref)))
+                    }, items));
+                    generics
                 }
-                _ => (None, None)
+
+                _ => &no_generics
             }
         }
-        _ => (None, None)
+
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemStatic(..) => &no_generics,
+                ForeignItemFn(_, _, ref generics) => generics
+            }
+        }
+
+        NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => {
+            let substs = Substs::identity_for_item(tcx, def_id);
+            let anon_ty = tcx.mk_anon(def_id, substs);
+
+            // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
+            let bounds = compute_bounds(&icx, anon_ty, bounds,
+                                        SizedByDefault::Yes,
+                                        span);
+            return ty::GenericPredicates {
+                parent: None,
+                predicates: bounds.predicates(tcx, anon_ty)
+            };
+        }
+
+        _ => &no_generics
     };
 
+    let generics = tcx.item_generics(def_id);
+    let parent_count = generics.parent_count() as u32;
+    let has_own_self = generics.has_self && parent_count == 0;
+
+    let mut predicates = vec![];
+
     // Below we'll consider the bounds on the type parameters (including `Self`)
     // and the explicit where-clauses, but to get the full set of predicates
     // on a trait we need to add in the supertrait bounds and bounds found on
@@ -1543,16 +1502,18 @@ fn ty_generic_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // before uses of `U`.  This avoids false ambiguity errors
     // in trait checking. See `setup_constraining_predicates`
     // for details.
-    if let Some((self_ty, trait_ref)) = is_impl {
+    if let NodeItem(&Item { node: ItemImpl(..), .. }) = node {
+        let self_ty = tcx.item_type(def_id);
+        let trait_ref = tcx.impl_trait_ref(def_id);
         ctp::setup_constraining_predicates(&mut predicates,
                                            trait_ref,
                                            &mut ctp::parameters_for_impl(self_ty, trait_ref));
     }
 
-    tcx.maps.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
+    ty::GenericPredicates {
         parent: generics.parent,
         predicates: predicates
-    });
+    }
 }
 
 pub enum SizedByDefault { Yes, No, }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 8e6e83bf301..0f425baec10 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -287,6 +287,7 @@ fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
 pub fn provide(providers: &mut Providers) {
     collect::provide(providers);
+    check::provide(providers);
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 455a6a0fb32..096657a6e7a 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -909,25 +909,12 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
 
 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum ReprAttr {
-    ReprAny,
     ReprInt(IntType),
     ReprExtern,
     ReprPacked,
     ReprSimd,
 }
 
-impl ReprAttr {
-    pub fn is_ffi_safe(&self) -> bool {
-        match *self {
-            ReprAny => false,
-            ReprInt(ity) => ity.is_ffi_safe(),
-            ReprExtern => true,
-            ReprPacked => false,
-            ReprSimd => true,
-        }
-    }
-}
-
 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum IntType {
     SignedInt(ast::IntTy),
@@ -942,16 +929,6 @@ impl IntType {
             UnsignedInt(..) => false
         }
     }
-    fn is_ffi_safe(self) -> bool {
-        match self {
-            SignedInt(ast::IntTy::I8) | UnsignedInt(ast::UintTy::U8) |
-            SignedInt(ast::IntTy::I16) | UnsignedInt(ast::UintTy::U16) |
-            SignedInt(ast::IntTy::I32) | UnsignedInt(ast::UintTy::U32) |
-            SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) |
-            SignedInt(ast::IntTy::I128) | UnsignedInt(ast::UintTy::U128) => true,
-            SignedInt(ast::IntTy::Is) | UnsignedInt(ast::UintTy::Us) => false
-        }
-    }
 }
 
 pub trait HasAttrs: Sized {
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index ce64aef516f..fe492bd7fc8 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
     for a in type_attrs {
         for r in &attr::find_repr_attrs(diagnostic, a) {
             repr_type_name = match *r {
-                attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue,
+                attr::ReprPacked | attr::ReprSimd => continue,
                 attr::ReprExtern => "i32",
 
                 attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",
diff --git a/src/test/compile-fail/cycle-trait-default-type-trait.rs b/src/test/compile-fail/cycle-trait-default-type-trait.rs
index 6825572b26c..e6caeb34a8c 100644
--- a/src/test/compile-fail/cycle-trait-default-type-trait.rs
+++ b/src/test/compile-fail/cycle-trait-default-type-trait.rs
@@ -13,7 +13,6 @@
 
 trait Foo<X = Box<Foo>> {
     //~^ ERROR unsupported cyclic reference
-    //~| ERROR unsupported cyclic reference
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/impl-trait/auto-trait-leak.rs b/src/test/compile-fail/impl-trait/auto-trait-leak.rs
index f055d20e134..13e53cab172 100644
--- a/src/test/compile-fail/impl-trait/auto-trait-leak.rs
+++ b/src/test/compile-fail/impl-trait/auto-trait-leak.rs
@@ -52,23 +52,20 @@ fn after() -> impl Fn(i32) {
 // independently resolved and only require the concrete
 // return type, which can't depend on the obligation.
 fn cycle1() -> impl Clone {
+    //~^ ERROR unsupported cyclic reference between types/traits detected
+    //~| cyclic reference
+    //~| NOTE the cycle begins when processing `cycle1`...
+    //~| NOTE ...which then requires processing `cycle1::{{impl-Trait}}`...
+    //~| NOTE ...which then again requires processing `cycle1`, completing the cycle.
     send(cycle2().clone());
-    //~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
-    //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
-    //~| NOTE `std::rc::Rc<std::string::String>` cannot be sent between threads safely
-    //~| NOTE required because it appears within the type `impl std::clone::Clone`
-    //~| NOTE required by `send`
 
     Rc::new(Cell::new(5))
 }
 
 fn cycle2() -> impl Clone {
+    //~^ NOTE ...which then requires processing `cycle2::{{impl-Trait}}`...
+    //~| NOTE ...which then requires processing `cycle2`...
     send(cycle1().clone());
-    //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
-    //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
-    //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
-    //~| NOTE required because it appears within the type `impl std::clone::Clone`
-    //~| NOTE required by `send`
 
     Rc::new(String::from("foo"))
 }
diff --git a/src/test/compile-fail/impl-trait/equality.rs b/src/test/compile-fail/impl-trait/equality.rs
index 59ad1132b35..36df4f0eb4d 100644
--- a/src/test/compile-fail/impl-trait/equality.rs
+++ b/src/test/compile-fail/impl-trait/equality.rs
@@ -49,17 +49,6 @@ impl Leak for i32 {
     fn leak(self) -> i32 { self }
 }
 
-trait CheckIfSend: Sized {
-    type T: Default;
-    fn check(self) -> Self::T { Default::default() }
-}
-impl<T> CheckIfSend for T {
-    default type T = ();
-}
-impl<T: Send> CheckIfSend for T {
-    type T = bool;
-}
-
 fn main() {
     let _: u32 = hide(0_u32);
     //~^ ERROR mismatched types
@@ -73,12 +62,6 @@ fn main() {
     //~| found type `<impl Foo as Leak>::T`
     //~| expected i32, found associated type
 
-    let _: bool = CheckIfSend::check(hide(0_i32));
-    //~^ ERROR mismatched types
-    //~| expected type `bool`
-    //~| found type `<impl Foo as CheckIfSend>::T`
-    //~| expected bool, found associated type
-
     let mut x = (hide(0_u32), hide(0_i32));
     x = (x.1,
     //~^ ERROR mismatched types
diff --git a/src/test/compile-fail/resolve-self-in-impl.rs b/src/test/compile-fail/resolve-self-in-impl.rs
index 7a5ef3540e9..710d8e11ff0 100644
--- a/src/test/compile-fail/resolve-self-in-impl.rs
+++ b/src/test/compile-fail/resolve-self-in-impl.rs
@@ -26,6 +26,6 @@ impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits
 impl Tr for S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
 impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected
 impl S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
-impl Tr<Self::A> for S {} //~ ERROR `Self` type is used before it's determined
+impl Tr<Self::A> for S {} //~ ERROR unsupported cyclic reference between types/traits detected
 
 fn main() {}
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index da3a953d11e..048ccb529a2 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -112,10 +112,13 @@ enum EnumChangeValueCStyleVariant0 {
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_dirty(label="HirBody", cfg="cfail2")]
 #[rustc_clean(label="HirBody", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant0 {
     Variant1,
+
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     Variant2 = 22,
 }
 
diff --git a/src/test/run-pass/impl-trait/auto-trait-leak.rs b/src/test/run-pass/impl-trait/auto-trait-leak.rs
index c1201e7fa4f..011d910c5a5 100644
--- a/src/test/run-pass/impl-trait/auto-trait-leak.rs
+++ b/src/test/run-pass/impl-trait/auto-trait-leak.rs
@@ -29,16 +29,3 @@ fn after() -> impl FnMut(i32) {
     let mut p = Box::new(0);
     move |x| *p = x
 }
-
-// Cycles should work as the deferred obligations are
-// independently resolved and only require the concrete
-// return type, which can't depend on the obligation.
-fn cycle1() -> impl Clone {
-    send(cycle2().clone());
-    5
-}
-
-fn cycle2() -> impl Clone {
-    send(cycle1().clone());
-    String::from("foo")
-}
diff --git a/src/test/run-pass/impl-trait/equality.rs b/src/test/run-pass/impl-trait/equality.rs
index 72b0e588ff4..ceed454e5ad 100644
--- a/src/test/run-pass/impl-trait/equality.rs
+++ b/src/test/run-pass/impl-trait/equality.rs
@@ -28,6 +28,17 @@ impl<T> Leak<T> for T {
     fn leak(self) -> T { self }
 }
 
+trait CheckIfSend: Sized {
+    type T: Default;
+    fn check(self) -> Self::T { Default::default() }
+}
+impl<T> CheckIfSend for T {
+    default type T = ();
+}
+impl<T: Send> CheckIfSend for T {
+    type T = bool;
+}
+
 fn lucky_seven() -> impl Fn(usize) -> u8 {
     let a = [1, 2, 3, 4, 5, 6, 7];
     move |i| a[i]
@@ -40,4 +51,6 @@ fn main() {
     assert_eq!(std::mem::size_of_val(&lucky_seven()), 7);
 
     assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32);
+
+    assert_eq!(CheckIfSend::check(hide(0_i32)), false);
 }