about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-07-24 02:27:18 +0100
committervarkor <github@varkor.com>2018-08-19 20:02:33 +0100
commit5d07db436db3a3c1bf3e3940423ee91d2ca368c7 (patch)
treeb4061c0d3516f6120b81963e0cdb65f798d7bd01 /src
parent08d49a65e72c955f39b653a94a9013f11d328d21 (diff)
downloadrust-5d07db436db3a3c1bf3e3940423ee91d2ca368c7.tar.gz
rust-5d07db436db3a3c1bf3e3940423ee91d2ca368c7.zip
Refactor confirm.rs (part ii)
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/method/confirm.rs94
1 files changed, 67 insertions, 27 deletions
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index c9ac02928b3..401e57f3157 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>) {