about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-07-24 17:47:31 +0100
committervarkor <github@varkor.com>2018-08-19 20:02:34 +0100
commite79bc410bf5f8d07121cc685d611ca72c21b28d0 (patch)
treec9164aa1cc6d971ee706bbb68be3eae1906ecdc0
parentccef306b965697f01a5eb9fb69b9b7a34517cc8a (diff)
downloadrust-e79bc410bf5f8d07121cc685d611ca72c21b28d0.tar.gz
rust-e79bc410bf5f8d07121cc685d611ca72c21b28d0.zip
Consolidate into create_substs_for_generic_args
-rw-r--r--src/librustc_typeck/astconv.rs285
-rw-r--r--src/librustc_typeck/check/method/confirm.rs109
-rw-r--r--src/librustc_typeck/check/mod.rs169
3 files changed, 268 insertions, 295 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index ccea902e4b6..83c18265489 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -14,7 +14,7 @@
 
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use rustc_data_structures::array_vec::ArrayVec;
-use hir::{self, GenericArg};
+use hir::{self, GenericArg, GenericArgs};
 use hir::def::Def;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
@@ -22,7 +22,7 @@ use namespace::Namespace;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
-use rustc::ty::GenericParamDefKind;
+use rustc::ty::{GenericParamDef, GenericParamDefKind};
 use rustc::ty::wf::object_region_bounds;
 use rustc_target::spec::abi;
 use std::slice;
@@ -192,6 +192,153 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
         substs
     }
 
+    /// Creates the relevant generic argument substitutions
+    /// corresponding to a set of generic parameters.
+    pub fn create_substs_for_generic_args<'a, 'b, A, P, I>(
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        span: Span,
+        err_if_invalid: bool,
+        def_id: DefId,
+        parent_substs: &[Kind<'tcx>],
+        has_self: bool,
+        self_ty: Option<Ty<'tcx>>,
+        args_for_def_id: A,
+        provided_kind: P,
+        inferred_kind: I,
+    ) -> &'tcx Substs<'tcx> where
+        A: Fn(DefId) -> (Option<&'b GenericArgs>, bool),
+        P: Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
+        I: Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>
+    {
+        // Collect the segments of the path: we need to substitute arguments
+        // for parameters throughout the entire path (wherever there are
+        // generic parameters).
+        let mut parent_defs = tcx.generics_of(def_id);
+        let count = parent_defs.count();
+        let mut stack = vec![(def_id, parent_defs)];
+        while let Some(def_id) = parent_defs.parent {
+            parent_defs = tcx.generics_of(def_id);
+            stack.push((def_id, parent_defs));
+        }
+
+        // We manually build up the substitution, rather than using convenience
+        // methods in subst.rs so that we can iterate over the arguments and
+        // parameters in lock-step linearly, rather than trying to match each pair.
+        let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 {
+            AccumulateVec::Array(ArrayVec::new())
+        } else {
+            AccumulateVec::Heap(Vec::with_capacity(count))
+        };
+
+        fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) {
+            match substs {
+                AccumulateVec::Array(ref mut arr) => arr.push(kind),
+                AccumulateVec::Heap(ref mut vec) => vec.push(kind),
+            }
+        }
+
+        // Iterate over each segment of the path.
+        while let Some((def_id, defs)) = stack.pop() {
+            let mut params = defs.params.iter();
+            let mut next_param = params.next();
+
+            // If we have already computed substitutions for parents, we can use those directly.
+            while let Some(param) = next_param {
+                if let Some(&kind) = parent_substs.get(param.index as usize) {
+                    push_kind(&mut substs, kind);
+                    next_param = params.next();
+                } else {
+                    break;
+                }
+            }
+
+            // (Unless it's been handled in `parent_substs`) `Self` is handled first.
+            if has_self {
+                if let Some(param) = next_param {
+                    if param.index == 0 {
+                        if let GenericParamDefKind::Type { .. } = param.kind {
+                            push_kind(&mut substs, self_ty.map(|ty| ty.into())
+                                .unwrap_or_else(|| inferred_kind(None, param, true)));
+                            next_param = params.next();
+                        }
+                    }
+                }
+            }
+
+            // Check whether this segment takes generic arguments and the user has provided any.
+            let (generic_args, infer_types) = args_for_def_id(def_id);
+            if let Some(ref generic_args) = generic_args {
+                // We're going to iterate through the generic arguments that the user
+                // provided, matching them with the generic parameters we expect.
+                // Mismatches can occur as a result of elided lifetimes, or for malformed
+                // input. We try to handle both sensibly.
+                'args: for arg in &generic_args.args {
+                    while let Some(param) = next_param {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime => match arg {
+                                GenericArg::Lifetime(_) => {
+                                    push_kind(&mut substs, provided_kind(param, arg));
+                                    next_param = params.next();
+                                    continue 'args;
+                                }
+                                GenericArg::Type(_) => {
+                                    // We expected a lifetime argument, but got a type
+                                    // argument. That means we're inferring the lifetimes.
+                                    push_kind(&mut substs, inferred_kind(None, param, infer_types));
+                                    next_param = params.next();
+                                }
+                            }
+                            GenericParamDefKind::Type { .. } => match arg {
+                                GenericArg::Type(_) => {
+                                    push_kind(&mut substs, provided_kind(param, arg));
+                                    next_param = params.next();
+                                    continue 'args;
+                                }
+                                GenericArg::Lifetime(_) => {
+                                    // We expected a type argument, but got a lifetime
+                                    // argument. This is an error, but we need to handle it
+                                    // gracefully so we can report sensible errors. In this
+                                    // case, we're simply going to infer the remaining
+                                    // arguments.
+                                    if err_if_invalid {
+                                        tcx.sess.delay_span_bug(span,
+                                            "found a GenericArg::Lifetime where a \
+                                            GenericArg::Type was expected");
+                                    }
+                                    break 'args;
+                                }
+                            }
+                        }
+                    }
+                    // We should never be able to reach this point with well-formed input.
+                    // Getting to this point means the user supplied more arguments than
+                    // there are parameters.
+                    if err_if_invalid {
+                        tcx.sess.delay_span_bug(span,
+                            "GenericArg did not have matching GenericParamDef");
+                    }
+                }
+            }
+
+            // If there are fewer arguments than parameters, it means
+            // we're inferring the remaining arguments.
+            while let Some(param) = next_param {
+                match param.kind {
+                    GenericParamDefKind::Lifetime => {
+                        push_kind(&mut substs, inferred_kind(None, param, infer_types));
+                    }
+                    GenericParamDefKind::Type { .. } => {
+                        let kind = inferred_kind(Some(&substs), param, infer_types);
+                        push_kind(&mut substs, kind);
+                    }
+                }
+                next_param = params.next();
+            }
+        }
+
+        tcx.intern_substs(&substs)
+    }
+
     /// Given the type/region arguments provided to some path (along with
     /// an implicit Self, if this is a trait reference) returns the complete
     /// set of substitutions. This may involve applying defaulted type parameters.
@@ -271,95 +418,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
             false
         };
 
-        // Collect the segments of the path: we need to substitute arguments
-        // for parameters throughout the entire path (wherever there are
-        // generic parameters).
-        let mut parent_defs = self.tcx().generics_of(def_id);
-        let count = parent_defs.count();
-        let mut stack = vec![(def_id, parent_defs)];
-        while let Some(def_id) = parent_defs.parent {
-            parent_defs = self.tcx().generics_of(def_id);
-            stack.push((def_id, parent_defs));
-        }
-
-        // We manually build up the substitution, rather than using convenience
-        // methods in subst.rs so that we can iterate over the arguments and
-        // parameters in lock-step linearly, rather than trying to match each pair.
-        let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 {
-            AccumulateVec::Array(ArrayVec::new())
-        } else {
-            AccumulateVec::Heap(Vec::with_capacity(count))
-        };
-        fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) {
-            match substs {
-                AccumulateVec::Array(ref mut arr) => arr.push(kind),
-                AccumulateVec::Heap(ref mut vec) => vec.push(kind),
-            }
-        }
-
-        // Iterate over each segment of the path.
-        while let Some((_, defs)) = stack.pop() {
-            let mut params = defs.params.iter();
-            let mut next_param = params.next();
-
-            // `Self` is handled first.
-            if let Some(ty) = self_ty {
-                if let Some(param) = next_param {
-                    if param.index == 0 {
-                        if let GenericParamDefKind::Type { .. } = param.kind {
-                            push_kind(&mut substs, ty.into());
-                            next_param = params.next();
+        let substs = Self::create_substs_for_generic_args(
+            self.tcx(),
+            span,
+            false,
+            def_id,
+            &[][..],
+            self_ty.is_some(),
+            self_ty,
+            // Provide the generic args, and whether types should be inferred.
+            |_| (Some(generic_args), infer_types),
+            // Provide substitutions for parameters for which (valid) arguments have been provided.
+            |param, arg| {
+                match param.kind {
+                    GenericParamDefKind::Lifetime => match arg {
+                        GenericArg::Lifetime(lt) => {
+                            self.ast_region_to_region(&lt, Some(param)).into()
                         }
+                        _ => unreachable!(),
                     }
-                }
-            }
-
-            let args = &generic_args.args;
-            'args: for arg in args {
-                while let Some(param) = next_param {
-                    match param.kind {
-                        GenericParamDefKind::Lifetime => match arg {
-                            GenericArg::Lifetime(lt) => {
-                                push_kind(&mut substs,
-                                    self.ast_region_to_region(&lt, Some(param)).into());
-                                next_param = params.next();
-                                continue 'args;
-                            }
-                            GenericArg::Type(_) => {
-                                // We expected a lifetime argument, but got a type
-                                // argument. That means we're inferring the lifetimes.
-                                push_kind(&mut substs, tcx.types.re_static.into());
-                                next_param = params.next();
-                            }
-                        }
-                        GenericParamDefKind::Type { .. } => match arg {
-                            GenericArg::Type(ty) => {
-                                push_kind(&mut substs, self.ast_ty_to_ty(&ty).into());
-                                next_param = params.next();
-                                continue 'args;
-                            }
-                            GenericArg::Lifetime(_) => {
-                                break 'args;
-                            }
-                        }
+                    GenericParamDefKind::Type { .. } => match arg {
+                        GenericArg::Type(ty) => self.ast_ty_to_ty(&ty).into(),
+                        _ => unreachable!(),
                     }
                 }
-            }
-
-            while let Some(param) = next_param {
+            },
+            // Provide substitutions for parameters for which arguments are inferred.
+            |substs, param, infer_types| {
                 match param.kind {
-                    GenericParamDefKind::Lifetime => {
-                        push_kind(&mut substs, tcx.types.re_static.into());
-                    }
+                    GenericParamDefKind::Lifetime => tcx.types.re_static.into(),
                     GenericParamDefKind::Type { has_default, .. } => {
-                        if infer_types {
-                            // No type parameters were provided, we can infer all.
-                            push_kind(&mut substs, if !default_needs_object_self(param) {
-                                self.ty_infer_for_def(param, span).into()
-                            } else {
-                                self.ty_infer(span).into()
-                            });
-                        } else if has_default {
+                        if !infer_types && has_default {
                             // No type parameter provided, but a default exists.
 
                             // If we are converting an object type, then the
@@ -378,26 +467,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                                                     type parameters must be specified on object \
                                                     types"))
                                     .emit();
-                                push_kind(&mut substs, tcx.types.err.into());
+                                tcx.types.err.into()
                             } else {
                                 // This is a default type parameter.
-                                let kind = self.normalize_ty(
+                                self.normalize_ty(
                                     span,
                                     tcx.at(span).type_of(param.def_id)
-                                        .subst_spanned(tcx, &substs, Some(span))
-                                ).into();
-                                push_kind(&mut substs, kind);
+                                        .subst_spanned(tcx, substs.unwrap(), Some(span))
+                                ).into()
+                            }
+                        } else if infer_types {
+                            // No type parameters were provided, we can infer all.
+                            if !default_needs_object_self(param) {
+                                self.ty_infer_for_def(param, span).into()
+                            } else {
+                                self.ty_infer(span).into()
                             }
                         } else {
                             // We've already errored above about the mismatch.
-                            push_kind(&mut substs, tcx.types.err.into());
+                            tcx.types.err.into()
                         }
                     }
-                };
-                next_param = params.next();
-            }
-        }
-        let substs = self.tcx().intern_substs(&substs);
+                }
+            },
+        );
 
         let assoc_bindings = generic_args.bindings.iter().map(|binding| {
             ConvertedBinding {
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 401e57f3157..0acbd803103 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -14,7 +14,7 @@ use astconv::AstConv;
 use check::{FnCtxt, PlaceOp, callee, Needs};
 use hir::GenericArg;
 use hir::def_id::DefId;
-use rustc::ty::subst::{Kind, Substs};
+use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, GenericParamDefKind};
 use rustc::ty::subst::Subst;
@@ -24,8 +24,6 @@ use rustc::ty::fold::TypeFoldable;
 use rustc::infer::{self, InferOk};
 use syntax_pos::Span;
 use rustc::hir;
-use rustc_data_structures::accumulate_vec::AccumulateVec;
-use rustc_data_structures::array_vec::ArrayVec;
 
 use std::ops::Deref;
 
@@ -325,86 +323,41 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // parameters from the type and those from the method.
         assert_eq!(method_generics.parent_count, parent_substs.len());
 
-        // Collect the segments of the path: we need to substitute arguments
-        // for parameters throughout the entire path (wherever there are
-        // generic parameters).
-        let def_id = pick.item.def_id;
-        let mut parent_defs = self.tcx.generics_of(def_id);
-        let count = parent_defs.count();
-        let mut stack = vec![(def_id, parent_defs)];
-        while let Some(def_id) = parent_defs.parent {
-            parent_defs = self.tcx.generics_of(def_id);
-            stack.push((def_id, parent_defs));
-        }
-
-        // We manually build up the substitution, rather than using convenience
-        // methods in subst.rs so that we can iterate over the arguments and
-        // parameters in lock-step linearly, rather than trying to match each pair.
-        let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 {
-            AccumulateVec::Array(ArrayVec::new())
-        } else {
-            AccumulateVec::Heap(Vec::with_capacity(count))
-        };
-        fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) {
-            match substs {
-                AccumulateVec::Array(ref mut arr) => arr.push(kind),
-                AccumulateVec::Heap(ref mut vec) => vec.push(kind),
-            }
-        }
-
-        // Iterate over each segment of the path.
-        while let Some((_, defs)) = stack.pop() {
-            let mut params = defs.params.iter();
-            let mut next_param = params.next();
-
-            while let Some(param) = next_param {
-                if let Some(&kind) = parent_substs.get(param.index as usize) {
-                    push_kind(&mut substs, kind);
-                    next_param = params.next();
+        AstConv::create_substs_for_generic_args(
+            self.tcx,
+            self.span,
+            false,
+            pick.item.def_id,
+            parent_substs,
+            false,
+            None,
+            // Provide the generic args, and whether types should be inferred.
+            |_| {
+                // The last argument of the returned tuple here is unimportant.
+                if let Some(ref data) = segment.args {
+                    (Some(data), false)
                 } else {
-                    break;
+                    (None, false)
                 }
-            }
-
-            if let Some(ref data) = segment.args {
-                let args = &data.args;
-                'args: for arg in args {
-                    while let Some(param) = next_param {
-                        match param.kind {
-                            GenericParamDefKind::Lifetime => match arg {
-                                GenericArg::Lifetime(lt) => {
-                                    push_kind(&mut substs, AstConv::ast_region_to_region(
-                                        self.fcx, lt, Some(param)).into());
-                                    next_param = params.next();
-                                    continue 'args;
-                                }
-                                _ => {
-                                    push_kind(&mut substs, self.var_for_def(self.span, param));
-                                    next_param = params.next();
-                                }
-                            }
-                            GenericParamDefKind::Type { .. } => match arg {
-                                GenericArg::Type(ty) => {
-                                    push_kind(&mut substs, self.to_ty(ty).into());
-                                    next_param = params.next();
-                                    continue 'args;
-                                }
-                                _ => {
-                                    break 'args;
-                                }
-                            }
+            },
+            // Provide substitutions for parameters for which (valid) arguments have been provided.
+            |param, arg| {
+                match param.kind {
+                    GenericParamDefKind::Lifetime => match arg {
+                        GenericArg::Lifetime(lt) => {
+                            AstConv::ast_region_to_region(self.fcx, lt, Some(param)).into()
                         }
+                        _ => unreachable!(),
+                    }
+                    GenericParamDefKind::Type { .. } => match arg {
+                        GenericArg::Type(ty) => self.to_ty(ty).into(),
+                        _ => unreachable!(),
                     }
                 }
-            }
-
-            while let Some(param) = next_param {
-                push_kind(&mut substs, self.var_for_def(self.span, param));
-                next_param = params.next();
-            }
-        }
-
-        self.tcx.intern_substs(&substs)
+            },
+            // Provide substitutions for parameters for which arguments are inferred.
+            |_, param, _| self.var_for_def(self.span, param),
+        )
     }
 
     fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1ef296774ea..141d0aea462 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -95,7 +95,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, UnpackedKind, Subst, Substs};
+use rustc::ty::subst::{UnpackedKind, Subst, Substs};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@@ -103,8 +103,6 @@ use rustc::ty::fold::TypeFoldable;
 use rustc::ty::query::Providers;
 use rustc::ty::util::{Representability, IntTypeExt, Discr};
 use errors::{DiagnosticBuilder, DiagnosticId};
-use rustc_data_structures::accumulate_vec::AccumulateVec;
-use rustc_data_structures::array_vec::ArrayVec;
 
 use require_c_abi_if_variadic;
 use session::{CompileIncomplete, config, Session};
@@ -4282,8 +4280,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     {
         match *qpath {
             hir::QPath::Resolved(ref maybe_qself, ref path) => {
-                let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
-                let ty = AstConv::def_to_ty(self, opt_self_ty, path, true);
+                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
+                let ty = AstConv::def_to_ty(self, self_ty, path, true);
                 (path.def, ty)
             }
             hir::QPath::TypeRelative(ref qself, ref segment) => {
@@ -4873,7 +4871,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     // number of type parameters and type.
     pub fn instantiate_value_path(&self,
                                   segments: &[hir::PathSegment],
-                                  opt_self_ty: Option<Ty<'tcx>>,
+                                  self_ty: Option<Ty<'tcx>>,
                                   def: Def,
                                   span: Span,
                                   node_id: ast::NodeId)
@@ -4898,7 +4896,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 if segments.len() == 1 {
                     // `<T>::assoc` will end up here, and so can `T::assoc`.
-                    let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self");
+                    let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
                     ufcs_associated = Some((container, self_ty));
                 }
             }
@@ -4955,122 +4953,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.tcx.generics_of(*def_id).has_self
         }).unwrap_or(false);
 
-        // Collect the segments of the path: we need to substitute arguments
-        // for parameters throughout the entire path (wherever there are
-        // generic parameters).
         let def_id = def.def_id();
-        let mut parent_defs = self.tcx.generics_of(def_id);
-        let count = parent_defs.count();
-        let mut stack = vec![(def_id, parent_defs)];
-        while let Some(def_id) = parent_defs.parent {
-            parent_defs = self.tcx.generics_of(def_id);
-            stack.push((def_id, parent_defs));
-        }
 
-        // We manually build up the substitution, rather than using convenience
-        // methods in subst.rs so that we can iterate over the arguments and
-        // parameters in lock-step linearly, rather than trying to match each pair.
-        let mut substs: AccumulateVec<[Kind<'tcx>; 8]> = if count <= 8 {
-            AccumulateVec::Array(ArrayVec::new())
-        } else {
-            AccumulateVec::Heap(Vec::with_capacity(count))
-        };
-        fn push_kind<'tcx>(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, kind: Kind<'tcx>) {
-            match substs {
-                AccumulateVec::Array(ref mut arr) => arr.push(kind),
-                AccumulateVec::Heap(ref mut vec) => vec.push(kind),
-            }
-        }
-
-        // Iterate over each segment of the path.
-        while let Some((def_id, defs)) = stack.pop() {
-            let mut params = defs.params.iter();
-            let mut next_param = params.next();
-
-            // `Self` is handled first.
-            if has_self {
-                if let Some(param) = next_param {
-                    if param.index == 0 {
-                        if let GenericParamDefKind::Type { .. } = param.kind {
-                            push_kind(&mut substs, opt_self_ty.map(|ty| ty.into())
-                                .unwrap_or_else(|| self.var_for_def(span, param)));
-                            next_param = params.next();
+        let substs = AstConv::create_substs_for_generic_args(
+            self.tcx,
+            span,
+            true,
+            def_id,
+            &[][..],
+            has_self,
+            self_ty,
+            // Provide the generic args, and whether types should be inferred.
+            |def_id| {
+                if let Some(&PathSeg(_, index)) = path_segs.iter().find(|&PathSeg(did, _)| {
+                    *did == def_id
+                }) {
+                    // If we've encountered an `impl Trait`-related error, we're just
+                    // going to infer the arguments for better error messages.
+                    if !supress_errors[&index] {
+                        // Check whether the user has provided generic arguments.
+                        if let Some(ref data) = segments[index].args {
+                            return (Some(data), segments[index].infer_types);
                         }
                     }
+                    return (None, segments[index].infer_types);
                 }
-            }
 
-            let mut infer_types = true;
-            // Check whether this segment takes generic arguments.
-            if let Some(&PathSeg(_, index)) = path_segs
-                .iter()
-                .find(|&PathSeg(did, _)| *did == def_id) {
-                // If we've encountered an `impl Trait`-related error, we're just
-                // going to infer the arguments for better error messages.
-                if !supress_errors[&index] {
-                    infer_types = segments[index].infer_types;
-                    // Check whether the user has provided generic arguments.
-                    if let Some(ref data) = segments[index].args {
-                        let args = &data.args;
-                        // We're going to iterate through the generic arguments that the user
-                        // provided, matching them with the generic parameters we expect.
-                        // Mismatches can occur as a result of elided lifetimes, or for malformed
-                        // input. We try to handle both sensibly.
-                        'args: for arg in args {
-                            while let Some(param) = next_param {
-                                match param.kind {
-                                    GenericParamDefKind::Lifetime => match arg {
-                                        GenericArg::Lifetime(lt) => {
-                                            push_kind(&mut substs,
-                                                AstConv::ast_region_to_region(self, lt, Some(param))
-                                                .into());
-                                            next_param = params.next();
-                                            continue 'args;
-                                        }
-                                        GenericArg::Type(_) => {
-                                            // We expected a lifetime argument, but got a type
-                                            // argument. That means we're inferring the lifetimes.
-                                            push_kind(&mut substs,
-                                                self.re_infer(span, Some(param)).unwrap().into());
-                                            next_param = params.next();
-                                        }
-                                    }
-                                    GenericParamDefKind::Type { .. } => match arg {
-                                        GenericArg::Type(ty) => {
-                                            push_kind(&mut substs, self.to_ty(ty).into());
-                                            next_param = params.next();
-                                            continue 'args;
-                                        }
-                                        GenericArg::Lifetime(_) => {
-                                            // We expected a type argument, but got a lifetime
-                                            // argument. This is an error, but we need to handle it
-                                            // gracefully so we can report sensible errors. In this
-                                            // case, we're simply going to infer the remaining
-                                            // arguments.
-                                            self.tcx.sess.delay_span_bug(span,
-                                                "found a GenericArg::Lifetime where a \
-                                                 GenericArg::Type was expected");
-                                            break 'args;
-                                        }
-                                    }
-                                }
-                            }
-                            // We should never be able to reach this point with well-formed input.
-                            // Getting to this point means the user supplied more arguments than
-                            // there are parameters.
-                            self.tcx.sess.delay_span_bug(span,
-                                "GenericArg did not have matching GenericParamDef");
+                (None, true)
+            },
+            // Provide substitutions for parameters for which (valid) arguments have been provided.
+            |param, arg| {
+                match param.kind {
+                    GenericParamDefKind::Lifetime => match arg {
+                        GenericArg::Lifetime(lt) => {
+                            AstConv::ast_region_to_region(self, lt, Some(param)).into()
                         }
+                        _ => unreachable!(),
+                    }
+                    GenericParamDefKind::Type { .. } => match arg {
+                        GenericArg::Type(ty) => self.to_ty(ty).into(),
+                        _ => unreachable!(),
                     }
                 }
-            }
-
-            // If there are fewer arguments than parameters, it means
-            // we're inferring the remaining arguments.
-            while let Some(param) = next_param {
+            },
+            // Provide substitutions for parameters for which arguments are inferred.
+            |substs, param, infer_types| {
                 match param.kind {
                     GenericParamDefKind::Lifetime => {
-                        push_kind(&mut substs, self.re_infer(span, Some(param)).unwrap().into());
+                        self.re_infer(span, Some(param)).unwrap().into()
                     }
                     GenericParamDefKind::Type { has_default, .. } => {
                         if !infer_types && has_default {
@@ -5078,24 +5008,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             // inferring the type arguments: we provide the default where any
                             // is missing.
                             let default = self.tcx.type_of(param.def_id);
-                            let kind = self.normalize_ty(
+                            self.normalize_ty(
                                 span,
-                                default.subst_spanned(self.tcx, &substs, Some(span))
-                            ).into();
-                            push_kind(&mut substs, kind);
+                                default.subst_spanned(self.tcx, substs.unwrap(), Some(span))
+                            ).into()
                         } else {
                             // If no type arguments were provided, we have to infer them.
                             // This case also occurs as a result of some malformed input, e.g.
                             // a lifetime argument being given instead of a type paramter.
                             // Using inference instead of `TyError` gives better error messages.
-                            push_kind(&mut substs, self.var_for_def(span, param));
+                            self.var_for_def(span, param)
                         }
                     }
                 }
-                next_param = params.next();
-            }
-        }
-        let substs = self.tcx.intern_substs(&substs);
+            },
+        );
 
         // The things we are substituting into the type should not contain
         // escaping late-bound regions, and nor should the base type scheme.