about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/error_reporting.rs2
-rw-r--r--src/librustc/infer/mod.rs44
-rw-r--r--src/librustc/middle/cstore.rs16
-rw-r--r--src/librustc/middle/dead.rs25
-rw-r--r--src/librustc/mir/repr.rs9
-rw-r--r--src/librustc/traits/error_reporting.rs4
-rw-r--r--src/librustc/traits/fulfill.rs3
-rw-r--r--src/librustc/traits/mod.rs4
-rw-r--r--src/librustc/traits/object_safety.rs19
-rw-r--r--src/librustc/traits/select.rs49
-rw-r--r--src/librustc/traits/specialize/mod.rs13
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs19
-rw-r--r--src/librustc/traits/util.rs22
-rw-r--r--src/librustc/ty/context.rs14
-rw-r--r--src/librustc/ty/flags.rs4
-rw-r--r--src/librustc/ty/fold.rs6
-rw-r--r--src/librustc/ty/maps.rs5
-rw-r--r--src/librustc/ty/mod.rs170
-rw-r--r--src/librustc/ty/relate.rs114
-rw-r--r--src/librustc/ty/structural_impls.rs26
-rw-r--r--src/librustc/ty/sty.rs32
-rw-r--r--src/librustc/ty/subst.rs347
-rw-r--r--src/librustc/ty/trait_def.rs4
-rw-r--r--src/librustc/ty/util.rs9
-rw-r--r--src/librustc/util/ppaux.rs128
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs5
-rw-r--r--src/librustc_const_eval/eval.rs16
-rw-r--r--src/librustc_driver/test.rs14
-rw-r--r--src/librustc_lint/builtin.rs11
-rw-r--r--src/librustc_metadata/astencode.rs18
-rw-r--r--src/librustc_metadata/common.rs13
-rw-r--r--src/librustc_metadata/csearch.rs15
-rw-r--r--src/librustc_metadata/decoder.rs80
-rw-r--r--src/librustc_metadata/encoder.rs55
-rw-r--r--src/librustc_metadata/tls_context.rs2
-rw-r--r--src/librustc_metadata/tydecode.rs53
-rw-r--r--src/librustc_metadata/tyencode.rs27
-rw-r--r--src/librustc_mir/build/scope.rs2
-rw-r--r--src/librustc_mir/hair/cx/mod.rs6
-rw-r--r--src/librustc_save_analysis/lib.rs3
-rw-r--r--src/librustc_trans/_match.rs2
-rw-r--r--src/librustc_trans/adt.rs4
-rw-r--r--src/librustc_trans/base.rs10
-rw-r--r--src/librustc_trans/callee.rs26
-rw-r--r--src/librustc_trans/collector.rs51
-rw-r--r--src/librustc_trans/common.rs4
-rw-r--r--src/librustc_trans/consts.rs8
-rw-r--r--src/librustc_trans/context.rs20
-rw-r--r--src/librustc_trans/controlflow.rs4
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs8
-rw-r--r--src/librustc_trans/debuginfo/mod.rs2
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs4
-rw-r--r--src/librustc_trans/expr.rs2
-rw-r--r--src/librustc_trans/glue.rs4
-rw-r--r--src/librustc_trans/intrinsic.rs5
-rw-r--r--src/librustc_trans/meth.rs27
-rw-r--r--src/librustc_trans/mir/constant.rs9
-rw-r--r--src/librustc_trans/monomorphize.rs5
-rw-r--r--src/librustc_trans/partitioning.rs4
-rw-r--r--src/librustc_trans/trans_item.rs7
-rw-r--r--src/librustc_trans/type_of.rs5
-rw-r--r--src/librustc_typeck/astconv.rs46
-rw-r--r--src/librustc_typeck/check/_match.rs19
-rw-r--r--src/librustc_typeck/check/autoderef.rs2
-rw-r--r--src/librustc_typeck/check/compare_method.rs20
-rw-r--r--src/librustc_typeck/check/dropck.rs17
-rw-r--r--src/librustc_typeck/check/intrinsic.rs8
-rw-r--r--src/librustc_typeck/check/method/confirm.rs31
-rw-r--r--src/librustc_typeck/check/method/mod.rs6
-rw-r--r--src/librustc_typeck/check/method/probe.rs59
-rw-r--r--src/librustc_typeck/check/method/suggest.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs120
-rw-r--r--src/librustc_typeck/check/writeback.rs41
-rw-r--r--src/librustc_typeck/collect.rs662
-rw-r--r--src/librustc_typeck/lib.rs4
-rw-r--r--src/librustc_typeck/rscope.rs31
-rw-r--r--src/librustc_typeck/variance/constraints.rs9
-rw-r--r--src/librustc_typeck/variance/solve.rs30
-rw-r--r--src/librustdoc/clean/inline.rs20
-rw-r--r--src/librustdoc/clean/mod.rs24
80 files changed, 1226 insertions, 1548 deletions
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index b0dec3277a9..21fccd2c613 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1366,7 +1366,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
                 hir::TyPath(ref maybe_qself, ref path) => {
                     match self.tcx.expect_def(cur_ty.id) {
                         Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
-                            let generics = self.tcx.lookup_item_type(did).generics;
+                            let generics = self.tcx.lookup_generics(did);
 
                             let expected =
                                 generics.regions.len(subst::TypeSpace) as u32;
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 1e360cd43da..1b65b5dae07 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -25,9 +25,7 @@ use middle::mem_categorization as mc;
 use middle::mem_categorization::McResult;
 use middle::region::CodeExtent;
 use mir::tcx::LvalueTy;
-use ty::subst;
-use ty::subst::Substs;
-use ty::subst::Subst;
+use ty::subst::{Subst, Substs};
 use ty::adjustment;
 use ty::{TyVid, IntVid, FloatVid};
 use ty::{self, Ty, TyCtxt};
@@ -1236,43 +1234,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
     /// type/region parameter to a fresh inference variable.
-    pub fn fresh_substs_for_generics(&self,
-                                     span: Span,
-                                     generics: &ty::Generics<'tcx>)
-                                     -> &'tcx subst::Substs<'tcx>
-    {
-        let substs = Substs::from_generics(generics, |def, _| {
+    pub fn fresh_substs_for_item(&self,
+                                 span: Span,
+                                 def_id: DefId)
+                                 -> &'tcx Substs<'tcx> {
+        Substs::for_item(self.tcx, def_id, |def, _| {
             self.region_var_for_def(span, def)
         }, |def, substs| {
             self.type_var_for_def(span, def, substs)
-        });
-
-        self.tcx.mk_substs(substs)
-    }
-
-    /// Given a set of generics defined on a trait, returns a substitution mapping each output
-    /// type/region parameter to a fresh inference variable, and mapping the self type to
-    /// `self_ty`.
-    pub fn fresh_substs_for_trait(&self,
-                                  span: Span,
-                                  generics: &ty::Generics<'tcx>,
-                                  self_ty: Ty<'tcx>)
-                                  -> &'tcx subst::Substs<'tcx>
-    {
-        assert!(generics.types.len(subst::SelfSpace) == 1);
-        assert!(generics.types.len(subst::FnSpace) == 0);
-
-        let substs = Substs::from_generics(generics, |def, _| {
-            self.region_var_for_def(span, def)
-        }, |def, substs| {
-            if def.space == subst::SelfSpace {
-                self_ty
-            } else {
-                self.type_var_for_def(span, def, substs)
-            }
-        });
-
-        self.tcx.mk_substs(substs)
+        })
     }
 
     pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 481fd332404..abb22783ddc 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -154,7 +154,7 @@ pub trait CrateStore<'tcx> {
     fn item_variances(&self, def: DefId) -> ty::ItemVariances;
     fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> ty::TypeScheme<'tcx>;
+                     -> Ty<'tcx>;
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
     fn item_name(&self, def: DefId) -> ast::Name;
     fn opt_item_name(&self, def: DefId) -> Option<ast::Name>;
@@ -162,6 +162,8 @@ pub trait CrateStore<'tcx> {
                            -> ty::GenericPredicates<'tcx>;
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx>;
+    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                         -> &'tcx ty::Generics<'tcx>;
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>;
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>;
@@ -187,8 +189,7 @@ pub trait CrateStore<'tcx> {
     fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
 
     // trait/impl-item info
-    fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                         -> Option<DefId>;
+    fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
     fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                               -> Option<ty::ImplOrTraitItem<'tcx>>;
 
@@ -334,7 +335,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn item_variances(&self, def: DefId) -> ty::ItemVariances { bug!("item_variances") }
     fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { bug!("repr_attrs") }
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> ty::TypeScheme<'tcx> { bug!("item_type") }
+                     -> Ty<'tcx> { bug!("item_type") }
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
         bug!("visible_parent_map")
     }
@@ -344,6 +345,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
                            -> ty::GenericPredicates<'tcx> { bug!("item_predicates") }
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
+    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                         -> &'tcx ty::Generics<'tcx> { bug!("item_generics") }
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>
         { bug!("trait_def") }
@@ -379,8 +382,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
 
     // trait/impl-item info
-    fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                         -> Option<DefId> { bug!("trait_of_item") }
+    fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
     fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                               -> Option<ty::ImplOrTraitItem<'tcx>> { bug!("impl_or_trait_item") }
 
@@ -583,7 +585,7 @@ pub mod tls {
     pub trait DecodingContext<'tcx> {
         fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
         fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx>;
-        fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> Substs<'tcx>;
+        fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx>;
         fn translate_def_id(&self, def_id: DefId) -> DefId;
     }
 
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 2b59e603cc8..7412b5fc804 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -18,7 +18,7 @@ use hir::{self, pat_util, PatKind};
 use hir::intravisit::{self, Visitor};
 
 use middle::privacy;
-use ty::{self, TyCtxt};
+use ty::{self, subst, TyCtxt};
 use hir::def::Def;
 use hir::def_id::{DefId};
 use lint;
@@ -88,15 +88,24 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     fn lookup_and_handle_definition(&mut self, id: ast::NodeId) {
         use ty::TypeVariants::{TyEnum, TyStruct};
 
+        let def = self.tcx.expect_def(id);
+
         // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar`
-        self.tcx.tables.borrow().item_substs.get(&id)
-            .and_then(|substs| substs.substs.self_ty())
-            .map(|ty| match ty.sty {
-                TyEnum(tyid, _) | TyStruct(tyid, _) => self.check_def_id(tyid.did),
-                _ => (),
-            });
+        match def {
+            Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_)
+            if self.tcx.trait_of_item(def.def_id()).is_some() => {
+                if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) {
+                    match substs.substs.types.get(subst::SelfSpace, 0).sty {
+                        TyEnum(tyid, _) | TyStruct(tyid, _) => {
+                            self.check_def_id(tyid.did)
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            _ => {}
+        }
 
-        let def = self.tcx.expect_def(id);
         match def {
             Def::Const(_) | Def::AssociatedConst(..) => {
                 self.check_def_id(def.def_id());
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 2bde3d6554f..f511d820fac 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -1073,10 +1073,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         let variant_def = &adt_def.variants[variant];
 
                         ppaux::parameterized(fmt, substs, variant_def.did,
-                                             ppaux::Ns::Value, &[],
-                                             |tcx| {
-                            Some(tcx.lookup_item_type(variant_def.did).generics)
-                        })?;
+                                             ppaux::Ns::Value, &[])?;
 
                         match variant_def.kind {
                             ty::VariantKind::Unit => Ok(()),
@@ -1169,9 +1166,7 @@ impl<'tcx> Debug for Literal<'tcx> {
         use self::Literal::*;
         match *self {
             Item { def_id, substs } => {
-                ppaux::parameterized(
-                    fmt, substs, def_id, ppaux::Ns::Value, &[],
-                    |tcx| Some(tcx.lookup_item_type(def_id).generics))
+                ppaux::parameterized(fmt, substs, def_id, ppaux::Ns::Value, &[])
             }
             Value { ref value } => {
                 write!(fmt, "const ")?;
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 5d50eac1716..e67c0ba8053 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -221,9 +221,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         self.tcx.lookup_trait_def(trait_ref.def_id)
             .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| {
-                let ity = tcx.lookup_item_type(def_id);
-                let impl_substs = self.fresh_substs_for_generics(obligation.cause.span,
-                                                                 &ity.generics);
+                let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
                 let impl_trait_ref = tcx
                     .impl_trait_ref(def_id)
                     .unwrap()
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 1ee1dc50b71..3698027dca8 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -160,10 +160,9 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
             // We can resolve the `impl Trait` to its concrete type.
             if let Some(ty_scheme) = tcx.opt_lookup_item_type(def_id) {
                 let concrete_ty = ty_scheme.ty.subst(tcx, substs);
-                let concrete_substs = Substs::new_trait(vec![], vec![], concrete_ty);
                 let predicate = ty::TraitRef {
                     def_id: self.predicate.def_id(),
-                    substs: tcx.mk_substs(concrete_substs)
+                    substs: Substs::new_trait(tcx, vec![], vec![], concrete_ty)
                 }.to_predicate();
 
                 let original_obligation = Obligation::new(self.cause.clone(),
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index dc0807ba38f..b86a54f01cf 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -17,7 +17,7 @@ pub use self::ObligationCauseCode::*;
 
 use hir::def_id::DefId;
 use middle::free_region::FreeRegionMap;
-use ty::subst;
+use ty::subst::Substs;
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use infer::InferCtxt;
 
@@ -272,7 +272,7 @@ pub enum Vtable<'tcx, N> {
 #[derive(Clone, PartialEq, Eq)]
 pub struct VtableImplData<'tcx, N> {
     pub impl_def_id: DefId,
-    pub substs: &'tcx subst::Substs<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
     pub nested: Vec<N>
 }
 
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 8ddb14e08e3..ecfa7930d02 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -166,25 +166,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
-        let trait_def = self.lookup_trait_def(trait_def_id);
-        let trait_predicates = self.lookup_predicates(trait_def_id);
-        self.generics_require_sized_self(&trait_def.generics, &trait_predicates)
+        self.generics_require_sized_self(trait_def_id)
     }
 
-    fn generics_require_sized_self(self,
-                                   generics: &ty::Generics<'gcx>,
-                                   predicates: &ty::GenericPredicates<'gcx>)
-                                   -> bool
-    {
+    fn generics_require_sized_self(self, def_id: DefId) -> bool {
         let sized_def_id = match self.lang_items.sized_trait() {
             Some(def_id) => def_id,
             None => { return false; /* No Sized trait, can't require it! */ }
         };
 
         // Search for a predicate like `Self : Sized` amongst the trait bounds.
-        let free_substs = self.construct_free_substs(generics,
+        let free_substs = self.construct_free_substs(def_id,
             self.region_maps.node_extent(ast::DUMMY_NODE_ID));
-        let predicates = predicates.instantiate(self, &free_substs).predicates;
+        let predicates = self.lookup_predicates(def_id);
+        let predicates = predicates.instantiate(self, free_substs).predicates;
         elaborate_predicates(self, predicates)
             .any(|predicate| {
                 match predicate {
@@ -214,7 +209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     {
         // Any method that has a `Self : Sized` requisite is otherwise
         // exempt from the regulations.
-        if self.generics_require_sized_self(&method.generics, &method.predicates) {
+        if self.generics_require_sized_self(method.def_id) {
             return None;
         }
 
@@ -231,7 +226,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                  -> bool
     {
         // Any method that has a `Self : Sized` requisite can't be called.
-        if self.generics_require_sized_self(&method.generics, &method.predicates) {
+        if self.generics_require_sized_self(method.def_id) {
             return false;
         }
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 73108e7d37f..9099d6cd740 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -42,6 +42,7 @@ use traits;
 use ty::fast_reject;
 use ty::relate::TypeRelation;
 
+use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::snapshot_vec::{SnapshotVecDelegate, SnapshotVec};
 use std::cell::RefCell;
 use std::fmt;
@@ -1935,7 +1936,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
             // for `PhantomData<T>`, we pass `T`
             ty::TyStruct(def, substs) if def.is_phantom_data() => {
-                substs.types.get_slice(TypeSpace).to_vec()
+                substs.types.as_full_slice().to_vec()
             }
 
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
@@ -2584,17 +2585,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 } else {
                     return Err(Unimplemented);
                 };
-                let mut ty_params = vec![];
+                let mut ty_params = BitVector::new(substs_a.types.len(TypeSpace));
+                let mut found = false;
                 for ty in field.walk() {
                     if let ty::TyParam(p) = ty.sty {
                         assert!(p.space == TypeSpace);
-                        let idx = p.idx as usize;
-                        if !ty_params.contains(&idx) {
-                            ty_params.push(idx);
-                        }
+                        ty_params.insert(p.idx as usize);
+                        found = true;
                     }
                 }
-                if ty_params.is_empty() {
+                if !found {
                     return Err(Unimplemented);
                 }
 
@@ -2602,12 +2602,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 // TyError and ensure they do not affect any other fields.
                 // This could be checked after type collection for any struct
                 // with a potentially unsized trailing field.
-                let mut new_substs = substs_a.clone();
-                for &i in &ty_params {
-                    new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err;
-                }
+                let types = substs_a.types.map_enumerated(|(_, i, ty)| {
+                    if ty_params.contains(i) {
+                        tcx.types.err
+                    } else {
+                        ty
+                    }
+                });
+                let substs = Substs::new(tcx, types, substs_a.regions.clone());
                 for &ty in fields.split_last().unwrap().1 {
-                    if ty.subst(tcx, &new_substs).references_error() {
+                    if ty.subst(tcx, substs).references_error() {
                         return Err(Unimplemented);
                     }
                 }
@@ -2618,11 +2622,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
                 // Check that the source structure with the target's
                 // type parameters is a subtype of the target.
-                for &i in &ty_params {
-                    let param_b = *substs_b.types.get(TypeSpace, i);
-                    new_substs.types.get_mut_slice(TypeSpace)[i] = param_b;
-                }
-                let new_struct = tcx.mk_struct(def, tcx.mk_substs(new_substs));
+                let types = substs_a.types.map_enumerated(|(_, i, ty)| {
+                    if ty_params.contains(i) {
+                        *substs_b.types.get(TypeSpace, i)
+                    } else {
+                        ty
+                    }
+                });
+                let substs = Substs::new(tcx, types, substs_a.regions.clone());
+                let new_struct = tcx.mk_struct(def, substs);
                 let origin = TypeOrigin::Misc(obligation.cause.span);
                 let InferOk { obligations, .. } =
                     self.infcx.sub_types(false, origin, new_struct, target)
@@ -2691,12 +2699,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             snapshot);
         let skol_obligation_trait_ref = skol_obligation.trait_ref;
 
-        let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
-                                                         obligation.cause.span,
-                                                         impl_def_id);
+        let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span,
+                                                           impl_def_id);
 
         let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
-                                                  &impl_substs);
+                                                  impl_substs);
 
         let impl_trait_ref =
             project::normalize_with_depth(self,
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 38cccb9753d..42865ca927d 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -18,7 +18,7 @@
 // fits together with the rest of the trait machinery.
 
 use super::{SelectionContext, FulfillmentContext};
-use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig};
+use super::util::impl_trait_ref_and_oblig;
 
 use rustc_data_structures::fnv::FnvHashMap;
 use hir::def_id::DefId;
@@ -101,7 +101,7 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     };
 
     // directly inherent the method generics, since those do not vary across impls
-    infcx.tcx.mk_substs(target_substs.with_method_from_subst(source_substs))
+    source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
 }
 
 /// Is impl1 a specialization of impl2?
@@ -141,11 +141,8 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     // create a parameter environment corresponding to a (skolemized) instantiation of impl1
-    let scheme = tcx.lookup_item_type(impl1_def_id);
-    let predicates = tcx.lookup_predicates(impl1_def_id);
     let mut penv = tcx.construct_parameter_environment(DUMMY_SP,
-                                                       &scheme.generics,
-                                                       &predicates,
+                                                       impl1_def_id,
                                                        region::DUMMY_CODE_EXTENT);
     let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
                              .unwrap()
@@ -188,10 +185,10 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                        target_impl: DefId)
                                        -> Result<&'tcx Substs<'tcx>, ()> {
     let selcx = &mut SelectionContext::new(&infcx);
-    let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl);
+    let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
     let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx,
                                                                    target_impl,
-                                                                   &target_substs);
+                                                                   target_substs);
 
     // do the impls unify? If not, no specialization.
     if let Err(_) = infcx.eq_trait_refs(true,
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index a47cd23c64a..13193e1b2d7 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -122,19 +122,18 @@ impl<'a, 'gcx, 'tcx> Children {
                     if le == ge {
                         // overlap, but no specialization; error out
                         let trait_ref = impl_header.trait_ref.unwrap();
+                        let self_ty = trait_ref.self_ty();
                         Err(OverlapError {
                             with_impl: possible_sibling,
                             trait_desc: trait_ref.to_string(),
-                            self_desc: trait_ref.substs.self_ty().and_then(|ty| {
-                                // only report the Self type if it has at least
-                                // some outer concrete shell; otherwise, it's
-                                // not adding much information.
-                                if ty.has_concrete_skeleton() {
-                                    Some(ty.to_string())
-                                } else {
-                                    None
-                                }
-                            })
+                            // only report the Self type if it has at least
+                            // some outer concrete shell; otherwise, it's
+                            // not adding much information.
+                            self_desc: if self_ty.has_concrete_skeleton() {
+                                Some(self_ty.to_string())
+                            } else {
+                                None
+                            }
                         })
                     } else {
                         Ok((le, ge))
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 80a3ad9122b..1954ce1993c 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -9,10 +9,8 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
-use infer::InferCtxt;
 use ty::subst::{Subst, Substs};
 use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
-use syntax_pos::Span;
 use util::common::ErrorReported;
 use util::nodemap::FnvHashSet;
 
@@ -349,19 +347,6 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a,
     (impl_trait_ref, impl_obligations)
 }
 
-// determine the `self` type, using fresh variables for all variables
-// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
-// would return ($0, $1) where $0 and $1 are freshly instantiated type
-// variables.
-pub fn fresh_type_vars_for_impl<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                                span: Span,
-                                                impl_def_id: DefId)
-                                                -> &'tcx Substs<'tcx>
-{
-    let impl_generics = infcx.tcx.lookup_item_type(impl_def_id).generics;
-    infcx.fresh_substs_for_generics(span, &impl_generics)
-}
-
 /// See `super::obligations_for_generics`
 pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
                                      recursion_depth: usize,
@@ -401,7 +386,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             Ok(def_id) => {
                 Ok(ty::TraitRef {
                     def_id: def_id,
-                    substs: self.mk_substs(Substs::empty().with_self_ty(param_ty))
+                    substs: Substs::new_trait(self, vec![], vec![], param_ty)
                 })
             }
             Err(e) => {
@@ -421,7 +406,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     {
         let trait_ref = ty::TraitRef {
             def_id: trait_def_id,
-            substs: self.mk_substs(Substs::new_trait(ty_params, vec![], param_ty))
+            substs: Substs::new_trait(self, ty_params, vec![], param_ty)
         };
         predicate_for_trait_ref(cause, trait_ref, recursion_depth)
     }
@@ -509,10 +494,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             TupleArgumentsFlag::No => sig.0.inputs[0],
             TupleArgumentsFlag::Yes => self.mk_tup(sig.0.inputs.to_vec()),
         };
-        let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty);
         let trait_ref = ty::TraitRef {
             def_id: fn_trait_def_id,
-            substs: self.mk_substs(trait_substs),
+            substs: Substs::new_trait(self, vec![arguments_tuple], vec![], self_ty),
         };
         ty::Binder((trait_ref, sig.0.output))
     }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index dfb5482ad87..9356b408a51 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -63,6 +63,7 @@ pub struct CtxtArenas<'tcx> {
     layout: TypedArena<Layout>,
 
     // references
+    generics: TypedArena<ty::Generics<'tcx>>,
     trait_defs: TypedArena<ty::TraitDef<'tcx>>,
     adt_defs: TypedArena<ty::AdtDefData<'tcx, 'tcx>>,
 }
@@ -78,6 +79,7 @@ impl<'tcx> CtxtArenas<'tcx> {
             stability: TypedArena::new(),
             layout: TypedArena::new(),
 
+            generics: TypedArena::new(),
             trait_defs: TypedArena::new(),
             adt_defs: TypedArena::new()
         }
@@ -341,7 +343,8 @@ pub struct GlobalCtxt<'tcx> {
     pub adt_defs: RefCell<DepTrackingMap<maps::AdtDefs<'tcx>>>,
 
     /// Maps from the def-id of an item (trait/struct/enum/fn) to its
-    /// associated predicates.
+    /// associated generics and predicates.
+    pub generics: RefCell<DepTrackingMap<maps::Generics<'tcx>>>,
     pub predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
 
     /// Maps from the def-id of a trait to the list of
@@ -583,13 +586,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.tables.borrow_mut().node_types.insert(id, ty);
     }
 
+    pub fn alloc_generics(self, generics: ty::Generics<'gcx>)
+                          -> &'gcx ty::Generics<'gcx> {
+        self.global_interners.arenas.generics.alloc(generics)
+    }
+
     pub fn intern_trait_def(self, def: ty::TraitDef<'gcx>)
                             -> &'gcx ty::TraitDef<'gcx> {
         let did = def.trait_ref.def_id;
-        let interned = self.global_interners.arenas.trait_defs.alloc(def);
+        let interned = self.alloc_trait_def(def);
         if let Some(prev) = self.trait_defs.borrow_mut().insert(did, interned) {
             bug!("Tried to overwrite interned TraitDef: {:?}", prev)
         }
+        self.generics.borrow_mut().insert(did, interned.generics);
         interned
     }
 
@@ -711,6 +720,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            generics: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             fulfilled_predicates: RefCell::new(fulfilled_predicates),
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 6cc759c420d..312b09cd27d 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ty::subst;
+use ty::subst::{self, Substs};
 use ty::{self, Ty, TypeFlags, TypeFoldable};
 
 pub struct FlagComputation {
@@ -207,7 +207,7 @@ impl FlagComputation {
         self.add_substs(projection_ty.trait_ref.substs);
     }
 
-    fn add_substs(&mut self, substs: &subst::Substs) {
+    fn add_substs(&mut self, substs: &Substs) {
         self.add_tys(substs.types.as_full_slice());
         for &r in substs.regions.as_full_slice() {
             self.add_region(r);
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 597261cca72..2e114a801d6 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -40,7 +40,7 @@
 //! and does not need to visit anything else.
 
 use middle::region;
-use ty::subst;
+use ty::subst::Substs;
 use ty::adjustment;
 use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
 
@@ -145,8 +145,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
     }
 
     fn fold_substs(&mut self,
-                   substs: &'tcx subst::Substs<'tcx>)
-                   -> &'tcx subst::Substs<'tcx> {
+                   substs: &'tcx Substs<'tcx>)
+                   -> &'tcx Substs<'tcx> {
         substs.super_fold_with(self)
     }
 
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 57b1dd66bea..d5686906e6a 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -10,7 +10,7 @@
 
 use dep_graph::{DepNode, DepTrackingMapConfig};
 use hir::def_id::DefId;
-use ty;
+use ty::{self, Ty};
 use std::marker::PhantomData;
 use std::rc::Rc;
 use syntax::{attr, ast};
@@ -30,7 +30,8 @@ macro_rules! dep_map_ty {
 }
 
 dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> }
-dep_map_ty! { Tcache: ItemSignature(DefId) -> ty::TypeScheme<'tcx> }
+dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> }
+dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> }
 dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
 dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
 dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc<Vec<ty::ImplOrTraitItemId>> }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 6ac57a877a7..36784e40064 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -173,15 +173,14 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> {
                               -> ImplHeader<'tcx>
     {
         let tcx = selcx.tcx();
-        let impl_generics = tcx.lookup_item_type(impl_def_id).generics;
-        let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics);
+        let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
 
         let header = ImplHeader {
             impl_def_id: impl_def_id,
             self_ty: tcx.lookup_item_type(impl_def_id).ty,
             trait_ref: tcx.impl_trait_ref(impl_def_id),
             predicates: tcx.lookup_predicates(impl_def_id).predicates
-        }.subst(tcx, &impl_substs);
+        }.subst(tcx, impl_substs);
 
         let traits::Normalized { value: mut header, obligations } =
             traits::normalize(selcx, traits::ObligationCause::dummy(), &header);
@@ -348,7 +347,7 @@ impl Visibility {
 #[derive(Clone, Debug)]
 pub struct Method<'tcx> {
     pub name: Name,
-    pub generics: Generics<'tcx>,
+    pub generics: &'tcx Generics<'tcx>,
     pub predicates: GenericPredicates<'tcx>,
     pub fty: &'tcx BareFnTy<'tcx>,
     pub explicit_self: ExplicitSelfCategory,
@@ -360,7 +359,7 @@ pub struct Method<'tcx> {
 
 impl<'tcx> Method<'tcx> {
     pub fn new(name: Name,
-               generics: ty::Generics<'tcx>,
+               generics: &'tcx ty::Generics<'tcx>,
                predicates: GenericPredicates<'tcx>,
                fty: &'tcx BareFnTy<'tcx>,
                explicit_self: ExplicitSelfCategory,
@@ -453,7 +452,7 @@ pub struct MethodCallee<'tcx> {
     /// Impl method ID, for inherent methods, or trait method ID, otherwise.
     pub def_id: DefId,
     pub ty: Ty<'tcx>,
-    pub substs: &'tcx subst::Substs<'tcx>
+    pub substs: &'tcx Substs<'tcx>
 }
 
 /// With method calls, we store some extra information in
@@ -760,6 +759,7 @@ impl RegionParameterDef {
 pub struct Generics<'tcx> {
     pub types: VecPerParamSpace<TypeParameterDef<'tcx>>,
     pub regions: VecPerParamSpace<RegionParameterDef>,
+    pub has_self: bool,
 }
 
 impl<'tcx> Generics<'tcx> {
@@ -767,6 +767,7 @@ impl<'tcx> Generics<'tcx> {
         Generics {
             types: VecPerParamSpace::empty(),
             regions: VecPerParamSpace::empty(),
+            has_self: false,
         }
     }
 
@@ -1224,7 +1225,7 @@ impl<'tcx> TraitRef<'tcx> {
     }
 
     pub fn self_ty(&self) -> Ty<'tcx> {
-        self.substs.self_ty().unwrap()
+        *self.substs.types.get(subst::SelfSpace, 0)
     }
 
     pub fn input_types(&self) -> &[Ty<'tcx>] {
@@ -1298,23 +1299,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         // so for now just grab environment for the impl
                         let impl_id = tcx.map.get_parent(id);
                         let impl_def_id = tcx.map.local_def_id(impl_id);
-                        let scheme = tcx.lookup_item_type(impl_def_id);
-                        let predicates = tcx.lookup_predicates(impl_def_id);
                         tcx.construct_parameter_environment(impl_item.span,
-                                                            &scheme.generics,
-                                                            &predicates,
+                                                            impl_def_id,
                                                             tcx.region_maps.item_extent(id))
                     }
                     hir::ImplItemKind::Method(_, ref body) => {
                         let method_def_id = tcx.map.local_def_id(id);
                         match tcx.impl_or_trait_item(method_def_id) {
                             MethodTraitItem(ref method_ty) => {
-                                let method_generics = &method_ty.generics;
-                                let method_bounds = &method_ty.predicates;
                                 tcx.construct_parameter_environment(
                                     impl_item.span,
-                                    method_generics,
-                                    method_bounds,
+                                    method_ty.def_id,
                                     tcx.region_maps.call_site_extent(id, body.id))
                             }
                             _ => {
@@ -1332,11 +1327,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         // so for now just grab environment for the trait
                         let trait_id = tcx.map.get_parent(id);
                         let trait_def_id = tcx.map.local_def_id(trait_id);
-                        let trait_def = tcx.lookup_trait_def(trait_def_id);
-                        let predicates = tcx.lookup_predicates(trait_def_id);
                         tcx.construct_parameter_environment(trait_item.span,
-                                                            &trait_def.generics,
-                                                            &predicates,
+                                                            trait_def_id,
                                                             tcx.region_maps.item_extent(id))
                     }
                     hir::MethodTraitItem(_, ref body) => {
@@ -1346,8 +1338,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         let method_def_id = tcx.map.local_def_id(id);
                         match tcx.impl_or_trait_item(method_def_id) {
                             MethodTraitItem(ref method_ty) => {
-                                let method_generics = &method_ty.generics;
-                                let method_bounds = &method_ty.predicates;
                                 let extent = if let Some(ref body) = *body {
                                     // default impl: use call_site extent as free_id_outlive bound.
                                     tcx.region_maps.call_site_extent(id, body.id)
@@ -1357,8 +1347,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                                 };
                                 tcx.construct_parameter_environment(
                                     trait_item.span,
-                                    method_generics,
-                                    method_bounds,
+                                    method_ty.def_id,
                                     extent)
                             }
                             _ => {
@@ -1375,13 +1364,10 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                     hir::ItemFn(_, _, _, _, _, ref body) => {
                         // We assume this is a function.
                         let fn_def_id = tcx.map.local_def_id(id);
-                        let fn_scheme = tcx.lookup_item_type(fn_def_id);
-                        let fn_predicates = tcx.lookup_predicates(fn_def_id);
 
                         tcx.construct_parameter_environment(
                             item.span,
-                            &fn_scheme.generics,
-                            &fn_predicates,
+                            fn_def_id,
                             tcx.region_maps.call_site_extent(id, body.id))
                     }
                     hir::ItemEnum(..) |
@@ -1391,20 +1377,14 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                     hir::ItemConst(..) |
                     hir::ItemStatic(..) => {
                         let def_id = tcx.map.local_def_id(id);
-                        let scheme = tcx.lookup_item_type(def_id);
-                        let predicates = tcx.lookup_predicates(def_id);
                         tcx.construct_parameter_environment(item.span,
-                                                            &scheme.generics,
-                                                            &predicates,
+                                                            def_id,
                                                             tcx.region_maps.item_extent(id))
                     }
                     hir::ItemTrait(..) => {
                         let def_id = tcx.map.local_def_id(id);
-                        let trait_def = tcx.lookup_trait_def(def_id);
-                        let predicates = tcx.lookup_predicates(def_id);
                         tcx.construct_parameter_environment(item.span,
-                                                            &trait_def.generics,
-                                                            &predicates,
+                                                            def_id,
                                                             tcx.region_maps.item_extent(id))
                     }
                     _ => {
@@ -1425,11 +1405,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
             }
             Some(ast_map::NodeForeignItem(item)) => {
                 let def_id = tcx.map.local_def_id(id);
-                let scheme = tcx.lookup_item_type(def_id);
-                let predicates = tcx.lookup_predicates(def_id);
                 tcx.construct_parameter_environment(item.span,
-                                                    &scheme.generics,
-                                                    &predicates,
+                                                    def_id,
                                                     ROOT_CODE_EXTENT)
             }
             _ => {
@@ -1462,7 +1439,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
 /// `lookup_predicates`.
 #[derive(Clone, Debug)]
 pub struct TypeScheme<'tcx> {
-    pub generics: Generics<'tcx>,
+    pub generics: &'tcx Generics<'tcx>,
     pub ty: Ty<'tcx>,
 }
 
@@ -1917,9 +1894,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
                 };
                 let sized_predicate = Binder(TraitRef {
                     def_id: sized_trait,
-                    substs: tcx.mk_substs(Substs::new_trait(
-                        vec![], vec![], ty
-                    ))
+                    substs: Substs::new_trait(tcx, vec![], vec![], ty)
                 }).to_predicate();
                 let predicates = tcx.lookup_predicates(self.did).predicates;
                 if predicates.into_iter().any(|p| p == sized_predicate) {
@@ -2170,7 +2145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn node_id_item_substs(self, id: NodeId) -> ItemSubsts<'gcx> {
         match self.tables.borrow().item_substs.get(&id) {
             None => ItemSubsts {
-                substs: self.global_tcx().mk_substs(Substs::empty())
+                substs: Substs::empty(self.global_tcx())
             },
             Some(ts) => ts.clone(),
         }
@@ -2508,27 +2483,36 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     // Register a given item type
-    pub fn register_item_type(self, did: DefId, ty: TypeScheme<'gcx>) {
-        self.tcache.borrow_mut().insert(did, ty);
+    pub fn register_item_type(self, did: DefId, scheme: TypeScheme<'gcx>) {
+        self.tcache.borrow_mut().insert(did, scheme.ty);
+        self.generics.borrow_mut().insert(did, scheme.generics);
     }
 
     // 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 lookup_item_type(self, did: DefId) -> TypeScheme<'gcx> {
-        lookup_locally_or_in_crate_store(
+        let ty = lookup_locally_or_in_crate_store(
             "tcache", did, &self.tcache,
-            || self.sess.cstore.item_type(self.global_tcx(), did))
+            || self.sess.cstore.item_type(self.global_tcx(), did));
+
+        TypeScheme {
+            ty: ty,
+            generics: self.lookup_generics(did)
+        }
     }
 
     pub fn opt_lookup_item_type(self, did: DefId) -> Option<TypeScheme<'gcx>> {
-        if let Some(scheme) = self.tcache.borrow_mut().get(&did) {
-            return Some(scheme.clone());
+        if did.krate != LOCAL_CRATE {
+            return Some(self.lookup_item_type(did));
         }
 
-        if did.krate == LOCAL_CRATE {
-            None
+        if let Some(ty) = self.tcache.borrow().get(&did).cloned() {
+            Some(TypeScheme {
+                ty: ty,
+                generics: self.lookup_generics(did)
+            })
         } else {
-            Some(self.sess.cstore.item_type(self.global_tcx(), did))
+            None
         }
     }
 
@@ -2557,6 +2541,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.lookup_adt_def_master(did)
     }
 
+    /// Given the did of an item, returns its generics.
+    pub fn lookup_generics(self, did: DefId) -> &'gcx Generics<'gcx> {
+        lookup_locally_or_in_crate_store(
+            "generics", did, &self.generics,
+            || self.sess.cstore.item_generics(self.global_tcx(), did))
+    }
+
     /// Given the did of an item, returns its full set of predicates.
     pub fn lookup_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
         lookup_locally_or_in_crate_store(
@@ -2812,18 +2803,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// If the given def ID describes an item belonging to a trait (either a
-    /// default method or an implementation of a trait method), return the ID of
-    /// the trait that the method belongs to. Otherwise, return `None`.
+    /// If the given def ID describes an item belonging to a trait,
+    /// return the ID of the trait that the trait item belongs to.
+    /// Otherwise, return `None`.
     pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
         if def_id.krate != LOCAL_CRATE {
-            return self.sess.cstore.trait_of_item(self.global_tcx(), def_id);
+            return self.sess.cstore.trait_of_item(def_id);
         }
-        match self.impl_or_trait_items.borrow().get(&def_id).cloned() {
+        match self.impl_or_trait_items.borrow().get(&def_id) {
             Some(impl_or_trait_item) => {
                 match impl_or_trait_item.container() {
                     TraitContainer(def_id) => Some(def_id),
-                    ImplContainer(def_id) => self.trait_id_of_impl(def_id),
+                    ImplContainer(_) => None
                 }
             }
             None => None
@@ -2837,18 +2828,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// the same).
     /// Otherwise, return `None`.
     pub fn trait_item_of_item(self, def_id: DefId) -> Option<ImplOrTraitItemId> {
-        let impl_item = match self.impl_or_trait_items.borrow().get(&def_id) {
+        let impl_or_trait_item = match self.impl_or_trait_items.borrow().get(&def_id) {
             Some(m) => m.clone(),
             None => return None,
         };
-        let name = impl_item.name();
-        match self.trait_of_item(def_id) {
-            Some(trait_did) => {
-                self.trait_items(trait_did).iter()
-                    .find(|item| item.name() == name)
-                    .map(|item| item.id())
+        match impl_or_trait_item.container() {
+            TraitContainer(_) => Some(impl_or_trait_item.id()),
+            ImplContainer(def_id) => {
+                self.trait_id_of_impl(def_id).and_then(|trait_did| {
+                    let name = impl_or_trait_item.name();
+                    self.trait_items(trait_did).iter()
+                        .find(|item| item.name() == name)
+                        .map(|item| item.id())
+                })
             }
-            None => None
         }
     }
 
@@ -2860,7 +2853,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // regions, so it shouldn't matter what we use for the free id
         let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID);
         ty::ParameterEnvironment {
-            free_substs: self.mk_substs(Substs::empty()),
+            free_substs: Substs::empty(self),
             caller_bounds: Vec::new(),
             implicit_region_bound: ty::ReEmpty,
             free_id_outlive: free_id_outlive
@@ -2872,28 +2865,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// In general, this means converting from bound parameters to
     /// free parameters. Since we currently represent bound/free type
     /// parameters in the same way, this only has an effect on regions.
-    pub fn construct_free_substs(self, generics: &Generics<'gcx>,
-                                 free_id_outlive: CodeExtent) -> Substs<'gcx> {
-        // map T => T
-        let types = generics.types.map(|def| {
-            debug!("construct_parameter_environment(): push_types_from_defs: def={:?}",
-                    def);
+    pub fn construct_free_substs(self, def_id: DefId,
+                                 free_id_outlive: CodeExtent)
+                                 -> &'gcx Substs<'gcx> {
+
+        let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
+            // map bound 'a => free 'a
+            ReFree(FreeRegion { scope: free_id_outlive,
+                                bound_region: def.to_bound_region() })
+        }, |def, _| {
+            // map T => T
             self.global_tcx().mk_param_from_def(def)
         });
 
-        // map bound 'a => free 'a
-        let regions = generics.regions.map(|def| {
-            let region =
-                ReFree(FreeRegion { scope: free_id_outlive,
-                                    bound_region: def.to_bound_region() });
-            debug!("push_region_params {:?}", region);
-            region
-        });
-
-        Substs {
-            types: types,
-            regions: regions,
-        }
+        debug!("construct_parameter_environment: {:?}", substs);
+        substs
     }
 
     /// See `ParameterEnvironment` struct def'n for details.
@@ -2901,8 +2887,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// for the `free_id_outlive` parameter. (But note that that is not always quite right.)
     pub fn construct_parameter_environment(self,
                                            span: Span,
-                                           generics: &ty::Generics<'gcx>,
-                                           generic_predicates: &ty::GenericPredicates<'gcx>,
+                                           def_id: DefId,
                                            free_id_outlive: CodeExtent)
                                            -> ParameterEnvironment<'gcx>
     {
@@ -2910,14 +2895,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // Construct the free substs.
         //
 
-        let free_substs = self.construct_free_substs(generics, free_id_outlive);
+        let free_substs = self.construct_free_substs(def_id, free_id_outlive);
 
         //
         // Compute the bounds on Self and the type parameters.
         //
 
         let tcx = self.global_tcx();
-        let bounds = generic_predicates.instantiate(tcx, &free_substs);
+        let generic_predicates = tcx.lookup_predicates(def_id);
+        let bounds = generic_predicates.instantiate(tcx, free_substs);
         let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds));
         let predicates = bounds.predicates;
 
@@ -2935,7 +2921,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         //
 
         let unnormalized_env = ty::ParameterEnvironment {
-            free_substs: tcx.mk_substs(free_substs),
+            free_substs: free_substs,
             implicit_region_bound: ty::ReScope(free_id_outlive),
             caller_bounds: predicates,
             free_id_outlive: free_id_outlive,
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index aa48474e50c..388e8926403 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -14,7 +14,7 @@
 //! type equality, etc.
 
 use hir::def_id::DefId;
-use ty::subst::{ParamSpace, Substs};
+use ty::subst::Substs;
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
 use std::rc::Rc;
@@ -145,82 +145,44 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
                                         -> RelateResult<'tcx, &'tcx Substs<'tcx>>
     where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
 {
-    let mut substs = Substs::empty();
-
-    for &space in &ParamSpace::all() {
-        let a_tps = a_subst.types.get_slice(space);
-        let b_tps = b_subst.types.get_slice(space);
-        let t_variances = variances.map(|v| v.types.get_slice(space));
-        let tps = relate_type_params(relation, t_variances, a_tps, b_tps)?;
-        substs.types.replace(space, tps);
-    }
-
-    for &space in &ParamSpace::all() {
-        let a_regions = a_subst.regions.get_slice(space);
-        let b_regions = b_subst.regions.get_slice(space);
-        let r_variances = variances.map(|v| v.regions.get_slice(space));
-        let regions = relate_region_params(relation,
-                                           r_variances,
-                                           a_regions,
-                                           b_regions)?;
-        substs.regions.replace(space, regions);
-    }
-
-    Ok(relation.tcx().mk_substs(substs))
-}
-
-fn relate_type_params<'a, 'gcx, 'tcx, R>(relation: &mut R,
-                                         variances: Option<&[ty::Variance]>,
-                                         a_tys: &[Ty<'tcx>],
-                                         b_tys: &[Ty<'tcx>])
-                                         -> RelateResult<'tcx, Vec<Ty<'tcx>>>
-    where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
-{
-    if a_tys.len() != b_tys.len() {
-        return Err(TypeError::TyParamSize(expected_found(relation,
-                                                         &a_tys.len(),
-                                                         &b_tys.len())));
-    }
-
-    (0 .. a_tys.len())
-        .map(|i| {
-            let a_ty = a_tys[i];
-            let b_ty = b_tys[i];
-            let v = variances.map_or(ty::Invariant, |v| v[i]);
-            relation.relate_with_variance(v, &a_ty, &b_ty)
-        })
-        .collect()
-}
+    let tcx = relation.tcx();
+    let mut result = Ok(());
+
+    let types = a_subst.types.map_enumerated(|(space, i, a_ty)| {
+        if result.is_err() { return tcx.types.err; }
+
+        let b_ty = b_subst.types.get(space, i);
+        let variance = variances.map_or(ty::Invariant, |v| {
+            *v.types.get(space, i)
+        });
+        match relation.relate_with_variance(variance, a_ty, b_ty) {
+            Ok(ty) => ty,
+            Err(e) => {
+                result = Err(e);
+                tcx.types.err
+            }
+        }
+    });
+    result?;
+
+    let regions = a_subst.regions.map_enumerated(|(space, i, a_r)| {
+        if result.is_err() { return ty::ReStatic; }
+
+        let b_r = b_subst.regions.get(space, i);
+        let variance = variances.map_or(ty::Invariant, |v| {
+            *v.regions.get(space, i)
+        });
+        match relation.relate_with_variance(variance, a_r, b_r) {
+            Ok(r) => r,
+            Err(e) => {
+                result = Err(e);
+                ty::ReStatic
+            }
+        }
+    });
+    result?;
 
-fn relate_region_params<'a, 'gcx, 'tcx, R>(relation: &mut R,
-                                           variances: Option<&[ty::Variance]>,
-                                           a_rs: &[ty::Region],
-                                           b_rs: &[ty::Region])
-                                           -> RelateResult<'tcx, Vec<ty::Region>>
-    where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
-{
-    let num_region_params = a_rs.len();
-
-    debug!("relate_region_params(a_rs={:?}, \
-            b_rs={:?}, variances={:?})",
-           a_rs,
-           b_rs,
-           variances);
-
-    assert_eq!(num_region_params,
-               variances.map_or(num_region_params,
-                                |v| v.len()));
-
-    assert_eq!(num_region_params, b_rs.len());
-
-    (0..a_rs.len())
-        .map(|i| {
-            let a_r = a_rs[i];
-            let b_r = b_rs[i];
-            let variance = variances.map_or(ty::Invariant, |v| v[i]);
-            relation.relate_with_variance(variance, &a_r, &b_r)
-        })
-        .collect()
+    Ok(Substs::new(tcx, types, regions))
 }
 
 impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 14005c1bd8b..9021b0587a0 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use infer::type_variable;
-use ty::subst::{self, VecPerParamSpace};
+use ty::subst::{Substs, VecPerParamSpace};
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
@@ -702,13 +702,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx subst::Substs<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let substs = subst::Substs {
-            regions: self.regions.fold_with(folder),
-            types: self.types.fold_with(folder)
-        };
-        folder.tcx().mk_substs(substs)
+        let types = self.types.fold_with(folder);
+        let regions = self.regions.fold_with(folder);
+        Substs::new(folder.tcx(), types, regions)
     }
 
     fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
@@ -839,6 +837,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
         ty::Generics {
             types: self.types.fold_with(folder),
             regions: self.regions.fold_with(folder),
+            has_self: self.has_self
         }
     }
 
@@ -1018,19 +1017,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx>  {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::TypeScheme {
-            generics: self.generics.fold_with(folder),
-            ty: self.ty.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.generics.visit_with(visitor) || self.ty.visit_with(visitor)
-    }
-}
-
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::error::ExpectedFound {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 91214873f19..f31b844f04f 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -359,18 +359,7 @@ pub struct ExistentialTraitRef<'tcx> {
     pub substs: &'tcx Substs<'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> {
-    pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                         trait_ref: ty::TraitRef<'tcx>)
-                         -> ty::ExistentialTraitRef<'tcx> {
-        let mut substs = trait_ref.substs.clone();
-        substs.types.pop(subst::SelfSpace);
-        ty::ExistentialTraitRef {
-            def_id: trait_ref.def_id,
-            substs: tcx.mk_substs(substs)
-        }
-    }
-
+impl<'tcx> ExistentialTraitRef<'tcx> {
     pub fn input_types(&self) -> &[Ty<'tcx>] {
         // Select only the "input types" from a trait-reference. For
         // now this is all the types that appear in the
@@ -382,7 +371,7 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> {
 
 pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>;
 
-impl<'a, 'gcx, 'tcx> PolyExistentialTraitRef<'tcx> {
+impl<'tcx> PolyExistentialTraitRef<'tcx> {
     pub fn def_id(&self) -> DefId {
         self.0.def_id
     }
@@ -391,23 +380,6 @@ impl<'a, 'gcx, 'tcx> PolyExistentialTraitRef<'tcx> {
         // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
         self.0.input_types()
     }
-
-    /// Object types don't have a self-type specified. Therefore, when
-    /// we convert the principal trait-ref into a normal trait-ref,
-    /// you must give *some* self-type. A common choice is `mk_err()`
-    /// or some skolemized type.
-    pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                        self_ty: Ty<'tcx>)
-                        -> ty::PolyTraitRef<'tcx>
-    {
-        // otherwise the escaping regions would be captured by the binder
-        assert!(!self_ty.has_escaping_regions());
-
-        self.map_bound(|trait_ref| TraitRef {
-            def_id: trait_ref.def_id,
-            substs: tcx.mk_substs(trait_ref.substs.with_self_ty(self_ty)),
-        })
-    }
 }
 
 /// Binder is a binder for higher-ranked lifetimes. It is part of the
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 34e7899e2fd..00537f9d6c5 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -34,43 +34,45 @@ pub struct Substs<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> Substs<'tcx> {
-    pub fn new(t: VecPerParamSpace<Ty<'tcx>>,
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+               t: VecPerParamSpace<Ty<'tcx>>,
                r: VecPerParamSpace<ty::Region>)
-               -> Substs<'tcx>
+               -> &'tcx Substs<'tcx>
     {
-        Substs { types: t, regions: r }
+        tcx.mk_substs(Substs { types: t, regions: r })
     }
 
-    pub fn new_fn(t: Vec<Ty<'tcx>>,
+    pub fn new_fn(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                  t: Vec<Ty<'tcx>>,
                   r: Vec<ty::Region>)
-                  -> Substs<'tcx>
+                  -> &'tcx Substs<'tcx>
     {
-        Substs::new(VecPerParamSpace::new(vec![], vec![], t),
+        Substs::new(tcx, VecPerParamSpace::new(vec![], vec![], t),
                     VecPerParamSpace::new(vec![], vec![], r))
     }
 
-    pub fn new_type(t: Vec<Ty<'tcx>>,
+    pub fn new_type(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                    t: Vec<Ty<'tcx>>,
                     r: Vec<ty::Region>)
-                    -> Substs<'tcx>
+                    -> &'tcx Substs<'tcx>
     {
-        Substs::new(VecPerParamSpace::new(vec![], t, vec![]),
+        Substs::new(tcx, VecPerParamSpace::new(vec![], t, vec![]),
                     VecPerParamSpace::new(vec![], r, vec![]))
     }
 
-    pub fn new_trait(t: Vec<Ty<'tcx>>,
+    pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                     t: Vec<Ty<'tcx>>,
                      r: Vec<ty::Region>,
                      s: Ty<'tcx>)
-                    -> Substs<'tcx>
+                    -> &'tcx Substs<'tcx>
     {
-        Substs::new(VecPerParamSpace::new(vec![s], t, vec![]),
+        Substs::new(tcx, VecPerParamSpace::new(vec![s], t, vec![]),
                     VecPerParamSpace::new(vec![], r, vec![]))
     }
 
-    pub fn empty() -> Substs<'tcx> {
-        Substs {
-            types: VecPerParamSpace::empty(),
-            regions: VecPerParamSpace::empty(),
-        }
+    pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
+        Substs::new(tcx, VecPerParamSpace::empty(),
+                    VecPerParamSpace::empty())
     }
 
     /// Creates a Substs for generic parameter definitions,
@@ -78,26 +80,57 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     /// The closures get to observe the Substs as they're
     /// being built, which can be used to correctly
     /// substitute defaults of type parameters.
-    pub fn from_generics<FR, FT>(generics: &ty::Generics<'tcx>,
-                                 mut mk_region: FR,
-                                 mut mk_type: FT)
-                                 -> Substs<'tcx>
+    pub fn for_item<FR, FT>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                            def_id: DefId,
+                            mut mk_region: FR,
+                            mut mk_type: FT)
+                            -> &'tcx Substs<'tcx>
     where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
           FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
-        let mut substs = Substs::empty();
+        let defs = tcx.lookup_generics(def_id);
+        let mut substs = Substs {
+            types: VecPerParamSpace {
+                self_limit: 0,
+                type_limit: 0,
+                content: Vec::with_capacity(defs.types.content.len())
+            },
+            regions: VecPerParamSpace {
+                self_limit: 0,
+                type_limit: 0,
+                content: Vec::with_capacity(defs.regions.content.len())
+            }
+        };
+
         for &space in &ParamSpace::all() {
-            for def in generics.regions.get_slice(space) {
+            for def in defs.regions.get_slice(space) {
+                assert_eq!(def.space, space);
+                assert!(space != SelfSpace);
+
                 let region = mk_region(def, &substs);
-                assert_eq!(substs.regions.len(def.space), def.index as usize);
-                substs.regions.push(def.space, region);
+                substs.regions.content.push(region);
+
+                if space == TypeSpace {
+                    substs.regions.type_limit += 1;
+                }
             }
-            for def in generics.types.get_slice(space) {
+
+            for def in defs.types.get_slice(space) {
+                assert_eq!(def.space, space);
+
                 let ty = mk_type(def, &substs);
-                assert_eq!(substs.types.len(def.space), def.index as usize);
-                substs.types.push(def.space, ty);
+                substs.types.content.push(ty);
+
+                if space == SelfSpace {
+                    substs.types.self_limit += 1;
+                }
+
+                if space <= TypeSpace {
+                    substs.types.type_limit += 1;
+                }
             }
         }
-        substs
+
+        Substs::new(tcx, substs.types, substs.regions)
     }
 
     pub fn is_noop(&self) -> bool {
@@ -112,66 +145,32 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         *self.regions.get(def.space, def.index as usize)
     }
 
-    pub fn self_ty(&self) -> Option<Ty<'tcx>> {
-        self.types.get_self().cloned()
-    }
-
-    pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> {
-        assert!(self.self_ty().is_none());
-        let mut s = (*self).clone();
-        s.types.push(SelfSpace, self_ty);
-        s
-    }
-
-    pub fn erase_regions(self) -> Substs<'tcx> {
-        let Substs { types, regions } = self;
-        let regions = regions.map(|_| ty::ReErased);
-        Substs { types: types, regions: regions }
-    }
-
-    pub fn with_method(self,
-                       m_types: Vec<Ty<'tcx>>,
-                       m_regions: Vec<ty::Region>)
-                       -> Substs<'tcx>
-    {
-        let Substs { types, regions } = self;
-        let types = types.with_slice(FnSpace, &m_types);
-        let regions = regions.with_slice(FnSpace, &m_regions);
-        Substs { types: types, regions: regions }
-    }
-
-    pub fn with_method_from(&self,
-                            meth_substs: &Substs<'tcx>)
-                            -> Substs<'tcx>
-    {
-        let Substs { types, regions } = self.clone();
-        let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
-        let regions = regions.with_slice(FnSpace, meth_substs.regions.get_slice(FnSpace));
-        Substs { types: types, regions: regions }
-    }
-
-    pub fn with_method_from_subst(&self, other: &Substs<'tcx>) -> Substs<'tcx> {
-        let Substs { types, regions } = self.clone();
-        let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace));
-        let regions = regions.with_slice(FnSpace, other.regions.get_slice(FnSpace));
-        Substs { types: types, regions: regions }
-    }
-
-    /// Creates a trait-ref out of this substs, ignoring the FnSpace substs
-    pub fn to_trait_ref(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_id: DefId)
-                        -> ty::TraitRef<'tcx> {
-        let Substs { mut types, mut regions } = self.clone();
-        types.truncate(FnSpace, 0);
-        regions.truncate(FnSpace, 0);
-
-        ty::TraitRef {
-            def_id: trait_id,
-            substs: tcx.mk_substs(Substs { types: types, regions: regions })
-        }
+    /// Transform from substitutions for a child of `source_ancestor`
+    /// (e.g. a trait or impl) to substitutions for the same child
+    /// in a different item, with `target_substs` as the base for
+    /// the target impl/trait, with the source child-specific
+    /// parameters (e.g. method parameters) on top of that base.
+    pub fn rebase_onto(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                       source_ancestor: DefId,
+                       target_substs: &Substs<'tcx>)
+                       -> &'tcx Substs<'tcx> {
+        let defs = tcx.lookup_generics(source_ancestor);
+        assert_eq!(self.types.len(SelfSpace), defs.types.len(SelfSpace));
+        assert_eq!(self.types.len(TypeSpace), defs.types.len(TypeSpace));
+        assert_eq!(target_substs.types.len(FnSpace), 0);
+        assert_eq!(defs.types.len(FnSpace), 0);
+        assert_eq!(self.regions.len(TypeSpace), defs.regions.len(TypeSpace));
+        assert_eq!(target_substs.regions.len(FnSpace), 0);
+        assert_eq!(defs.regions.len(FnSpace), 0);
+
+        let Substs { mut types, mut regions } = target_substs.clone();
+        types.content.extend(&self.types.as_full_slice()[defs.types.content.len()..]);
+        regions.content.extend(&self.regions.as_full_slice()[defs.regions.content.len()..]);
+        Substs::new(tcx, types, regions)
     }
 }
 
-impl<'tcx> Encodable for Substs<'tcx> {
+impl<'tcx> Encodable for &'tcx Substs<'tcx> {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
             ecx.encode_substs(rbml_w, self);
@@ -180,19 +179,10 @@ impl<'tcx> Encodable for Substs<'tcx> {
     }
 }
 
-impl<'tcx> Decodable for Substs<'tcx> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Substs<'tcx>, D::Error> {
-        cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
-            Ok(dcx.decode_substs(rbml_r))
-        })
-    }
-}
-
 impl<'tcx> Decodable for &'tcx Substs<'tcx> {
     fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> {
         let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
-            let substs = dcx.decode_substs(rbml_r);
-            dcx.tcx().mk_substs(substs)
+            dcx.decode_substs(rbml_r)
         });
 
         Ok(substs)
@@ -307,70 +297,6 @@ impl<T> VecPerParamSpace<T> {
         }
     }
 
-    /// Appends `value` to the vector associated with `space`.
-    ///
-    /// Unlike the `push` method in `Vec`, this should not be assumed
-    /// to be a cheap operation (even when amortized over many calls).
-    pub fn push(&mut self, space: ParamSpace, value: T) {
-        let (_, limit) = self.limits(space);
-        match space {
-            SelfSpace => { self.type_limit += 1; self.self_limit += 1; }
-            TypeSpace => { self.type_limit += 1; }
-            FnSpace => { }
-        }
-        self.content.insert(limit, value);
-    }
-
-    /// Appends `values` to the vector associated with `space`.
-    ///
-    /// Unlike the `extend` method in `Vec`, this should not be assumed
-    /// to be a cheap operation (even when amortized over many calls).
-    pub fn extend<I:Iterator<Item=T>>(&mut self, space: ParamSpace, values: I) {
-        // This could be made more efficient, obviously.
-        for item in values {
-            self.push(space, item);
-        }
-    }
-
-    pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
-        let (start, limit) = self.limits(space);
-        if start == limit {
-            None
-        } else {
-            match space {
-                SelfSpace => { self.type_limit -= 1; self.self_limit -= 1; }
-                TypeSpace => { self.type_limit -= 1; }
-                FnSpace => {}
-            }
-            if self.content.is_empty() {
-                None
-            } else {
-                Some(self.content.remove(limit - 1))
-            }
-        }
-    }
-
-    pub fn truncate(&mut self, space: ParamSpace, len: usize) {
-        // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
-        while self.len(space) > len {
-            self.pop(space);
-        }
-    }
-
-    pub fn replace(&mut self, space: ParamSpace, elems: Vec<T>) {
-        // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
-        self.truncate(space, 0);
-        for t in elems {
-            self.push(space, t);
-        }
-    }
-
-    pub fn get_self<'a>(&'a self) -> Option<&'a T> {
-        let v = self.get_slice(SelfSpace);
-        assert!(v.len() <= 1);
-        if v.is_empty() { None } else { Some(&v[0]) }
-    }
-
     pub fn len(&self, space: ParamSpace) -> usize {
         self.get_slice(space).len()
     }
@@ -384,19 +310,6 @@ impl<T> VecPerParamSpace<T> {
         &self.content[start.. limit]
     }
 
-    pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] {
-        let (start, limit) = self.limits(space);
-        &mut self.content[start.. limit]
-    }
-
-    pub fn opt_get<'a>(&'a self,
-                       space: ParamSpace,
-                       index: usize)
-                       -> Option<&'a T> {
-        let v = self.get_slice(space);
-        if index < v.len() { Some(&v[index]) } else { None }
-    }
-
     pub fn get<'a>(&'a self, space: ParamSpace, index: usize) -> &'a T {
         &self.get_slice(space)[index]
     }
@@ -409,12 +322,6 @@ impl<T> VecPerParamSpace<T> {
         &self.content
     }
 
-    pub fn all_vecs<P>(&self, mut pred: P) -> bool where
-        P: FnMut(&[T]) -> bool,
-    {
-        ParamSpace::all().iter().all(|&space| { pred(self.get_slice(space)) })
-    }
-
     pub fn all<P>(&self, pred: P) -> bool where P: FnMut(&T) -> bool {
         self.as_full_slice().iter().all(pred)
     }
@@ -424,7 +331,7 @@ impl<T> VecPerParamSpace<T> {
     }
 
     pub fn is_empty(&self) -> bool {
-        self.all_vecs(|v| v.is_empty())
+        self.content.is_empty()
     }
 
     pub fn map<U, P>(&self, pred: P) -> VecPerParamSpace<U> where P: FnMut(&T) -> U {
@@ -442,18 +349,6 @@ impl<T> VecPerParamSpace<T> {
                                        self.self_limit,
                                        self.type_limit)
     }
-
-    pub fn with_slice(mut self, space: ParamSpace, slice: &[T])
-                    -> VecPerParamSpace<T>
-        where T: Clone
-    {
-        assert!(self.is_empty_in(space));
-        for t in slice {
-            self.push(space, t.clone());
-        }
-
-        self
-    }
 }
 
 #[derive(Clone)]
@@ -581,7 +476,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
         // the specialized routine `ty::replace_late_regions()`.
         match r {
             ty::ReEarlyBound(data) => {
-                match self.substs.regions.opt_get(data.space, data.index as usize) {
+                match self.substs.regions.get_slice(data.space).get(data.index as usize) {
                     Some(&r) => {
                         self.shift_region_through_binders(r)
                     }
@@ -637,7 +532,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
 impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
     fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
         // Look up the type in the substitutions. It really should be in there.
-        let opt_ty = self.substs.types.opt_get(p.space, p.idx as usize);
+        let opt_ty = self.substs.types.get_slice(p.space).get(p.idx as usize);
         let ty = match opt_ty {
             Some(t) => *t,
             None => {
@@ -718,3 +613,67 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
         ty::fold::shift_region(region, self.region_binders_passed)
     }
 }
+
+// Helper methods that modify substitutions.
+
+impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> {
+    pub fn from_method(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                       trait_id: DefId,
+                       substs: &Substs<'tcx>)
+                       -> ty::TraitRef<'tcx> {
+        let Substs { mut types, mut regions } = substs.clone();
+        let defs = tcx.lookup_generics(trait_id);
+        types.content.truncate(defs.types.type_limit);
+        regions.content.truncate(defs.regions.type_limit);
+
+        ty::TraitRef {
+            def_id: trait_id,
+            substs: Substs::new(tcx, types, regions)
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> {
+    pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                         trait_ref: ty::TraitRef<'tcx>)
+                         -> ty::ExistentialTraitRef<'tcx> {
+        let Substs { mut types, regions } = trait_ref.substs.clone();
+
+        assert_eq!(types.self_limit, 1);
+        types.self_limit = 0;
+        types.type_limit -= 1;
+        types.content.remove(0);
+
+        ty::ExistentialTraitRef {
+            def_id: trait_ref.def_id,
+            substs: Substs::new(tcx, types, regions)
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> {
+    /// Object types don't have a self-type specified. Therefore, when
+    /// we convert the principal trait-ref into a normal trait-ref,
+    /// you must give *some* self-type. A common choice is `mk_err()`
+    /// or some skolemized type.
+    pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                        self_ty: Ty<'tcx>)
+                        -> ty::PolyTraitRef<'tcx>  {
+        // otherwise the escaping regions would be captured by the binder
+        assert!(!self_ty.has_escaping_regions());
+
+        self.map_bound(|trait_ref| {
+            let Substs { mut types, regions } = trait_ref.substs.clone();
+
+            assert_eq!(types.self_limit, 0);
+            types.self_limit = 1;
+            types.type_limit += 1;
+            types.content.insert(0, self_ty);
+
+            ty::TraitRef {
+                def_id: trait_ref.def_id,
+                substs: Substs::new(tcx, types, regions)
+            }
+        })
+    }
+}
diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs
index a76dfc35dc1..61285e8f8b0 100644
--- a/src/librustc/ty/trait_def.rs
+++ b/src/librustc/ty/trait_def.rs
@@ -34,7 +34,7 @@ pub struct TraitDef<'tcx> {
     /// `Eq`, there is a single bound `Self : Eq`). This is so that
     /// default methods get to assume that the `Self` parameters
     /// implements the trait.
-    pub generics: ty::Generics<'tcx>,
+    pub generics: &'tcx ty::Generics<'tcx>,
 
     pub trait_ref: ty::TraitRef<'tcx>,
 
@@ -76,7 +76,7 @@ pub struct TraitDef<'tcx> {
 impl<'a, 'gcx, 'tcx> TraitDef<'tcx> {
     pub fn new(unsafety: hir::Unsafety,
                paren_sugar: bool,
-               generics: ty::Generics<'tcx>,
+               generics: &'tcx ty::Generics<'tcx>,
                trait_ref: ty::TraitRef<'tcx>,
                associated_type_names: Vec<Name>)
                -> TraitDef<'tcx> {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 3c1f6e91992..5a73439beac 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -11,7 +11,6 @@
 //! misc. type-system utilities too small to deserve their own file
 
 use hir::def_id::DefId;
-use ty::subst;
 use infer::InferCtxt;
 use hir::pat_util;
 use traits::{self, Reveal};
@@ -695,12 +694,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                         return false;
                     }
 
-                    let types_a = substs_a.types.get_slice(subst::TypeSpace);
-                    let types_b = substs_b.types.get_slice(subst::TypeSpace);
+                    let types_a = substs_a.types.as_full_slice();
+                    let types_b = substs_b.types.as_full_slice();
 
-                    let mut pairs = types_a.iter().zip(types_b);
-
-                    pairs.all(|(&a, &b)| same_type(a, b))
+                    types_a.iter().zip(types_b).all(|(&a, &b)| same_type(a, b))
                 }
                 _ => {
                     a == b
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index fb0b6413fab..cdbd3070523 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -10,7 +10,7 @@
 
 
 use hir::def_id::DefId;
-use ty::subst::{self, Subst};
+use ty::subst::{self, Subst, Substs};
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use ty::{TyBool, TyChar, TyStruct, TyEnum};
 use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
@@ -65,69 +65,57 @@ pub enum Ns {
 fn number_of_supplied_defaults<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                                substs: &subst::Substs,
                                                space: subst::ParamSpace,
-                                               generics: ty::Generics<'tcx>)
+                                               generics: &ty::Generics<'tcx>)
                                                -> usize
 {
-    let has_self = substs.self_ty().is_some();
     let ty_params = generics.types.get_slice(space);
     let tps = substs.types.get_slice(space);
     if ty_params.last().map_or(false, |def| def.default.is_some()) {
         let substs = tcx.lift(&substs);
         ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| {
-            match def.default {
-                Some(default) => {
-                    if !has_self && default.has_self_ty() {
-                        // In an object type, there is no `Self`, and
-                        // thus if the default value references Self,
-                        // the user will be required to give an
-                        // explicit value. We can't even do the
-                        // substitution below to check without causing
-                        // an ICE. (#18956).
-                        false
-                    } else {
-                        let default = tcx.lift(&default);
-                        substs.and_then(|substs| default.subst(tcx, substs))
-                            == Some(actual)
-                    }
-                }
-                None => false
-            }
+            substs.and_then(|substs| def.default.subst(tcx, substs))
+                == Some(actual)
         }).count()
     } else {
         0
     }
 }
 
-pub fn parameterized<GG>(f: &mut fmt::Formatter,
-                         substs: &subst::Substs,
-                         did: DefId,
-                         ns: Ns,
-                         projections: &[ty::ProjectionPredicate],
-                         get_generics: GG)
-                         -> fmt::Result
-    where GG: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>)
-                                         -> Option<ty::Generics<'tcx>>
-{
-    if let (Ns::Value, Some(self_ty)) = (ns, substs.self_ty()) {
-        write!(f, "<{} as ", self_ty)?;
-    }
+pub fn parameterized(f: &mut fmt::Formatter,
+                     substs: &subst::Substs,
+                     did: DefId,
+                     ns: Ns,
+                     projections: &[ty::ProjectionPredicate])
+                     -> fmt::Result {
+    let (fn_trait_kind, verbose, item_name, is_in_trait) = ty::tls::with(|tcx| {
+        let is_in_trait = ns == Ns::Value && tcx.trait_of_item(did).is_some();
+        if is_in_trait {
+            write!(f, "<{} as ", substs.types.get(subst::SelfSpace, 0))?;
+        }
 
-    let (fn_trait_kind, verbose, item_name) = ty::tls::with(|tcx| {
         let (did, item_name) = if ns == Ns::Value {
             // Try to get the impl/trait parent, if this is an
             // associated value item (method or constant).
-            tcx.trait_of_item(did).or_else(|| tcx.impl_of_method(did))
-               .map_or((did, None), |parent| (parent, Some(tcx.item_name(did))))
+            tcx.trait_of_item(did).or_else(|| {
+                // An impl could be a trait impl or an inherent one.
+                tcx.impl_of_method(did).map(|impl_def_id| {
+                    tcx.trait_id_of_impl(impl_def_id)
+                       .unwrap_or(impl_def_id)
+                })
+            }).map_or((did, None), |parent| (parent, Some(tcx.item_name(did))))
         } else {
             (did, None)
         };
         write!(f, "{}", tcx.item_path_str(did))?;
-        Ok((tcx.lang_items.fn_trait_kind(did), tcx.sess.verbose(), item_name))
+        Ok((tcx.lang_items.fn_trait_kind(did),
+            tcx.sess.verbose(),
+            item_name,
+            is_in_trait))
     })?;
 
     if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
         let projection_ty = projections[0].ty;
-        if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty {
+        if let TyTuple(ref args) = substs.types.get(subst::TypeSpace, 0).sty {
             return fn_sig(f, args, false, projection_ty);
         }
     }
@@ -176,11 +164,8 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
         0
     } else {
         ty::tls::with(|tcx| {
-            if let Some(generics) = get_generics(tcx) {
-                number_of_supplied_defaults(tcx, substs, subst::TypeSpace, generics)
-            } else {
-                0
-            }
+            let generics = tcx.lookup_generics(did);
+            number_of_supplied_defaults(tcx, substs, subst::TypeSpace, generics)
         })
     };
 
@@ -204,7 +189,7 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
     if ns == Ns::Value {
         empty.set(true);
 
-        if substs.self_ty().is_some() {
+        if is_in_trait {
             write!(f, ">")?;
         }
 
@@ -288,7 +273,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
 /// projection bounds, so we just stuff them altogether. But in
 /// reality we should eventually sort things out better.
 #[derive(Clone, Debug)]
-struct TraitAndProjections<'tcx>(ty::ExistentialTraitRef<'tcx>,
+struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>,
                                  Vec<ty::ProjectionPredicate<'tcx>>);
 
 impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
@@ -307,8 +292,7 @@ impl<'tcx> fmt::Display for TraitAndProjections<'tcx> {
         parameterized(f, trait_ref.substs,
                       trait_ref.def_id,
                       Ns::Type,
-                      projection_bounds,
-                      |tcx| Some(tcx.lookup_trait_def(trait_ref.def_id).generics.clone()))
+                      projection_bounds)
     }
 }
 
@@ -316,12 +300,16 @@ impl<'tcx> fmt::Display for ty::TraitObject<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // Generate the main trait ref, including associated types.
         ty::tls::with(|tcx| {
-            let principal = tcx.lift(&self.principal.0)
-                               .expect("could not lift TraitRef for printing");
+            // Use a type that can't appear in defaults of type parameters.
+            let dummy_self = tcx.mk_infer(ty::FreshTy(0));
+
+            let principal = tcx.lift(&self.principal)
+                               .expect("could not lift TraitRef for printing")
+                               .with_self_ty(tcx, dummy_self).0;
             let projections = self.projection_bounds.iter().map(|p| {
-                let projection = tcx.lift(p)
-                                    .expect("could not lift projection for printing");
-                projection.with_self_ty(tcx, tcx.types.err).0
+                tcx.lift(p)
+                    .expect("could not lift projection for printing")
+                    .with_self_ty(tcx, dummy_self).0
             }).collect();
 
             let tap = ty::Binder(TraitAndProjections(principal, projections));
@@ -380,7 +368,7 @@ impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for subst::Substs<'tcx> {
+impl<'tcx> fmt::Debug for Substs<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "Substs[types={:?}, regions={:?}]",
                self.types, self.regions)
@@ -404,7 +392,14 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", *self)
+        ty::tls::with(|tcx| {
+            let dummy_self = tcx.mk_infer(ty::FreshTy(0));
+
+            let trait_ref = tcx.lift(&ty::Binder(*self))
+                               .expect("could not lift TraitRef for printing")
+                               .with_self_ty(tcx, dummy_self).0;
+            parameterized(f, trait_ref.substs, trait_ref.def_id, Ns::Type, &[])
+        })
     }
 }
 
@@ -813,15 +808,7 @@ impl fmt::Display for ty::Binder<ty::OutlivesPredicate<ty::Region, ty::Region>>
 
 impl<'tcx> fmt::Display for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        parameterized(f, self.substs, self.def_id, Ns::Type, &[],
-                      |tcx| Some(tcx.lookup_trait_def(self.def_id).generics.clone()))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::ExistentialTraitRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        parameterized(f, self.substs, self.def_id, Ns::Type, &[],
-                      |tcx| Some(tcx.lookup_trait_def(self.def_id).generics.clone()))
+        parameterized(f, self.substs, self.def_id, Ns::Type, &[])
     }
 }
 
@@ -874,9 +861,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                 }
 
                 write!(f, "{} {{", bare_fn.sig.0)?;
-                parameterized(
-                    f, substs, def_id, Ns::Value, &[],
-                    |tcx| tcx.opt_lookup_item_type(def_id).map(|t| t.generics))?;
+                parameterized(f, substs, def_id, Ns::Value, &[])?;
                 write!(f, "}}")
             }
             TyFnPtr(ref bare_fn) => {
@@ -899,12 +884,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                           !tcx.tcache.borrow().contains_key(&def.did) {
                         write!(f, "{}<..>", tcx.item_path_str(def.did))
                     } else {
-                        parameterized(
-                            f, substs, def.did, Ns::Type, &[],
-                            |tcx| {
-                                tcx.opt_lookup_item_type(def.did).
-                                    map(|t| t.generics)
-                            })
+                        parameterized(f, substs, def.did, Ns::Type, &[])
                     }
                 })
             }
@@ -916,7 +896,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                     // by looking up the projections associated with the def_id.
                     let item_predicates = tcx.lookup_predicates(def_id);
                     let substs = tcx.lift(&substs).unwrap_or_else(|| {
-                        tcx.mk_substs(subst::Substs::empty())
+                        Substs::empty(tcx)
                     });
                     let bounds = item_predicates.instantiate(tcx, substs);
 
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index f6e9484eda1..df91ec2b98d 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -859,10 +859,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil()));
         let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
             .unwrap_or_else(|e| tcx.sess.fatal(&e));
-        let substs = tcx.mk_substs(Substs::new(
+        let substs = Substs::new(tcx,
             VecPerParamSpace::new(vec![], vec![], vec![ty]),
-            VecPerParamSpace::new(vec![], vec![], vec![])
-        ));
+            VecPerParamSpace::new(vec![], vec![], vec![]));
         let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs);
 
         self.patch.new_block(BasicBlockData {
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 73b54c4374f..d71add3258f 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -22,8 +22,9 @@ use rustc::traits;
 use rustc::hir::def::{Def, PathResolution};
 use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util::def_to_path;
-use rustc::ty::{self, Ty, TyCtxt, subst};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
+use rustc::ty::subst::Substs;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::NodeMap;
@@ -93,7 +94,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// This generally happens in late/trans const evaluation.
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
-                                        substs: Option<&'tcx subst::Substs<'tcx>>)
+                                        substs: Option<&'tcx Substs<'tcx>>)
                                         -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         match tcx.map.find(node_id) {
@@ -110,7 +111,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         // If we have a trait item and the substitutions for it,
                         // `resolve_trait_associated_const` will select an impl
                         // or the default.
-                        let trait_id = tcx.trait_of_item(def_id).unwrap();
+                        let trait_id = tcx.map.get_parent(node_id);
+                        let trait_id = tcx.map.local_def_id(trait_id);
                         resolve_trait_associated_const(tcx, ti, trait_id, substs)
                     } else {
                         // Technically, without knowing anything about the
@@ -1045,16 +1047,14 @@ fn infer<'a, 'tcx>(i: ConstInt,
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 ti: &'tcx hir::TraitItem,
                                                 trait_id: DefId,
-                                                rcvr_substs: &'tcx subst::Substs<'tcx>)
+                                                rcvr_substs: &'tcx Substs<'tcx>)
                                                 -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
 {
-    let trait_ref = ty::Binder(
-        rcvr_substs.clone().erase_regions().to_trait_ref(tcx, trait_id)
-    );
+    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
-    tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
+    tcx.populate_implementations_for_trait_if_necessary(trait_id);
     tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 7711091685d..c84b195dd4b 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -21,7 +21,7 @@ use rustc::middle::region::CodeExtentData;
 use rustc::middle::resolve_lifetime;
 use rustc::middle::stability;
 use rustc::ty::subst;
-use rustc::ty::subst::Subst;
+use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
@@ -678,8 +678,8 @@ fn subst_ty_renumber_bound() {
             env.t_fn(&[t_param], env.t_nil())
         };
 
-        let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
-        let t_substituted = t_source.subst(env.infcx.tcx, &substs);
+        let substs = Substs::new_type(env.infcx.tcx, vec![t_rptr_bound1], vec![]);
+        let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
         let t_expected = {
@@ -713,8 +713,8 @@ fn subst_ty_renumber_some_bounds() {
             env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
         };
 
-        let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
-        let t_substituted = t_source.subst(env.infcx.tcx, &substs);
+        let substs = Substs::new_type(env.infcx.tcx, vec![t_rptr_bound1], vec![]);
+        let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = (&'a isize, fn(&'a isize))
         //
@@ -775,8 +775,8 @@ fn subst_region_renumber_region() {
             env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
         };
 
-        let substs = subst::Substs::new_type(vec![], vec![re_bound1]);
-        let t_substituted = t_source.subst(env.infcx.tcx, &substs);
+        let substs = Substs::new_type(env.infcx.tcx, vec![], vec![re_bound1]);
+        let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
         //
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index ed17f3533d4..61d92723982 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -465,16 +465,14 @@ impl LateLintPass for MissingCopyImplementations {
                     return;
                 }
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
-                (def, cx.tcx.mk_struct(def,
-                                       cx.tcx.mk_substs(Substs::empty())))
+                (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx)))
             }
             hir::ItemEnum(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
                     return;
                 }
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
-                (def, cx.tcx.mk_enum(def,
-                                     cx.tcx.mk_substs(Substs::empty())))
+                (def, cx.tcx.mk_enum(def, Substs::empty(cx.tcx)))
             }
             _ => return,
         };
@@ -898,7 +896,7 @@ impl LateLintPass for UnconditionalRecursion {
                 // A trait method, from any number of possible sources.
                 // Attempt to select a concrete impl before checking.
                 ty::TraitContainer(trait_def_id) => {
-                    let trait_ref = callee_substs.to_trait_ref(tcx, trait_def_id);
+                    let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs);
                     let trait_ref = ty::Binder(trait_ref);
                     let span = tcx.map.span(expr_id);
                     let obligation =
@@ -918,8 +916,7 @@ impl LateLintPass for UnconditionalRecursion {
                             // If `T` is `Self`, then this call is inside
                             // a default method definition.
                             Ok(Some(traits::VtableParam(_))) => {
-                                let self_ty = callee_substs.self_ty();
-                                let on_self = self_ty.map_or(false, |t| t.is_self());
+                                let on_self = trait_ref.self_ty().is_self();
                                 // We can only be recurring in a default
                                 // method if we're being called literally
                                 // on the `Self` type.
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index c552e612504..1b00eee76f6 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -34,7 +34,7 @@ use middle::const_qualif::ConstQualif;
 use rustc::hir::def::{self, Def};
 use rustc::hir::def_id::DefId;
 use middle::region;
-use rustc::ty::subst;
+use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
 
 use syntax::ast;
@@ -507,7 +507,7 @@ impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
                     Ok(this.read_ty(dcx))
                 }).unwrap(),
                 substs: this.read_struct_field("substs", 3, |this| {
-                    Ok(dcx.tcx.mk_substs(this.read_substs(dcx)))
+                    Ok(this.read_substs(dcx))
                 }).unwrap()
             }))
         }).unwrap()
@@ -525,7 +525,7 @@ trait rbml_writer_helpers<'tcx> {
     fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region);
     fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
     fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                       substs: &subst::Substs<'tcx>);
+                       substs: &Substs<'tcx>);
     fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture);
     fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                                 adj: &adjustment::AutoAdjustment<'tcx>);
@@ -569,7 +569,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
     }
 
     fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                       substs: &subst::Substs<'tcx>) {
+                       substs: &Substs<'tcx>) {
         self.emit_opaque(|this| Ok(tyencode::enc_substs(&mut this.cursor,
                                                         &ecx.ty_str_ctxt(),
                                                         substs)));
@@ -839,7 +839,7 @@ trait rbml_decoder_decoder_helpers<'tcx> {
     fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                               -> ty::Predicate<'tcx>;
     fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                           -> subst::Substs<'tcx>;
+                           -> &'tcx Substs<'tcx>;
     fn read_upvar_capture(&mut self, dcx: &DecodeContext)
                           -> ty::UpvarCapture;
     fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -859,7 +859,7 @@ trait rbml_decoder_decoder_helpers<'tcx> {
                           cdata: &cstore::CrateMetadata) -> Vec<Ty<'tcx>>;
     fn read_substs_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              cdata: &cstore::CrateMetadata)
-                             -> subst::Substs<'tcx>;
+                             -> &'tcx Substs<'tcx>;
 }
 
 impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
@@ -884,7 +884,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
 
     fn read_substs_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>,
                              cdata: &cstore::CrateMetadata)
-                             -> subst::Substs<'tcx>
+                             -> &'tcx Substs<'tcx>
     {
         self.read_opaque(|_, doc| {
             Ok(
@@ -946,7 +946,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
     }
 
     fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                           -> subst::Substs<'tcx> {
+                           -> &'tcx Substs<'tcx> {
         self.read_opaque(|_, doc| {
             Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc,
                                              &mut |d| convert_def_id(dcx, d))
@@ -1140,7 +1140,7 @@ fn decode_side_tables(dcx: &DecodeContext,
                     }
                     c::tag_table_item_subst => {
                         let item_substs = ty::ItemSubsts {
-                            substs: dcx.tcx.mk_substs(val_dsr.read_substs(dcx))
+                            substs: val_dsr.read_substs(dcx)
                         };
                         dcx.tcx.tables.borrow_mut().item_substs.insert(
                             id, item_substs);
diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs
index 0011b59c70e..99a3f3b00c8 100644
--- a/src/librustc_metadata/common.rs
+++ b/src/librustc_metadata/common.rs
@@ -196,16 +196,11 @@ pub const tag_attribute_is_sugared_doc: usize = 0x8c;
 // GAP 0x8d
 pub const tag_items_data_region: usize = 0x8e;
 
-pub const tag_region_param_def: usize = 0x8f;
-pub const tag_region_param_def_ident: usize = 0x90;
-pub const tag_region_param_def_def_id: usize = 0x91;
-pub const tag_region_param_def_space: usize = 0x92;
-pub const tag_region_param_def_index: usize = 0x93;
+pub const tag_item_generics: usize = 0x8f;
+// GAP 0x90, 0x91, 0x92, 0x93, 0x94
 
-pub const tag_type_param_def: usize = 0x94;
-
-pub const tag_item_generics: usize = 0x95;
-pub const tag_method_ty_generics: usize = 0x96;
+pub const tag_item_predicates: usize = 0x95;
+// GAP 0x96
 
 pub const tag_predicate: usize = 0x97;
 // GAP 0x98, 0x99
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index 2cdbd1b8601..f6d698eb969 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -86,7 +86,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     }
 
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> ty::TypeScheme<'tcx>
+                     -> Ty<'tcx>
     {
         self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
@@ -109,6 +109,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::get_super_predicates(&cdata, def.index, tcx)
     }
 
+    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                         -> &'tcx ty::Generics<'tcx>
+    {
+        self.dep_graph.read(DepNode::MetaData(def));
+        let cdata = self.get_crate_data(def.krate);
+        decoder::get_generics(&cdata, def.index, tcx)
+    }
+
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
@@ -231,11 +239,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::get_parent_impl(&*cdata, impl_def.index)
     }
 
-    fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option<DefId>
-    {
+    fn trait_of_item(&self, def_id: DefId) -> Option<DefId> {
         self.dep_graph.read(DepNode::MetaData(def_id));
         let cdata = self.get_crate_data(def_id.krate);
-        decoder::get_trait_of_item(&cdata, def_id.index, tcx)
+        decoder::get_trait_of_item(&cdata, def_id.index)
     }
 
     fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index eeb1859c013..e42825ef1e5 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -264,11 +264,6 @@ fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata:
     })
 }
 
-pub fn item_type<'a, 'tcx>(_item_id: DefId, item: rbml::Doc,
-                           tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> {
-    doc_type(item, tcx, cdata)
-}
-
 fn doc_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd)
                            -> ty::TraitRef<'tcx> {
     TyDecoder::with_doc(tcx, cdata.cnum, doc,
@@ -383,7 +378,7 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd,
                                tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx>
 {
     let item_doc = cdata.lookup_item(item_id);
-    let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
+    let generics = doc_generics(item_doc, tcx, cdata);
     let unsafety = parse_unsafety(item_doc);
     let associated_type_names = parse_associated_type_names(item_doc);
     let paren_sugar = parse_paren_sugar(item_doc);
@@ -493,7 +488,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
             // from the ctor.
             debug!("evaluating the ctor-type of {:?}",
                    variant.name);
-            let ctor_ty = get_type(cdata, variant.did.index, tcx).ty;
+            let ctor_ty = get_type(cdata, variant.did.index, tcx);
             debug!("evaluating the ctor-type of {:?}.. {:?}",
                    variant.name,
                    ctor_ty);
@@ -513,7 +508,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
         } else {
             for field in &variant.fields {
                 debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
-                let ty = get_type(cdata, field.did.index, tcx).ty;
+                let ty = get_type(cdata, field.did.index, tcx);
                 field.fulfill_ty(ty);
                 debug!("evaluating the type of {:?}::{:?}: {:?}",
                        variant.name, field.name, ty);
@@ -530,7 +525,7 @@ pub fn get_predicates<'a, 'tcx>(cdata: Cmd,
                                 -> ty::GenericPredicates<'tcx>
 {
     let item_doc = cdata.lookup_item(item_id);
-    doc_predicates(item_doc, tcx, cdata, tag_item_generics)
+    doc_predicates(item_doc, tcx, cdata, tag_item_predicates)
 }
 
 pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd,
@@ -542,17 +537,20 @@ pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd,
     doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
 }
 
+pub fn get_generics<'a, 'tcx>(cdata: Cmd,
+                              item_id: DefIndex,
+                              tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                              -> &'tcx ty::Generics<'tcx>
+{
+    let item_doc = cdata.lookup_item(item_id);
+    doc_generics(item_doc, tcx, cdata)
+}
+
 pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                          -> ty::TypeScheme<'tcx>
+                          -> Ty<'tcx>
 {
     let item_doc = cdata.lookup_item(id);
-    let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx,
-                      cdata);
-    let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
-    ty::TypeScheme {
-        generics: generics,
-        ty: t
-    }
+    doc_type(item_doc, tcx, cdata)
 }
 
 pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option<attr::Stability> {
@@ -960,8 +958,8 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a
             }))
         }
         Some('r') | Some('p') => {
-            let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
-            let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
+            let generics = doc_generics(item_doc, tcx, cdata);
+            let predicates = doc_predicates(item_doc, tcx, cdata, tag_item_predicates);
             let ity = tcx.lookup_item_type(def_id).ty;
             let fty = match ity.sty {
                 ty::TyFnDef(_, _, fty) => fty,
@@ -1393,10 +1391,7 @@ pub fn each_implementation_for_trait<F>(cdata: Cmd,
     }
 }
 
-pub fn get_trait_of_item<'a, 'tcx>(cdata: Cmd,
-                                   id: DefIndex,
-                                   tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                   -> Option<DefId> {
+pub fn get_trait_of_item(cdata: Cmd, id: DefIndex) -> Option<DefId> {
     let item_doc = cdata.lookup_item(id);
     let parent_item_id = match item_parent_item(cdata, item_doc) {
         None => return None,
@@ -1405,10 +1400,6 @@ pub fn get_trait_of_item<'a, 'tcx>(cdata: Cmd,
     let parent_item_doc = cdata.lookup_item(parent_item_id.index);
     match item_family(parent_item_doc) {
         Trait => Some(item_def_id(parent_item_doc, cdata)),
-        Impl | DefaultImpl => {
-            reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref)
-                .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id)
-        }
         _ => None
     }
 }
@@ -1537,11 +1528,7 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd,
     };
     let applicable = match item_family(item_doc) {
         ImmStatic | MutStatic => true,
-        Fn => {
-            let ty::TypeScheme { generics, .. } = get_type(cdata, id, tcx);
-            let no_generics = generics.types.is_empty();
-            no_generics
-        },
+        Fn => get_generics(cdata, id, tcx).types.is_empty(),
         _ => false,
     };
 
@@ -1573,30 +1560,13 @@ pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool {
 
 fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          cdata: Cmd,
-                          tag: usize)
-                          -> ty::Generics<'tcx>
+                          cdata: Cmd)
+                          -> &'tcx ty::Generics<'tcx>
 {
-    let doc = reader::get_doc(base_doc, tag);
-
-    let mut generics = ty::Generics::empty();
-    for p in reader::tagged_docs(doc, tag_type_param_def) {
-        let bd =
-            TyDecoder::with_doc(tcx, cdata.cnum, p,
-                                &mut |did| translate_def_id(cdata, did))
-            .parse_type_param_def();
-        generics.types.push(bd.space, bd);
-    }
-
-    for p in reader::tagged_docs(doc, tag_region_param_def) {
-        let bd =
-            TyDecoder::with_doc(tcx, cdata.cnum, p,
-                                &mut |did| translate_def_id(cdata, did))
-            .parse_region_param_def();
-        generics.regions.push(bd.space, bd);
-    }
-
-    generics
+    let doc = reader::get_doc(base_doc, tag_item_generics);
+    TyDecoder::with_doc(tcx, cdata.cnum, doc,
+                        &mut |did| translate_def_id(cdata, did))
+        .parse_generics()
 }
 
 fn doc_predicate<'a, 'tcx>(cdata: Cmd,
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index d19eb639182..1e74b3c1ef4 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -175,8 +175,7 @@ fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
                                     index: &mut CrateIndex<'a, 'tcx>,
                                     scheme: &ty::TypeScheme<'tcx>,
                                     predicates: &ty::GenericPredicates<'tcx>) {
-    encode_generics(rbml_w, ecx, index,
-                    &scheme.generics, &predicates, tag_item_generics);
+    encode_generics(rbml_w, ecx, index, &scheme.generics, &predicates);
     encode_type(ecx, rbml_w, scheme.ty);
 }
 
@@ -510,50 +509,26 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
                              ecx: &EncodeContext<'a, 'tcx>,
                              index: &mut CrateIndex<'a, 'tcx>,
                              generics: &ty::Generics<'tcx>,
-                             predicates: &ty::GenericPredicates<'tcx>,
-                             tag: usize)
+                             predicates: &ty::GenericPredicates<'tcx>)
 {
-    rbml_w.start_tag(tag);
-
-    for param in generics.types.as_full_slice() {
-        rbml_w.start_tag(tag_type_param_def);
-        tyencode::enc_type_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param);
-        rbml_w.mark_stable_position();
-        rbml_w.end_tag();
-    }
-
-    // Region parameters
-    for param in generics.regions.as_full_slice() {
-        rbml_w.start_tag(tag_region_param_def);
-        tyencode::enc_region_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param);
-        rbml_w.mark_stable_position();
-        rbml_w.end_tag();
-    }
-
-    encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
-
+    rbml_w.start_tag(tag_item_generics);
+    tyencode::enc_generics(rbml_w.writer, &ecx.ty_str_ctxt(), generics);
+    rbml_w.mark_stable_position();
     rbml_w.end_tag();
-}
 
-fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
-                                             _ecx: &EncodeContext<'a,'tcx>,
-                                             index: &mut CrateIndex<'a, 'tcx>,
-                                             predicates: &ty::GenericPredicates<'tcx>)
-{
-    for predicate in &predicates.predicates {
-        rbml_w.wr_tagged_u32(tag_predicate,
-            index.add_xref(XRef::Predicate(predicate.clone())));
-    }
+    encode_predicates(rbml_w, index, predicates, tag_item_predicates);
 }
 
 fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
-                              ecx: &EncodeContext<'a,'tcx>,
                               index: &mut CrateIndex<'a, 'tcx>,
                               predicates: &ty::GenericPredicates<'tcx>,
                               tag: usize)
 {
     rbml_w.start_tag(tag);
-    encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
+    for predicate in &predicates.predicates {
+        rbml_w.wr_tagged_u32(tag_predicate,
+            index.add_xref(XRef::Predicate(predicate.clone())));
+    }
     rbml_w.end_tag();
 }
 
@@ -564,8 +539,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
     encode_name(rbml_w, method_ty.name);
     encode_generics(rbml_w, ecx, index,
-                    &method_ty.generics, &method_ty.predicates,
-                    tag_method_ty_generics);
+                    &method_ty.generics, &method_ty.predicates);
     encode_visibility(rbml_w, method_ty.vis);
     encode_explicit_self(rbml_w, &method_ty.explicit_self);
     match method_ty.explicit_self {
@@ -695,7 +669,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_attributes(rbml_w, &ii.attrs);
         encode_defaultness(rbml_w, ii.defaultness);
     } else {
-        encode_predicates(rbml_w, ecx, index,
+        encode_predicates(rbml_w, index,
                           &ecx.tcx.lookup_predicates(associated_type.def_id),
                           tag_item_generics);
     }
@@ -1134,9 +1108,8 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id));
         encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
         encode_generics(rbml_w, ecx, index,
-                        &trait_def.generics, &trait_predicates,
-                        tag_item_generics);
-        encode_predicates(rbml_w, ecx, index,
+                        &trait_def.generics, &trait_predicates);
+        encode_predicates(rbml_w, index,
                           &tcx.lookup_super_predicates(def_id),
                           tag_item_super_predicates);
         encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs
index 23142ca80ef..6e78cbcd28e 100644
--- a/src/librustc_metadata/tls_context.rs
+++ b/src/librustc_metadata/tls_context.rs
@@ -74,7 +74,7 @@ impl<'a, 'tcx: 'a> tls::DecodingContext<'tcx> for DecodingContext<'a, 'tcx> {
         ty
     }
 
-    fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> Substs<'tcx> {
+    fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx> {
         let def_id_convert = &mut |did| {
             decoder::translate_def_id(self.crate_metadata, did)
         };
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index 11c155cbd5b..3f0fa9073aa 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -20,8 +20,7 @@ use rustc::hir;
 
 use rustc::hir::def_id::{DefId, DefIndex};
 use middle::region;
-use rustc::ty::subst;
-use rustc::ty::subst::VecPerParamSpace;
+use rustc::ty::subst::{self, Substs, VecPerParamSpace};
 use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
 use rbml;
@@ -132,21 +131,31 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
     fn parse_vec_per_param_space<T, F>(&mut self, mut f: F) -> VecPerParamSpace<T> where
         F: FnMut(&mut TyDecoder<'a, 'tcx>) -> T,
     {
-        let mut r = VecPerParamSpace::empty();
-        for &space in &subst::ParamSpace::all() {
+        let (mut a, mut b, mut c) =  (vec![], vec![], vec![]);
+        for r in &mut [&mut a, &mut b, &mut c] {
             assert_eq!(self.next(), '[');
             while self.peek() != ']' {
-                r.push(space, f(self));
+                r.push(f(self));
             }
             assert_eq!(self.next(), ']');
         }
-        r
+        VecPerParamSpace::new(a, b, c)
     }
 
-    pub fn parse_substs(&mut self) -> subst::Substs<'tcx> {
+    pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> {
         let regions = self.parse_vec_per_param_space(|this| this.parse_region());
         let types = self.parse_vec_per_param_space(|this| this.parse_ty());
-        subst::Substs { types: types, regions: regions }
+        Substs::new(self.tcx, types, regions)
+    }
+
+    pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> {
+        let regions = self.parse_vec_per_param_space(|this| this.parse_region_param_def());
+        let types = self.parse_vec_per_param_space(|this| this.parse_type_param_def());
+        self.tcx.alloc_generics(ty::Generics {
+            regions: regions,
+            types: types,
+            has_self: self.next() == 'S'
+        })
     }
 
     fn parse_bound_region(&mut self) -> ty::BoundRegion {
@@ -302,15 +311,17 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
     }
 
     pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> {
-        let def = self.parse_def();
-        let substs = self.tcx.mk_substs(self.parse_substs());
-        ty::TraitRef {def_id: def, substs: substs}
+        ty::TraitRef {
+            def_id: self.parse_def(),
+            substs: self.parse_substs()
+        }
     }
 
     pub fn parse_existential_trait_ref(&mut self) -> ty::ExistentialTraitRef<'tcx> {
-        let def = self.parse_def();
-        let substs = self.tcx.mk_substs(self.parse_substs());
-        ty::ExistentialTraitRef {def_id: def, substs: substs}
+        ty::ExistentialTraitRef {
+            def_id: self.parse_def(),
+            substs: self.parse_substs()
+        }
     }
 
     pub fn parse_ty(&mut self) -> Ty<'tcx> {
@@ -342,7 +353,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 let substs = self.parse_substs();
                 assert_eq!(self.next(), ']');
                 let def = self.tcx.lookup_adt_def(did);
-                return tcx.mk_enum(def, self.tcx.mk_substs(substs));
+                return tcx.mk_enum(def, substs);
             }
             'x' => {
                 assert_eq!(self.next(), '[');
@@ -406,7 +417,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             }
             'F' => {
                 let def_id = self.parse_def();
-                let substs = self.tcx.mk_substs(self.parse_substs());
+                let substs = self.parse_substs();
                 return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty());
             }
             'G' => {
@@ -452,7 +463,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 let substs = self.parse_substs();
                 assert_eq!(self.next(), ']');
                 let def = self.tcx.lookup_adt_def(did);
-                return self.tcx.mk_struct(def, self.tcx.mk_substs(substs));
+                return self.tcx.mk_struct(def, substs);
             }
             'k' => {
                 assert_eq!(self.next(), '[');
@@ -464,7 +475,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 }
                 assert_eq!(self.next(), '.');
                 assert_eq!(self.next(), ']');
-                return self.tcx.mk_closure(did, self.tcx.mk_substs(substs), tys);
+                return self.tcx.mk_closure(did, substs, tys);
             }
             'P' => {
                 assert_eq!(self.next(), '[');
@@ -477,7 +488,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 let def_id = self.parse_def();
                 let substs = self.parse_substs();
                 assert_eq!(self.next(), ']');
-                return self.tcx.mk_anon(def_id, self.tcx.mk_substs(substs));
+                return self.tcx.mk_anon(def_id, substs);
             }
             'e' => {
                 return tcx.types.err;
@@ -622,7 +633,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
         }
     }
 
-    pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> {
+    fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> {
         let name = self.parse_name(':');
         let def_id = self.parse_def();
         let space = self.parse_param_space();
@@ -644,7 +655,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
         }
     }
 
-    pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
+    fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
         let name = self.parse_name(':');
         let def_id = self.parse_def();
         let space = self.parse_param_space();
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index 8deb1eb6ac3..130d1548582 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -19,8 +19,7 @@ use std::io::prelude::*;
 
 use rustc::hir::def_id::DefId;
 use middle::region;
-use rustc::ty::subst;
-use rustc::ty::subst::VecPerParamSpace;
+use rustc::ty::subst::{self, Substs, VecPerParamSpace};
 use rustc::ty::ParamTy;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::FnvHashMap;
@@ -266,13 +265,27 @@ fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Cursor<Vec<u8>>,
 }
 
 pub fn enc_substs<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                            substs: &subst::Substs<'tcx>) {
+                            substs: &Substs<'tcx>) {
     enc_vec_per_param_space(w, cx, &substs.regions,
                             |w, cx, &r| enc_region(w, cx, r));
     enc_vec_per_param_space(w, cx, &substs.types,
                             |w, cx, &ty| enc_ty(w, cx, ty));
 }
 
+pub fn enc_generics<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
+                              generics: &ty::Generics<'tcx>) {
+    enc_vec_per_param_space(w, cx, &generics.regions,
+                            |w, cx, r| enc_region_param_def(w, cx, r));
+    enc_vec_per_param_space(w, cx, &generics.types,
+                            |w, cx, ty| enc_type_param_def(w, cx, ty));
+
+    if generics.has_self {
+        write!(w, "S");
+    } else {
+        write!(w, "N");
+    }
+}
+
 pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: ty::Region) {
     match r {
         ty::ReLateBound(id, br) => {
@@ -420,8 +433,8 @@ fn enc_builtin_bounds(w: &mut Cursor<Vec<u8>>, _cx: &ctxt, bs: &ty::BuiltinBound
     write!(w, ".");
 }
 
-pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                                    v: &ty::TypeParameterDef<'tcx>) {
+fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
+                                v: &ty::TypeParameterDef<'tcx>) {
     write!(w, "{}:{}|{}|{}|{}|",
              v.name, (cx.ds)(cx.tcx, v.def_id),
              v.space.to_uint(), v.index, (cx.ds)(cx.tcx, v.default_def_id));
@@ -429,8 +442,8 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>
     enc_object_lifetime_default(w, cx, v.object_lifetime_default);
 }
 
-pub fn enc_region_param_def(w: &mut Cursor<Vec<u8>>, cx: &ctxt,
-                            v: &ty::RegionParameterDef) {
+fn enc_region_param_def(w: &mut Cursor<Vec<u8>>, cx: &ctxt,
+                        v: &ty::RegionParameterDef) {
     write!(w, "{}:{}|{}|{}|",
              v.name, (cx.ds)(cx.tcx, v.def_id),
              v.space.to_uint(), v.index);
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 6af9ad02b91..22989048388 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -750,7 +750,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                               -> TerminatorKind<'tcx> {
     let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
                        .unwrap_or_else(|e| tcx.sess.fatal(&e));
-    let substs = tcx.mk_substs(Substs::new_fn(vec![data.item_ty], vec![]));
+    let substs = Substs::new_fn(tcx, vec![data.item_ty], vec![]);
     TerminatorKind::Call {
         func: Operand::Constant(Constant {
             span: data.span,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index df1fec75939..972e7f5be70 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -147,16 +147,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                         params: Vec<Ty<'tcx>>)
                         -> (Ty<'tcx>, Literal<'tcx>) {
         let method_name = token::intern(method_name);
-        let substs = Substs::new_trait(params, vec![], self_ty);
+        let substs = Substs::new_trait(self.tcx, params, vec![], self_ty);
         for trait_item in self.tcx.trait_items(trait_def_id).iter() {
             match *trait_item {
                 ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
                     if method.name == method_name {
                         let method_ty = self.tcx.lookup_item_type(method.def_id);
-                        let method_ty = method_ty.ty.subst(self.tcx, &substs);
+                        let method_ty = method_ty.ty.subst(self.tcx, substs);
                         return (method_ty, Literal::Item {
                             def_id: method.def_id,
-                            substs: self.tcx.mk_substs(substs),
+                            substs: substs,
                         });
                     }
                 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 16cd9186ce9..6c9cf1a5625 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -299,8 +299,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                             let mut result = String::from("<");
                             result.push_str(&rustc::hir::print::ty_to_string(&ty));
 
-                            if let Some(def_id) = self.tcx
-                                    .trait_of_item(self.tcx.map.local_def_id(id)) {
+                            if let Some(def_id) = self.tcx.trait_id_of_impl(impl_id) {
                                 result.push_str(" as ");
                                 result.push_str(&self.tcx.item_path_str(def_id));
                             }
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
index 27a8c1f1df4..d6866b27f98 100644
--- a/src/librustc_trans/_match.rs
+++ b/src/librustc_trans/_match.rs
@@ -895,7 +895,7 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                            &format!("comparison of `{}`", rhs_t),
                            StrEqFnLangItem);
         let args = [lhs_data, lhs_len, rhs_data, rhs_len];
-        Callee::def(bcx.ccx(), did, bcx.tcx().mk_substs(Substs::empty()))
+        Callee::def(bcx.ccx(), did, Substs::empty(bcx.tcx()))
             .call(bcx, debug_loc, ArgVals(&args), None)
     }
 
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 23c4258caf7..d48ec98a20d 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -48,7 +48,7 @@ use std;
 use std::rc::Rc;
 
 use llvm::{ValueRef, True, IntEQ, IntNE};
-use rustc::ty::subst;
+use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
 use syntax::ast;
 use syntax::attr;
@@ -544,7 +544,7 @@ impl<'tcx> Case<'tcx> {
 
 fn get_cases<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                        adt: ty::AdtDef<'tcx>,
-                       substs: &subst::Substs<'tcx>)
+                       substs: &Substs<'tcx>)
                        -> Vec<Case<'tcx>> {
     adt.variants.iter().map(|vi| {
         let field_tys = vi.fields.iter().map(|field| {
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 749a7495421..ee5d1d11fa0 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -218,7 +218,7 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Allocate space:
     let def_id = require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem);
-    let r = Callee::def(bcx.ccx(), def_id, bcx.tcx().mk_substs(Substs::empty()))
+    let r = Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx()))
         .call(bcx, debug_loc, ArgVals(&[size, align]), None);
 
     Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
@@ -670,11 +670,9 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
                                              source_ty: Ty<'tcx>,
                                              target_ty: Ty<'tcx>)
                                              -> CustomCoerceUnsized {
-    let trait_substs = Substs::new_trait(vec![target_ty], vec![], source_ty);
-
     let trait_ref = ty::Binder(ty::TraitRef {
         def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(),
-        substs: scx.tcx().mk_substs(trait_substs)
+        substs: Substs::new_trait(scx.tcx(), vec![target_ty], vec![], source_ty)
     });
 
     match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
@@ -1410,7 +1408,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
                 common::validate_substs(instance.substs);
                 (instance.substs, Some(instance.def), Some(inlined_id))
             }
-            None => (ccx.tcx().mk_substs(Substs::empty()), None, None)
+            None => (Substs::empty(ccx.tcx()), None, None)
         };
 
         let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
@@ -2175,7 +2173,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
                     Ok(id) => id,
                     Err(s) => ccx.sess().fatal(&s)
                 };
-                let empty_substs = ccx.tcx().mk_substs(Substs::empty());
+                let empty_substs = Substs::empty(ccx.tcx());
                 let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx).val;
                 let args = {
                     let opaque_rust_main =
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index aaec2a47025..d50959b5ab3 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -22,7 +22,7 @@ use back::symbol_names;
 use llvm::{self, ValueRef, get_params};
 use middle::cstore::LOCAL_CRATE;
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst;
+use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::hir::map as hir_map;
 use abi::{Abi, FnType};
@@ -105,13 +105,12 @@ impl<'tcx> Callee<'tcx> {
     /// Function or method definition.
     pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
                    def_id: DefId,
-                   substs: &'tcx subst::Substs<'tcx>)
+                   substs: &'tcx Substs<'tcx>)
                    -> Callee<'tcx> {
         let tcx = ccx.tcx();
 
-        if substs.self_ty().is_some() {
-            // Only trait methods can have a Self parameter.
-            return Callee::trait_method(ccx, def_id, substs);
+        if let Some(trait_id) = tcx.trait_of_item(def_id) {
+            return Callee::trait_method(ccx, trait_id, def_id, substs);
         }
 
         let maybe_node_id = inline::get_local_instance(ccx, def_id)
@@ -144,24 +143,21 @@ impl<'tcx> Callee<'tcx> {
 
     /// Trait method, which has to be resolved to an impl method.
     pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
+                            trait_id: DefId,
                             def_id: DefId,
-                            substs: &'tcx subst::Substs<'tcx>)
+                            substs: &'tcx Substs<'tcx>)
                             -> Callee<'tcx> {
         let tcx = ccx.tcx();
 
-        let method_item = tcx.impl_or_trait_item(def_id);
-        let trait_id = method_item.container().id();
-        let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
-        let trait_ref = tcx.normalize_associated_type(&trait_ref);
+        let trait_ref = ty::TraitRef::from_method(tcx, trait_id, substs);
+        let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
         match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
             traits::VtableImpl(vtable_impl) => {
                 let impl_did = vtable_impl.impl_def_id;
                 let mname = tcx.item_name(def_id);
                 // create a concatenated set of substitutions which includes
                 // those from the impl and those from the method:
-                let impl_substs = vtable_impl.substs.with_method_from(&substs);
-                let substs = tcx.mk_substs(impl_substs);
-                let mth = meth::get_impl_method(tcx, impl_did, substs, mname);
+                let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname);
 
                 // Translate the function, bypassing Callee::def.
                 // That is because default methods have the same ID as the
@@ -275,7 +271,7 @@ impl<'tcx> Callee<'tcx> {
 /// Given a DefId and some Substs, produces the monomorphic item type.
 fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     def_id: DefId,
-                    substs: &'tcx subst::Substs<'tcx>)
+                    substs: &'tcx Substs<'tcx>)
                     -> Ty<'tcx> {
     let ty = tcx.lookup_item_type(def_id).ty;
     monomorphize::apply_param_substs(tcx, substs, &ty)
@@ -427,7 +423,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 /// - `substs`: values for each of the fn/method's parameters
 fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     def_id: DefId,
-                    substs: &'tcx subst::Substs<'tcx>)
+                    substs: &'tcx Substs<'tcx>)
                     -> Datum<'tcx, Rvalue> {
     let tcx = ccx.tcx();
 
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 277110347d0..82c86928783 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -732,7 +732,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             create_fn_trans_item(scx.tcx(),
                                  exchange_free_fn_def_id,
                                  fn_substs,
-                                 scx.tcx().mk_substs(Substs::empty()));
+                                 Substs::empty(scx.tcx()));
 
         output.push(exchange_free_fn_trans_item);
     }
@@ -753,8 +753,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                    .drop_trait()
                                    .unwrap();
 
-        let self_type_substs = scx.tcx().mk_substs(
-            Substs::empty().with_self_ty(ty));
+        let self_type_substs = Substs::new_trait(scx.tcx(), vec![], vec![], ty);
 
         let trait_ref = ty::TraitRef {
             def_id: drop_trait_def_id,
@@ -770,7 +769,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             let trans_item = create_fn_trans_item(scx.tcx(),
                                                   destructor_did,
                                                   substs,
-                                                  scx.tcx().mk_substs(Substs::empty()));
+                                                  Substs::empty(scx.tcx()));
             output.push(trans_item);
         }
 
@@ -854,26 +853,15 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
            fn_substs,
            param_substs);
 
-    let is_trait_method = scx.tcx().trait_of_item(fn_def_id).is_some();
-
-    if is_trait_method {
+    if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) {
         match scx.tcx().impl_or_trait_item(fn_def_id) {
             ty::MethodTraitItem(ref method) => {
-                match method.container {
-                    ty::TraitContainer(trait_def_id) => {
-                        debug!(" => trait method, attempting to find impl");
-                        do_static_trait_method_dispatch(scx,
-                                                        method,
-                                                        trait_def_id,
-                                                        fn_substs,
-                                                        param_substs)
-                    }
-                    ty::ImplContainer(_) => {
-                        // This is already a concrete implementation
-                        debug!(" => impl method");
-                        Some((fn_def_id, fn_substs))
-                    }
-                }
+                debug!(" => trait method, attempting to find impl");
+                do_static_trait_method_dispatch(scx,
+                                                method,
+                                                trait_def_id,
+                                                fn_substs,
+                                                param_substs)
             }
             _ => bug!()
         }
@@ -903,13 +891,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
            callee_substs,
            param_substs);
 
+
     let rcvr_substs = monomorphize::apply_param_substs(tcx,
                                                        param_substs,
                                                        &callee_substs);
-
-    let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
-    let trait_ref = tcx.normalize_associated_type(&trait_ref);
-    let vtbl = fulfill_obligation(scx, DUMMY_SP, trait_ref);
+    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
+    let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref));
 
     // Now that we know which impl is being used, we can dispatch to
     // the actual function:
@@ -919,10 +906,10 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             substs: impl_substs,
             nested: _ }) =>
         {
-            let callee_substs = impl_substs.with_method_from(&rcvr_substs);
             let impl_method = meth::get_impl_method(tcx,
+                                                    rcvr_substs,
                                                     impl_did,
-                                                    tcx.mk_substs(callee_substs),
+                                                    impl_substs,
                                                     trait_method.name);
             Some((impl_method.method.def_id, &impl_method.substs))
         }
@@ -1076,7 +1063,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
                                 Some(create_fn_trans_item(scx.tcx(),
                                     impl_method.method.def_id,
                                     impl_method.substs,
-                                    scx.tcx().mk_substs(Substs::empty())))
+                                    Substs::empty(scx.tcx())))
                             } else {
                                 None
                             }
@@ -1248,9 +1235,13 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                     // The substitutions we have are on the impl, so we grab
                     // the method type from the impl to substitute into.
+                    let impl_substs = Substs::for_item(tcx, impl_def_id,
+                                                       |_, _| ty::ReErased,
+                                                       |_, _| tcx.types.err);
                     let mth = meth::get_impl_method(tcx,
-                                                    impl_def_id,
                                                     callee_substs,
+                                                    impl_def_id,
+                                                    impl_substs,
                                                     default_impl.name);
 
                     assert!(mth.is_provided);
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 79cf77cd9d3..b1aaea7d984 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -523,7 +523,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
         let tcx = ccx.tcx();
         match tcx.lang_items.eh_personality() {
             Some(def_id) if !base::wants_msvc_seh(ccx.sess()) => {
-                Callee::def(ccx, def_id, tcx.mk_substs(Substs::empty())).reify(ccx).val
+                Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx).val
             }
             _ => {
                 if let Some(llpersonality) = ccx.eh_personality().get() {
@@ -550,7 +550,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
         let tcx = ccx.tcx();
         assert!(ccx.sess().target.target.options.custom_unwind_resume);
         if let Some(def_id) = tcx.lang_items.eh_unwind_resume() {
-            return Callee::def(ccx, def_id, tcx.mk_substs(Substs::empty()));
+            return Callee::def(ccx, def_id, Substs::empty(tcx));
         }
 
         let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 3ecba3691d2..0e989889677 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -208,7 +208,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let arg_ids = args.iter().map(|arg| arg.pat.id);
     let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
 
-    let substs = ccx.tcx().mk_substs(substs.clone().erase_regions());
+    let substs = ccx.tcx().erase_regions(&substs);
     let substs = monomorphize::apply_param_substs(ccx.tcx(),
                                                   param_substs,
                                                   &substs);
@@ -222,7 +222,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 param_substs: &'tcx Substs<'tcx>)
                                 -> &'tcx hir::Expr {
     let substs = ccx.tcx().node_id_item_substs(ref_expr.id).substs;
-    let substs = ccx.tcx().mk_substs(substs.clone().erase_regions());
+    let substs = ccx.tcx().erase_regions(&substs);
     let substs = monomorphize::apply_param_substs(ccx.tcx(),
                                                   param_substs,
                                                   &substs);
@@ -271,7 +271,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                            param_substs: &'tcx Substs<'tcx>)
                            -> Result<ValueRef, ConstEvalFailure> {
     let expr = get_const_expr(ccx, def_id, ref_expr, param_substs);
-    let empty_substs = ccx.tcx().mk_substs(Substs::empty());
+    let empty_substs = Substs::empty(ccx.tcx());
     match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
         Err(Runtime(err)) => {
             report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit();
@@ -1160,7 +1160,7 @@ pub fn trans_static(ccx: &CrateContext,
         let v = if use_mir {
             ::mir::trans_static_initializer(ccx, def_id)
         } else {
-            let empty_substs = ccx.tcx().mk_substs(Substs::empty());
+            let empty_substs = Substs::empty(ccx.tcx());
             const_expr(ccx, expr, empty_substs, None, TrueConst::Yes)
                 .map(|(v, _)| v)
         }.map_err(|e| e.into_inner())?;
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 65eea1bbb63..c31dbf8943e 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -30,7 +30,7 @@ use monomorphize::Instance;
 use partitioning::CodegenUnit;
 use trans_item::TransItem;
 use type_::{Type, TypeNames};
-use rustc::ty::subst::{Substs, VecPerParamSpace};
+use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
 use session::config::NoDebugInfo;
 use session::Session;
@@ -571,16 +571,9 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
     /// Given the def-id of some item that has no type parameters, make
     /// a suitable "empty substs" for it.
     pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
-        let scheme = self.tcx().lookup_item_type(item_def_id);
-        self.empty_substs_for_scheme(&scheme)
-    }
-
-    pub fn empty_substs_for_scheme(&self, scheme: &ty::TypeScheme<'tcx>)
-                                   -> &'tcx Substs<'tcx> {
-        assert!(scheme.generics.types.is_empty());
-        self.tcx().mk_substs(
-            Substs::new(VecPerParamSpace::empty(),
-                        scheme.generics.regions.map(|_| ty::ReErased)))
+        Substs::for_item(self.tcx(), item_def_id, |_, _| ty::ReErased, |_, _| {
+            bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
+        })
     }
 
     pub fn symbol_hasher(&self) -> &RefCell<Sha256> {
@@ -999,11 +992,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
         self.shared().empty_substs_for_def_id(item_def_id)
     }
-
-    pub fn empty_substs_for_scheme(&self, scheme: &ty::TypeScheme<'tcx>)
-                                   -> &'tcx Substs<'tcx> {
-        self.shared().empty_substs_for_scheme(scheme)
-    }
 }
 
 pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
diff --git a/src/librustc_trans/controlflow.rs b/src/librustc_trans/controlflow.rs
index 8845f124218..8b3a8a2bfcc 100644
--- a/src/librustc_trans/controlflow.rs
+++ b/src/librustc_trans/controlflow.rs
@@ -401,7 +401,7 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc");
     let args = vec!(expr_file_line);
     let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicFnLangItem);
-    Callee::def(ccx, did, ccx.tcx().mk_substs(Substs::empty()))
+    Callee::def(ccx, did, Substs::empty(ccx.tcx()))
         .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx
 }
 
@@ -429,6 +429,6 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc");
     let args = vec!(file_line, index, len);
     let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicBoundsCheckFnLangItem);
-    Callee::def(ccx, did, ccx.tcx().mk_substs(Substs::empty()))
+    Callee::def(ccx, did, Substs::empty(ccx.tcx()))
         .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx
 }
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 6a99f12b278..e80dd28c5e5 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -27,7 +27,7 @@ use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType};
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util;
-use rustc::ty::subst;
+use rustc::ty::subst::Substs;
 use rustc::hir::map as hir_map;
 use rustc::hir::{self, PatKind};
 use {type_of, adt, machine, monomorphize};
@@ -315,7 +315,7 @@ impl<'tcx> TypeMap<'tcx> {
         fn from_def_id_and_substs<'a, 'tcx>(type_map: &mut TypeMap<'tcx>,
                                             cx: &CrateContext<'a, 'tcx>,
                                             def_id: DefId,
-                                            substs: &subst::Substs<'tcx>,
+                                            substs: &Substs<'tcx>,
                                             output: &mut String) {
             // First, find out the 'real' def_id of the type. Items inlined from
             // other crates have to be mapped back to their source.
@@ -346,7 +346,7 @@ impl<'tcx> TypeMap<'tcx> {
             // Add the def-index as the second part
             output.push_str(&format!("{:x}", def_id.index.as_usize()));
 
-            let tps = substs.types.get_slice(subst::TypeSpace);
+            let tps = substs.types.as_full_slice();
             if !tps.is_empty() {
                 output.push('<');
 
@@ -1086,7 +1086,7 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
 // Creates MemberDescriptions for the fields of a struct
 struct StructMemberDescriptionFactory<'tcx> {
     variant: ty::VariantDef<'tcx>,
-    substs: &'tcx subst::Substs<'tcx>,
+    substs: &'tcx Substs<'tcx>,
     is_simd: bool,
     span: Span,
 }
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index 1aae3b3127f..963cc09e1ab 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -266,7 +266,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     // Get_template_parameters() will append a `<...>` clause to the function
     // name if necessary.
-    let generics = cx.tcx().lookup_item_type(fn_def_id).generics;
+    let generics = cx.tcx().lookup_generics(fn_def_id);
     let template_parameters = get_template_parameters(cx,
                                                       &generics,
                                                       instance.substs,
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 4bca091ef95..20dbc8ac78e 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -12,7 +12,7 @@
 
 use common::CrateContext;
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst;
+use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty};
 
 use rustc::hir;
@@ -173,7 +173,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     // would be possible but with inlining and LTO we have to use the least
     // common denominator - otherwise we would run into conflicts.
     fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                  substs: &subst::Substs<'tcx>,
+                                  substs: &Substs<'tcx>,
                                   output: &mut String) {
         if substs.types.is_empty() {
             return;
diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs
index 6c894ddad1a..beb589c80bf 100644
--- a/src/librustc_trans/expr.rs
+++ b/src/librustc_trans/expr.rs
@@ -175,7 +175,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 hir::ExprPath(..) => {
                     match bcx.tcx().expect_def(expr.id) {
                         Def::Const(did) | Def::AssociatedConst(did) => {
-                            let empty_substs = bcx.tcx().mk_substs(Substs::empty());
+                            let empty_substs = Substs::empty(bcx.tcx());
                             let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
                                                                     empty_substs);
                             // Temporarily get cleanup scopes out of the way,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 93e5f4ba1e2..080844782f2 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -50,7 +50,7 @@ pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem);
     let args = [PointerCast(bcx, v, Type::i8p(bcx.ccx())), size, align];
-    Callee::def(bcx.ccx(), def_id, bcx.tcx().mk_substs(Substs::empty()))
+    Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx()))
         .call(bcx, debug_loc, ArgVals(&args), None).bcx
 }
 
@@ -356,7 +356,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let trait_ref = ty::Binder(ty::TraitRef {
         def_id: tcx.lang_items.drop_trait().unwrap(),
-        substs: tcx.mk_substs(Substs::empty().with_self_ty(t))
+        substs: Substs::new_trait(tcx, vec![], vec![], t)
     });
     let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) {
         traits::VtableImpl(data) => data,
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 7be173d17b4..133a98a2470 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -15,8 +15,7 @@ use intrinsics::{self, Intrinsic};
 use libc;
 use llvm;
 use llvm::{ValueRef, TypeKind};
-use rustc::ty::subst;
-use rustc::ty::subst::FnSpace;
+use rustc::ty::subst::{FnSpace, Substs};
 use abi::{Abi, FnType};
 use adt;
 use base::*;
@@ -1284,7 +1283,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
 fn generic_simd_intrinsic<'blk, 'tcx, 'a>
     (bcx: Block<'blk, 'tcx>,
      name: &str,
-     substs: &'tcx subst::Substs<'tcx>,
+     substs: &'tcx Substs<'tcx>,
      callee_ty: Ty<'tcx>,
      args: Option<&[P<hir::Expr>]>,
      llargs: &[ValueRef],
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 169242fbf72..b051028ebda 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -15,8 +15,7 @@ use arena::TypedArena;
 use back::symbol_names;
 use llvm::{ValueRef, get_params};
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst::{FnSpace, Subst, Substs};
-use rustc::ty::subst;
+use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, Reveal};
 use abi::FnType;
 use base::*;
@@ -221,20 +220,20 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     impl_id: DefId,
-                                    substs: &'tcx subst::Substs<'tcx>)
+                                    substs: &'tcx Substs<'tcx>)
                                     -> Vec<Option<ImplMethod<'tcx>>>
 {
     debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs);
 
-    let trt_id = match tcx.impl_trait_ref(impl_id) {
+    let trait_id = match tcx.impl_trait_ref(impl_id) {
         Some(t_id) => t_id.def_id,
         None       => bug!("make_impl_vtable: don't know how to \
                             make a vtable for a type impl!")
     };
 
-    tcx.populate_implementations_for_trait_if_necessary(trt_id);
+    tcx.populate_implementations_for_trait_if_necessary(trait_id);
 
-    let trait_item_def_ids = tcx.trait_item_def_ids(trt_id);
+    let trait_item_def_ids = tcx.trait_item_def_ids(trait_id);
     trait_item_def_ids
         .iter()
 
@@ -260,7 +259,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let name = trait_method_type.name;
 
             // Some methods cannot be called on an object; skip those.
-            if !tcx.is_vtable_safe_method(trt_id, &trait_method_type) {
+            if !tcx.is_vtable_safe_method(trait_id, &trait_method_type) {
                 debug!("get_vtable_methods: not vtable safe");
                 return None;
             }
@@ -270,15 +269,13 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             // the method may have some early-bound lifetimes, add
             // regions for those
-            let num_dummy_regions = trait_method_type.generics.regions.len(FnSpace);
-            let dummy_regions = vec![ty::ReErased; num_dummy_regions];
-            let method_substs = substs.clone()
-                                      .with_method(vec![], dummy_regions);
-            let method_substs = tcx.mk_substs(method_substs);
+            let method_substs = Substs::for_item(tcx, trait_method_def_id,
+                                                 |_, _| ty::ReErased,
+                                                 |_, _| tcx.types.err);
 
             // The substitutions we have are on the impl, so we grab
             // the method type from the impl to substitute into.
-            let mth = get_impl_method(tcx, impl_id, method_substs, name);
+            let mth = get_impl_method(tcx, method_substs, impl_id, substs, name);
 
             debug!("get_vtable_methods: mth={:?}", mth);
 
@@ -309,8 +306,9 @@ pub struct ImplMethod<'tcx> {
 
 /// Locates the applicable definition of a method, given its name.
 pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 impl_def_id: DefId,
                                  substs: &'tcx Substs<'tcx>,
+                                 impl_def_id: DefId,
+                                 impl_substs: &'tcx Substs<'tcx>,
                                  name: Name)
                                  -> ImplMethod<'tcx>
 {
@@ -322,6 +320,7 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
         Some(node_item) => {
             let substs = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
+                let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs);
                 let substs = traits::translate_substs(&infcx, impl_def_id,
                                                       substs, node_item.node);
                 tcx.lift(&substs).unwrap_or_else(|| {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 31fee560fe3..4da973bb7f9 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -232,12 +232,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                  args: IndexVec<mir::Arg, Const<'tcx>>)
                  -> Result<Const<'tcx>, ConstEvalFailure> {
         // Try to resolve associated constants.
-        if instance.substs.self_ty().is_some() {
-            // Only trait items can have a Self parameter.
-            let trait_item = ccx.tcx().impl_or_trait_item(instance.def);
-            let trait_id = trait_item.container().id();
-            let substs = instance.substs;
-            let trait_ref = ty::Binder(substs.to_trait_ref(ccx.tcx(), trait_id));
+        if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
+            let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
+            let trait_ref = ty::Binder(trait_ref);
             let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
             if let traits::VtableImpl(vtable_impl) = vtable {
                 let name = ccx.tcx().item_name(instance.def);
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index 663c5167d14..26278e886c2 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -12,7 +12,6 @@ use llvm::ValueRef;
 use llvm;
 use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
-use rustc::ty::subst;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TypeFoldable, TyCtxt};
 use attributes;
@@ -33,7 +32,7 @@ use trans_item::TransItem;
 
 pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 fn_id: DefId,
-                                psubsts: &'tcx subst::Substs<'tcx>)
+                                psubsts: &'tcx Substs<'tcx>)
                                 -> (ValueRef, Ty<'tcx>) {
     debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts);
     assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types());
@@ -174,7 +173,7 @@ pub struct Instance<'tcx> {
 
 impl<'tcx> fmt::Display for Instance<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[], |_| None)
+        ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[])
     }
 }
 
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index ade6e8abeb3..f24ab0f6557 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -125,6 +125,7 @@ use rustc::hir::map::DefPathData;
 use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
 use rustc::ty::TyCtxt;
 use rustc::ty::item_path::characteristic_def_id_of_type;
+use rustc::ty::subst;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher, SipHasher};
 use std::sync::Arc;
@@ -486,7 +487,8 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // its self-type. If the self-type does not provide a characteristic
             // DefId, we use the location of the impl after all.
 
-            if let Some(self_ty) = instance.substs.self_ty() {
+            if tcx.trait_of_item(instance.def).is_some() {
+                let self_ty = *instance.substs.types.get(subst::SelfSpace, 0);
                 // This is an implementation of a trait method.
                 return characteristic_def_id_of_type(self_ty).or(Some(instance.def));
             }
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 2dd07cf4405..ebd4a80deb9 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -28,7 +28,7 @@ use rustc::hir;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::subst;
+use rustc::ty::subst::{Substs, VecPerParamSpace};
 use rustc_const_eval::fatal_const_eval_err;
 use std::hash::{Hash, Hasher};
 use syntax::ast::{self, NodeId};
@@ -352,8 +352,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
             },
             TransItem::Static(node_id) => {
                 let def_id = hir_map.local_def_id(node_id);
-                let instance = Instance::new(def_id,
-                                             tcx.mk_substs(subst::Substs::empty()));
+                let instance = Instance::new(def_id, Substs::empty(tcx));
                 to_string_internal(tcx, "static ", instance)
             },
         };
@@ -561,7 +560,7 @@ fn push_item_name(tcx: TyCtxt,
 }
 
 fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              types: &'tcx subst::VecPerParamSpace<Ty<'tcx>>,
+                              types: &'tcx VecPerParamSpace<Ty<'tcx>>,
                               projections: &[ty::PolyExistentialProjection<'tcx>],
                               output: &mut String) {
     if types.is_empty() && projections.is_empty() {
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index e6794149fcb..7e592d1b74d 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -11,7 +11,6 @@
 #![allow(non_camel_case_types)]
 
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst;
 use abi::FnType;
 use adt;
 use common::*;
@@ -257,7 +256,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
           // avoids creating more than one copy of the enum when one
           // of the enum's variants refers to the enum itself.
           let repr = adt::represent_type(cx, t);
-          let tps = substs.types.get_slice(subst::TypeSpace);
+          let tps = substs.types.as_full_slice();
           let name = llvm_type_name(cx, def.did, tps);
           adt::incomplete_type_of(cx, &repr, &name[..])
       }
@@ -336,7 +335,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
               // in *after* placing it into the type cache. This prevents
               // infinite recursion with recursive struct types.
               let repr = adt::represent_type(cx, t);
-              let tps = substs.types.get_slice(subst::TypeSpace);
+              let tps = substs.types.as_full_slice();
               let name = llvm_type_name(cx, def.did, tps);
               adt::incomplete_type_of(cx, &repr, &name[..])
           }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 11ca012fded..5655c7c8e72 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -81,6 +81,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>>>;
 
+    /// Returns the generic type and lifetime parameters for an item.
+    fn get_generics(&self, span: Span, id: DefId)
+                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>;
+
     /// Identify the type scheme for an item with a type, like a type
     /// alias, fn, or struct. This allows you to figure out the set of
     /// type parameters defined on the item.
@@ -348,7 +352,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         rscope: &RegionScope,
         span: Span,
         param_mode: PathParamMode,
-        decl_generics: &ty::Generics<'tcx>,
+        def_id: DefId,
         item_segment: &hir::PathSegment)
         -> &'tcx Substs<'tcx>
     {
@@ -362,11 +366,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     .span_label(span, &format!("only traits may use parentheses"))
                     .emit();
 
-                return tcx.mk_substs(Substs::from_generics(decl_generics, |_, _| {
+                return Substs::for_item(tcx, def_id, |_, _| {
                     ty::ReStatic
                 }, |_, _| {
                     tcx.types.err
-                }));
+                });
             }
         }
 
@@ -374,7 +378,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             self.create_substs_for_ast_path(rscope,
                                             span,
                                             param_mode,
-                                            decl_generics,
+                                            def_id,
                                             &item_segment.parameters,
                                             None);
 
@@ -392,16 +396,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         rscope: &RegionScope,
         span: Span,
         param_mode: PathParamMode,
-        decl_generics: &ty::Generics<'tcx>,
+        def_id: DefId,
         parameters: &hir::PathParameters,
         self_ty: Option<Ty<'tcx>>)
         -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
     {
         let tcx = self.tcx();
 
-        debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
+        debug!("create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \
                parameters={:?})",
-               decl_generics, self_ty, parameters);
+               def_id, self_ty, parameters);
 
         let (lifetimes, num_types_provided) = match *parameters {
             hir::AngleBracketedParameters(ref data) => {
@@ -417,6 +421,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
         // whatever & would get replaced with).
+        let decl_generics = match self.get_generics(span, def_id) {
+            Ok(generics) => generics,
+            Err(ErrorReported) => {
+                // No convenient way to recover from a cycle here. Just bail. Sorry!
+                self.tcx().sess.abort_if_errors();
+                bug!("ErrorReported returned, but no errors reports?")
+            }
+        };
         let expected_num_region_params = decl_generics.regions.len(TypeSpace);
         let supplied_num_region_params = lifetimes.len();
         let regions = if expected_num_region_params == supplied_num_region_params {
@@ -438,7 +450,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         };
 
         // If a self-type was declared, one should be provided.
-        assert_eq!(decl_generics.types.get_self().is_some(), self_ty.is_some());
+        assert_eq!(decl_generics.has_self, self_ty.is_some());
 
         // Check the number of type parameters supplied by the user.
         if let Some(num_provided) = num_types_provided {
@@ -460,7 +472,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         };
 
         let mut output_assoc_binding = None;
-        let substs = Substs::from_generics(decl_generics, |def, _| {
+        let substs = Substs::for_item(tcx, def_id, |def, _| {
             assert_eq!(def.space, TypeSpace);
             regions[def.index as usize]
         }, |def, substs| {
@@ -532,7 +544,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 vec![output_assoc_binding.unwrap_or_else(|| {
                     // This is an error condition, but we should
                     // get the associated type binding anyway.
-                    self.convert_parenthesized_parameters(rscope, &substs, data).1
+                    self.convert_parenthesized_parameters(rscope, substs, data).1
                 })]
             }
         };
@@ -540,7 +552,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}",
                decl_generics, self_ty, substs);
 
-        (tcx.mk_substs(substs), assoc_bindings)
+        (substs, assoc_bindings)
     }
 
     /// Returns the appropriate lifetime to use for any output lifetimes
@@ -803,7 +815,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         self.create_substs_for_ast_path(rscope,
                                         span,
                                         param_mode,
-                                        &trait_def.generics,
+                                        trait_def_id,
                                         &trait_segment.parameters,
                                         Some(self_ty))
     }
@@ -910,10 +922,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         -> Ty<'tcx>
     {
         let tcx = self.tcx();
-        let (generics, decl_ty) = match self.get_item_type_scheme(span, did) {
-            Ok(ty::TypeScheme { generics,  ty: decl_ty }) => {
-                (generics, decl_ty)
-            }
+        let decl_ty = match self.get_item_type_scheme(span, did) {
+            Ok(type_scheme) => type_scheme.ty,
             Err(ErrorReported) => {
                 return tcx.types.err;
             }
@@ -922,7 +932,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let substs = self.ast_path_substs_for_ty(rscope,
                                                  span,
                                                  param_mode,
-                                                 &generics,
+                                                 did,
                                                  item_segment);
 
         // FIXME(#12938): This is a hack until we have full support for DST.
@@ -1682,7 +1692,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // Create the anonymized type.
                 let def_id = tcx.map.local_def_id(ast_ty.id);
                 if let Some(anon_scope) = rscope.anon_type_scope() {
-                    let substs = anon_scope.fresh_substs(tcx);
+                    let substs = anon_scope.fresh_substs(self, ast_ty.span);
                     let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs);
 
                     // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 04f22b19511..af24a7b5117 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -547,10 +547,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
 
         // Type check the path.
-        let scheme = tcx.lookup_item_type(def.def_id());
-        let predicates = tcx.lookup_predicates(def.def_id());
-        let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
-                                                 opt_ty, def, pat.span, pat.id);
+        let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
         self.demand_suptype(pat.span, expected, pat_ty);
     }
 
@@ -607,18 +604,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
 
         // Type check the path.
-        let scheme = tcx.lookup_item_type(def.def_id());
-        let scheme = if scheme.ty.is_fn() {
+        let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
+
+        let pat_ty = if pat_ty.is_fn() {
             // Replace constructor type with constructed type for tuple struct patterns.
-            let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap();
-            ty::TypeScheme { ty: fn_ret, generics: scheme.generics }
+            tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap()
         } else {
             // Leave the type as is for unit structs (backward compatibility).
-            scheme
+            pat_ty
         };
-        let predicates = tcx.lookup_predicates(def.def_id());
-        let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
-                                                 opt_ty, def, pat.span, pat.id);
+        self.write_ty(pat.id, pat_ty);
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index 265422468fe..9a3cbabe553 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
                 Some(f) => f,
                 None => return None
             },
-            substs: tcx.mk_substs(Substs::new_trait(vec![], vec![], self.cur_ty))
+            substs: Substs::new_trait(tcx, vec![], vec![], self.cur_ty)
         };
 
         let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index d501a8a184c..3cb528eba63 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -194,10 +194,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     // Create mapping from trait to skolemized.
     let trait_to_skol_substs =
-        trait_to_impl_substs
-        .subst(tcx, impl_to_skol_substs).clone()
-        .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
-                     impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
+        impl_to_skol_substs.rebase_onto(tcx, impl_m.container_id(),
+                                        trait_to_impl_substs.subst(tcx, impl_to_skol_substs));
     debug!("compare_impl_method: trait_to_skol_substs={:?}",
            trait_to_skol_substs);
 
@@ -208,7 +206,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                            impl_m,
                                            &trait_m.generics,
                                            &impl_m.generics,
-                                           &trait_to_skol_substs,
+                                           trait_to_skol_substs,
                                            impl_to_skol_substs) {
         return;
     }
@@ -226,7 +224,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
         // Normalize the associated types in the trait_bounds.
-        let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs);
+        let trait_bounds = trait_m.predicates.instantiate(tcx, trait_to_skol_substs);
 
         // Create obligations for each predicate declared by the impl
         // definition in the context of the trait's parameter
@@ -323,7 +321,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             infcx.parameter_environment.free_id_outlive,
             &trait_m.fty.sig);
         let trait_sig =
-            trait_sig.subst(tcx, &trait_to_skol_substs);
+            trait_sig.subst(tcx, trait_to_skol_substs);
         let trait_sig =
             assoc::normalize_associated_types_in(&infcx,
                                                  &mut fulfillment_cx,
@@ -454,16 +452,14 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         // Create mapping from trait to skolemized.
         let trait_to_skol_substs =
-            trait_to_impl_substs
-            .subst(tcx, impl_to_skol_substs).clone()
-            .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
-                         impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
+            impl_to_skol_substs.rebase_onto(tcx, impl_c.container.id(),
+                                            trait_to_impl_substs.subst(tcx, impl_to_skol_substs));
         debug!("compare_const_impl: trait_to_skol_substs={:?}",
             trait_to_skol_substs);
 
         // Compute skolemized form of impl and trait const tys.
         let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
-        let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
+        let trait_ty = trait_c.ty.subst(tcx, trait_to_skol_substs);
         let mut origin = TypeOrigin::Misc(impl_c_span);
 
         let err = infcx.commit_if_ok(|_| {
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 1e2446788ad..7d79fc4fbf8 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -15,7 +15,7 @@ use hir::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use rustc::infer;
 use middle::region;
-use rustc::ty::subst::{self, Subst};
+use rustc::ty::subst::{self, Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::traits::{self, Reveal};
 use util::nodemap::FnvHashSet;
@@ -41,16 +41,14 @@ use syntax_pos::{self, Span};
 ///    cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
 ///
 pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> {
-    let ty::TypeScheme { generics: ref dtor_generics,
-                         ty: dtor_self_type } = ccx.tcx.lookup_item_type(drop_impl_did);
+    let dtor_self_type = ccx.tcx.lookup_item_type(drop_impl_did).ty;
     let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did);
     match dtor_self_type.sty {
         ty::TyEnum(adt_def, self_to_impl_substs) |
         ty::TyStruct(adt_def, self_to_impl_substs) => {
             ensure_drop_params_and_item_params_correspond(ccx,
                                                           drop_impl_did,
-                                                          dtor_generics,
-                                                          &dtor_self_type,
+                                                          dtor_self_type,
                                                           adt_def.did)?;
 
             ensure_drop_predicates_are_implied_by_item_defn(ccx,
@@ -73,8 +71,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
 fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
     ccx: &CrateCtxt<'a, 'tcx>,
     drop_impl_did: DefId,
-    drop_impl_generics: &ty::Generics<'tcx>,
-    drop_impl_ty: &ty::Ty<'tcx>,
+    drop_impl_ty: Ty<'tcx>,
     self_type_did: DefId) -> Result<(), ()>
 {
     let tcx = ccx.tcx;
@@ -93,8 +90,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
 
         let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP);
         let fresh_impl_substs =
-            infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
-        let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs);
+            infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
+        let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
 
         if let Err(_) = infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span),
                                        named_type, fresh_impl_self_ty) {
@@ -131,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
     drop_impl_did: DefId,
     dtor_predicates: &ty::GenericPredicates<'tcx>,
     self_type_did: DefId,
-    self_to_impl_substs: &subst::Substs<'tcx>) -> Result<(), ()> {
+    self_to_impl_substs: &Substs<'tcx>) -> Result<(), ()> {
 
     // Here is an example, analogous to that from
     // `compare_impl_method`.
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 4334f043772..bfedb4fa6e1 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -36,11 +36,11 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let def_id = tcx.map.local_def_id(it.id);
     let i_ty = tcx.lookup_item_type(def_id);
 
-    let mut substs = Substs::empty();
-    substs.types = i_ty.generics.types.map(|def| tcx.mk_param_from_def(def));
+    let substs = Substs::for_item(tcx, def_id,
+                                  |_, _| ty::ReErased,
+                                  |def, _| tcx.mk_param_from_def(def));
 
-    let fty = tcx.mk_fn_def(def_id, tcx.mk_substs(substs),
-                            tcx.mk_bare_fn(ty::BareFnTy {
+    let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: abi,
         sig: ty::Binder(FnSig {
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 250bf9265d1..c071fce9896 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -12,7 +12,7 @@ use super::probe;
 
 use check::{FnCtxt, callee};
 use hir::def_id::DefId;
-use rustc::ty::subst::{self};
+use rustc::ty::subst::{self, Substs};
 use rustc::traits;
 use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
 use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
@@ -42,10 +42,6 @@ struct InstantiatedMethodSig<'tcx> {
     /// argument is the receiver.
     method_sig: ty::FnSig<'tcx>,
 
-    /// Substitutions for all types/early-bound-regions declared on
-    /// the method.
-    all_substs: subst::Substs<'tcx>,
-
     /// Generic bounds on the method's parameters which must be added
     /// as pending obligations.
     method_predicates: ty::InstantiatedPredicates<'tcx>,
@@ -105,9 +101,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
         // Create the final signature for the method, replacing late-bound regions.
         let InstantiatedMethodSig {
-            method_sig, all_substs, method_predicates
+            method_sig, method_predicates
         } = self.instantiate_method_sig(&pick, all_substs);
-        let all_substs = self.tcx.mk_substs(all_substs);
         let method_self_ty = method_sig.inputs[0];
 
         // Unify the (adjusted) self type with what the method expects.
@@ -198,7 +193,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
     fn fresh_receiver_substs(&mut self,
                              self_ty: Ty<'tcx>,
                              pick: &probe::Pick<'tcx>)
-                             -> &'tcx subst::Substs<'tcx>
+                             -> &'tcx Substs<'tcx>
     {
         match pick.kind {
             probe::InherentImplPick => {
@@ -256,16 +251,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
             probe::TraitPick => {
                 let trait_def_id = pick.item.container().id();
-                let trait_def = self.tcx.lookup_trait_def(trait_def_id);
 
                 // Make a trait reference `$0 : Trait<$1...$n>`
                 // consisting entirely of type variables. Later on in
                 // the process we will unify the transformed-self-type
                 // of the method with the actual type in order to
                 // unify some of these variables.
-                self.fresh_substs_for_trait(self.span,
-                                            &trait_def.generics,
-                                            self.next_ty_var())
+                self.fresh_substs_for_item(self.span, trait_def_id)
             }
 
             probe::WhereClausePick(ref poly_trait_ref) => {
@@ -308,8 +300,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
     fn instantiate_method_substs(&mut self,
                                  pick: &probe::Pick<'tcx>,
                                  mut supplied_method_types: Vec<Ty<'tcx>>,
-                                 substs: &subst::Substs<'tcx>)
-                                 -> subst::Substs<'tcx>
+                                 substs: &Substs<'tcx>)
+                                 -> &'tcx Substs<'tcx>
     {
         // Determine the values for the generic parameters of the method.
         // If they were not explicitly supplied, just construct fresh
@@ -335,7 +327,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // parameters from the type and those from the method.
         //
         // FIXME -- permit users to manually specify lifetimes
-        subst::Substs::from_generics(&method.generics, |def, _| {
+        Substs::for_item(self.tcx, method.def_id, |def, _| {
             if def.space != subst::FnSpace {
                 substs.region_for_def(def)
             } else {
@@ -376,7 +368,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
     fn instantiate_method_sig(&mut self,
                               pick: &probe::Pick<'tcx>,
-                              all_substs: subst::Substs<'tcx>)
+                              all_substs: &'tcx Substs<'tcx>)
                               -> InstantiatedMethodSig<'tcx>
     {
         debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
@@ -387,7 +379,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // type/early-bound-regions substitutions performed. There can
         // be no late-bound regions appearing here.
         let method_predicates = pick.item.as_opt_method().unwrap()
-                                    .predicates.instantiate(self.tcx, &all_substs);
+                                    .predicates.instantiate(self.tcx, all_substs);
         let method_predicates = self.normalize_associated_types_in(self.span,
                                                                    &method_predicates);
 
@@ -405,20 +397,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
                method_sig);
 
-        let method_sig = self.instantiate_type_scheme(self.span, &all_substs, &method_sig);
+        let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
         debug!("type scheme substituted, method_sig={:?}",
                method_sig);
 
         InstantiatedMethodSig {
             method_sig: method_sig,
-            all_substs: all_substs,
             method_predicates: method_predicates,
         }
     }
 
     fn add_obligations(&mut self,
                        fty: Ty<'tcx>,
-                       all_substs: &subst::Substs<'tcx>,
+                       all_substs: &Substs<'tcx>,
                        method_predicates: &ty::InstantiatedPredicates<'tcx>) {
         debug!("add_obligations: fty={:?} all_substs={:?} method_predicates={:?}",
                fty,
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index ff34f37bde0..e5107af6ca0 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -13,7 +13,7 @@
 use check::FnCtxt;
 use hir::def::Def;
 use hir::def_id::DefId;
-use rustc::ty::subst;
+use rustc::ty::subst::{self, Substs};
 use rustc::traits;
 use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
 use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
@@ -189,7 +189,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         assert!(trait_def.generics.regions.is_empty());
 
         // Construct a trait-reference `self_ty : Trait<input_tys>`
-        let substs = subst::Substs::from_generics(&trait_def.generics, |def, _| {
+        let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| {
             self.region_var_for_def(span, def)
         }, |def, substs| {
             if def.space == subst::SelfSpace {
@@ -201,7 +201,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         });
 
-        let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs));
+        let trait_ref = ty::TraitRef::new(trait_def_id, substs);
 
         // Construct an obligation
         let poly_trait_ref = trait_ref.to_poly_trait_ref();
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index f6ac3235cf3..448ea243655 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -16,8 +16,7 @@ use super::suggest;
 use check::{FnCtxt};
 use hir::def_id::DefId;
 use hir::def::Def;
-use rustc::ty::subst;
-use rustc::ty::subst::Subst;
+use rustc::ty::subst::{self, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
 use rustc::infer::{InferOk, TypeOrigin};
@@ -80,9 +79,9 @@ struct Candidate<'tcx> {
 
 #[derive(Debug)]
 enum CandidateKind<'tcx> {
-    InherentImplCandidate(subst::Substs<'tcx>,
+    InherentImplCandidate(&'tcx Substs<'tcx>,
                           /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
-    ExtensionImplCandidate(/* Impl */ DefId, subst::Substs<'tcx>,
+    ExtensionImplCandidate(/* Impl */ DefId, &'tcx Substs<'tcx>,
                            /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
     ObjectCandidate,
     TraitCandidate,
@@ -421,10 +420,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         }
 
         let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
-        let impl_ty = impl_ty.subst(self.tcx, &impl_substs);
+        let impl_ty = impl_ty.subst(self.tcx, impl_substs);
 
         // Determine the receiver type that the method itself expects.
-        let xform_self_ty = self.xform_self_ty(&item, impl_ty, &impl_substs);
+        let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs);
 
         // We can't use normalize_associated_types_in as it will pollute the
         // fcx's fulfillment context after this probe is over.
@@ -519,14 +518,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                        trait_ref,
                        trait_ref.substs,
                        m);
-                assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
-                           trait_ref.substs.types.get_slice(subst::TypeSpace).len());
-                assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
-                           trait_ref.substs.regions.get_slice(subst::TypeSpace).len());
-                assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
-                           trait_ref.substs.types.get_slice(subst::SelfSpace).len());
-                assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
-                           trait_ref.substs.regions.get_slice(subst::SelfSpace).len());
+                assert_eq!(m.generics.types.len(subst::TypeSpace),
+                           trait_ref.substs.types.len(subst::TypeSpace));
+                assert_eq!(m.generics.regions.len(subst::TypeSpace),
+                           trait_ref.substs.regions.len(subst::TypeSpace));
+                assert_eq!(m.generics.types.len(subst::SelfSpace),
+                           trait_ref.substs.types.len(subst::SelfSpace));
+                assert_eq!(m.generics.regions.len(subst::SelfSpace),
+                           trait_ref.substs.regions.len(subst::SelfSpace));
             }
 
             // Because this trait derives from a where-clause, it
@@ -665,7 +664,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             let impl_trait_ref =
                 self.tcx.impl_trait_ref(impl_def_id)
                 .unwrap() // we know this is a trait impl
-                .subst(self.tcx, &impl_substs);
+                .subst(self.tcx, impl_substs);
 
             debug!("impl_trait_ref={:?}", impl_trait_ref);
 
@@ -753,14 +752,21 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             // for the purposes of our method lookup, we only take
             // receiver type into account, so we can just substitute
             // fresh types here to use during substitution and subtyping.
-            let trait_def = self.tcx.lookup_trait_def(trait_def_id);
-            let substs = self.fresh_substs_for_trait(self.span,
-                                                     &trait_def.generics,
-                                                     step.self_ty);
+            let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| {
+                self.region_var_for_def(self.span, def)
+            }, |def, substs| {
+                if def.space == subst::SelfSpace {
+                    assert_eq!(def.index, 0);
+                    step.self_ty
+                } else {
+                    assert_eq!(def.space, subst::TypeSpace);
+                    self.type_var_for_def(self.span, def, substs)
+                }
+            });
 
             let xform_self_ty = self.xform_self_ty(&item,
                                                    step.self_ty,
-                                                   &substs);
+                                                   substs);
             self.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
                 item: item.clone(),
@@ -1192,7 +1198,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn xform_self_ty(&self,
                      item: &ty::ImplOrTraitItem<'tcx>,
                      impl_ty: Ty<'tcx>,
-                     substs: &subst::Substs<'tcx>)
+                     substs: &Substs<'tcx>)
                      -> Ty<'tcx>
     {
         match item.as_opt_method() {
@@ -1205,7 +1211,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn xform_method_self_ty(&self,
                             method: &Rc<ty::Method<'tcx>>,
                             impl_ty: Ty<'tcx>,
-                            substs: &subst::Substs<'tcx>)
+                            substs: &Substs<'tcx>)
                             -> Ty<'tcx>
     {
         debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
@@ -1236,7 +1242,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
            method.generics.regions.is_empty_in(subst::FnSpace) {
             xform_self_ty.subst(self.tcx, substs)
         } else {
-            let substs = subst::Substs::from_generics(&method.generics, |def, _| {
+            let substs = Substs::for_item(self.tcx, method.def_id, |def, _| {
                 if def.space != subst::FnSpace {
                     substs.region_for_def(def)
                 } else {
@@ -1251,14 +1257,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                     self.type_var_for_def(self.span, def, cur_substs)
                 }
             });
-            xform_self_ty.subst(self.tcx, &substs)
+            xform_self_ty.subst(self.tcx, substs)
         }
     }
 
     /// Get the type of an impl and generate substitutions with placeholders.
     fn impl_ty_and_substs(&self,
                           impl_def_id: DefId)
-                          -> (Ty<'tcx>, subst::Substs<'tcx>)
+                          -> (Ty<'tcx>, &'tcx Substs<'tcx>)
     {
         let impl_pty = self.tcx.lookup_item_type(impl_def_id);
 
@@ -1270,8 +1276,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             impl_pty.generics.regions.map(
                 |_| ty::ReErased); // see erase_late_bound_regions() for an expl of why 'erased
 
-        let substs = subst::Substs::new(type_vars, region_placeholders);
-        (impl_pty.ty, substs)
+        (impl_pty.ty, Substs::new(self.tcx, type_vars, region_placeholders))
     }
 
     /// Replace late-bound-regions bound by `value` with `'static` using
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index dc6fa334b74..573dae46456 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -54,10 +54,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| {
                     let fn_once_substs =
-                        Substs::new_trait(vec![self.next_ty_var()], vec![], ty);
-                    let trait_ref =
-                        ty::TraitRef::new(fn_once,
-                                          tcx.mk_substs(fn_once_substs));
+                        Substs::new_trait(tcx, vec![self.next_ty_var()], vec![], ty);
+                    let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
                     let poly_trait_ref = trait_ref.to_poly_trait_ref();
                     let obligation = Obligation::misc(span,
                                                       self.body_id,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c41bb1930d4..700fb2ecf42 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -90,7 +90,6 @@ use hir::pat_util;
 use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
 use rustc::ty::subst::{self, Subst, Substs};
 use rustc::traits::{self, Reveal};
-use rustc::ty::{GenericPredicates, TypeScheme};
 use rustc::ty::{ParamTy, ParameterEnvironment};
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
@@ -745,26 +744,20 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
           let impl_def_id = ccx.tcx.map.local_def_id(it.id);
           match ccx.tcx.impl_trait_ref(impl_def_id) {
               Some(impl_trait_ref) => {
-                  let trait_def_id = impl_trait_ref.def_id;
-
                   check_impl_items_against_trait(ccx,
                                                  it.span,
                                                  impl_def_id,
                                                  &impl_trait_ref,
                                                  impl_items);
-                  check_on_unimplemented(
-                      ccx,
-                      &ccx.tcx.lookup_trait_def(trait_def_id).generics,
-                      it,
-                      ccx.tcx.item_name(trait_def_id));
+                  let trait_def_id = impl_trait_ref.def_id;
+                  check_on_unimplemented(ccx, trait_def_id, it);
               }
               None => { }
           }
       }
       hir::ItemTrait(..) => {
         let def_id = ccx.tcx.map.local_def_id(it.id);
-        let generics = &ccx.tcx.lookup_trait_def(def_id).generics;
-        check_on_unimplemented(ccx, generics, it, it.name);
+        check_on_unimplemented(ccx, def_id, it);
       }
       hir::ItemStruct(..) => {
         check_struct(ccx, it.id, it.span);
@@ -872,9 +865,9 @@ fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 }
 
 fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                    generics: &ty::Generics,
-                                    item: &hir::Item,
-                                    name: ast::Name) {
+                                    def_id: DefId,
+                                    item: &hir::Item) {
+    let generics = ccx.tcx.lookup_generics(def_id);
     if let Some(ref attr) = item.attrs.iter().find(|a| {
         a.check_name("rustc_on_unimplemented")
     }) {
@@ -894,6 +887,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         }) {
                             Some(_) => (),
                             None => {
+                                let name = ccx.tcx.item_name(def_id);
                                 span_err!(ccx.tcx.sess, attr.span, E0230,
                                                  "there is no type parameter \
                                                           {} on trait {}",
@@ -1301,6 +1295,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         &self.ast_ty_to_ty_cache
     }
 
+    fn get_generics(&self, _: Span, id: DefId)
+                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
+    {
+        Ok(self.tcx().lookup_generics(id))
+    }
+
     fn get_item_type_scheme(&self, _: Span, id: DefId)
                             -> Result<ty::TypeScheme<'tcx>, ErrorReported>
     {
@@ -1364,7 +1364,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
 
     fn ty_infer_for_def(&self,
                         ty_param_def: &ty::TypeParameterDef<'tcx>,
-                        substs: &subst::Substs<'tcx>,
+                        substs: &Substs<'tcx>,
                         span: Span) -> Ty<'tcx> {
         self.type_var_for_def(span, ty_param_def, substs)
     }
@@ -1690,25 +1690,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                  node_id: ast::NodeId)
                                  -> Ty<'tcx> {
         debug!("instantiate_type_path(did={:?}, path={:?})", did, path);
-        let mut type_scheme = self.tcx.lookup_item_type(did);
-        if type_scheme.ty.is_fn() {
+        let mut ty = self.tcx.lookup_item_type(did).ty;
+        if ty.is_fn() {
             // Tuple variants have fn type even in type namespace, extract true variant type from it
-            let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap();
-            type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics }
+            ty = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap();
         }
         let type_predicates = self.tcx.lookup_predicates(did);
         let substs = AstConv::ast_path_substs_for_ty(self, self,
                                                      path.span,
                                                      PathParamMode::Optional,
-                                                     &type_scheme.generics,
+                                                     did,
                                                      path.segments.last().unwrap());
-        debug!("instantiate_type_path: ty={:?} substs={:?}", &type_scheme.ty, substs);
+        debug!("instantiate_type_path: ty={:?} substs={:?}", ty, substs);
         let bounds = self.instantiate_bounds(path.span, substs, &type_predicates);
         let cause = traits::ObligationCause::new(path.span, self.body_id,
                                                  traits::ItemObligation(did));
         self.add_obligations_for_parameters(cause, &bounds);
 
-        let ty_substituted = self.instantiate_type_scheme(path.span, substs, &type_scheme.ty);
+        let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty);
         self.write_ty(node_id, ty_substituted);
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
@@ -2775,7 +2774,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let ity = self.tcx.lookup_item_type(did);
         debug!("impl_self_ty: ity={:?}", ity);
 
-        let substs = self.fresh_substs_for_generics(span, &ity.generics);
+        let substs = self.fresh_substs_for_item(span, did);
         let substd_ty = self.instantiate_type_scheme(span, &substs, &ity.ty);
 
         TypeAndSubsts { substs: substs, ty: substd_ty }
@@ -3443,10 +3442,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
                                                                          expr.id, expr.span);
               if def != Def::Err {
-                  let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
-                                                                                     def);
-                  self.instantiate_value_path(segments, scheme, &predicates,
-                                              opt_ty, def, expr.span, id);
+                  self.instantiate_value_path(segments, opt_ty, def, expr.span, id);
               } else {
                   self.set_tainted_by_errors();
                   self.write_error(id);
@@ -4036,54 +4032,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         *self.ps.borrow_mut() = prev;
     }
 
-    // Returns the type parameter count and the type for the given definition.
-    fn type_scheme_and_predicates_for_def(&self,
-                                          sp: Span,
-                                          defn: Def)
-                                          -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
-        match defn {
-            Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
-                let typ = self.local_ty(sp, nid);
-                (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
-                 ty::GenericPredicates::empty())
-            }
-            Def::Fn(id) | Def::Method(id) |
-            Def::Static(id, _) | Def::Variant(_, id) |
-            Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => {
-                (self.tcx.lookup_item_type(id), self.tcx.lookup_predicates(id))
-            }
-            Def::Trait(_) |
-            Def::Enum(..) |
-            Def::TyAlias(..) |
-            Def::AssociatedTy(..) |
-            Def::PrimTy(_) |
-            Def::TyParam(..) |
-            Def::Mod(..) |
-            Def::ForeignMod(..) |
-            Def::Label(..) |
-            Def::SelfTy(..) |
-            Def::Err => {
-                span_bug!(sp, "expected value, found {:?}", defn);
-            }
-        }
-    }
-
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
     pub fn instantiate_value_path(&self,
                                   segments: &[hir::PathSegment],
-                                  type_scheme: TypeScheme<'tcx>,
-                                  type_predicates: &ty::GenericPredicates<'tcx>,
                                   opt_self_ty: Option<Ty<'tcx>>,
                                   def: Def,
                                   span: Span,
                                   node_id: ast::NodeId)
                                   -> Ty<'tcx> {
-        debug!("instantiate_value_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
+        debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
                segments,
                def,
-               node_id,
-               type_scheme);
+               node_id);
 
         // We need to extract the type parameters supplied by the user in
         // the path `path`. Due to the current setup, this is a bit of a
@@ -4210,11 +4171,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::ForeignMod(..) |
             Def::Local(..) |
             Def::Label(..) |
-            Def::Upvar(..) => {}
-
-            Def::Err => {
-                self.set_tainted_by_errors();
-            }
+            Def::Upvar(..) |
+            Def::Err => {}
         }
 
         // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory, but
@@ -4232,6 +4190,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             fn_segment.is_some() as usize;
         self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
 
+        match def {
+            Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
+                let ty = self.local_ty(span, nid);
+                let ty = self.normalize_associated_types_in(span, &ty);
+                self.write_ty(node_id, ty);
+                self.write_substs(node_id, ty::ItemSubsts {
+                    substs: Substs::empty(self.tcx)
+                });
+                return ty;
+            }
+            _ => {}
+        }
+        let scheme = self.tcx.lookup_item_type(def.def_id());
+        let type_predicates = self.tcx.lookup_predicates(def.def_id());
+
         // Now we have to compare the types that the user *actually*
         // provided against the types that were *expected*. If the user
         // did not provide any types, then we want to substitute inference
@@ -4240,16 +4213,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // a problem.
         self.check_path_parameter_count(subst::TypeSpace,
                                         span,
-                                        &type_scheme.generics,
+                                        scheme.generics,
                                         !require_type_space,
                                         &mut type_segment);
         self.check_path_parameter_count(subst::FnSpace,
                                         span,
-                                        &type_scheme.generics,
+                                        scheme.generics,
                                         true,
                                         &mut fn_segment);
 
-        let substs = Substs::from_generics(&type_scheme.generics, |def, _| {
+        let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| {
             let i = def.index as usize;
             let segment = match def.space {
                 subst::SelfSpace => None,
@@ -4307,9 +4280,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // The things we are substituting into the type should not contain
         // escaping late-bound regions, and nor should the base type scheme.
-        let substs = self.tcx.mk_substs(substs);
         assert!(!substs.has_escaping_regions());
-        assert!(!type_scheme.has_escaping_regions());
+        assert!(!scheme.ty.has_escaping_regions());
 
         // Add all the obligations that are required, substituting and
         // normalized appropriately.
@@ -4320,7 +4292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Substitute the values for the type parameters into the type of
         // the referenced item.
-        let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty);
+        let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty);
 
 
         if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 5f8861f3099..6a475864f3b 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -18,7 +18,6 @@ use hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{TypeFolder,TypeFoldable};
-use rustc::ty::subst::ParamSpace;
 use rustc::infer::{InferCtxt, FixupError};
 use rustc::util::nodemap::DefIdMap;
 use write_substs_to_tcx;
@@ -68,7 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         wbcx.visit_closures();
         wbcx.visit_liberated_fn_sigs();
         wbcx.visit_fru_field_types();
-        wbcx.visit_anon_types();
+        wbcx.visit_anon_types(item_id);
         wbcx.visit_deferred_obligations(item_id);
     }
 }
@@ -104,22 +103,20 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
 
         let free_substs = fcx.parameter_environment.free_substs;
-        for &space in &ParamSpace::all() {
-            for (i, r) in free_substs.regions.get_slice(space).iter().enumerate() {
-                match *r {
-                    ty::ReFree(ty::FreeRegion {
-                        bound_region: ty::BoundRegion::BrNamed(def_id, name, _), ..
-                    }) => {
-                        let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion {
-                            space: space,
-                            index: i as u32,
-                            name: name,
-                        });
-                        wbcx.free_to_bound_regions.insert(def_id, bound_region);
-                    }
-                    _ => {
-                        bug!("{:?} is not a free region for an early-bound lifetime", r);
-                    }
+        for (space, i, r) in free_substs.regions.iter_enumerated() {
+            match *r {
+                ty::ReFree(ty::FreeRegion {
+                    bound_region: ty::BoundRegion::BrNamed(def_id, name, _), ..
+                }) => {
+                    let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion {
+                        space: space,
+                        index: i as u32,
+                        name: name,
+                    });
+                    wbcx.free_to_bound_regions.insert(def_id, bound_region);
+                }
+                _ => {
+                    bug!("{:?} is not a free region for an early-bound lifetime", r);
                 }
             }
         }
@@ -300,11 +297,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
     }
 
-    fn visit_anon_types(&self) {
+    fn visit_anon_types(&self, item_id: ast::NodeId) {
         if self.fcx.writeback_errors.get() {
             return
         }
 
+        let item_def_id = self.fcx.tcx.map.local_def_id(item_id);
+
         let gcx = self.tcx().global_tcx();
         for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
             let reason = ResolvingAnonTy(def_id);
@@ -345,9 +344,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                 }
             });
 
-            gcx.tcache.borrow_mut().insert(def_id, ty::TypeScheme {
+            gcx.register_item_type(def_id, ty::TypeScheme {
                 ty: outside_ty,
-                generics: ty::Generics::empty()
+                generics: gcx.lookup_generics(item_def_id)
             });
         }
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a2a162a7f5f..77723ea9733 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -65,7 +65,7 @@ use middle::lang_items::SizedTraitLangItem;
 use middle::const_val::ConstVal;
 use rustc_const_eval::EvalHint::UncheckedExprHint;
 use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err};
-use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace};
+use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
 use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
 use rustc::ty::{VariantKind};
@@ -120,6 +120,7 @@ struct ItemCtxt<'a,'tcx:'a> {
 
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum AstConvRequest {
+    GetGenerics(DefId),
     GetItemTypeScheme(DefId),
     GetTraitDef(DefId),
     EnsureSuperPredicates(DefId),
@@ -187,6 +188,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
         err.span_label(span, &format!("cyclic reference"));
 
         match cycle[0] {
+            AstConvRequest::GetGenerics(def_id) |
             AstConvRequest::GetItemTypeScheme(def_id) |
             AstConvRequest::GetTraitDef(def_id) => {
                 err.note(
@@ -209,6 +211,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
 
         for request in &cycle[1..] {
             match *request {
+                AstConvRequest::GetGenerics(def_id) |
                 AstConvRequest::GetItemTypeScheme(def_id) |
                 AstConvRequest::GetTraitDef(def_id) => {
                     err.note(
@@ -231,6 +234,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
         }
 
         match cycle[0] {
+            AstConvRequest::GetGenerics(def_id) |
             AstConvRequest::GetItemTypeScheme(def_id) |
             AstConvRequest::GetTraitDef(def_id) => {
                 err.note(
@@ -303,6 +307,14 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         &self.ccx.ast_ty_to_ty_cache
     }
 
+    fn get_generics(&self, span: Span, id: DefId)
+                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
+    {
+        self.ccx.cycle_check(span, AstConvRequest::GetGenerics(id), || {
+            Ok(generics_of_def_id(self.ccx, id))
+        })
+    }
+
     fn get_item_type_scheme(&self, span: Span, id: DefId)
                             -> Result<ty::TypeScheme<'tcx>, ErrorReported>
     {
@@ -544,7 +556,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-
 fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             container: ImplOrTraitItemContainer,
                             name: ast::Name,
@@ -553,25 +564,22 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             sig: &hir::MethodSig,
                             defaultness: hir::Defaultness,
                             untransformed_rcvr_ty: Ty<'tcx>,
-                            rcvr_ty_generics: &ty::Generics<'tcx>,
                             rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
-    let ty_generics = ty_generics_for_fn(ccx, &sig.generics, rcvr_ty_generics);
+    let def_id = ccx.tcx.map.local_def_id(id);
+    let ty_generics = generics_of_def_id(ccx, def_id);
 
     let ty_generic_predicates =
         ty_generic_predicates_for_fn(ccx, &sig.generics, rcvr_ty_predicates);
 
     let (fty, explicit_self_category) = {
         let anon_scope = match container {
-            ImplContainer(_) => Some(AnonTypeScope::new(&ty_generics)),
+            ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
             TraitContainer(_) => None
         };
         AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
                               sig, untransformed_rcvr_ty, anon_scope)
     };
 
-    let def_id = ccx.tcx.map.local_def_id(id);
-    let substs = mk_item_substs(ccx.tcx, &ty_generics);
-
     let ty_method = ty::Method::new(name,
                                     ty_generics,
                                     ty_generic_predicates,
@@ -582,16 +590,14 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                     def_id,
                                     container);
 
+    let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
+                                ccx.tcx.map.span(id), def_id);
     let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty);
     debug!("method {} (id {}) has type {:?}",
             name, id, fty);
-    ccx.tcx.register_item_type(def_id, TypeScheme {
-        generics: ty_method.generics.clone(),
-        ty: fty
-    });
-    ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone());
-
+    ccx.tcx.tcache.borrow_mut().insert(def_id, fty);
     write_ty_to_tcx(ccx, id, fty);
+    ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone());
 
     debug!("writing method type: def_id={:?} mty={:?}",
             def_id, ty_method);
@@ -601,7 +607,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 }
 
 fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                           struct_generics: &ty::Generics<'tcx>,
+                           struct_generics: &'tcx ty::Generics<'tcx>,
                            struct_predicates: &ty::GenericPredicates<'tcx>,
                            field: &hir::StructField,
                            ty_f: ty::FieldDefMaster<'tcx>)
@@ -613,7 +619,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     /* add the field to the tcache */
     ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(field.id),
                                ty::TypeScheme {
-                                   generics: struct_generics.clone(),
+                                   generics: struct_generics,
                                    ty: tt
                                });
     ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(field.id),
@@ -709,8 +715,9 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             }
         }
         hir::ItemEnum(ref enum_definition, _) => {
-            let (scheme, predicates) = convert_typed_item(ccx, it);
-            write_ty_to_tcx(ccx, it.id, scheme.ty);
+            let def_id = ccx.tcx.map.local_def_id(it.id);
+            let scheme = type_scheme_of_def_id(ccx, def_id);
+            let predicates = predicates_of_item(ccx, it);
             convert_enum_variant_types(ccx,
                                        tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)),
                                        scheme,
@@ -737,7 +744,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             // Create generics from the generics specified in the impl head.
             debug!("convert: ast_generics={:?}", generics);
             let def_id = ccx.tcx.map.local_def_id(it.id);
-            let ty_generics = ty_generics_for_impl(ccx, generics);
+            let ty_generics = generics_of_def_id(ccx, def_id);
             let mut ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics);
 
             debug!("convert: impl_bounds={:?}", ty_predicates);
@@ -746,7 +753,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             write_ty_to_tcx(ccx, it.id, selfty);
 
             tcx.register_item_type(def_id,
-                                   TypeScheme { generics: ty_generics.clone(),
+                                   TypeScheme { generics: ty_generics,
                                                 ty: selfty });
             let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
                 AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
@@ -791,7 +798,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                 .to_ty(&ExplicitRscope, &ty);
                     tcx.register_item_type(ccx.tcx.map.local_def_id(impl_item.id),
                                            TypeScheme {
-                                               generics: ty_generics.clone(),
+                                               generics: ty_generics,
                                                ty: ty,
                                            });
                     // Trait-associated constants are always public.
@@ -829,7 +836,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
                     convert_method(ccx, ImplContainer(def_id),
                                    impl_item.name, impl_item.id, method_vis,
-                                   sig, impl_item.defaultness, selfty, &ty_generics,
+                                   sig, impl_item.defaultness, selfty,
                                    &ty_predicates);
                 }
             }
@@ -856,7 +863,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                         .to_ty(&ExplicitRscope, ty);
                     tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id),
                                            TypeScheme {
-                                               generics: trait_def.generics.clone(),
+                                               generics: trait_def.generics,
                                                ty: ty,
                                            });
                     convert_associated_const(ccx,
@@ -898,7 +905,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                    sig,
                                    hir::Defaultness::Default,
                                    tcx.mk_self_type(),
-                                   &trait_def.generics,
                                    &trait_predicates);
 
                 }
@@ -917,11 +923,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                                        trait_item_def_ids);
         },
         hir::ItemStruct(ref struct_def, _) => {
-            let (scheme, predicates) = convert_typed_item(ccx, it);
-            write_ty_to_tcx(ccx, it.id, scheme.ty);
+            let def_id = ccx.tcx.map.local_def_id(it.id);
+            let scheme = type_scheme_of_def_id(ccx, def_id);
+            let predicates = predicates_of_item(ccx, it);
 
-            let it_def_id = ccx.tcx.map.local_def_id(it.id);
-            let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant();
+            let variant = tcx.lookup_adt_def_master(def_id).struct_variant();
 
             for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) {
                 convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
@@ -933,15 +939,14 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
         },
         hir::ItemTy(_, ref generics) => {
             ensure_no_ty_param_bounds(ccx, it.span, generics, "type");
-            let (scheme, _) = convert_typed_item(ccx, it);
-            write_ty_to_tcx(ccx, it.id, scheme.ty);
+            let def_id = ccx.tcx.map.local_def_id(it.id);
+            type_scheme_of_def_id(ccx, def_id);
+            predicates_of_item(ccx, it);
         },
         _ => {
-            // This call populates the type cache with the converted type
-            // of the item in passing. All we have to do here is to write
-            // it into the node type table.
-            let (scheme, _) = convert_typed_item(ccx, it);
-            write_ty_to_tcx(ccx, it.id, scheme.ty);
+            let def_id = ccx.tcx.map.local_def_id(it.id);
+            type_scheme_of_def_id(ccx, def_id);
+            predicates_of_item(ccx, it);
         },
     }
 }
@@ -952,6 +957,8 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                   scheme: ty::TypeScheme<'tcx>,
                                   predicates: ty::GenericPredicates<'tcx>) {
     let tcx = ccx.tcx;
+    let def_id = tcx.map.local_def_id(ctor_id);
+    tcx.generics.borrow_mut().insert(def_id, scheme.generics);
     let ctor_ty = match variant.kind {
         VariantKind::Unit | VariantKind::Struct => scheme.ty,
         VariantKind::Tuple => {
@@ -960,8 +967,8 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 .iter()
                 .map(|field| field.unsubst_ty())
                 .collect();
-            let def_id = tcx.map.local_def_id(ctor_id);
-            let substs = mk_item_substs(tcx, &scheme.generics);
+            let substs = mk_item_substs(&ccx.icx(&predicates),
+                                        ccx.tcx.map.span(ctor_id), def_id);
             tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: abi::Abi::Rust,
@@ -974,12 +981,8 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         }
     };
     write_ty_to_tcx(ccx, ctor_id, ctor_ty);
+    tcx.tcache.borrow_mut().insert(def_id, ctor_ty);
     tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates);
-    tcx.register_item_type(tcx.map.local_def_id(ctor_id),
-                           TypeScheme {
-                               generics: scheme.generics,
-                               ty: ctor_ty
-                           });
 }
 
 fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@@ -1237,7 +1240,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 
     let (unsafety, generics, items) = match it.node {
-        hir::ItemTrait(unsafety, ref generics, _, ref items) => (unsafety, generics, items),
+        hir::ItemTrait(unsafety, ref generics, _, ref items) => {
+            (unsafety, generics, items)
+        }
         _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"),
     };
 
@@ -1253,9 +1258,8 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         err.emit();
     }
 
-    let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics));
-
-    let ty_generics = ty_generics_for_trait(ccx, it.id, substs, generics);
+    let ty_generics = generics_of_def_id(ccx, def_id);
+    let substs = mk_item_substs(&ccx.icx(generics), it.span, def_id);
 
     let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| {
         match trait_item.node {
@@ -1264,51 +1268,14 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         }
     }).collect();
 
-    let trait_ref = ty::TraitRef {
-        def_id: def_id,
-        substs: substs,
-    };
-
+    let trait_ref = ty::TraitRef::new(def_id, substs);
     let trait_def = ty::TraitDef::new(unsafety,
                                       paren_sugar,
                                       ty_generics,
                                       trait_ref,
                                       associated_type_names);
 
-    return tcx.intern_trait_def(trait_def);
-
-    fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                 generics: &hir::Generics)
-                                 -> Substs<'tcx>
-    {
-        let tcx = ccx.tcx;
-
-        // Creates a no-op substitution for the trait's type parameters.
-        let regions =
-            generics.lifetimes
-                    .iter()
-                    .enumerate()
-                    .map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion {
-                        space: TypeSpace,
-                        index: i as u32,
-                        name: def.lifetime.name
-                    }))
-                    .collect();
-
-        // Start with the generics in the type parameters...
-        let types: Vec<_> =
-            generics.ty_params
-                    .iter()
-                    .enumerate()
-                    .map(|(i, def)| tcx.mk_param(TypeSpace,
-                                                 i as u32, def.name))
-                    .collect();
-
-        // ...and also create the `Self` parameter.
-        let self_ty = tcx.mk_self_type();
-
-        Substs::new_trait(types, regions, self_ty)
-    }
+    tcx.intern_trait_def(trait_def)
 }
 
 fn trait_defines_associated_type_named(ccx: &CrateCtxt,
@@ -1410,105 +1377,243 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item)
     }
 }
 
-fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                  def_id: DefId)
-                                  -> ty::TypeScheme<'tcx>
-{
-    if let Some(node_id) = ccx.tcx.map.as_local_node_id(def_id) {
-        match ccx.tcx.map.find(node_id) {
-            Some(hir_map::NodeItem(item)) => {
-                type_scheme_of_item(ccx, &item)
+fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                def_id: DefId)
+                                -> &'tcx ty::Generics<'tcx> {
+    let tcx = ccx.tcx;
+    let node_id = if let Some(id) = tcx.map.as_local_node_id(def_id) {
+        id
+    } else {
+        return tcx.lookup_generics(def_id);
+    };
+    tcx.generics.memoize(def_id, || {
+        use rustc::hir::map::*;
+        use rustc::hir::*;
+
+        let mut opt_self = None;
+        let mut base_def_id = None;
+        let mut allow_defaults = false;
+
+        let no_generics = hir::Generics::empty();
+        let (space, ast_generics) = match tcx.map.get(node_id) {
+            NodeImplItem(&ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) |
+            NodeTraitItem(&TraitItem { node: MethodTraitItem(ref sig, _), .. }) => {
+                let parent_id = tcx.map.get_parent(node_id);
+                base_def_id = Some(tcx.map.local_def_id(parent_id));
+                (FnSpace, &sig.generics)
             }
-            Some(hir_map::NodeForeignItem(foreign_item)) => {
-                let abi = ccx.tcx.map.get_foreign_abi(node_id);
-                type_scheme_of_foreign_item(ccx, &foreign_item, abi)
+
+            NodeImplItem(_) |
+            NodeTraitItem(_) => {
+                let parent_id = tcx.map.get_parent(node_id);
+                base_def_id = Some(tcx.map.local_def_id(parent_id));
+                (FnSpace, &no_generics)
             }
-            x => {
-                bug!("unexpected sort of node in get_item_type_scheme(): {:?}",
-                     x);
+
+            NodeItem(item) => {
+                match item.node {
+                    ItemFn(_, _, _, _, ref generics, _) => (FnSpace, generics),
+                    ItemImpl(_, _, ref generics, _, _, _) => (TypeSpace, generics),
+                    ItemTy(_, ref generics) |
+                    ItemEnum(_, ref generics) |
+                    ItemStruct(_, ref generics) => {
+                        allow_defaults = true;
+                        (TypeSpace, generics)
+                    }
+                    ItemTrait(_, ref generics, _, _) => {
+                        // Add in the self type parameter.
+                        //
+                        // Something of a hack: use the node id for the trait, also as
+                        // the node id for the Self type parameter.
+                        let param_id = item.id;
+
+                        let parent = ccx.tcx.map.get_parent(param_id);
+
+                        let def = ty::TypeParameterDef {
+                            space: SelfSpace,
+                            index: 0,
+                            name: keywords::SelfType.name(),
+                            def_id: tcx.map.local_def_id(param_id),
+                            default_def_id: tcx.map.local_def_id(parent),
+                            default: None,
+                            object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
+                        };
+                        tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
+                        opt_self = Some(def);
+
+                        allow_defaults = true;
+                        (TypeSpace, generics)
+                    }
+                    _ => (TypeSpace, &no_generics)
+                }
+            }
+
+            NodeForeignItem(item) => {
+                match item.node {
+                    ForeignItemStatic(..) => (TypeSpace, &no_generics),
+                    ForeignItemFn(_, ref generics) => (FnSpace, generics)
+                }
             }
+
+            _ => (TypeSpace, &no_generics)
+        };
+
+        let empty_generics = ty::Generics::empty();
+        let base_generics = base_def_id.map_or(&empty_generics, |def_id| {
+            generics_of_def_id(ccx, def_id)
+        });
+
+        let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
+        let regions = early_lifetimes.iter().enumerate().map(|(i, l)| {
+            ty::RegionParameterDef {
+                name: l.lifetime.name,
+                space: space,
+                index: i as u32,
+                def_id: tcx.map.local_def_id(l.lifetime.id),
+                bounds: l.bounds.iter().map(|l| {
+                    ast_region_to_region(tcx, l)
+                }).collect()
+            }
+        }).collect();
+
+        // Now create the real type parameters.
+        let types = ast_generics.ty_params.iter().enumerate().map(|(i, _)| {
+            get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32, allow_defaults)
+        }).collect();
+
+        let has_self = base_generics.has_self || opt_self.is_some();
+        let (regions, types) = match space {
+            SelfSpace => bug!(),
+            TypeSpace => {
+                assert_eq!(base_generics.regions.as_full_slice().len(), 0);
+                assert_eq!(base_generics.types.as_full_slice().len(), 0);
+                (VecPerParamSpace::new(vec![], regions, vec![]),
+                 VecPerParamSpace::new(opt_self.into_iter().collect(), types, vec![]))
+            }
+            FnSpace => {
+                assert_eq!(base_generics.regions.len(FnSpace), 0);
+                assert_eq!(base_generics.types.len(FnSpace), 0);
+                (VecPerParamSpace::new(base_generics.regions.get_slice(SelfSpace).to_vec(),
+                                       base_generics.regions.get_slice(TypeSpace).to_vec(),
+                                       regions),
+                 VecPerParamSpace::new(base_generics.types.get_slice(SelfSpace).to_vec(),
+                                       base_generics.types.get_slice(TypeSpace).to_vec(),
+                                       types))
+            }
+        };
+
+        // Debugging aid.
+        if tcx.has_attr(def_id, "rustc_object_lifetime_default") {
+            let object_lifetime_default_reprs: String =
+                types.as_full_slice().iter().map(|t| {
+                    match t.object_lifetime_default {
+                        ty::ObjectLifetimeDefault::Specific(r) => r.to_string(),
+                        d => format!("{:?}", d),
+                    }
+                }).collect::<Vec<String>>().join(",");
+            tcx.sess.span_err(tcx.map.span(node_id), &object_lifetime_default_reprs);
         }
-    } else {
-        ccx.tcx.lookup_item_type(def_id)
-    }
+
+        tcx.alloc_generics(ty::Generics {
+            regions: regions,
+            types: types,
+            has_self: has_self
+        })
+    })
 }
 
-fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                item: &hir::Item)
-                                -> ty::TypeScheme<'tcx>
-{
-    let item_def_id = ccx.tcx.map.local_def_id(item.id);
-    ccx.tcx.tcache.memoize(item_def_id, || {
-        // NB. Since the `memoized` function enters a new task, and we
-        // are giving this task access to the item `item`, we must
-        // register a read.
-        assert!(!ccx.tcx.map.is_inlined_def_id(item_def_id));
-        ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
-        compute_type_scheme_of_item(ccx, item)
+fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                            def_id: DefId)
+                            -> Ty<'tcx> {
+    let node_id = if let Some(id) = ccx.tcx.map.as_local_node_id(def_id) {
+        id
+    } else {
+        return ccx.tcx.lookup_item_type(def_id).ty;
+    };
+    ccx.tcx.tcache.memoize(def_id, || {
+        use rustc::hir::map::*;
+        use rustc::hir::*;
+
+        let ty = match ccx.tcx.map.get(node_id) {
+            NodeItem(item) => {
+                match item.node {
+                    ItemStatic(ref t, _, _) | ItemConst(ref t, _) => {
+                        ccx.icx(&()).to_ty(&ExplicitRscope, &t)
+                    }
+                    ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
+                        let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
+                                                          Some(AnonTypeScope::new(def_id)));
+                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
+                        ccx.tcx.mk_fn_def(def_id, substs, tofd)
+                    }
+                    ItemTy(ref t, ref generics) => {
+                        ccx.icx(generics).to_ty(&ExplicitRscope, &t)
+                    }
+                    ItemEnum(ref ei, ref generics) => {
+                        let def = convert_enum_def(ccx, item, ei);
+                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
+                        ccx.tcx.mk_enum(def, substs)
+                    }
+                    ItemStruct(ref si, ref generics) => {
+                        let def = convert_struct_def(ccx, item, si);
+                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
+                        ccx.tcx.mk_struct(def, substs)
+                    }
+                    ItemDefaultImpl(..) |
+                    ItemTrait(..) |
+                    ItemImpl(..) |
+                    ItemMod(..) |
+                    ItemForeignMod(..) |
+                    ItemExternCrate(..) |
+                    ItemUse(..) => {
+                        span_bug!(
+                            item.span,
+                            "compute_type_of_item: unexpected item type: {:?}",
+                            item.node);
+                    }
+                }
+            }
+            NodeForeignItem(foreign_item) => {
+                let abi = ccx.tcx.map.get_foreign_abi(node_id);
+
+                match foreign_item.node {
+                    ForeignItemFn(ref fn_decl, ref generics) => {
+                        compute_type_of_foreign_fn_decl(
+                            ccx, ccx.tcx.map.local_def_id(foreign_item.id),
+                            fn_decl, generics, abi)
+                    }
+                    ForeignItemStatic(ref t, _) => {
+                        ccx.icx(&()).to_ty(&ExplicitRscope, t)
+                    }
+                }
+            }
+            x => {
+                bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+            }
+        };
+
+        write_ty_to_tcx(ccx, node_id, ty);
+        ty
     })
 }
 
-fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                        it: &hir::Item)
-                                        -> ty::TypeScheme<'tcx>
-{
-    let tcx = ccx.tcx;
-    match it.node {
-        hir::ItemStatic(ref t, _, _) | hir::ItemConst(ref t, _) => {
-            let ty = ccx.icx(&()).to_ty(&ExplicitRscope, &t);
-            ty::TypeScheme { ty: ty, generics: ty::Generics::empty() }
-        }
-        hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
-            let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
-            let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
-                                              Some(AnonTypeScope::new(&ty_generics)));
-            let def_id = ccx.tcx.map.local_def_id(it.id);
-            let substs = mk_item_substs(tcx, &ty_generics);
-            let ty = tcx.mk_fn_def(def_id, substs, tofd);
-            ty::TypeScheme { ty: ty, generics: ty_generics }
-        }
-        hir::ItemTy(ref t, ref generics) => {
-            let ty_generics = ty_generics_for_type(ccx, generics);
-            let ty = ccx.icx(generics).to_ty(&ExplicitRscope, &t);
-            ty::TypeScheme { ty: ty, generics: ty_generics }
-        }
-        hir::ItemEnum(ref ei, ref generics) => {
-            let def = convert_enum_def(ccx, it, ei);
-            let ty_generics = ty_generics_for_type(ccx, generics);
-            let substs = mk_item_substs(tcx, &ty_generics);
-            let t = tcx.mk_enum(def, substs);
-            ty::TypeScheme { ty: t, generics: ty_generics }
-        }
-        hir::ItemStruct(ref si, ref generics) => {
-            let def = convert_struct_def(ccx, it, si);
-            let ty_generics = ty_generics_for_type(ccx, generics);
-            let substs = mk_item_substs(tcx, &ty_generics);
-            let t = tcx.mk_struct(def, substs);
-            ty::TypeScheme { ty: t, generics: ty_generics }
-        }
-        hir::ItemDefaultImpl(..) |
-        hir::ItemTrait(..) |
-        hir::ItemImpl(..) |
-        hir::ItemMod(..) |
-        hir::ItemForeignMod(..) |
-        hir::ItemExternCrate(..) |
-        hir::ItemUse(..) => {
-            span_bug!(
-                it.span,
-                "compute_type_scheme_of_item: unexpected item type: {:?}",
-                it.node);
+fn type_scheme_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+                                   def_id: DefId)
+                                   -> ty::TypeScheme<'tcx> {
+    if def_id.is_local() {
+        ty::TypeScheme {
+            generics: generics_of_def_id(ccx, def_id),
+            ty: type_of_def_id(ccx, def_id)
         }
+    } else {
+        ccx.tcx.lookup_item_type(def_id)
     }
 }
 
-fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 it: &hir::Item)
-                                -> (ty::TypeScheme<'tcx>, ty::GenericPredicates<'tcx>)
-{
-    let tcx = ccx.tcx;
-
-    let tag = type_scheme_of_item(ccx, it);
-    let scheme = TypeScheme { generics: tag.generics, ty: tag.ty };
+                                -> ty::GenericPredicates<'tcx> {
+    let def_id = ccx.tcx.map.local_def_id(it.id);
     let predicates = match it.node {
         hir::ItemStatic(..) | hir::ItemConst(..) => {
             ty::GenericPredicates::empty()
@@ -1516,12 +1621,8 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         hir::ItemFn(_, _, _, _, ref ast_generics, _) => {
             ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty())
         }
-        hir::ItemTy(_, ref generics) => {
-            ty_generic_predicates_for_type_or_impl(ccx, generics)
-        }
-        hir::ItemEnum(_, ref generics) => {
-            ty_generic_predicates_for_type_or_impl(ccx, generics)
-        }
+        hir::ItemTy(_, ref generics) |
+        hir::ItemEnum(_, ref generics) |
         hir::ItemStruct(_, ref generics) => {
             ty_generic_predicates_for_type_or_impl(ccx, generics)
         }
@@ -1534,68 +1635,16 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         hir::ItemForeignMod(..) => {
             span_bug!(
                 it.span,
-                "compute_type_scheme_of_item: unexpected item type: {:?}",
+                "predicates_of_item: unexpected item type: {:?}",
                 it.node);
         }
     };
 
-    let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
-                                                             predicates.clone());
+    let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id,
+                                                                 predicates.clone());
     assert!(prev_predicates.is_none());
 
-    // Debugging aid.
-    if tcx.has_attr(ccx.tcx.map.local_def_id(it.id), "rustc_object_lifetime_default") {
-        let object_lifetime_default_reprs: String =
-            scheme.generics.types.as_full_slice().iter()
-                                 .map(|t| match t.object_lifetime_default {
-                                     ty::ObjectLifetimeDefault::Specific(r) => r.to_string(),
-                                     d => format!("{:?}", d),
-                                 })
-                                 .collect::<Vec<String>>()
-                                 .join(",");
-
-        tcx.sess.span_err(it.span, &object_lifetime_default_reprs);
-    }
-
-    return (scheme, predicates);
-}
-
-fn type_scheme_of_foreign_item<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
-    item: &hir::ForeignItem,
-    abi: abi::Abi)
-    -> ty::TypeScheme<'tcx>
-{
-    let item_def_id = ccx.tcx.map.local_def_id(item.id);
-    ccx.tcx.tcache.memoize(item_def_id, || {
-        // NB. Since the `memoized` function enters a new task, and we
-        // are giving this task access to the item `item`, we must
-        // register a read.
-        assert!(!ccx.tcx.map.is_inlined_def_id(item_def_id));
-        ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
-        compute_type_scheme_of_foreign_item(ccx, item, abi)
-    })
-}
-
-fn compute_type_scheme_of_foreign_item<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
-    it: &hir::ForeignItem,
-    abi: abi::Abi)
-    -> ty::TypeScheme<'tcx>
-{
-    match it.node {
-        hir::ForeignItemFn(ref fn_decl, ref generics) => {
-            compute_type_scheme_of_foreign_fn_decl(
-                ccx, ccx.tcx.map.local_def_id(it.id),
-                fn_decl, generics, abi)
-        }
-        hir::ForeignItemStatic(ref t, _) => {
-            ty::TypeScheme {
-                generics: ty::Generics::empty(),
-                ty: AstConv::ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, t)
-            }
-        }
-    }
+    predicates
 }
 
 fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@@ -1605,11 +1654,8 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // 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 tcx = ccx.tcx;
-    let abi = tcx.map.get_foreign_abi(it.id);
-
-    let scheme = type_scheme_of_foreign_item(ccx, it, abi);
-    write_ty_to_tcx(ccx, it.id, scheme.ty);
+    let def_id = ccx.tcx.map.local_def_id(it.id);
+    type_scheme_of_def_id(ccx, def_id);
 
     let predicates = match it.node {
         hir::ForeignItemFn(_, ref generics) => {
@@ -1620,21 +1666,10 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         }
     };
 
-    let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
-                                                             predicates);
+    let prev_predicates = ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
     assert!(prev_predicates.is_none());
 }
 
-fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &hir::Generics)
-                                  -> ty::Generics<'tcx> {
-    ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty(), true)
-}
-
-fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &hir::Generics)
-                                  -> ty::Generics<'tcx> {
-    ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty(), false)
-}
-
 fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                                    generics: &hir::Generics)
                                                    -> ty::GenericPredicates<'tcx>
@@ -1642,50 +1677,6 @@ fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty())
 }
 
-fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                   trait_id: ast::NodeId,
-                                   substs: &'tcx Substs<'tcx>,
-                                   ast_generics: &hir::Generics)
-                                   -> ty::Generics<'tcx>
-{
-    debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})",
-           ccx.tcx.map.local_def_id(trait_id), substs);
-
-    let mut generics = ty_generics_for_type(ccx, ast_generics);
-
-    // Add in the self type parameter.
-    //
-    // Something of a hack: use the node id for the trait, also as
-    // the node id for the Self type parameter.
-    let param_id = trait_id;
-
-    let parent = ccx.tcx.map.get_parent(param_id);
-
-    let def = ty::TypeParameterDef {
-        space: SelfSpace,
-        index: 0,
-        name: keywords::SelfType.name(),
-        def_id: ccx.tcx.map.local_def_id(param_id),
-        default_def_id: ccx.tcx.map.local_def_id(parent),
-        default: None,
-        object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
-    };
-
-    ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
-
-    generics.types.push(SelfSpace, def);
-
-    return generics;
-}
-
-fn ty_generics_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                               generics: &hir::Generics,
-                               base_generics: &ty::Generics<'tcx>)
-                               -> ty::Generics<'tcx>
-{
-    ty_generics(ccx, FnSpace, generics, base_generics, false)
-}
-
 fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                          generics: &hir::Generics,
                                          base_predicates: &ty::GenericPredicates<'tcx>)
@@ -1859,42 +1850,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     result
 }
 
-fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                        space: ParamSpace,
-                        ast_generics: &hir::Generics,
-                        base_generics: &ty::Generics<'tcx>,
-                        allow_defaults: bool)
-                        -> ty::Generics<'tcx>
-{
-    let tcx = ccx.tcx;
-    let mut result = base_generics.clone();
-
-    let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
-    for (i, l) in early_lifetimes.iter().enumerate() {
-        let bounds = l.bounds.iter()
-                             .map(|l| ast_region_to_region(tcx, l))
-                             .collect();
-        let def = ty::RegionParameterDef { name: l.lifetime.name,
-                                           space: space,
-                                           index: i as u32,
-                                           def_id: ccx.tcx.map.local_def_id(l.lifetime.id),
-                                           bounds: bounds };
-        result.regions.push(space, def);
-    }
-
-    assert!(result.types.is_empty_in(space));
-
-    // Now create the real type parameters.
-    for i in 0..ast_generics.ty_params.len() {
-        let def =
-            get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32, allow_defaults);
-        debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
-        result.types.push(space, def);
-    }
-
-    result
-}
-
 fn convert_default_type_parameter<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                             path: &P<hir::Ty>,
                                             space: ParamSpace,
@@ -1969,6 +1924,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
 
+    debug!("get_or_create_type_parameter_def: def for type param: {:?}, {:?}",
+           def, space);
+
     def
 }
 
@@ -2122,16 +2080,14 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
     }
 }
 
-fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
+fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
     ccx: &CrateCtxt<'a, 'tcx>,
-    id: DefId,
+    def_id: DefId,
     decl: &hir::FnDecl,
     ast_generics: &hir::Generics,
     abi: abi::Abi)
-    -> ty::TypeScheme<'tcx>
+    -> Ty<'tcx>
 {
-    let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty());
-
     let rb = BindingRscope::new();
     let input_tys = decl.inputs
                         .iter()
@@ -2167,34 +2123,32 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
         }
     }
 
-    let substs = mk_item_substs(ccx.tcx, &ty_generics);
-    let t_fn = ccx.tcx.mk_fn_def(id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy {
+    let id = ccx.tcx.map.as_local_node_id(def_id).unwrap();
+    let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.map.span(id), def_id);
+    ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy {
         abi: abi,
         unsafety: hir::Unsafety::Unsafe,
         sig: ty::Binder(ty::FnSig {inputs: input_tys,
                                     output: output,
                                     variadic: decl.variadic}),
-    }));
-
-    ty::TypeScheme {
-        generics: ty_generics,
-        ty: t_fn
-    }
+    }))
 }
 
-pub fn mk_item_substs<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                      ty_generics: &ty::Generics)
-                                      -> &'tcx Substs<'tcx>
-{
-    let types =
-        ty_generics.types.map(
-            |def| tcx.mk_param_from_def(def));
-
-    let regions =
-        ty_generics.regions.map(
-            |def| def.to_early_bound_region());
+pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
+                                        span: Span,
+                                        def_id: DefId)
+                                        -> &'tcx Substs<'tcx> {
+    let tcx = astconv.tcx();
+    // FIXME(eddyb) Do this request from Substs::for_item in librustc.
+    if let Err(ErrorReported) = astconv.get_generics(span, def_id) {
+        // No convenient way to recover from a cycle here. Just bail. Sorry!
+        tcx.sess.abort_if_errors();
+        bug!("ErrorReported returned, but no errors reports?")
+    }
 
-    tcx.mk_substs(Substs::new(types, regions))
+    Substs::for_item(tcx, def_id,
+                     |def, _| def.to_early_bound_region(),
+                     |def, _| tcx.mk_param_from_def(def))
 }
 
 /// Checks that all the type parameters on an impl
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 4ce6f8210c3..8a8232535c7 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -231,7 +231,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 _ => ()
             }
             let main_def_id = tcx.map.local_def_id(main_id);
-            let substs = tcx.mk_substs(Substs::empty());
+            let substs = Substs::empty(tcx);
             let se_ty = tcx.mk_fn_def(main_def_id, substs,
                                       tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
@@ -284,7 +284,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
             }
 
             let start_def_id = ccx.tcx.map.local_def_id(start_id);
-            let substs = tcx.mk_substs(Substs::empty());
+            let substs = Substs::empty(tcx);
             let se_ty = tcx.mk_fn_def(start_def_id, substs,
                                       tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs
index 58d1ec9d02a..9aca779dd89 100644
--- a/src/librustc_typeck/rscope.rs
+++ b/src/librustc_typeck/rscope.rs
@@ -8,10 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-use rustc::ty::{self, TyCtxt};
+use rustc::hir::def_id::DefId;
+use rustc::ty;
 use rustc::ty::subst::Substs;
 
+use astconv::AstConv;
+
 use std::cell::Cell;
 use syntax_pos::Span;
 
@@ -71,33 +73,34 @@ pub trait RegionScope {
 }
 
 #[derive(Copy, Clone)]
-pub struct AnonTypeScope<'a> {
-    generics: &'a ty::Generics<'a>
+pub struct AnonTypeScope {
+    enclosing_item: DefId
 }
 
-impl<'a, 'b, 'gcx, 'tcx> AnonTypeScope<'a> {
-    pub fn new(generics: &'a ty::Generics<'a>) -> AnonTypeScope<'a> {
+impl<'gcx: 'tcx, 'tcx> AnonTypeScope {
+    pub fn new(enclosing_item: DefId) -> AnonTypeScope {
         AnonTypeScope {
-            generics: generics
+            enclosing_item: enclosing_item
         }
     }
 
-    pub fn fresh_substs(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
+    pub fn fresh_substs(&self, astconv: &AstConv<'gcx, 'tcx>, span: Span)
+                        -> &'tcx Substs<'tcx> {
         use collect::mk_item_substs;
 
-        mk_item_substs(tcx, self.generics)
+        mk_item_substs(astconv, span, self.enclosing_item)
     }
 }
 
 /// A scope wrapper which optionally allows anonymized types.
 #[derive(Copy, Clone)]
-pub struct MaybeWithAnonTypes<'a, R> {
+pub struct MaybeWithAnonTypes<R> {
     base_scope: R,
-    anon_scope: Option<AnonTypeScope<'a>>
+    anon_scope: Option<AnonTypeScope>
 }
 
-impl<'a, R: RegionScope> MaybeWithAnonTypes<'a, R>  {
-    pub fn new(base_scope: R, anon_scope: Option<AnonTypeScope<'a>>) -> Self {
+impl<R: RegionScope> MaybeWithAnonTypes<R>  {
+    pub fn new(base_scope: R, anon_scope: Option<AnonTypeScope>) -> Self {
         MaybeWithAnonTypes {
             base_scope: base_scope,
             anon_scope: anon_scope
@@ -105,7 +108,7 @@ impl<'a, R: RegionScope> MaybeWithAnonTypes<'a, R>  {
     }
 }
 
-impl<'a, R: RegionScope> RegionScope for MaybeWithAnonTypes<'a, R> {
+impl<R: RegionScope> RegionScope for MaybeWithAnonTypes<R> {
     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
         self.base_scope.object_lifetime_default(span)
     }
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 6e6f9ce65c5..8c9b4beb79d 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -16,8 +16,7 @@
 use dep_graph::DepTrackingMapConfig;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
-use rustc::ty::subst;
-use rustc::ty::subst::ParamSpace;
+use rustc::ty::subst::{self, ParamSpace, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::ItemVariances;
 use rustc::hir::map as hir_map;
@@ -370,8 +369,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_substs(
                     generics,
                     def.did,
-                    item_type.generics.types.get_slice(subst::TypeSpace),
-                    item_type.generics.regions.get_slice(subst::TypeSpace),
+                    item_type.generics.types.as_full_slice(),
+                    item_type.generics.regions.as_full_slice(),
                     substs,
                     variance);
             }
@@ -449,7 +448,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                                    def_id: DefId,
                                    type_param_defs: &[ty::TypeParameterDef<'tcx>],
                                    region_param_defs: &[ty::RegionParameterDef],
-                                   substs: &subst::Substs<'tcx>,
+                                   substs: &Substs<'tcx>,
                                    variance: VarianceTermPtr<'a>) {
         debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
                def_id,
diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs
index 8bb49410a5b..22edf219dff 100644
--- a/src/librustc_typeck/variance/solve.rs
+++ b/src/librustc_typeck/variance/solve.rs
@@ -16,6 +16,7 @@
 //! inferred is then written into the `variance_map` in the tcx.
 
 use rustc::ty;
+use rustc::ty::subst;
 use std::rc::Rc;
 
 use super::constraints::*;
@@ -108,7 +109,9 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
         let num_inferred = self.terms_cx.num_inferred();
         while index < num_inferred {
             let item_id = inferred_infos[index].item_id;
-            let mut item_variances = ty::ItemVariances::empty();
+
+            let (mut rs, mut rt, mut rf) = (vec![], vec![], vec![]);
+            let (mut ts, mut tt, mut tf) = (vec![], vec![], vec![]);
 
             while index < num_inferred && inferred_infos[index].item_id == item_id {
                 let info = &inferred_infos[index];
@@ -116,13 +119,34 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
                 debug!("Index {} Info {} / {:?} / {:?} Variance {:?}",
                        index, info.index, info.kind, info.space, variance);
                 match info.kind {
-                    TypeParam => { item_variances.types.push(info.space, variance); }
-                    RegionParam => { item_variances.regions.push(info.space, variance); }
+                    TypeParam => {
+                        let types = match info.space {
+                            subst::SelfSpace => &mut ts,
+                            subst::TypeSpace => &mut tt,
+                            subst::FnSpace => &mut tf
+                        };
+                        assert_eq!(types.len(), info.index);
+                        types.push(variance);
+                    }
+                    RegionParam => {
+                        let regions = match info.space {
+                            subst::SelfSpace => &mut rs,
+                            subst::TypeSpace => &mut rt,
+                            subst::FnSpace => &mut rf
+                        };
+                        assert_eq!(regions.len(), info.index);
+                        regions.push(variance);
+                    }
                 }
 
                 index += 1;
             }
 
+            let item_variances = ty::ItemVariances {
+                regions: subst::VecPerParamSpace::new(rs, rt, rf),
+                types: subst::VecPerParamSpace::new(ts, tt, tf)
+            };
+
             debug!("item_id={} item_variances={:?}",
                     item_id,
                     item_variances);
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index cea12404298..b4be201440c 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -161,7 +161,7 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc
     let def = tcx.lookup_trait_def(did);
     let trait_items = tcx.trait_items(did).clean(cx);
     let predicates = tcx.lookup_predicates(did);
-    let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
+    let generics = (def.generics, &predicates, subst::TypeSpace).clean(cx);
     let generics = filter_non_trait_generics(did, generics);
     let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
     clean::Trait {
@@ -189,7 +189,7 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx
     let predicates = tcx.lookup_predicates(did);
     clean::Function {
         decl: decl,
-        generics: (&t.generics, &predicates, subst::FnSpace).clean(cx),
+        generics: (t.generics, &predicates, subst::FnSpace).clean(cx),
         unsafety: style,
         constness: constness,
         abi: abi,
@@ -209,7 +209,7 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
             &[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple,
             _ => doctree::Plain,
         },
-        generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
+        generics: (t.generics, &predicates, subst::TypeSpace).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
     }
@@ -222,7 +222,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match t.ty.sty {
         ty::TyEnum(edef, _) if !tcx.sess.cstore.is_typedef(did) => {
             return clean::EnumItem(clean::Enum {
-                generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
+                generics: (t.generics, &predicates, subst::TypeSpace).clean(cx),
                 variants_stripped: false,
                 variants: edef.variants.clean(cx),
             })
@@ -232,7 +232,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     clean::TypedefItem(clean::Typedef {
         type_: t.ty.clean(cx),
-        generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
+        generics: (t.generics, &predicates, subst::TypeSpace).clean(cx),
     }, false)
 }
 
@@ -389,15 +389,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
             }
             ty::TypeTraitItem(ref assoc_ty) => {
                 let did = assoc_ty.def_id;
-                let type_scheme = ty::TypeScheme {
-                    ty: assoc_ty.ty.unwrap(),
-                    generics: ty::Generics::empty()
-                };
                 // Not sure the choice of ParamSpace actually matters here,
                 // because an associated type won't have generics on the LHS
                 let typedef = clean::Typedef {
-                    type_: type_scheme.ty.clean(cx),
-                    generics: (&type_scheme.generics,
+                    type_: assoc_ty.ty.unwrap().clean(cx),
+                    generics: (&ty::Generics::empty(),
                                &ty::GenericPredicates::empty(),
                                subst::TypeSpace).clean(cx)
                 };
@@ -438,7 +434,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
             provided_trait_methods: provided,
             trait_: trait_,
             for_: for_,
-            generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),
+            generics: (ty.generics, &predicates, subst::TypeSpace).clean(cx),
             items: trait_items,
             polarity: polarity.map(|p| { p.clean(cx) }),
         }),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ffe5b9aad2f..f8a3a0af697 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -41,7 +41,7 @@ use rustc::hir::def::Def;
 use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
 use rustc::hir::fold::Folder;
 use rustc::hir::print as pprust;
-use rustc::ty::subst::{self, ParamSpace, VecPerParamSpace};
+use rustc::ty::subst::{self, ParamSpace, Substs, VecPerParamSpace};
 use rustc::ty;
 use rustc::middle::stability;
 
@@ -631,7 +631,7 @@ impl Clean<TyParamBound> for hir::TyParamBound {
 }
 
 fn external_path_params(cx: &DocContext, trait_did: Option<DefId>,
-                        bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
+                        bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
     let lifetimes = substs.regions.get_slice(subst::TypeSpace)
                     .iter()
                     .filter_map(|v| v.clean(cx))
@@ -676,7 +676,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<DefId>,
 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
 // from Fn<(A, B,), C> to Fn(A, B) -> C
 fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>,
-                 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
+                 bindings: Vec<TypeBinding>, substs: &Substs) -> Path {
     Path {
         global: false,
         segments: vec![PathSegment {
@@ -692,20 +692,20 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
             Some(tcx) => tcx,
             None => return RegionBound(Lifetime::statik())
         };
-        let empty = subst::Substs::empty();
+        let empty = Substs::empty(tcx);
         let (did, path) = match *self {
             ty::BoundSend =>
                 (tcx.lang_items.send_trait().unwrap(),
-                 external_path(cx, "Send", None, vec![], &empty)),
+                 external_path(cx, "Send", None, vec![], empty)),
             ty::BoundSized =>
                 (tcx.lang_items.sized_trait().unwrap(),
-                 external_path(cx, "Sized", None, vec![], &empty)),
+                 external_path(cx, "Sized", None, vec![], empty)),
             ty::BoundCopy =>
                 (tcx.lang_items.copy_trait().unwrap(),
-                 external_path(cx, "Copy", None, vec![], &empty)),
+                 external_path(cx, "Copy", None, vec![], empty)),
             ty::BoundSync =>
                 (tcx.lang_items.sync_trait().unwrap(),
-                 external_path(cx, "Sync", None, vec![], &empty)),
+                 external_path(cx, "Sync", None, vec![], empty)),
         };
         inline::record_extern_fqn(cx, did, TypeTrait);
         TraitBound(PolyTrait {
@@ -765,7 +765,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
     }
 }
 
-impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
+impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
     fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
         let mut v = Vec::new();
         v.extend(self.regions.as_full_slice().iter().filter_map(|r| r.clean(cx))
@@ -891,7 +891,7 @@ impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
 impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
     fn clean(&self, cx: &DocContext) -> WherePredicate {
         WherePredicate::BoundPredicate {
-            ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
+            ty: self.trait_ref.self_ty().clean(cx),
             bounds: vec![self.trait_ref.clean(cx)]
         }
     }
@@ -1353,7 +1353,7 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
             predicates: self.predicates.predicates[method_start..].to_vec()
         };
 
-        let generics = (&self.generics, &method_predicates,
+        let generics = (self.generics, &method_predicates,
                         subst::FnSpace).clean(cx);
         let mut decl = (self.def_id, &self.fty.sig).clean(cx);
         match self.explicit_self {
@@ -2923,7 +2923,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
             // applied to this associated type in question.
             let def = cx.tcx().lookup_trait_def(did);
             let predicates = cx.tcx().lookup_predicates(did);
-            let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
+            let generics = (def.generics, &predicates, subst::TypeSpace).clean(cx);
             generics.where_predicates.iter().filter_map(|pred| {
                 let (name, self_type, trait_, bounds) = match *pred {
                     WherePredicate::BoundPredicate {