about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/mod.rs122
-rw-r--r--src/librustc/traits/error_reporting.rs28
-rw-r--r--src/librustc/traits/util.rs3
-rw-r--r--src/librustc/ty/subst.rs31
-rw-r--r--src/librustc_typeck/astconv.rs47
-rw-r--r--src/librustc_typeck/check/method/confirm.rs84
-rw-r--r--src/librustc_typeck/check/method/mod.rs33
-rw-r--r--src/librustc_typeck/check/method/probe.rs35
-rw-r--r--src/librustc_typeck/check/mod.rs50
-rw-r--r--src/librustc_typeck/collect.rs6
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustc_typeck/variance/constraints.rs4
12 files changed, 213 insertions, 232 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 24fadc549fa..79eea7314cd 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1172,15 +1172,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tcx.mk_var(self.next_ty_var_id(false))
     }
 
-    pub fn next_ty_var_with_default(&self,
-                                    default: Option<type_variable::Default<'tcx>>) -> Ty<'tcx> {
-        let ty_var_id = self.type_variables
-                            .borrow_mut()
-                            .new_var(false, default);
-
-        self.tcx.mk_var(ty_var_id)
-    }
-
     pub fn next_diverging_ty_var(&self) -> Ty<'tcx> {
         self.tcx.mk_var(self.next_ty_var_id(true))
     }
@@ -1205,35 +1196,49 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         ty::ReVar(self.region_vars.new_region_var(origin))
     }
 
+    /// Create a region inference variable for the given
+    /// region parameter definition.
+    pub fn region_var_for_def(&self,
+                              span: Span,
+                              def: &ty::RegionParameterDef)
+                              -> ty::Region {
+        self.next_region_var(EarlyBoundRegion(span, def.name))
+    }
+
+    /// Create a type inference variable for the given
+    /// type parameter definition. The substitutions are
+    /// for actual parameters that may be referred to by
+    /// the default of this type parameter, if it exists.
+    /// E.g. `struct Foo<A, B, C = (A, B)>(...);` when
+    /// used in a path such as `Foo::<T, U>::new()` will
+    /// use an inference variable for `C` with `[T, U]`
+    /// as the substitutions for the default, `(T, U)`.
+    pub fn type_var_for_def(&self,
+                            span: Span,
+                            def: &ty::TypeParameterDef<'tcx>,
+                            substs: &Substs<'tcx>)
+                            -> Ty<'tcx> {
+        let default = def.default.map(|default| {
+            type_variable::Default {
+                ty: default.subst_spanned(self.tcx, substs, Some(span)),
+                origin_span: span,
+                def_id: def.default_def_id
+            }
+        });
+
+
+        let ty_var_id = self.type_variables
+                            .borrow_mut()
+                            .new_var(false, default);
+
+        self.tcx.mk_var(ty_var_id)
+    }
+
     pub fn region_vars_for_defs(&self,
                                 span: Span,
                                 defs: &[ty::RegionParameterDef])
                                 -> Vec<ty::Region> {
-        defs.iter()
-            .map(|d| self.next_region_var(EarlyBoundRegion(span, d.name)))
-            .collect()
-    }
-
-    // We have to take `&mut Substs` in order to provide the correct substitutions for defaults
-    // along the way, for this reason we don't return them.
-    pub fn type_vars_for_defs(&self,
-                              span: Span,
-                              space: subst::ParamSpace,
-                              substs: &mut Substs<'tcx>,
-                              defs: &[ty::TypeParameterDef<'tcx>]) {
-
-        for def in defs.iter() {
-            let default = def.default.map(|default| {
-                type_variable::Default {
-                    ty: default.subst_spanned(self.tcx, substs, Some(span)),
-                    origin_span: span,
-                    def_id: def.default_def_id
-                }
-            });
-
-            let ty_var = self.next_ty_var_with_default(default);
-            substs.types.push(space, ty_var);
-        }
+        defs.iter().map(|def| self.region_var_for_def(span, def)).collect()
     }
 
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
@@ -1243,21 +1248,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                      generics: &ty::Generics<'tcx>)
                                      -> &'tcx subst::Substs<'tcx>
     {
-        let type_params = subst::VecPerParamSpace::empty();
-
-        let region_params =
-            generics.regions.map(
-                |d| self.next_region_var(EarlyBoundRegion(span, d.name)));
-
-        let mut substs = subst::Substs::new(type_params, region_params);
-
-        for space in subst::ParamSpace::all().iter() {
-            self.type_vars_for_defs(
-                span,
-                *space,
-                &mut substs,
-                generics.types.get_slice(*space));
-        }
+        let type_defs = generics.types.as_full_slice();
+        let region_defs = generics.regions.as_full_slice();
+        let substs = Substs::from_param_defs(region_defs, type_defs, |def| {
+            self.region_var_for_def(span, def)
+        }, |def, substs| {
+            self.type_var_for_def(span, def, substs)
+        });
 
         self.tcx.mk_substs(substs)
     }
@@ -1269,25 +1266,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                   span: Span,
                                   generics: &ty::Generics<'tcx>,
                                   self_ty: Ty<'tcx>)
-                                  -> subst::Substs<'tcx>
+                                  -> &'tcx subst::Substs<'tcx>
     {
-
         assert!(generics.types.len(subst::SelfSpace) == 1);
         assert!(generics.types.len(subst::FnSpace) == 0);
-        assert!(generics.regions.len(subst::SelfSpace) == 0);
-        assert!(generics.regions.len(subst::FnSpace) == 0);
-
-        let type_params = Vec::new();
-
-        let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
-        let regions = self.region_vars_for_defs(span, region_param_defs);
 
-        let mut substs = subst::Substs::new_trait(type_params, regions, self_ty);
-
-        let type_parameter_defs = generics.types.get_slice(subst::TypeSpace);
-        self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs);
+        let type_defs = generics.types.as_full_slice();
+        let region_defs = generics.regions.as_full_slice();
+        let substs = Substs::from_param_defs(region_defs, type_defs, |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)
+            }
+        });
 
-        return substs;
+        self.tcx.mk_substs(substs)
     }
 
     pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index b5133738ada..5d50eac1716 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -31,7 +31,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::error::ExpectedFound;
 use ty::fast_reject;
 use ty::fold::TypeFolder;
-use ty::subst::{self, Subst, TypeSpace};
+use ty::subst::{Subst, TypeSpace};
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
 use std::cmp;
@@ -167,27 +167,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         });
     }
 
-    fn impl_substs(&self,
-                   did: DefId,
-                   obligation: PredicateObligation<'tcx>)
-                   -> subst::Substs<'tcx> {
-        let tcx = self.tcx;
-
-        let ity = tcx.lookup_item_type(did);
-        let (tps, rps, _) =
-            (ity.generics.types.get_slice(TypeSpace),
-             ity.generics.regions.get_slice(TypeSpace),
-             ity.ty);
-
-        let rps = self.region_vars_for_defs(obligation.cause.span, rps);
-        let mut substs = subst::Substs::new_type(vec![], rps);
-        self.type_vars_for_defs(obligation.cause.span,
-                                TypeSpace,
-                                &mut substs,
-                                tps);
-        substs
-    }
-
     fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
         /// returns the fuzzy category of a given type, or None
         /// if the type can be equated to any type.
@@ -242,10 +221,13 @@ 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_trait_ref = tcx
                     .impl_trait_ref(def_id)
                     .unwrap()
-                    .subst(tcx, &self.impl_substs(def_id, obligation.clone()));
+                    .subst(tcx, impl_substs);
 
                 let impl_self_ty = impl_trait_ref.self_ty();
 
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 818eb4eb2fb..80a3ad9122b 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -358,8 +358,7 @@ pub fn fresh_type_vars_for_impl<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
                                                 impl_def_id: DefId)
                                                 -> &'tcx Substs<'tcx>
 {
-    let tcx = infcx.tcx;
-    let impl_generics = tcx.lookup_item_type(impl_def_id).generics;
+    let impl_generics = infcx.tcx.lookup_item_type(impl_def_id).generics;
     infcx.fresh_substs_for_generics(span, &impl_generics)
 }
 
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 63399ee1388..34e7899e2fd 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -73,6 +73,33 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         }
     }
 
+    /// Creates a Substs for generic parameter definitions,
+    /// by calling closures to obtain each region and type.
+    /// 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>
+    where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
+          FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
+        let mut substs = Substs::empty();
+        for &space in &ParamSpace::all() {
+            for def in generics.regions.get_slice(space) {
+                let region = mk_region(def, &substs);
+                assert_eq!(substs.regions.len(def.space), def.index as usize);
+                substs.regions.push(def.space, region);
+            }
+            for def in generics.types.get_slice(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
+    }
+
     pub fn is_noop(&self) -> bool {
         self.regions.is_empty() && self.types.is_empty()
     }
@@ -81,6 +108,10 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         *self.types.get(ty_param_def.space, ty_param_def.index as usize)
     }
 
+    pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region {
+        *self.regions.get(def.space, def.index as usize)
+    }
+
     pub fn self_ty(&self) -> Option<Ty<'tcx>> {
         self.types.get_self().cloned()
     }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index a0af98dec72..ea7b447632c 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -55,7 +55,7 @@ use hir::def_id::DefId;
 use hir::print as pprust;
 use middle::resolve_lifetime as rl;
 use rustc::lint;
-use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
+use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::wf::object_region_bounds;
@@ -115,11 +115,15 @@ pub trait AstConv<'gcx, 'tcx> {
     fn get_free_substs(&self) -> Option<&Substs<'tcx>>;
 
     /// What type should we use when a type is omitted?
-    fn ty_infer(&self,
-                param_and_substs: Option<ty::TypeParameterDef<'tcx>>,
-                substs: Option<&mut Substs<'tcx>>,
-                space: Option<ParamSpace>,
-                span: Span) -> Ty<'tcx>;
+    fn ty_infer(&self, span: Span) -> Ty<'tcx>;
+
+    /// Same as ty_infer, but with a known type parameter definition.
+    fn ty_infer_for_def(&self,
+                        _def: &ty::TypeParameterDef<'tcx>,
+                        _substs: &Substs<'tcx>,
+                        span: Span) -> Ty<'tcx> {
+        self.ty_infer(span)
+    }
 
     /// Projecting an associated type from a (potentially)
     /// higher-ranked trait reference is more complicated, because of
@@ -535,26 +539,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                 self_ty: Option<Ty<'tcx>>)
                                 -> Vec<Ty<'tcx>>
     {
-        fn default_type_parameter<'tcx>(p: &ty::TypeParameterDef<'tcx>, self_ty: Option<Ty<'tcx>>)
-                                        -> Option<ty::TypeParameterDef<'tcx>>
-        {
+        let use_default = |p: &ty::TypeParameterDef<'tcx>| {
             if let Some(ref default) = p.default {
                 if self_ty.is_none() && default.has_self_ty() {
                     // There is no suitable inference default for a type parameter
                     // that references self with no self-type provided.
-                    return None;
+                    return false;
                 }
             }
 
-            Some(p.clone())
-        }
+            true
+        };
 
         if param_mode == PathParamMode::Optional && types_provided.is_empty() {
-            ty_param_defs
-                .iter()
-                .map(|p| self.ty_infer(default_type_parameter(p, self_ty), Some(&mut substs),
-                                       Some(TypeSpace), span))
-                .collect()
+            ty_param_defs.iter().map(|def| {
+                let ty_var = if use_default(def) {
+                    self.ty_infer_for_def(def, &substs, span)
+                } else {
+                    self.ty_infer(span)
+                };
+                substs.types.push(def.space, ty_var);
+                ty_var
+            }).collect()
         } else {
             types_provided
         }
@@ -1828,7 +1834,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // values in a ExprClosure, or as
                 // the type of local variables. Both of these cases are
                 // handled specially and will not descend into this routine.
-                self.ty_infer(None, None, None, ast_ty.span)
+                self.ty_infer(ast_ty.span)
             }
         };
 
@@ -1845,7 +1851,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     {
         match a.ty.node {
             hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
-            hir::TyInfer => self.ty_infer(None, None, None, a.ty.span),
+            hir::TyInfer => self.ty_infer(a.ty.span),
             _ => self.ast_ty_to_ty(rscope, &a.ty),
         }
     }
@@ -2067,8 +2073,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let output_ty = match decl.output {
             _ if is_infer && expected_ret_ty.is_some() =>
                 expected_ret_ty.unwrap(),
-            _ if is_infer =>
-                self.ty_infer(None, None, None, decl.output.span()),
+            _ if is_infer => self.ty_infer(decl.output.span()),
             hir::Return(ref output) =>
                 self.ast_ty_to_ty(&rb, &output),
             hir::DefaultReturn(..) => bug!(),
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 5fac65bbfd6..d1d72599555 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -198,7 +198,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
     fn fresh_receiver_substs(&mut self,
                              self_ty: Ty<'tcx>,
                              pick: &probe::Pick<'tcx>)
-                             -> subst::Substs<'tcx>
+                             -> &'tcx subst::Substs<'tcx>
     {
         match pick.kind {
             probe::InherentImplPick => {
@@ -231,7 +231,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                            original_poly_trait_ref,
                            upcast_trait_ref,
                            trait_def_id);
-                    upcast_trait_ref.substs.clone()
+                    upcast_trait_ref.substs
                 })
             }
 
@@ -249,9 +249,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                 let impl_trait_ref =
                     self.instantiate_type_scheme(
                         self.span,
-                        &impl_polytype.substs,
+                        impl_polytype.substs,
                         &self.tcx.impl_trait_ref(impl_def_id).unwrap());
-                impl_trait_ref.substs.clone()
+                impl_trait_ref.substs
             }
 
             probe::TraitPick => {
@@ -271,7 +271,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             probe::WhereClausePick(ref poly_trait_ref) => {
                 // Where clauses can have bound regions in them. We need to instantiate
                 // those to convert from a poly-trait-ref to a trait-ref.
-                self.replace_late_bound_regions_with_fresh_var(&poly_trait_ref).substs.clone()
+                self.replace_late_bound_regions_with_fresh_var(&poly_trait_ref).substs
             }
         }
     }
@@ -303,8 +303,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
     fn instantiate_method_substs(&mut self,
                                  pick: &probe::Pick<'tcx>,
-                                 supplied_method_types: Vec<Ty<'tcx>>,
-                                 substs: subst::Substs<'tcx>)
+                                 mut supplied_method_types: Vec<Ty<'tcx>>,
+                                 substs: &subst::Substs<'tcx>)
                                  -> subst::Substs<'tcx>
     {
         // Determine the values for the generic parameters of the method.
@@ -312,50 +312,42 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // variables.
         let num_supplied_types = supplied_method_types.len();
         let method = pick.item.as_opt_method().unwrap();
-        let method_types = method.generics.types.get_slice(subst::FnSpace);
-        let num_method_types = method_types.len();
-
+        let num_method_types = method.generics.types.len(subst::FnSpace);
+
+        if num_supplied_types > 0 && num_supplied_types != num_method_types {
+            if num_method_types == 0 {
+                span_err!(self.tcx.sess, self.span, E0035,
+                    "does not take type parameters");
+            } else {
+                span_err!(self.tcx.sess, self.span, E0036,
+                    "incorrect number of type parameters given for this method: \
+                     expected {}, found {}",
+                    num_method_types, num_supplied_types);
+            }
+            supplied_method_types = vec![self.tcx.types.err; num_method_types];
+        }
 
         // Create subst for early-bound lifetime parameters, combining
         // parameters from the type and those from the method.
         //
         // FIXME -- permit users to manually specify lifetimes
-        let method_regions =
-            self.region_vars_for_defs(
-                self.span,
-                pick.item.as_opt_method().unwrap()
-                    .generics.regions.get_slice(subst::FnSpace));
-
-        let subst::Substs { types, regions } = substs;
-        let regions = regions.with_slice(subst::FnSpace, &method_regions);
-        let mut final_substs = subst::Substs { types: types, regions: regions };
-
-        if num_supplied_types == 0 {
-            self.type_vars_for_defs(
-                self.span,
-                subst::FnSpace,
-                &mut final_substs,
-                method_types);
-        } else if num_method_types == 0 {
-            span_err!(self.tcx.sess, self.span, E0035,
-                "does not take type parameters");
-            self.type_vars_for_defs(
-                self.span,
-                subst::FnSpace,
-                &mut final_substs,
-                method_types);
-        } else if num_supplied_types != num_method_types {
-            span_err!(self.tcx.sess, self.span, E0036,
-                "incorrect number of type parameters given for this method: expected {}, found {}",
-                num_method_types, num_supplied_types);
-            final_substs.types.replace(
-                subst::FnSpace,
-                vec![self.tcx.types.err; num_method_types]);
-        } else {
-            final_substs.types.replace(subst::FnSpace, supplied_method_types);
-        }
-
-        return final_substs;
+        let type_defs = method.generics.types.as_full_slice();
+        let region_defs = method.generics.regions.as_full_slice();
+        subst::Substs::from_param_defs(region_defs, type_defs, |def| {
+            if def.space != subst::FnSpace {
+                substs.region_for_def(def)
+            } else {
+                self.region_var_for_def(self.span, def)
+            }
+        }, |def, cur_substs| {
+            if def.space != subst::FnSpace {
+                substs.type_for_def(def)
+            } else if supplied_method_types.is_empty() {
+                self.type_var_for_def(self.span, def, cur_substs)
+            } else {
+                supplied_method_types[def.index as usize]
+            }
+        })
     }
 
     fn unify_receivers(&mut self,
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index e6401be5b3e..532a5c0de4e 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -182,29 +182,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let trait_def = self.tcx.lookup_trait_def(trait_def_id);
 
-        let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
-        let expected_number_of_input_types = type_parameter_defs.len();
-
+        if let Some(ref input_types) = opt_input_types {
+            assert_eq!(trait_def.generics.types.len(subst::TypeSpace), input_types.len());
+        }
         assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
         assert!(trait_def.generics.regions.is_empty());
 
         // Construct a trait-reference `self_ty : Trait<input_tys>`
-        let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty);
-
-        match opt_input_types {
-            Some(input_types) => {
-                assert_eq!(expected_number_of_input_types, input_types.len());
-                substs.types.replace(subst::ParamSpace::TypeSpace, input_types);
+        let type_defs = trait_def.generics.types.as_full_slice();
+        let region_defs = trait_def.generics.regions.as_full_slice();
+        let substs = subst::Substs::from_param_defs(region_defs, type_defs, |def| {
+            self.region_var_for_def(span, def)
+        }, |def, substs| {
+            if def.space == subst::SelfSpace {
+                self_ty
+            } else if let Some(ref input_types) = opt_input_types {
+                input_types[def.index as usize]
+            } else {
+                self.type_var_for_def(span, def, substs)
             }
-
-            None => {
-                self.type_vars_for_defs(
-                    span,
-                    subst::ParamSpace::TypeSpace,
-                    &mut substs,
-                    type_parameter_defs);
-            }
-        }
+        });
 
         let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs));
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index e4701bb1195..44e371482c5 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1227,28 +1227,29 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             return impl_ty;
         }
 
-        let mut placeholder;
+        let placeholder;
         let mut substs = substs;
         if
             !method.generics.types.is_empty_in(subst::FnSpace) ||
             !method.generics.regions.is_empty_in(subst::FnSpace)
         {
-            // In general, during probe we erase regions. See
-            // `impl_self_ty()` for an explanation.
-            let method_regions =
-                method.generics.regions.get_slice(subst::FnSpace)
-                .iter()
-                .map(|_| ty::ReErased)
-                .collect();
-
-            placeholder = (*substs).clone().with_method(Vec::new(), method_regions);
-
-            self.type_vars_for_defs(
-                self.span,
-                subst::FnSpace,
-                &mut placeholder,
-                method.generics.types.get_slice(subst::FnSpace));
-
+            let type_defs = method.generics.types.as_full_slice();
+            let region_defs = method.generics.regions.as_full_slice();
+            placeholder = subst::Substs::from_param_defs(region_defs, type_defs, |def| {
+                if def.space != subst::FnSpace {
+                    substs.region_for_def(def)
+                } else {
+                    // In general, during probe we erase regions. See
+                    // `impl_self_ty()` for an explanation.
+                    ty::ReErased
+                }
+            }, |def, cur_substs| {
+                if def.space != subst::FnSpace {
+                    substs.type_for_def(def)
+                } else {
+                    self.type_var_for_def(self.span, def, cur_substs)
+                }
+            });
             substs = &placeholder;
         }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fae64f37419..b5018d51b7f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1358,27 +1358,15 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         trait_def.associated_type_names.contains(&assoc_name)
     }
 
-    fn ty_infer(&self,
-                ty_param_def: Option<ty::TypeParameterDef<'tcx>>,
-                substs: Option<&mut subst::Substs<'tcx>>,
-                space: Option<subst::ParamSpace>,
-                span: Span) -> Ty<'tcx> {
-        // Grab the default doing subsitution
-        let default = ty_param_def.and_then(|def| {
-            def.default.map(|ty| type_variable::Default {
-                ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)),
-                origin_span: span,
-                def_id: def.default_def_id
-            })
-        });
-
-        let ty_var = self.next_ty_var_with_default(default);
+    fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
+        self.next_ty_var()
+    }
 
-        // Finally we add the type variable to the substs
-        match substs {
-            None => ty_var,
-            Some(substs) => { substs.types.push(space.unwrap(), ty_var); ty_var }
-        }
+    fn ty_infer_for_def(&self,
+                        ty_param_def: &ty::TypeParameterDef<'tcx>,
+                        substs: &subst::Substs<'tcx>,
+                        span: Span) -> Ty<'tcx> {
+        self.type_var_for_def(span, ty_param_def, substs)
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -2785,20 +2773,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         span: Span, // (potential) receiver for this impl
                         did: DefId)
                         -> TypeAndSubsts<'tcx> {
-        let tcx = self.tcx;
-
-        let ity = tcx.lookup_item_type(did);
-        let (tps, rps, raw_ty) =
-            (ity.generics.types.get_slice(subst::TypeSpace),
-             ity.generics.regions.get_slice(subst::TypeSpace),
-             ity.ty);
+        let ity = self.tcx.lookup_item_type(did);
+        debug!("impl_self_ty: ity={:?}", ity);
 
-        debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty);
-
-        let rps = self.region_vars_for_defs(span, rps);
-        let mut substs = subst::Substs::new_type(vec![], rps);
-        self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps);
-        let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty);
+        let substs = self.fresh_substs_for_generics(span, &ity.generics);
+        let substd_ty = self.instantiate_type_scheme(span, &substs, &ity.ty);
 
         TypeAndSubsts { substs: substs, ty: substd_ty }
     }
@@ -4532,7 +4511,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // everything.
         if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) {
             substs.types.replace(space, Vec::new());
-            self.type_vars_for_defs(span, space, substs, &desired[..]);
+            for def in desired {
+                let ty_var = self.type_var_for_def(span, def, substs);
+                substs.types.push(def.space, ty_var);
+            }
             return;
         }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 69545aefb44..0ddc051d4a8 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -362,11 +362,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         None
     }
 
-    fn ty_infer(&self,
-                _ty_param_def: Option<ty::TypeParameterDef<'tcx>>,
-                _substs: Option<&mut Substs<'tcx>>,
-                _space: Option<ParamSpace>,
-                span: Span) -> Ty<'tcx> {
+    fn ty_infer(&self, span: Span) -> Ty<'tcx> {
         struct_span_err!(
             self.tcx().sess,
             span,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 11743ade2d4..4ce6f8210c3 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -132,7 +132,7 @@ pub mod coherence;
 pub mod variance;
 
 pub struct TypeAndSubsts<'tcx> {
-    pub substs: Substs<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
     pub ty: Ty<'tcx>,
 }
 
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 1e342d4b819..50c568cfef8 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -464,7 +464,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.declared_variance(p.def_id, def_id, TypeParam,
                                        p.space, p.index as usize);
             let variance_i = self.xform(variance, variance_decl);
-            let substs_ty = *substs.types.get(p.space, p.index as usize);
+            let substs_ty = substs.type_for_def(p);
             debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
                    variance_decl, variance_i);
             self.add_constraints_from_ty(generics, substs_ty, variance_i);
@@ -475,7 +475,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.declared_variance(p.def_id, def_id,
                                        RegionParam, p.space, p.index as usize);
             let variance_i = self.xform(variance, variance_decl);
-            let substs_r = *substs.regions.get(p.space, p.index as usize);
+            let substs_r = substs.region_for_def(p);
             self.add_constraints_from_region(generics, substs_r, variance_i);
         }
     }