about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-05-14 18:27:13 +0100
committervarkor <github@varkor.com>2018-05-15 14:22:11 +0100
commitd9190da9825b729ce63becf727b2cfdad3e8561a (patch)
tree1bffa6455bfc02acbcd9963f47823469d8e22987
parent030f10f752b6584e4f1974c104dd644dfffd80ad (diff)
downloadrust-d9190da9825b729ce63becf727b2cfdad3e8561a.tar.gz
rust-d9190da9825b729ce63becf727b2cfdad3e8561a.zip
Refactor Substs methods on generic parameters
-rw-r--r--src/librustc/infer/mod.rs17
-rw-r--r--src/librustc/traits/mod.rs18
-rw-r--r--src/librustc/ty/context.rs27
-rw-r--r--src/librustc/ty/subst.rs82
-rw-r--r--src/librustc/ty/util.rs17
-rw-r--r--src/librustc_mir/monomorphize/collector.rs18
-rw-r--r--src/librustc_mir/shim.rs16
-rw-r--r--src/librustc_typeck/astconv.rs144
-rw-r--r--src/librustc_typeck/check/closure.rs24
-rw-r--r--src/librustc_typeck/check/method/confirm.rs59
-rw-r--r--src/librustc_typeck/check/method/mod.rs28
-rw-r--r--src/librustc_typeck/check/method/probe.rs58
-rw-r--r--src/librustc_typeck/check/mod.rs129
-rw-r--r--src/librustc_typeck/check/wfcheck.rs39
-rw-r--r--src/librustc_typeck/collect.rs23
15 files changed, 393 insertions, 306 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 8dd661d0403..d90ba51fffc 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -21,9 +21,9 @@ use hir::def_id::DefId;
 use middle::free_region::RegionRelations;
 use middle::region;
 use middle::lang_items;
-use ty::subst::Substs;
+use ty::subst::{UnpackedKind, Substs};
 use ty::{TyVid, IntVid, FloatVid};
-use ty::{self, Ty, TyCtxt};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::TypeFoldable;
 use ty::relate::RelateResult;
@@ -941,10 +941,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                  span: Span,
                                  def_id: DefId)
                                  -> &'tcx Substs<'tcx> {
-        Substs::for_item(self.tcx, def_id, |def, _| {
-            self.region_var_for_def(span, def)
-        }, |def, _| {
-            self.type_var_for_def(span, def)
+        Substs::for_item(self.tcx, def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    UnpackedKind::Lifetime(self.region_var_for_def(span, param))
+                }
+                GenericParamDefKind::Type(_) => {
+                    UnpackedKind::Type(self.type_var_for_def(span, param))
+                }
+            }
         })
     }
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index a765ffe2396..4b5c767b031 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -22,8 +22,8 @@ use hir::def_id::DefId;
 use infer::outlives::env::OutlivesEnvironment;
 use middle::region;
 use middle::const_val::ConstEvalErr;
-use ty::subst::Substs;
-use ty::{self, AdtKind, Slice, Ty, TyCtxt, TypeFoldable, ToPredicate};
+use ty::subst::{UnpackedKind, Substs};
+use ty::{self, AdtKind, Slice, Ty, TyCtxt, GenericParamDefKind, TypeFoldable, ToPredicate};
 use ty::error::{ExpectedFound, TypeError};
 use infer::{InferCtxt};
 
@@ -841,10 +841,16 @@ fn vtable_methods<'a, 'tcx>(
                 // the method may have some early-bound lifetimes, add
                 // regions for those
                 let substs = trait_ref.map_bound(|trait_ref| {
-                    Substs::for_item(
-                        tcx, def_id,
-                        |_, _| tcx.types.re_erased,
-                        |def, _| trait_ref.substs.type_for_def(def))
+                    Substs::for_item(tcx, def_id, |param, _| {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime => {
+                                UnpackedKind::Lifetime(tcx.types.re_erased)
+                            }
+                            GenericParamDefKind::Type(_) => {
+                                UnpackedKind::Type(trait_ref.substs.type_for_def(param))
+                            }
+                        }
+                    })
                 });
 
                 // the trait type may have higher-ranked lifetimes in it;
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 995d6c55767..924271ea3d4 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -32,7 +32,7 @@ use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use middle::stability;
 use mir::{self, Mir, interpret};
-use ty::subst::{Kind, Substs, Subst};
+use ty::subst::{Kind, UnpackedKind, Substs, Subst};
 use ty::ReprOptions;
 use ty::Instance;
 use traits;
@@ -44,6 +44,7 @@ use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predic
 use ty::RegionKind;
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
+use ty::GenericParamDefKind;
 use ty::layout::{LayoutDetails, TargetDataLayout};
 use ty::maps;
 use ty::steal::Steal;
@@ -2325,16 +2326,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
         let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
         let adt_def = self.adt_def(def_id);
-        let substs = Substs::for_item(self, def_id, |_, _| bug!(), |def, substs| {
-            if def.index == 0 {
-                ty
-            } else {
-                match def.kind {
-                    ty::GenericParamDefKind::Type(ty_param) => {
-                        assert!(ty_param.has_default);
-                        self.type_of(def.def_id).subst(self, substs)
+        let substs = Substs::for_item(self, def_id, |param, substs| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => bug!(),
+                GenericParamDefKind::Type(_) => {
+                    if param.index == 0 {
+                        UnpackedKind::Type(ty)
+                    } else {
+                        match param.kind {
+                            ty::GenericParamDefKind::Type(ty_param) => {
+                                assert!(ty_param.has_default);
+                                UnpackedKind::Type(
+                                    self.type_of(param.def_id).subst(self, substs))
+                            }
+                            _ => unreachable!()
+                        }
                     }
-                    _ => unreachable!()
                 }
             }
         });
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index d4db2ae481a..5c2b5c5cd45 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -11,7 +11,7 @@
 // Type substitutions.
 
 use hir::def_id::DefId;
-use ty::{self, Lift, Slice, Region, Ty, TyCtxt};
+use ty::{self, Lift, Slice, Region, Ty, TyCtxt, GenericParamDefKind};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
@@ -174,80 +174,80 @@ impl<'tcx> Decodable for Kind<'tcx> {
     }
 }
 
-/// A substitution mapping type/region parameters to new values.
+/// A substitution mapping generic parameters to new values.
 pub type Substs<'tcx> = Slice<Kind<'tcx>>;
 
 impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     /// Creates a Substs that maps each generic parameter to itself.
     pub fn identity_for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId)
                              -> &'tcx Substs<'tcx> {
-        Substs::for_item(tcx, def_id, |def, _| {
-            tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
-        }, |def, _| tcx.mk_ty_param_from_def(def))
+        Substs::for_item(tcx, def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    UnpackedKind::Lifetime(
+                        tcx.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())))
+                }
+                GenericParamDefKind::Type(_) => {
+                    UnpackedKind::Type(tcx.mk_ty_param_from_def(param))
+                }
+            }
+        })
     }
 
     /// Creates a Substs for generic parameter definitions,
-    /// by calling closures to obtain each region and type.
+    /// by calling closures to obtain each kind.
     /// 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 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::GenericParamDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Ty<'tcx> {
+    /// substitute defaults of generic parameters.
+    pub fn for_item<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                       def_id: DefId,
+                       mut mk_kind: F)
+                       -> &'tcx Substs<'tcx>
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> UnpackedKind<'tcx>
+    {
         let defs = tcx.generics_of(def_id);
         let mut substs = Vec::with_capacity(defs.count());
-        Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
+        Substs::fill_item(&mut substs, tcx, defs, &mut mk_kind);
         tcx.intern_substs(&substs)
     }
 
-    pub fn extend_to<FR, FT>(&self,
-                             tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                             def_id: DefId,
-                             mut mk_region: FR,
-                             mut mk_type: FT)
-                             -> &'tcx Substs<'tcx>
-    where FR: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Ty<'tcx>
+    pub fn extend_to<F>(&self,
+                        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                        def_id: DefId,
+                        mut mk_kind: F)
+                        -> &'tcx Substs<'tcx>
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> UnpackedKind<'tcx>
     {
         let defs = tcx.generics_of(def_id);
         let mut result = Vec::with_capacity(defs.count());
         result.extend(self[..].iter().cloned());
-        Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type);
+        Substs::fill_single(&mut result, defs, &mut mk_kind);
         tcx.intern_substs(&result)
     }
 
-    pub fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+    pub fn fill_item<F>(substs: &mut Vec<Kind<'tcx>>,
                              tcx: TyCtxt<'a, 'gcx, 'tcx>,
                              defs: &ty::Generics,
-                             mk_region: &mut FR,
-                             mk_type: &mut FT)
-    where FR: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Ty<'tcx> {
+                             mk_kind: &mut F)
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> UnpackedKind<'tcx>
+    {
 
         if let Some(def_id) = defs.parent {
             let parent_defs = tcx.generics_of(def_id);
-            Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type);
+            Substs::fill_item(substs, tcx, parent_defs, mk_kind);
         }
-        Substs::fill_single(substs, defs, mk_region, mk_type)
+        Substs::fill_single(substs, defs, mk_kind)
     }
 
-    fn fill_single<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+    fn fill_single<F>(substs: &mut Vec<Kind<'tcx>>,
                            defs: &ty::Generics,
-                           mk_region: &mut FR,
-                           mk_type: &mut FT)
-    where FR: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
-          FT: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Ty<'tcx> {
+                           mk_kind: &mut F)
+    where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> UnpackedKind<'tcx>
+    {
         for param in &defs.params {
-            let kind = match param.kind {
-                ty::GenericParamDefKind::Lifetime => mk_region(param, substs).into(),
-                ty::GenericParamDefKind::Type(_) => mk_type(param, substs).into(),
-            };
+            let kind = mk_kind(param, substs);
             assert_eq!(param.index as usize, substs.len());
-            substs.push(kind);
+            substs.push(kind.pack());
         }
     }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index fdd0754730f..91280e5b8a3 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -17,9 +17,9 @@ use hir;
 use ich::NodeIdHashingMode;
 use middle::const_val::ConstVal;
 use traits::{self, ObligationCause};
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
 use ty::fold::TypeVisitor;
-use ty::subst::UnpackedKind;
+use ty::subst::{Substs, UnpackedKind};
 use ty::maps::TyCtxtAt;
 use ty::TypeVariants::*;
 use ty::layout::{Integer, IntegerExt};
@@ -573,11 +573,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '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 ty::Substs<'tcx> {
-        ty::Substs::for_item(self, item_def_id,
-                             |_, _| self.types.re_erased,
-                             |_, _| {
-            bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
+    pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
+        Substs::for_item(self, item_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => UnpackedKind::Lifetime(self.types.re_erased),
+                GenericParamDefKind::Type(_) => {
+                    bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
+                }
+            }
         })
     }
 
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index f8f6bec33a2..c8d4ccaf0bb 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -196,8 +196,8 @@ use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::interpret::{AllocId, ConstValue};
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
-use rustc::ty::subst::{Substs, Kind};
-use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
+use rustc::ty::subst::{Substs, Kind, UnpackedKind};
+use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
 use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::session::config;
 use rustc::mir::{self, Location, Promoted};
@@ -1112,10 +1112,16 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         continue;
                     }
 
-                    let substs = Substs::for_item(tcx,
-                                                  method.def_id,
-                                                  |_, _| tcx.types.re_erased,
-                                                  |def, _| trait_ref.substs.type_for_def(def));
+                    let substs = Substs::for_item(tcx, method.def_id, |param, _| {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime => {
+                                UnpackedKind::Lifetime(tcx.types.re_erased)
+                            }
+                            GenericParamDefKind::Type(_) => {
+                                UnpackedKind::Type(trait_ref.substs.type_for_def(param))
+                            }
+                        }
+                    });
 
                     let instance = ty::Instance::resolve(tcx,
                                                          ty::ParamEnv::reveal_all(),
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 5b2f3a8b8aa..8596d546b09 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -12,8 +12,8 @@ use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer;
 use rustc::mir::*;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind};
+use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
 use rustc::ty::maps::Providers;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -427,12 +427,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
     ) {
         let tcx = self.tcx;
 
-        let substs = Substs::for_item(
-            tcx,
-            self.def_id,
-            |_, _| tcx.types.re_erased,
-            |_, _| ty
-        );
+        let substs = Substs::for_item(tcx, self.def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => UnpackedKind::Lifetime(tcx.types.re_erased),
+                GenericParamDefKind::Type(_) => UnpackedKind::Type(ty),
+            }
+        });
 
         // `func == Clone::clone(&ty) -> ty`
         let func_ty = tcx.mk_fn_def(self.def_id, substs);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 12e1bfde224..f60c78702b6 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -20,7 +20,8 @@ use middle::resolve_lifetime as rl;
 use namespace::Namespace;
 use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
 use rustc::traits;
-use rustc::ty::{self, RegionKind, Ty, TyCtxt, GenericParamDefKind, ToPredicate, TypeFoldable};
+use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
 use rustc::ty::wf::object_region_bounds;
 use rustc_target::spec::abi;
 use std::slice;
@@ -264,66 +265,76 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         };
 
         let own_self = self_ty.is_some() as usize;
-        let substs = Substs::for_item(tcx, def_id, |def, _| {
-            let i = def.index as usize - own_self;
-            if let Some(lifetime) = parameters.lifetimes.get(i) {
-                self.ast_region_to_region(lifetime, Some(def))
-            } else {
-                tcx.types.re_static
-            }
-        }, |def, substs| {
-            let i = def.index as usize;
-
-            // Handle Self first, so we can adjust the index to match the AST.
-            if let (0, Some(ty)) = (i, self_ty) {
-                return ty;
-            }
+        let substs = Substs::for_item(tcx, def_id, |param, substs| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    let i = param.index as usize - own_self;
+                    let lt = if let Some(lifetime) = parameters.lifetimes.get(i) {
+                        self.ast_region_to_region(lifetime, Some(param))
+                    } else {
+                        tcx.types.re_static
+                    };
+                    UnpackedKind::Lifetime(lt)
+                }
+                GenericParamDefKind::Type(_) => {
+                    let i = param.index as usize;
 
-            let has_default = match def.kind {
-                GenericParamDefKind::Type(ty) => ty.has_default,
-                _ => unreachable!()
-            };
+                    // Handle Self first, so we can adjust the index to match the AST.
+                    if let (0, Some(ty)) = (i, self_ty) {
+                        return UnpackedKind::Type(ty);
+                    }
 
-            let i = i - (lt_accepted + own_self);
-            if i < ty_provided {
-                // A provided type parameter.
-                self.ast_ty_to_ty(&parameters.types[i])
-            } else if infer_types {
-                // No type parameters were provided, we can infer all.
-                let ty_var = if !default_needs_object_self(def) {
-                    self.ty_infer_for_def(def, span)
-                } else {
-                    self.ty_infer(span)
-                };
-                ty_var
-            } else if has_default {
-                // No type parameter provided, but a default exists.
-
-                // If we are converting an object type, then the
-                // `Self` parameter is unknown. However, some of the
-                // other type parameters may reference `Self` in their
-                // defaults. This will lead to an ICE if we are not
-                // careful!
-                if default_needs_object_self(def) {
-                    struct_span_err!(tcx.sess, span, E0393,
-                                     "the type parameter `{}` must be explicitly specified",
-                                     def.name)
-                        .span_label(span, format!("missing reference to `{}`", def.name))
-                        .note(&format!("because of the default `Self` reference, \
-                                        type parameters must be specified on object types"))
-                        .emit();
-                    tcx.types.err
-                } else {
-                    // This is a default type parameter.
-                    self.normalize_ty(
-                        span,
-                        tcx.at(span).type_of(def.def_id)
-                            .subst_spanned(tcx, substs, Some(span))
-                    )
+                    let has_default = match param.kind {
+                        GenericParamDefKind::Type(ty) => ty.has_default,
+                        _ => unreachable!()
+                    };
+
+                    let i = i - (lt_accepted + own_self);
+                    let ty = if i < ty_provided {
+                        // A provided type parameter.
+                        self.ast_ty_to_ty(&parameters.types[i])
+                    } else if infer_types {
+                        // No type parameters were provided, we can infer all.
+                        let ty_var = if !default_needs_object_self(param) {
+                            self.ty_infer_for_def(param, span)
+                        } else {
+                            self.ty_infer(span)
+                        };
+                        ty_var
+                    } else if has_default {
+                        // No type parameter provided, but a default exists.
+
+                        // If we are converting an object type, then the
+                        // `Self` parameter is unknown. However, some of the
+                        // other type parameters may reference `Self` in their
+                        // defaults. This will lead to an ICE if we are not
+                        // careful!
+                        if default_needs_object_self(param) {
+                            struct_span_err!(tcx.sess, span, E0393,
+                                             "the type parameter `{}` must be explicitly \
+                                             specified",
+                                             param.name)
+                                .span_label(span,
+                                            format!("missing reference to `{}`", param.name))
+                                .note(&format!("because of the default `Self` reference, \
+                                                type parameters must be specified on object \
+                                                types"))
+                                .emit();
+                            tcx.types.err
+                        } else {
+                            // This is a default type parameter.
+                            self.normalize_ty(
+                                span,
+                                tcx.at(span).type_of(param.def_id)
+                                    .subst_spanned(tcx, substs, Some(span))
+                            )
+                        }
+                    } else {
+                        // We've already errored above about the mismatch.
+                        tcx.types.err
+                    };
+                    UnpackedKind::Type(ty)
                 }
-            } else {
-                // We've already errored above about the mismatch.
-                tcx.types.err
             }
         });
 
@@ -1154,12 +1165,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let mut substs = Vec::with_capacity(generics.count());
         if let Some(parent_id) = generics.parent {
             let parent_generics = tcx.generics_of(parent_id);
-            Substs::fill_item(
-                &mut substs, tcx, parent_generics,
-                &mut |def, _| tcx.mk_region(
-                    ty::ReEarlyBound(def.to_early_bound_region_data())),
-                &mut |def, _| tcx.mk_ty_param_from_def(def)
-            );
+            Substs::fill_item(&mut substs, tcx, parent_generics, &mut |param, _| {
+                match param.kind {
+                    GenericParamDefKind::Lifetime => {
+                        UnpackedKind::Lifetime(
+                            tcx.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())))
+                    }
+                    GenericParamDefKind::Type(_) => {
+                        UnpackedKind::Type(tcx.mk_ty_param_from_def(param))
+                    }
+                }
+            });
 
             // Replace all lifetimes with 'static
             for subst in &mut substs {
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 94ef040d80a..152f020c476 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -18,8 +18,8 @@ use rustc::infer::{InferOk, InferResult};
 use rustc::infer::LateBoundRegionConversionTime;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::error_reporting::ArgKind;
-use rustc::ty::{self, ToPolyTraitRef, Ty};
-use rustc::ty::subst::Substs;
+use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
+use rustc::ty::subst::{UnpackedKind, Substs};
 use rustc::ty::TypeFoldable;
 use std::cmp;
 use std::iter;
@@ -104,15 +104,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // inference phase (`upvar.rs`).
         let base_substs =
             Substs::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
-        let substs = base_substs.extend_to(
-            self.tcx,
-            expr_def_id,
-            |_, _| span_bug!(expr.span, "closure has region param"),
-            |_, _| {
-                self.infcx
-                    .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span))
-            },
-        );
+        let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    span_bug!(expr.span, "closure has region param")
+                }
+                GenericParamDefKind::Type(_) => {
+                    UnpackedKind::Type(self.infcx
+                        .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)))
+                }
+            }
+        });
         if let Some(GeneratorTypes { yield_ty, interior, movability }) = generator_types {
             let substs = ty::GeneratorSubsts { substs };
             self.demand_eqtype(
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 9928ef549ff..c208e0fae64 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -15,8 +15,8 @@ use check::{FnCtxt, PlaceOp, callee, Needs};
 use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
-use rustc::ty::{self, Ty};
-use rustc::ty::subst::Subst;
+use rustc::ty::{self, Ty, GenericParamDefKind};
+use rustc::ty::subst::{UnpackedKind, Subst};
 use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
 use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
@@ -317,30 +317,37 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         assert_eq!(method_generics.parent_count, parent_substs.len());
         let provided = &segment.parameters;
         let own_counts = method_generics.own_counts();
-        Substs::for_item(self.tcx, pick.item.def_id, |def, _| {
-            let i = def.index as usize;
-            if i < parent_substs.len() {
-                parent_substs.region_at(i)
-            } else if let Some(lifetime)
-                    = provided.as_ref().and_then(|p| p.lifetimes.get(i - parent_substs.len())) {
-                AstConv::ast_region_to_region(self.fcx, lifetime, Some(def))
-            } else {
-                self.region_var_for_def(self.span, def)
-            }
-        }, |def, _cur_substs| {
-            let i = def.index as usize;
-            if i < parent_substs.len() {
-                parent_substs.type_at(i)
-            } else if let Some(ast_ty)
-                = provided.as_ref().and_then(|p| {
-                    let idx =
-                        i - parent_substs.len() - own_counts.lifetimes;
-                    p.types.get(idx)
-                })
-            {
-                self.to_ty(ast_ty)
-            } else {
-                self.type_var_for_def(self.span, def)
+        Substs::for_item(self.tcx, pick.item.def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    let i = param.index as usize;
+                    let lt = if i < parent_substs.len() {
+                        parent_substs.region_at(i)
+                    } else if let Some(lifetime)
+                            = provided.as_ref().and_then(|p| p.lifetimes.get(i - parent_substs.len())) {
+                        AstConv::ast_region_to_region(self.fcx, lifetime, Some(param))
+                    } else {
+                        self.region_var_for_def(self.span, param)
+                    };
+                    UnpackedKind::Lifetime(lt)
+                }
+                GenericParamDefKind::Type(_) => {
+                    let i = param.index as usize;
+                    let ty = if i < parent_substs.len() {
+                        parent_substs.type_at(i)
+                    } else if let Some(ast_ty)
+                        = provided.as_ref().and_then(|p| {
+                            let idx =
+                                i - parent_substs.len() - own_counts.lifetimes;
+                            p.types.get(idx)
+                        })
+                    {
+                        self.to_ty(ast_ty)
+                    } else {
+                        self.type_var_for_def(self.span, param)
+                    };
+                    UnpackedKind::Type(ty)
+                }
             }
         })
     }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 83f132d8869..298b8548e36 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -19,7 +19,8 @@ use namespace::Namespace;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
-use rustc::ty::subst::Subst;
+use rustc::ty::GenericParamDefKind;
+use rustc::ty::subst::{UnpackedKind, Subst};
 use rustc::infer::{self, InferOk};
 
 use syntax::ast;
@@ -253,16 +254,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                trait_def_id);
 
         // Construct a trait-reference `self_ty : Trait<input_tys>`
-        let substs = Substs::for_item(self.tcx,
-                                      trait_def_id,
-                                      |def, _| self.region_var_for_def(span, def),
-                                      |def, _substs| {
-            if def.index == 0 {
-                self_ty
-            } else if let Some(ref input_types) = opt_input_types {
-                input_types[def.index as usize - 1]
-            } else {
-                self.type_var_for_def(span, def)
+        let substs = Substs::for_item(self.tcx, trait_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    UnpackedKind::Lifetime(self.region_var_for_def(span, param))
+                }
+                GenericParamDefKind::Type(_) => {
+                    let ty = if param.index == 0 {
+                        self_ty
+                    } else if let Some(ref input_types) = opt_input_types {
+                        input_types[param.index as usize - 1]
+                    } else {
+                        self.type_var_for_def(span, param)
+                    };
+                    UnpackedKind::Type(ty)
+                }
             }
         });
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 9d762ca3834..a96796bb148 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -17,9 +17,10 @@ use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
 use namespace::Namespace;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{UnpackedKind, Subst, Substs};
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::util::nodemap::FxHashSet;
 use rustc::infer::{self, InferOk};
@@ -1387,21 +1388,28 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         if generics.params.is_empty() {
             xform_fn_sig.subst(self.tcx, substs)
         } else {
-            let substs = Substs::for_item(self.tcx, method, |def, _| {
-                let i = def.index as usize;
-                if i < substs.len() {
-                    substs.region_at(i)
-                } else {
-                    // In general, during probe we erase regions. See
-                    // `impl_self_ty()` for an explanation.
-                    self.tcx.types.re_erased
-                }
-            }, |def, _cur_substs| {
-                let i = def.index as usize;
-                if i < substs.len() {
-                    substs.type_at(i)
-                } else {
-                    self.type_var_for_def(self.span, def)
+            let substs = Substs::for_item(self.tcx, method, |param, _| {
+                match param.kind {
+                    GenericParamDefKind::Lifetime => {
+                        let i = param.index as usize;
+                        let lt = if i < substs.len() {
+                            substs.region_at(i)
+                        } else {
+                            // In general, during probe we erase regions. See
+                            // `impl_self_ty()` for an explanation.
+                            self.tcx.types.re_erased
+                        };
+                        UnpackedKind::Lifetime(lt)
+                    }
+                    GenericParamDefKind::Type(_) => {
+                        let i = param.index as usize;
+                        let ty = if i < substs.len() {
+                            substs.type_at(i)
+                        } else {
+                            self.type_var_for_def(self.span, param)
+                        };
+                        UnpackedKind::Type(ty)
+                    }
                 }
             });
             xform_fn_sig.subst(self.tcx, substs)
@@ -1414,12 +1422,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     }
 
     fn fresh_item_substs(&self, def_id: DefId) -> &'tcx Substs<'tcx> {
-        Substs::for_item(self.tcx,
-                         def_id,
-                         |_, _| self.tcx.types.re_erased,
-                         |_, _| self.next_ty_var(
-                             TypeVariableOrigin::SubstitutionPlaceholder(
-                                 self.tcx.def_span(def_id))))
+        Substs::for_item(self.tcx, def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    UnpackedKind::Lifetime(self.tcx.types.re_erased)
+                }
+                GenericParamDefKind::Type(_) => {
+                    UnpackedKind::Type(self.next_ty_var(
+                        TypeVariableOrigin::SubstitutionPlaceholder(
+                        self.tcx.def_span(def_id))))
+                }
+            }
+        })
     }
 
     /// Replace late-bound-regions bound by `value` with `'static` using
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 7e33bf9722f..99e47f92daf 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -94,7 +94,7 @@ use rustc::infer::anon_types::AnonTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
 use rustc::mir::interpret::{GlobalId};
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@@ -4758,71 +4758,78 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             (None, None) => (0, false)
         };
-        let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| {
-            let mut i = def.index as usize;
-
-            let segment = if i < fn_start {
-                i -= has_self as usize;
-                type_segment
-            } else {
-                i -= fn_start;
-                fn_segment
-            };
-            let lifetimes = segment.map_or(&[][..], |(s, _)| {
-                s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
-            });
-
-            if let Some(lifetime) = lifetimes.get(i) {
-                AstConv::ast_region_to_region(self, lifetime, Some(def))
-            } else {
-                self.re_infer(span, Some(def)).unwrap()
-            }
-        }, |def, substs| {
-            let mut i = def.index as usize;
-
-            let segment = if i < fn_start {
-                // Handle Self first, so we can adjust the index to match the AST.
-                if has_self && i == 0 {
-                    return opt_self_ty.unwrap_or_else(|| {
-                        self.type_var_for_def(span, def)
+        let substs = Substs::for_item(self.tcx, def.def_id(), |param, substs| {
+            match param.kind {
+                GenericParamDefKind::Lifetime => {
+                    let mut i = param.index as usize;
+
+                    let segment = if i < fn_start {
+                        i -= has_self as usize;
+                        type_segment
+                    } else {
+                        i -= fn_start;
+                        fn_segment
+                    };
+                    let lifetimes = segment.map_or(&[][..], |(s, _)| {
+                        s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
                     });
+
+                    let lt = if let Some(lifetime) = lifetimes.get(i) {
+                        AstConv::ast_region_to_region(self, lifetime, Some(param))
+                    } else {
+                        self.re_infer(span, Some(param)).unwrap()
+                    };
+                    UnpackedKind::Lifetime(lt)
                 }
-                i -= has_self as usize;
-                type_segment
-            } else {
-                i -= fn_start;
-                fn_segment
-            };
-            let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
-                (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
-            });
+                GenericParamDefKind::Type(_) => {
+                    let mut i = param.index as usize;
+
+                    let segment = if i < fn_start {
+                        // Handle Self first, so we can adjust the index to match the AST.
+                        if has_self && i == 0 {
+                            return UnpackedKind::Type(opt_self_ty.unwrap_or_else(|| {
+                                self.type_var_for_def(span, param)
+                            }));
+                        }
+                        i -= has_self as usize;
+                        type_segment
+                    } else {
+                        i -= fn_start;
+                        fn_segment
+                    };
+                    let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
+                        (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
+                    });
 
-            // Skip over the lifetimes in the same segment.
-            if let Some((_, generics)) = segment {
-                i -= generics.own_counts().lifetimes;
-            }
+                    // Skip over the lifetimes in the same segment.
+                    if let Some((_, generics)) = segment {
+                        i -= generics.own_counts().lifetimes;
+                    }
 
-            let has_default = match def.kind {
-                GenericParamDefKind::Type(ty) => ty.has_default,
-                _ => unreachable!()
-            };
+                    let has_default = match param.kind {
+                        GenericParamDefKind::Type(ty) => ty.has_default,
+                        _ => unreachable!()
+                    };
 
-            if let Some(ast_ty) = types.get(i) {
-                // A provided type parameter.
-                self.to_ty(ast_ty)
-            } else if !infer_types && has_default {
-                // No type parameter provided, but a default exists.
-                let default = self.tcx.type_of(def.def_id);
-                self.normalize_ty(
-                    span,
-                    default.subst_spanned(self.tcx, substs, Some(span))
-                )
-            } else {
-                // No type parameters were provided, we can infer all.
-                // This can also be reached in some error cases:
-                // We prefer to use inference variables instead of
-                // TyError to let type inference recover somewhat.
-                self.type_var_for_def(span, def)
+                    let ty = if let Some(ast_ty) = types.get(i) {
+                        // A provided type parameter.
+                        self.to_ty(ast_ty)
+                    } else if !infer_types && has_default {
+                        // No type parameter provided, but a default exists.
+                        let default = self.tcx.type_of(param.def_id);
+                        self.normalize_ty(
+                            span,
+                            default.subst_spanned(self.tcx, substs, Some(span))
+                        )
+                    } else {
+                        // No type parameters were provided, we can infer all.
+                        // This can also be reached in some error cases:
+                        // We prefer to use inference variables instead of
+                        // TyError to let type inference recover somewhat.
+                        self.type_var_for_def(span, param)
+                    };
+                    UnpackedKind::Type(ty)
+                }
             }
         });
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index a37137c68cb..5c6a78de313 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -11,11 +11,10 @@
 use check::{Inherited, FnCtxt};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 
-use ty::GenericParamDefKind;
-
 use hir::def_id::DefId;
 use rustc::traits::{self, ObligationCauseCode};
-use rustc::ty::{self, Lift, Ty, TyCtxt};
+use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind};
+use rustc::ty::subst::{UnpackedKind, Substs};
 use rustc::ty::util::ExplicitSelf;
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc::middle::lang_items;
@@ -406,22 +405,28 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
     // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
     //
     // First we build the defaulted substitution.
-    let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
-            // All regions are identity.
-            fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
-        }, |def, _| {
-            // If the param has a default,
-            if is_our_default(def) {
-                let default_ty = fcx.tcx.type_of(def.def_id);
-                // and it's not a dependent default
-                if !default_ty.needs_subst() {
-                    // then substitute with the default.
-                    return default_ty;
+    let substs = Substs::for_item(fcx.tcx, def_id, |param, _| {
+        match param.kind {
+            GenericParamDefKind::Lifetime => {
+                // All regions are identity.
+                UnpackedKind::Lifetime(
+                    fcx.tcx.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())))
+            }
+            GenericParamDefKind::Type(_) => {
+                // If the param has a default,
+                if is_our_default(param) {
+                    let default_ty = fcx.tcx.type_of(param.def_id);
+                    // and it's not a dependent default
+                    if !default_ty.needs_subst() {
+                        // then substitute with the default.
+                        return UnpackedKind::Type(default_ty);
+                    }
                 }
+                // Mark unwanted params as err.
+                UnpackedKind::Type(fcx.tcx.types.err)
             }
-            // Mark unwanted params as err.
-            fcx.tcx.types.err
-        });
+        }
+    });
     // Now we build the substituted predicates.
     for &pred in predicates.predicates.iter() {
         struct CountParams { params: FxHashSet<u32> }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d4f9fb948fe..1a2480bf45e 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -30,7 +30,8 @@ use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::resolve_lifetime as rl;
 use rustc::mir::mono::Linkage;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{UnpackedKind, Substs};
+use rustc::ty::GenericParamDefKind;
 use rustc::ty::{ToPredicate, ReprOptions};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
@@ -1096,15 +1097,17 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
 
             let substs = ty::ClosureSubsts {
-                substs: Substs::for_item(
-                    tcx,
-                    def_id,
-                    |def, _| {
-                        let region = def.to_early_bound_region_data();
-                        tcx.mk_region(ty::ReEarlyBound(region))
-                    },
-                    |def, _| tcx.mk_ty_param_from_def(def)
-                )
+                substs: Substs::for_item(tcx, def_id, |param, _| {
+                    match param.kind {
+                        GenericParamDefKind::Lifetime => {
+                            let region = param.to_early_bound_region_data();
+                            UnpackedKind::Lifetime(tcx.mk_region(ty::ReEarlyBound(region)))
+                        }
+                        GenericParamDefKind::Type(_) => {
+                            UnpackedKind::Type(tcx.mk_ty_param_from_def(param))
+                        }
+                    }
+                })
             };
 
             tcx.mk_closure(def_id, substs)