about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-06-15 10:51:44 +0100
committervarkor <github@varkor.com>2018-06-20 12:23:46 +0100
commita65a9d77f3c4e0a573f9c43b51f9076e96201edc (patch)
tree49aeab48b632c18e4c7d0341cda32697fe9dbd5e
parent37204027b609f9bd218641c764e692335597ff26 (diff)
downloadrust-a65a9d77f3c4e0a573f9c43b51f9076e96201edc.tar.gz
rust-a65a9d77f3c4e0a573f9c43b51f9076e96201edc.zip
Fix accidental quadratic loops
-rw-r--r--src/librustc_typeck/astconv.rs41
-rw-r--r--src/librustc_typeck/check/mod.rs59
2 files changed, 52 insertions, 48 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 48c5353a400..d0cd1cf61ff 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -271,22 +271,24 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         };
 
         let own_self = self_ty.is_some() as usize;
+        // FIXME(varkor): Separating out the parameters is messy.
+        let lifetimes: Vec<_> = generic_args.args.iter().filter_map(|arg| match arg {
+            GenericArg::Lifetime(lt) => Some(lt),
+            _ => None,
+        }).collect();
+        let types: Vec<_> = generic_args.args.iter().filter_map(|arg| match arg {
+            GenericArg::Type(ty) => Some(ty),
+            _ => None,
+        }).collect();
         let substs = Substs::for_item(tcx, def_id, |param, substs| {
             match param.kind {
                 GenericParamDefKind::Lifetime => {
-                    let mut i = param.index as usize - own_self;
-                    for arg in &generic_args.args {
-                        match arg {
-                            GenericArg::Lifetime(lt) => {
-                                if i == 0 {
-                                    return self.ast_region_to_region(lt, Some(param)).into();
-                                }
-                                i -= 1;
-                            }
-                            _ => {}
-                        }
+                    let i = param.index as usize - own_self;
+                    if let Some(lt) = lifetimes.get(i) {
+                        self.ast_region_to_region(lt, Some(param)).into()
+                    } else {
+                        tcx.types.re_static.into()
                     }
-                    tcx.types.re_static.into()
                 }
                 GenericParamDefKind::Type { has_default, .. } => {
                     let i = param.index as usize;
@@ -296,21 +298,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                         return ty.into();
                     }
 
-                    let mut i = i - (lt_accepted + own_self);
+                    let i = i - (lt_accepted + own_self);
                     if i < ty_provided {
                         // A provided type parameter.
-                        for arg in &generic_args.args {
-                            match arg {
-                                GenericArg::Type(ty) => {
-                                    if i == 0 {
-                                        return self.ast_ty_to_ty(ty).into();
-                                    }
-                                    i -= 1;
-                                }
-                                _ => {}
-                            }
-                        }
-                        bug!()
+                        self.ast_ty_to_ty(&types[i]).into()
                     } else if infer_types {
                         // No type parameters were provided, we can infer all.
                         if !default_needs_object_self(param) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index bececfc08ac..93739fbada2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4813,11 +4813,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             (None, None) => (0, false)
         };
+        // FIXME(varkor): Separating out the parameters is messy.
+        let mut lifetimes_type_seg = vec![];
+        let mut types_type_seg = vec![];
+        let mut infer_types_type_seg = true;
+        if let Some((seg, _)) = type_segment {
+            if let Some(ref data) = seg.args {
+                for arg in &data.args {
+                    match arg {
+                        GenericArg::Lifetime(lt) => lifetimes_type_seg.push(lt),
+                        GenericArg::Type(ty) => types_type_seg.push(ty),
+                    }
+                }
+            }
+            infer_types_type_seg = seg.infer_types;
+        }
+
+        let mut lifetimes_fn_seg = vec![];
+        let mut types_fn_seg = vec![];
+        let mut infer_types_fn_seg = true;
+        if let Some((seg, _)) = fn_segment {
+            if let Some(ref data) = seg.args {
+                for arg in &data.args {
+                    match arg {
+                        GenericArg::Lifetime(lt) => lifetimes_fn_seg.push(lt),
+                        GenericArg::Type(ty) => types_fn_seg.push(ty),
+                    }
+                }
+            }
+            infer_types_fn_seg = seg.infer_types;
+        }
+
         let substs = Substs::for_item(self.tcx, def.def_id(), |param, substs| {
             let mut i = param.index as usize;
 
-            let segment = if i < fn_start {
-                if let GenericParamDefKind::Type {..} = param.kind {
+            let (segment, lifetimes, types, infer_types) = if i < fn_start {
+                if let GenericParamDefKind::Type { .. } = param.kind {
                     // Handle Self first, so we can adjust the index to match the AST.
                     if has_self && i == 0 {
                         return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| {
@@ -4826,39 +4857,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
                 i -= has_self as usize;
-                type_segment
+                (type_segment, &lifetimes_type_seg, &types_type_seg, infer_types_type_seg)
             } else {
                 i -= fn_start;
-                fn_segment
+                (fn_segment, &lifetimes_fn_seg, &types_fn_seg, infer_types_fn_seg)
             };
 
             match param.kind {
                 GenericParamDefKind::Lifetime => {
-                    let lifetimes = segment.map_or(vec![], |(s, _)| {
-                        s.args.as_ref().map_or(vec![], |data| {
-                            data.args.iter().filter_map(|arg| match arg {
-                                GenericArg::Lifetime(lt) => Some(lt),
-                                _ => None,
-                            }).collect()
-                        })
-                    });
-
                     if let Some(lifetime) = lifetimes.get(i) {
                         AstConv::ast_region_to_region(self, lifetime, Some(param)).into()
                     } else {
                         self.re_infer(span, Some(param)).unwrap().into()
                     }
                 }
-                GenericParamDefKind::Type {..} => {
-                    let (types, infer_types) = segment.map_or((vec![], true), |(s, _)| {
-                        (s.args.as_ref().map_or(vec![], |data| {
-                            data.args.iter().filter_map(|arg| match arg {
-                                GenericArg::Type(ty) => Some(ty),
-                                _ => None,
-                            }).collect()
-                        }), s.infer_types)
-                    });
-
+                GenericParamDefKind::Type { .. } => {
                     // Skip over the lifetimes in the same segment.
                     if let Some((_, generics)) = segment {
                         i -= generics.own_counts().lifetimes;