diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index c9ac02928b3ba..401e57f315764 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::Substs; +use rustc::ty::subst::{Kind, Substs}; use rustc::traits; use rustc::ty::{self, Ty, GenericParamDefKind}; use rustc::ty::subst::Subst; @@ -24,6 +24,8 @@ 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; @@ -323,48 +325,86 @@ 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()); - let inferred_lifetimes = if if let Some(ref data) = segment.args { - !data.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }) - } else { - true - } { - method_generics.own_counts().lifetimes + // 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 { - 0 + 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), + } + } - Substs::for_item(self.tcx, pick.item.def_id, |param, _| { - let param_idx = param.index as usize; - if param_idx < parent_substs.len() { - parent_substs[param_idx] - } else { - let param_idx = (param.index as usize - parent_substs.len()) - .saturating_sub(inferred_lifetimes); + // 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(); + } else { + break; + } + } - if let Some(ref data) = segment.args { - if let Some(arg) = data.args.get(param_idx) { + 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) => { - return AstConv::ast_region_to_region( - self.fcx, lt, Some(param)).into(); + 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) => return self.to_ty(ty).into(), - _ => {} + GenericArg::Type(ty) => { + push_kind(&mut substs, self.to_ty(ty).into()); + next_param = params.next(); + continue 'args; + } + _ => { + break 'args; + } } } } } + } - self.var_for_def(self.span, param) + 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) } fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {