about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorJonas Platte <jplatte+git@posteo.de>2017-10-16 21:07:26 +0200
committerJonas Platte <jplatte+git@posteo.de>2017-12-21 13:38:10 +0100
commit78493ed21aaeb20a8d5f7bd08f26c0c9fd496ed4 (patch)
tree628b8d1cc99f88db6f47d5f07e1ff3d10b8adb3c /src/librustc
parentab7abfcf3457ebc67ac7fef5c3028a6ae4402156 (diff)
downloadrust-78493ed21aaeb20a8d5f7bd08f26c0c9fd496ed4.tar.gz
rust-78493ed21aaeb20a8d5f7bd08f26c0c9fd496ed4.zip
Add GenericParam, refactor Generics in ast, hir, rustdoc
The Generics now contain one Vec of an enum for the generic parameters,
rather than two separate Vec's for lifetime and type parameters.

Additionally, places that previously used Vec<LifetimeDef> now use
Vec<GenericParam> instead.
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/hir/intravisit.rs42
-rw-r--r--src/librustc/hir/lowering.rs229
-rw-r--r--src/librustc/hir/map/collector.rs2
-rw-r--r--src/librustc/hir/map/def_collector.rs29
-rw-r--r--src/librustc/hir/mod.rs107
-rw-r--r--src/librustc/hir/print.rs105
-rw-r--r--src/librustc/ich/impls_hir.rs14
-rw-r--r--src/librustc/lint/context.rs19
-rw-r--r--src/librustc/lint/mod.rs4
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs146
11 files changed, 402 insertions, 297 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 3a1b0b8c58e..74714edfc86 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -279,6 +279,9 @@ pub trait Visitor<'v> : Sized {
     fn visit_ty(&mut self, t: &'v Ty) {
         walk_ty(self, t)
     }
+    fn visit_generic_param(&mut self, p: &'v GenericParam) {
+        walk_generic_param(self, p)
+    }
     fn visit_generics(&mut self, g: &'v Generics) {
         walk_generics(self, g)
     }
@@ -336,9 +339,6 @@ pub trait Visitor<'v> : Sized {
     fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
         walk_lifetime(self, lifetime)
     }
-    fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) {
-        walk_lifetime_def(self, lifetime)
-    }
     fn visit_qpath(&mut self, qpath: &'v QPath, id: NodeId, span: Span) {
         walk_qpath(self, qpath, id, span)
     }
@@ -430,17 +430,12 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
     }
 }
 
-pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) {
-    visitor.visit_lifetime(&lifetime_def.lifetime);
-    walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
-}
-
 pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
                                   trait_ref: &'v PolyTraitRef,
                                   _modifier: TraitBoundModifier)
     where V: Visitor<'v>
 {
-    walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
+    walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
     visitor.visit_trait_ref(&trait_ref.trait_ref);
 }
 
@@ -581,7 +576,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         }
         TyBareFn(ref function_declaration) => {
             visitor.visit_fn_decl(&function_declaration.decl);
-            walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes);
+            walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
         }
         TyPath(ref qpath) => {
             visitor.visit_qpath(qpath, typ.id, typ.span);
@@ -729,14 +724,23 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyPar
     }
 }
 
-pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
-    for param in &generics.ty_params {
-        visitor.visit_id(param.id);
-        visitor.visit_name(param.span, param.name);
-        walk_list!(visitor, visit_ty_param_bound, &param.bounds);
-        walk_list!(visitor, visit_ty, &param.default);
+pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam) {
+    match *param {
+        GenericParam::Lifetime(ref ld) => {
+            visitor.visit_lifetime(&ld.lifetime);
+            walk_list!(visitor, visit_lifetime, &ld.bounds);
+        }
+        GenericParam::Type(ref ty_param) => {
+            visitor.visit_id(ty_param.id);
+            visitor.visit_name(ty_param.span, ty_param.name);
+            walk_list!(visitor, visit_ty_param_bound, &ty_param.bounds);
+            walk_list!(visitor, visit_ty, &ty_param.default);
+        }
     }
-    walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
+}
+
+pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
+    walk_list!(visitor, visit_generic_param, &generics.params);
     visitor.visit_id(generics.where_clause.id);
     walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
 }
@@ -748,11 +752,11 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
     match predicate {
         &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
                                                             ref bounds,
-                                                            ref bound_lifetimes,
+                                                            ref bound_generic_params,
                                                             ..}) => {
             visitor.visit_ty(bounded_ty);
             walk_list!(visitor, visit_ty_param_bound, bounds);
-            walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
+            walk_list!(visitor, visit_generic_param, bound_generic_params);
         }
         &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
                                                               ref bounds,
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 847cf64ce6a..22e661a876e 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -253,7 +253,9 @@ impl<'a> LoweringContext<'a> {
                     ItemKind::Ty(_, ref generics) |
                     ItemKind::Trait(_, _, ref generics, ..) => {
                         let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
-                        let count = generics.lifetimes.len();
+                        let count = generics.params.iter()
+                            .filter(|param| param.is_lifetime_param())
+                            .count();
                         self.lctx.type_def_lifetime_params.insert(def_id, count);
                     }
                     _ => {}
@@ -306,8 +308,8 @@ impl<'a> LoweringContext<'a> {
                     let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node {
                         hir::Item_::ItemImpl(_,_,_,ref generics,..) |
                         hir::Item_::ItemTrait(_,_,ref generics,..) =>
-                            generics.lifetimes.clone(),
-                        _ => Vec::new().into(),
+                            generics.lifetimes().cloned().collect::<Vec<_>>(),
+                        _ => Vec::new(),
                     };
 
                     self.lctx.with_parent_impl_lifetime_defs(&item_lifetimes, |this| {
@@ -532,14 +534,14 @@ impl<'a> LoweringContext<'a> {
         span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
     }
 
-    // Creates a new hir::LifetimeDef for every new lifetime encountered
-    // while evaluating `f`. Definitions are created with the parent provided.
-    // If no `parent_id` is provided, no definitions will be returned.
+    // Creates a new hir::GenericParam for every new lifetime and type parameter
+    // encountered while evaluating `f`. Definitions are created with the parent
+    // provided. If no `parent_id` is provided, no definitions will be returned.
     fn collect_in_band_defs<T, F>(
         &mut self,
         parent_id: Option<DefId>,
         f: F
-    ) -> (Vec<hir::TyParam>, Vec<hir::LifetimeDef>, T) where F: FnOnce(&mut LoweringContext) -> T
+    ) -> (Vec<hir::GenericParam>, T) where F: FnOnce(&mut LoweringContext) -> T
     {
         assert!(!self.is_collecting_in_band_lifetimes);
         assert!(self.lifetimes_to_define.is_empty());
@@ -554,7 +556,7 @@ impl<'a> LoweringContext<'a> {
         let in_band_ty_params = self.in_band_ty_params.split_off(0);
         let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
 
-        let lifetime_defs = match parent_id {
+        let mut params = match parent_id {
             Some(parent_id) => lifetimes_to_define.into_iter().map(|(span, name)| {
                     let def_node_id = self.next_id().node_id;
 
@@ -567,7 +569,7 @@ impl<'a> LoweringContext<'a> {
                         Mark::root()
                     );
 
-                    hir::LifetimeDef {
+                    hir::GenericParam::Lifetime(hir::LifetimeDef {
                         lifetime: hir::Lifetime {
                             id: def_node_id,
                             span,
@@ -576,12 +578,14 @@ impl<'a> LoweringContext<'a> {
                         bounds: Vec::new().into(),
                         pure_wrt_drop: false,
                         in_band: true,
-                    }
+                    })
                 }).collect(),
             None => Vec::new(),
         };
 
-        (in_band_ty_params, lifetime_defs, res)
+        params.extend(in_band_ty_params.into_iter().map(|tp| hir::GenericParam::Type(tp)));
+
+        (params, res)
     }
 
     // Evaluates `f` with the lifetimes in `lt_defs` in-scope.
@@ -635,24 +639,24 @@ impl<'a> LoweringContext<'a> {
     ) -> (hir::Generics, T)
         where F: FnOnce(&mut LoweringContext) -> T
     {
-        let (in_band_ty_defs, in_band_lifetime_defs, (mut lowered_generics, res)) =
-            self.with_in_scope_lifetime_defs(&generics.lifetimes, |this| {
-                this.collect_in_band_defs(parent_id, |this| {
-                    (this.lower_generics(generics), f(this))
-                })
-            });
-
-        lowered_generics.ty_params =
-            lowered_generics.ty_params
-                .iter().cloned()
-                .chain(in_band_ty_defs.into_iter())
-                .collect();
+        let (in_band_defs, (mut lowered_generics, res)) =
+            self.with_in_scope_lifetime_defs(
+                &generics.params
+                    .iter()
+                    .filter_map(|p| match *p {
+                        GenericParam::Lifetime(ref ld) => Some(ld.clone()),
+                        _ => None,
+                    })
+                    .collect::<Vec<_>>(),
+                |this| {
+                    this.collect_in_band_defs(parent_id, |this| {
+                        (this.lower_generics(generics), f(this))
+                    })
+                }
+            );
 
-        lowered_generics.lifetimes =
-            lowered_generics.lifetimes
-                .iter().cloned()
-               .chain(in_band_lifetime_defs.into_iter())
-               .collect();
+        lowered_generics.params =
+            lowered_generics.params.iter().cloned().chain(in_band_defs).collect();
 
         (lowered_generics, res)
     }
@@ -877,9 +881,16 @@ impl<'a> LoweringContext<'a> {
                 hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => {
-                self.with_in_scope_lifetime_defs(&f.lifetimes, |this|
-                    hir::TyBareFn(P(hir::BareFnTy {
-                        lifetimes: this.lower_lifetime_defs(&f.lifetimes),
+                self.with_in_scope_lifetime_defs(
+                    &f.generic_params
+                        .iter()
+                        .filter_map(|p| match *p {
+                            GenericParam::Lifetime(ref ld) => Some(ld.clone()),
+                            _ => None,
+                        })
+                        .collect::<Vec<_>>(),
+                    |this| hir::TyBareFn(P(hir::BareFnTy {
+                        generic_params: this.lower_generic_params(&f.generic_params, &NodeMap()),
                         unsafety: this.lower_unsafety(f.unsafety),
                         abi: f.abi,
                         decl: this.lower_fn_decl(&f.decl, None, false),
@@ -954,9 +965,7 @@ impl<'a> LoweringContext<'a> {
 
                         hir::TyImplTraitExistential(hir::ExistTy {
                             generics: hir::Generics {
-                                lifetimes: lifetime_defs,
-                                // Type parameters are taken from environment:
-                                ty_params: Vec::new().into(),
+                                params: lifetime_defs,
                                 where_clause: hir::WhereClause {
                                     id: self.next_id().node_id,
                                     predicates: Vec::new().into(),
@@ -1027,7 +1036,7 @@ impl<'a> LoweringContext<'a> {
         &mut self,
         parent_index: DefIndex,
         bounds: &hir::TyParamBounds
-    ) -> (HirVec<hir::Lifetime>, HirVec<hir::LifetimeDef>) {
+    ) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
 
         // This visitor walks over impl trait bounds and creates defs for all lifetimes which
         // appear in the bounds, excluding lifetimes that are created within the bounds.
@@ -1039,7 +1048,7 @@ impl<'a> LoweringContext<'a> {
             currently_bound_lifetimes: Vec<hir::LifetimeName>,
             already_defined_lifetimes: HashSet<hir::LifetimeName>,
             output_lifetimes: Vec<hir::Lifetime>,
-            output_lifetime_defs: Vec<hir::LifetimeDef>,
+            output_lifetime_params: Vec<hir::GenericParam>,
         }
 
         impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> {
@@ -1078,14 +1087,16 @@ impl<'a> LoweringContext<'a> {
                 let old_len = self.currently_bound_lifetimes.len();
 
                 // Record the introduction of 'a in `for<'a> ...`
-                for lt_def in &polytr.bound_lifetimes {
-                    // Introduce lifetimes one at a time so that we can handle
-                    // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
-                    self.currently_bound_lifetimes.push(lt_def.lifetime.name);
-
-                    // Visit the lifetime bounds
-                    for lt_bound in &lt_def.bounds {
-                        self.visit_lifetime(&lt_bound);
+                for param in &polytr.bound_generic_params {
+                    if let hir::GenericParam::Lifetime(ref lt_def) = *param {
+                        // Introduce lifetimes one at a time so that we can handle
+                        // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
+                        self.currently_bound_lifetimes.push(lt_def.lifetime.name);
+
+                        // Visit the lifetime bounds
+                        for lt_bound in &lt_def.bounds {
+                            self.visit_lifetime(&lt_bound);
+                        }
                     }
                 }
 
@@ -1133,12 +1144,12 @@ impl<'a> LoweringContext<'a> {
                         span: lifetime.span,
                         name: name,
                     };
-                    self.output_lifetime_defs.push(hir::LifetimeDef {
+                    self.output_lifetime_params.push(hir::GenericParam::Lifetime(hir::LifetimeDef {
                         lifetime: def_lifetime,
                         bounds: Vec::new().into(),
                         pure_wrt_drop: false,
                         in_band: false,
-                    });
+                    }));
                 }
             }
         }
@@ -1150,7 +1161,7 @@ impl<'a> LoweringContext<'a> {
             currently_bound_lifetimes: Vec::new(),
             already_defined_lifetimes: HashSet::new(),
             output_lifetimes: Vec::new(),
-            output_lifetime_defs: Vec::new(),
+            output_lifetime_params: Vec::new(),
         };
 
         for bound in bounds {
@@ -1159,7 +1170,7 @@ impl<'a> LoweringContext<'a> {
 
         (
             lifetime_collector.output_lifetimes.into(),
-            lifetime_collector.output_lifetime_defs.into()
+            lifetime_collector.output_lifetime_params.into()
         )
     }
 
@@ -1568,13 +1579,6 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_ty_params(&mut self, tps: &Vec<TyParam>, add_bounds: &NodeMap<Vec<TyParamBound>>)
-                       -> hir::HirVec<hir::TyParam> {
-        tps.iter().map(|tp| {
-            self.lower_ty_param(tp, add_bounds.get(&tp.id).map_or(&[][..], |x| &x))
-        }).collect()
-    }
-
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         let name = match self.lower_ident(l.ident) {
             x if x == "'_" => hir::LifetimeName::Underscore,
@@ -1620,12 +1624,31 @@ impl<'a> LoweringContext<'a> {
         lts.iter().map(|l| self.lower_lifetime(l)).collect()
     }
 
-    fn lower_lifetime_defs(&mut self, lts: &Vec<LifetimeDef>) -> hir::HirVec<hir::LifetimeDef> {
-        lts.iter().map(|l| self.lower_lifetime_def(l)).collect()
+    fn lower_generic_params(
+        &mut self,
+        params: &Vec<GenericParam>,
+        add_bounds: &NodeMap<Vec<TyParamBound>>,
+    ) -> hir::HirVec<hir::GenericParam> {
+        params.iter()
+            .map(|param| match *param {
+                GenericParam::Lifetime(ref lifetime_def) => {
+                    hir::GenericParam::Lifetime(self.lower_lifetime_def(lifetime_def))
+                }
+                GenericParam::Type(ref ty_param) => {
+                    hir::GenericParam::Type(self.lower_ty_param(
+                        ty_param,
+                        add_bounds.get(&ty_param.id).map_or(&[][..], |x| &x)
+                    ))
+                }
+            })
+            .collect()
     }
 
     fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
         // Collect `?Trait` bounds in where clause and move them to parameter definitions.
+        // FIXME: This could probably be done with less rightward drift. Also looks like two control
+        //        paths where report_error is called are also the only paths that advance to after
+        //        the match statement, so the error reporting could probably just be moved there.
         let mut add_bounds = NodeMap();
         for pred in &g.where_clause.predicates {
             if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
@@ -1640,17 +1663,20 @@ impl<'a> LoweringContext<'a> {
                         match bound_pred.bounded_ty.node {
                             TyKind::Path(None, ref path)
                                     if path.segments.len() == 1 &&
-                                       bound_pred.bound_lifetimes.is_empty() => {
+                                       bound_pred.bound_generic_params.is_empty() => {
                                 if let Some(Def::TyParam(def_id)) =
                                         self.resolver.get_resolution(bound_pred.bounded_ty.id)
                                                      .map(|d| d.base_def()) {
                                     if let Some(node_id) =
                                             self.resolver.definitions().as_local_node_id(def_id) {
-                                        for ty_param in &g.ty_params {
-                                            if node_id == ty_param.id {
-                                                add_bounds.entry(ty_param.id).or_insert(Vec::new())
-                                                                            .push(bound.clone());
-                                                continue 'next_bound;
+                                        for param in &g.params {
+                                            if let GenericParam::Type(ref ty_param) = *param {
+                                                if node_id == ty_param.id {
+                                                    add_bounds.entry(ty_param.id)
+                                                        .or_insert(Vec::new())
+                                                        .push(bound.clone());
+                                                    continue 'next_bound;
+                                                }
                                             }
                                         }
                                     }
@@ -1665,8 +1691,7 @@ impl<'a> LoweringContext<'a> {
         }
 
         hir::Generics {
-            ty_params: self.lower_ty_params(&g.ty_params, &add_bounds),
-            lifetimes: self.lower_lifetime_defs(&g.lifetimes),
+            params: self.lower_generic_params(&g.params, &add_bounds),
             where_clause: self.lower_where_clause(&g.where_clause),
             span: g.span,
         }
@@ -1684,24 +1709,33 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate {
         match *pred {
-            WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes,
+            WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_generic_params,
                                                                 ref bounded_ty,
                                                                 ref bounds,
                                                                 span}) => {
-                self.with_in_scope_lifetime_defs(bound_lifetimes, |this| {
-                    hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
-                        bound_lifetimes: this.lower_lifetime_defs(bound_lifetimes),
-                        bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
-                        bounds: bounds.iter().filter_map(|bound| match *bound {
-                            // Ignore `?Trait` bounds.
-                            // Tthey were copied into type parameters already.
-                            TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
-                            _ => Some(this.lower_ty_param_bound(
-                                    bound, ImplTraitContext::Disallowed))
-                        }).collect(),
-                        span,
-                    })
-                })
+                self.with_in_scope_lifetime_defs(
+                    &bound_generic_params.iter()
+                        .filter_map(|p| match *p {
+                            GenericParam::Lifetime(ref ld) => Some(ld.clone()),
+                            _ => None,
+                        })
+                        .collect::<Vec<_>>(),
+                    |this| {
+                        hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                            bound_generic_params:
+                                this.lower_generic_params(bound_generic_params, &NodeMap()),
+                            bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
+                            bounds: bounds.iter().filter_map(|bound| match *bound {
+                                // Ignore `?Trait` bounds.
+                                // Tthey were copied into type parameters already.
+                                TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
+                                _ => Some(this.lower_ty_param_bound(
+                                        bound, ImplTraitContext::Disallowed))
+                            }).collect(),
+                            span,
+                        })
+                    }
+                )
             }
             WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime,
                                                                   ref bounds,
@@ -1761,12 +1795,19 @@ impl<'a> LoweringContext<'a> {
                             p: &PolyTraitRef,
                             itctx: ImplTraitContext)
                             -> hir::PolyTraitRef {
-        let bound_lifetimes = self.lower_lifetime_defs(&p.bound_lifetimes);
-        let trait_ref = self.with_parent_impl_lifetime_defs(&bound_lifetimes,
-                                |this| this.lower_trait_ref(&p.trait_ref, itctx));
+        let bound_generic_params = self.lower_generic_params(&p.bound_generic_params, &NodeMap());
+        let trait_ref = self.with_parent_impl_lifetime_defs(
+            &bound_generic_params.iter()
+                .filter_map(|p| match *p {
+                    hir::GenericParam::Lifetime(ref ld) => Some(ld.clone()),
+                    _ => None,
+                })
+                .collect::<Vec<_>>(),
+            |this| this.lower_trait_ref(&p.trait_ref, itctx),
+        );
 
         hir::PolyTraitRef {
-            bound_lifetimes,
+            bound_generic_params,
             trait_ref,
             span: p.span,
         }
@@ -1945,11 +1986,19 @@ impl<'a> LoweringContext<'a> {
                     });
 
                 let new_impl_items = self.with_in_scope_lifetime_defs(
-                                            &ast_generics.lifetimes, |this| {
-                    impl_items.iter()
-                              .map(|item| this.lower_impl_item_ref(item))
-                              .collect()
-                });
+                    &ast_generics.params
+                        .iter()
+                        .filter_map(|p| match *p {
+                            GenericParam::Lifetime(ref ld) => Some(ld.clone()),
+                            _ => None,
+                        })
+                        .collect::<Vec<_>>(),
+                    |this| {
+                        impl_items.iter()
+                            .map(|item| this.lower_impl_item_ref(item))
+                            .collect()
+                    }
+                );
 
 
                 hir::ItemImpl(self.lower_unsafety(unsafety),
@@ -3621,7 +3670,7 @@ impl<'a> LoweringContext<'a> {
                 // Turn trait object paths into `TyTraitObject` instead.
                 if let Def::Trait(_) = path.def {
                     let principal = hir::PolyTraitRef {
-                        bound_lifetimes: hir_vec![],
+                        bound_generic_params: hir::HirVec::new(),
                         trait_ref: hir::TraitRef {
                             path: path.and_then(|path| path),
                             ref_id: id.node_id,
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 02a1e33eeb9..e3ca6f1591e 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -326,7 +326,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_generics(&mut self, generics: &'hir Generics) {
-        for ty_param in generics.ty_params.iter() {
+        for ty_param in generics.ty_params() {
             self.insert(ty_param.id, NodeTyParam(ty_param));
         }
 
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 2978f1eb409..002849c0399 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -183,14 +183,25 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         });
     }
 
-    fn visit_generics(&mut self, generics: &'a Generics) {
-        for ty_param in generics.ty_params.iter() {
-            self.create_def(ty_param.id,
-                            DefPathData::TypeParam(ty_param.ident.name.as_str()),
-                            REGULAR_SPACE);
+    fn visit_generic_param(&mut self, param: &'a GenericParam) {
+        match *param {
+            GenericParam::Lifetime(ref lifetime_def) => {
+                self.create_def(
+                    lifetime_def.lifetime.id,
+                    DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_str()),
+                    REGULAR_SPACE
+                );
+            }
+            GenericParam::Type(ref ty_param) => {
+                self.create_def(
+                    ty_param.id,
+                    DefPathData::TypeParam(ty_param.ident.name.as_str()),
+                    REGULAR_SPACE
+                );
+            }
         }
 
-        visit::walk_generics(self, generics);
+        visit::walk_generic_param(self, param);
     }
 
     fn visit_trait_item(&mut self, ti: &'a TraitItem) {
@@ -268,12 +279,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         visit::walk_ty(self, ty);
     }
 
-    fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) {
-        self.create_def(def.lifetime.id,
-                        DefPathData::LifetimeDef(def.lifetime.ident.name.as_str()),
-                        REGULAR_SPACE);
-    }
-
     fn visit_stmt(&mut self, stmt: &'a Stmt) {
         match stmt.node {
             StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 5e132865ca8..ca2f3475fdb 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -48,6 +48,8 @@ use rustc_data_structures::indexed_vec;
 use serialize::{self, Encoder, Encodable, Decoder, Decodable};
 use std::collections::BTreeMap;
 use std::fmt;
+use std::iter;
+use std::slice;
 
 /// HIR doesn't commit to a concrete storage type and has its own alias for a vector.
 /// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar
@@ -398,12 +400,67 @@ pub struct TyParam {
     pub synthetic: Option<SyntheticTyParamKind>,
 }
 
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum GenericParam {
+    Lifetime(LifetimeDef),
+    Type(TyParam),
+}
+
+impl GenericParam {
+    pub fn is_lifetime_param(&self) -> bool {
+        match *self {
+            GenericParam::Lifetime(_) => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_type_param(&self) -> bool {
+        match *self {
+            GenericParam::Type(_) => true,
+            _ => false,
+        }
+    }
+}
+
+pub trait GenericParamsExt {
+    fn lifetimes<'a>(&'a self) -> iter::FilterMap<
+        slice::Iter<GenericParam>,
+        fn(&GenericParam) -> Option<&LifetimeDef>,
+    >;
+
+    fn ty_params<'a>(&'a self) -> iter::FilterMap<
+        slice::Iter<GenericParam>,
+        fn(&GenericParam) -> Option<&TyParam>,
+    >;
+}
+
+impl GenericParamsExt for [GenericParam] {
+    fn lifetimes<'a>(&'a self) -> iter::FilterMap<
+        slice::Iter<GenericParam>,
+        fn(&GenericParam) -> Option<&LifetimeDef>,
+    > {
+        self.iter().filter_map(|param| match *param {
+            GenericParam::Lifetime(ref l) => Some(l),
+            _ => None,
+        })
+    }
+
+    fn ty_params<'a>(&'a self) -> iter::FilterMap<
+        slice::Iter<GenericParam>,
+        fn(&GenericParam) -> Option<&TyParam>,
+    > {
+        self.iter().filter_map(|param| match *param {
+            GenericParam::Type(ref t) => Some(t),
+            _ => None,
+        })
+    }
+}
+
 /// Represents lifetimes and type parameters attached to a declaration
 /// of a function, enum, trait, etc.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Generics {
-    pub lifetimes: HirVec<LifetimeDef>,
-    pub ty_params: HirVec<TyParam>,
+    pub params: HirVec<GenericParam>,
     pub where_clause: WhereClause,
     pub span: Span,
 }
@@ -411,8 +468,7 @@ pub struct Generics {
 impl Generics {
     pub fn empty() -> Generics {
         Generics {
-            lifetimes: HirVec::new(),
-            ty_params: HirVec::new(),
+            params: HirVec::new(),
             where_clause: WhereClause {
                 id: DUMMY_NODE_ID,
                 predicates: HirVec::new(),
@@ -422,15 +478,19 @@ impl Generics {
     }
 
     pub fn is_lt_parameterized(&self) -> bool {
-        !self.lifetimes.is_empty()
+        self.params.iter().any(|param| param.is_lifetime_param())
     }
 
     pub fn is_type_parameterized(&self) -> bool {
-        !self.ty_params.is_empty()
+        self.params.iter().any(|param| param.is_type_param())
+    }
+
+    pub fn lifetimes<'a>(&'a self) -> impl Iterator<Item = &'a LifetimeDef> {
+        self.params.lifetimes()
     }
 
-    pub fn is_parameterized(&self) -> bool {
-        self.is_lt_parameterized() || self.is_type_parameterized()
+    pub fn ty_params<'a>(&'a self) -> impl Iterator<Item = &'a TyParam> {
+        self.params.ty_params()
     }
 }
 
@@ -450,17 +510,22 @@ impl UnsafeGeneric {
 
 impl Generics {
     pub fn carries_unsafe_attr(&self) -> Option<UnsafeGeneric> {
-        for r in &self.lifetimes {
-            if r.pure_wrt_drop {
-                return Some(UnsafeGeneric::Region(r.clone(), "may_dangle"));
-            }
-        }
-        for t in &self.ty_params {
-            if t.pure_wrt_drop {
-                return Some(UnsafeGeneric::Type(t.clone(), "may_dangle"));
+        for param in &self.params {
+            match *param {
+                GenericParam::Lifetime(ref l) => {
+                    if l.pure_wrt_drop {
+                        return Some(UnsafeGeneric::Region(l.clone(), "may_dangle"));
+                    }
+                }
+                GenericParam::Type(ref t) => {
+                    if t.pure_wrt_drop {
+                        return Some(UnsafeGeneric::Type(t.clone(), "may_dangle"));
+                    }
+                }
             }
         }
-        return None;
+
+        None
     }
 }
 
@@ -493,8 +558,8 @@ pub enum WherePredicate {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct WhereBoundPredicate {
     pub span: Span,
-    /// Any lifetimes from a `for` binding
-    pub bound_lifetimes: HirVec<LifetimeDef>,
+    /// Any generics from a `for` binding
+    pub bound_generic_params: HirVec<GenericParam>,
     /// The type being bounded
     pub bounded_ty: P<Ty>,
     /// Trait and lifetime bounds (`Clone+Send+'static`)
@@ -1475,7 +1540,7 @@ pub enum PrimTy {
 pub struct BareFnTy {
     pub unsafety: Unsafety,
     pub abi: Abi,
-    pub lifetimes: HirVec<LifetimeDef>,
+    pub generic_params: HirVec<GenericParam>,
     pub decl: P<FnDecl>,
     pub arg_names: HirVec<Spanned<Name>>,
 }
@@ -1733,7 +1798,7 @@ pub struct TraitRef {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct PolyTraitRef {
     /// The `'a` in `<'a> Foo<&'a T>`
-    pub bound_lifetimes: HirVec<LifetimeDef>,
+    pub bound_generic_params: HirVec<GenericParam>,
 
     /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
     pub trait_ref: TraitRef,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 77469cb450b..2f9fc70252f 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -390,16 +390,7 @@ impl<'a> State<'a> {
                 self.pclose()?;
             }
             hir::TyBareFn(ref f) => {
-                let generics = hir::Generics {
-                    lifetimes: f.lifetimes.clone(),
-                    ty_params: hir::HirVec::new(),
-                    where_clause: hir::WhereClause {
-                        id: ast::DUMMY_NODE_ID,
-                        predicates: hir::HirVec::new(),
-                    },
-                    span: syntax_pos::DUMMY_SP,
-                };
-                self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics,
+                self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params,
                                  &f.arg_names[..])?;
             }
             hir::TyPath(ref qpath) => {
@@ -635,15 +626,15 @@ impl<'a> State<'a> {
                 self.s.word(&ga.asm.as_str())?;
                 self.end()?
             }
-            hir::ItemTy(ref ty, ref params) => {
+            hir::ItemTy(ref ty, ref generics) => {
                 self.ibox(indent_unit)?;
                 self.ibox(0)?;
                 self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
                 self.print_name(item.name)?;
-                self.print_generics(params)?;
+                self.print_generic_params(&generics.params)?;
                 self.end()?; // end the inner ibox
 
-                self.print_where_clause(&params.where_clause)?;
+                self.print_where_clause(&generics.where_clause)?;
                 self.s.space()?;
                 self.word_space("=")?;
                 self.print_type(&ty)?;
@@ -686,8 +677,8 @@ impl<'a> State<'a> {
                 self.print_unsafety(unsafety)?;
                 self.word_nbsp("impl")?;
 
-                if generics.is_parameterized() {
-                    self.print_generics(generics)?;
+                if !generics.params.is_empty() {
+                    self.print_generic_params(&generics.params)?;
                     self.s.space()?;
                 }
 
@@ -725,7 +716,7 @@ impl<'a> State<'a> {
                 self.print_unsafety(unsafety)?;
                 self.word_nbsp("trait")?;
                 self.print_name(item.name)?;
-                self.print_generics(generics)?;
+                self.print_generic_params(&generics.params)?;
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 for b in bounds.iter() {
                     if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
@@ -750,7 +741,7 @@ impl<'a> State<'a> {
                 self.print_visibility(&item.vis)?;
                 self.word_nbsp("trait")?;
                 self.print_name(item.name)?;
-                self.print_generics(generics)?;
+                self.print_generic_params(&generics.params)?;
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 // FIXME(durka) this seems to be some quite outdated syntax
                 for b in bounds.iter() {
@@ -775,25 +766,20 @@ impl<'a> State<'a> {
         self.print_path(&t.path, false)
     }
 
-    fn print_formal_lifetime_list(&mut self, lifetimes: &[hir::LifetimeDef]) -> io::Result<()> {
-        if !lifetimes.is_empty() {
-            self.s.word("for<")?;
-            let mut comma = false;
-            for lifetime_def in lifetimes {
-                if comma {
-                    self.word_space(",")?
-                }
-                self.print_lifetime_def(lifetime_def)?;
-                comma = true;
-            }
-            self.s.word(">")?;
+    fn print_formal_generic_params(
+        &mut self,
+        generic_params: &[hir::GenericParam]
+    ) -> io::Result<()> {
+        if !generic_params.is_empty() {
+            self.s.word("for")?;
+            self.print_generic_params(generic_params)?;
             self.nbsp()?;
         }
         Ok(())
     }
 
     fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef) -> io::Result<()> {
-        self.print_formal_lifetime_list(&t.bound_lifetimes)?;
+        self.print_formal_generic_params(&t.bound_generic_params)?;
         self.print_trait_ref(&t.trait_ref)
     }
 
@@ -806,7 +792,7 @@ impl<'a> State<'a> {
                           -> io::Result<()> {
         self.head(&visibility_qualified(visibility, "enum"))?;
         self.print_name(name)?;
-        self.print_generics(generics)?;
+        self.print_generic_params(&generics.params)?;
         self.print_where_clause(&generics.where_clause)?;
         self.s.space()?;
         self.print_variants(&enum_definition.variants, span)
@@ -859,7 +845,7 @@ impl<'a> State<'a> {
                         print_finalizer: bool)
                         -> io::Result<()> {
         self.print_name(name)?;
-        self.print_generics(generics)?;
+        self.print_generic_params(&generics.params)?;
         if !struct_def.is_struct() {
             if struct_def.is_tuple() {
                 self.popen()?;
@@ -1941,7 +1927,7 @@ impl<'a> State<'a> {
             self.nbsp()?;
             self.print_name(name)?;
         }
-        self.print_generics(generics)?;
+        self.print_generic_params(&generics.params)?;
 
         self.popen()?;
         let mut i = 0;
@@ -2056,31 +2042,19 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_generics(&mut self, generics: &hir::Generics) -> io::Result<()> {
-        let total = generics.lifetimes.len() + generics.ty_params.len();
-        if total == 0 {
-            return Ok(());
-        }
+    pub fn print_generic_params(&mut self, generic_params: &[hir::GenericParam]) -> io::Result<()> {
+        if !generic_params.is_empty() {
+            self.s.word("<")?;
 
-        self.s.word("<")?;
+            self.commasep(Inconsistent, generic_params, |s, param| {
+                match *param {
+                    hir::GenericParam::Lifetime(ref ld) => s.print_lifetime_def(ld),
+                    hir::GenericParam::Type(ref tp) => s.print_ty_param(tp),
+                }
+            })?;
 
-        let mut ints = Vec::new();
-        for i in 0..total {
-            ints.push(i);
+            self.s.word(">")?;
         }
-
-        self.commasep(Inconsistent, &ints[..], |s, &idx| {
-            if idx < generics.lifetimes.len() {
-                let lifetime = &generics.lifetimes[idx];
-                s.print_lifetime_def(lifetime)
-            } else {
-                let idx = idx - generics.lifetimes.len();
-                let param = &generics.ty_params[idx];
-                s.print_ty_param(param)
-            }
-        })?;
-
-        self.s.word(">")?;
         Ok(())
     }
 
@@ -2111,11 +2085,13 @@ impl<'a> State<'a> {
             }
 
             match predicate {
-                &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bound_lifetimes,
-                                                                              ref bounded_ty,
-                                                                              ref bounds,
-                                                                              ..}) => {
-                    self.print_formal_lifetime_list(bound_lifetimes)?;
+                &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                    ref bound_generic_params,
+                    ref bounded_ty,
+                    ref bounds,
+                    ..
+                }) => {
+                    self.print_formal_generic_params(bound_generic_params)?;
                     self.print_type(&bounded_ty)?;
                     self.print_bounds(":", bounds)?;
                 }
@@ -2184,17 +2160,16 @@ impl<'a> State<'a> {
                        unsafety: hir::Unsafety,
                        decl: &hir::FnDecl,
                        name: Option<ast::Name>,
-                       generics: &hir::Generics,
+                       generic_params: &[hir::GenericParam],
                        arg_names: &[Spanned<ast::Name>])
                        -> io::Result<()> {
         self.ibox(indent_unit)?;
-        if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
+        if !generic_params.is_empty() {
             self.s.word("for")?;
-            self.print_generics(generics)?;
+            self.print_generic_params(generic_params)?;
         }
         let generics = hir::Generics {
-            lifetimes: hir::HirVec::new(),
-            ty_params: hir::HirVec::new(),
+            params: hir::HirVec::new(),
             where_clause: hir::WhereClause {
                 id: ast::DUMMY_NODE_ID,
                 predicates: hir::HirVec::new(),
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 02a394f9634..bddbdec2c34 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -200,9 +200,13 @@ impl_stable_hash_for!(struct hir::TyParam {
     synthetic
 });
 
+impl_stable_hash_for!(enum hir::GenericParam {
+    Lifetime(lifetime_def),
+    Type(ty_param)
+});
+
 impl_stable_hash_for!(struct hir::Generics {
-    lifetimes,
-    ty_params,
+    params,
     where_clause,
     span
 });
@@ -224,7 +228,7 @@ impl_stable_hash_for!(enum hir::WherePredicate {
 
 impl_stable_hash_for!(struct hir::WhereBoundPredicate {
     span,
-    bound_lifetimes,
+    bound_generic_params,
     bounded_ty,
     bounds
 });
@@ -291,7 +295,7 @@ impl_stable_hash_for!(enum hir::PrimTy {
 impl_stable_hash_for!(struct hir::BareFnTy {
     unsafety,
     abi,
-    lifetimes,
+    generic_params,
     decl,
     arg_names
 });
@@ -345,7 +349,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitRef {
 
 
 impl_stable_hash_for!(struct hir::PolyTraitRef {
-    bound_lifetimes,
+    bound_generic_params,
     trait_ref,
     span
 });
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 75cd230e1e5..32ab458cb91 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -783,6 +783,11 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         hir_visit::walk_decl(self, d);
     }
 
+    fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
+        run_lints!(self, check_generic_param, late_passes, p);
+        hir_visit::walk_generic_param(self, p);
+    }
+
     fn visit_generics(&mut self, g: &'tcx hir::Generics) {
         run_lints!(self, check_generics, late_passes, g);
         hir_visit::walk_generics(self, g);
@@ -819,11 +824,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         hir_visit::walk_lifetime(self, lt);
     }
 
-    fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
-        run_lints!(self, check_lifetime_def, late_passes, lt);
-        hir_visit::walk_lifetime_def(self, lt);
-    }
-
     fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
         run_lints!(self, check_path, late_passes, p, id);
         hir_visit::walk_path(self, p);
@@ -945,6 +945,11 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
         run_lints!(self, check_expr_post, early_passes, e);
     }
 
+    fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
+        run_lints!(self, check_generic_param, early_passes, param);
+        ast_visit::walk_generic_param(self, param);
+    }
+
     fn visit_generics(&mut self, g: &'a ast::Generics) {
         run_lints!(self, check_generics, early_passes, g);
         ast_visit::walk_generics(self, g);
@@ -971,10 +976,6 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
         self.check_id(lt.id);
     }
 
-    fn visit_lifetime_def(&mut self, lt: &'a ast::LifetimeDef) {
-        run_lints!(self, check_lifetime_def, early_passes, lt);
-    }
-
     fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
         run_lints!(self, check_path, early_passes, p, id);
         self.check_id(id);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index f0761ce6178..f4abc54ad2e 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -155,6 +155,7 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
     fn check_expr(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { }
     fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { }
     fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { }
+    fn check_generic_param(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::GenericParam) { }
     fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { }
     fn check_fn(&mut self,
                 _: &LateContext<'a, 'tcx>,
@@ -196,7 +197,6 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
                           _: &'tcx hir::Variant,
                           _: &'tcx hir::Generics) { }
     fn check_lifetime(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Lifetime) { }
-    fn check_lifetime_def(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::LifetimeDef) { }
     fn check_path(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Path, _: ast::NodeId) { }
     fn check_attribute(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx ast::Attribute) { }
 
@@ -227,6 +227,7 @@ pub trait EarlyLintPass: LintPass {
     fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { }
     fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { }
     fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
+    fn check_generic_param(&mut self, _: &EarlyContext, _: &ast::GenericParam) { }
     fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
     fn check_fn(&mut self, _: &EarlyContext,
         _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
@@ -244,7 +245,6 @@ pub trait EarlyLintPass: LintPass {
     fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
     fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
     fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { }
-    fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { }
     fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { }
     fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { }
 
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 27f12c2c158..6f457c9d1e1 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -37,7 +37,7 @@ use hir::intravisit;
 // Returns true if the given set of generics implies that the item it's
 // associated with must be inlined.
 fn generics_require_inlining(generics: &hir::Generics) -> bool {
-    !generics.ty_params.is_empty()
+    generics.params.iter().any(|param| param.is_type_param())
 }
 
 // Returns true if the given item must be inlined because it may be
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index e976f08607a..8b302dbe67a 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -33,7 +33,7 @@ use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
 use std::slice;
 use rustc::lint;
 
-use hir;
+use hir::{self, GenericParamsExt};
 use hir::intravisit::{self, NestedVisitorMap, Visitor};
 
 /// The origin of a named lifetime definition.
@@ -491,19 +491,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 } else {
                     0
                 };
-                let lifetimes = generics
-                    .lifetimes
-                    .iter()
+                let lifetimes = generics.lifetimes()
                     .map(|def| Region::early(&self.tcx.hir, &mut index, def))
                     .collect();
-                let next_early_index = index + generics.ty_params.len() as u32;
+                let next_early_index = index + generics.ty_params().count() as u32;
                 let scope = Scope::Binder {
                     lifetimes,
                     next_early_index,
                     s: ROOT_SCOPE,
                 };
                 self.with(scope, |old_scope, this| {
-                    this.check_lifetime_defs(old_scope, &generics.lifetimes);
+                    this.check_lifetime_params(old_scope, &generics.params);
                     intravisit::walk_item(this, item);
                 });
             }
@@ -537,8 +535,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let was_in_fn_syntax = self.is_in_fn_syntax;
                 self.is_in_fn_syntax = true;
                 let scope = Scope::Binder {
-                    lifetimes: c.lifetimes
-                        .iter()
+                    lifetimes: c.generic_params
+                        .lifetimes()
                         .map(|def| Region::late(&self.tcx.hir, def))
                         .collect(),
                     s: self.scope,
@@ -547,7 +545,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 self.with(scope, |old_scope, this| {
                     // a bare fn has no bounds, so everything
                     // contained within is scoped within its binder.
-                    this.check_lifetime_defs(old_scope, &c.lifetimes);
+                    this.check_lifetime_params(old_scope, &c.generic_params);
                     intravisit::walk_ty(this, ty);
                 });
                 self.is_in_fn_syntax = was_in_fn_syntax;
@@ -621,7 +619,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
                 let mut elision = None;
                 let mut lifetimes = FxHashMap();
-                for lt_def in &generics.lifetimes {
+                for lt_def in generics.lifetimes() {
                     let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, &lt_def);
                     if let hir::LifetimeName::Underscore = lt_name {
                         // Pick the elided lifetime "definition" if one exists and use it to make an
@@ -632,7 +630,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                 }
 
-                let next_early_index = index + generics.ty_params.len() as u32;
+                let next_early_index = index + generics.ty_params().count() as u32;
 
                 if let Some(elision_region) = elision {
                     let scope = Scope::Elision {
@@ -678,11 +676,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let generics = &trait_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics.lifetimes.iter()
+                let lifetimes = generics.lifetimes()
                     .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
                     .collect();
 
-                let next_early_index = index + generics.ty_params.len() as u32;
+                let next_early_index = index + generics.ty_params().count() as u32;
                 let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
                 self.with(scope, |_old_scope, this| {
                     this.visit_generics(generics);
@@ -696,7 +694,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             },
             Const(_, _) => {
                 // Only methods and types support generics.
-                assert!(!trait_item.generics.is_parameterized());
+                assert!(trait_item.generics.params.is_empty());
                 intravisit::walk_trait_item(self, trait_item);
             },
         }
@@ -718,11 +716,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let generics = &impl_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics.lifetimes.iter()
+                let lifetimes = generics.lifetimes()
                     .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
                     .collect();
 
-                let next_early_index = index + generics.ty_params.len() as u32;
+                let next_early_index = index + generics.ty_params().count() as u32;
                 let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
                 self.with(scope, |_old_scope, this| {
                     this.visit_generics(generics);
@@ -731,7 +729,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             },
             Const(_, _) => {
                 // Only methods and types support generics.
-                assert!(!impl_item.generics.is_parameterized());
+                assert!(impl_item.generics.params.is_empty());
                 intravisit::walk_impl_item(self, impl_item);
             },
         }
@@ -767,8 +765,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
-        check_mixed_explicit_and_in_band_defs(self.tcx, &generics.lifetimes);
-        for ty_param in generics.ty_params.iter() {
+        check_mixed_explicit_and_in_band_defs(
+            self.tcx,
+            &generics.lifetimes().cloned().collect::<Vec<_>>()
+        );
+        for ty_param in generics.ty_params() {
             walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
             if let Some(ref ty) = ty_param.default {
                 self.visit_ty(&ty);
@@ -779,22 +780,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                     ref bounded_ty,
                     ref bounds,
-                    ref bound_lifetimes,
+                    ref bound_generic_params,
                     ..
                 }) => {
-                    if !bound_lifetimes.is_empty() {
+                    if bound_generic_params.iter().any(|p| p.is_lifetime_param()) {
                         self.trait_ref_hack = true;
                         let next_early_index = self.next_early_index();
                         let scope = Scope::Binder {
-                            lifetimes: bound_lifetimes
-                                .iter()
+                            lifetimes: bound_generic_params.lifetimes()
                                 .map(|def| Region::late(&self.tcx.hir, def))
                                 .collect(),
                             s: self.scope,
                             next_early_index,
                         };
                         let result = self.with(scope, |old_scope, this| {
-                            this.check_lifetime_defs(old_scope, bound_lifetimes);
+                            this.check_lifetime_params(old_scope, &bound_generic_params);
                             this.visit_ty(&bounded_ty);
                             walk_list!(this, visit_ty_param_bound, bounds);
                         });
@@ -834,7 +834,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     ) {
         debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
 
-        if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() {
+        if !self.trait_ref_hack ||
+            trait_ref.bound_generic_params.iter().any(|p| p.is_lifetime_param())
+        {
             if self.trait_ref_hack {
                 span_err!(
                     self.tcx.sess,
@@ -845,19 +847,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             }
             let next_early_index = self.next_early_index();
             let scope = Scope::Binder {
-                lifetimes: trait_ref
-                    .bound_lifetimes
-                    .iter()
+                lifetimes: trait_ref.bound_generic_params
+                    .lifetimes()
                     .map(|def| Region::late(&self.tcx.hir, def))
                     .collect(),
                 s: self.scope,
                 next_early_index,
             };
             self.with(scope, |old_scope, this| {
-                this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
-                for lifetime in &trait_ref.bound_lifetimes {
-                    this.visit_lifetime_def(lifetime);
-                }
+                this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
+                walk_list!(this, visit_generic_param, &trait_ref.bound_generic_params);
                 this.visit_trait_ref(&trait_ref.trait_ref)
             })
         } else {
@@ -1087,8 +1086,9 @@ fn compute_object_lifetime_defaults(
                         .map(|set| match *set {
                             Set1::Empty => "BaseDefault".to_string(),
                             Set1::One(Region::Static) => "'static".to_string(),
-                            Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes
-                                [i as usize]
+                            Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes()
+                                .nth(i as usize)
+                                .unwrap()
                                 .lifetime
                                 .name
                                 .name()
@@ -1124,9 +1124,7 @@ fn object_lifetime_defaults_for_item(
         }
     }
 
-    generics
-        .ty_params
-        .iter()
+    generics.ty_params()
         .map(|param| {
             let mut set = Set1::Empty;
 
@@ -1142,7 +1140,7 @@ fn object_lifetime_defaults_for_item(
 
                 // Ignore `for<'a> type: ...` as they can change what
                 // lifetimes mean (although we could "just" handle it).
-                if !data.bound_lifetimes.is_empty() {
+                if !data.bound_generic_params.is_empty() {
                     continue;
                 }
 
@@ -1163,8 +1161,7 @@ fn object_lifetime_defaults_for_item(
                         Set1::One(Region::Static)
                     } else {
                         generics
-                            .lifetimes
-                            .iter()
+                            .lifetimes()
                             .enumerate()
                             .find(|&(_, def)| def.lifetime.name == name)
                             .map_or(Set1::Many, |(i, def)| {
@@ -1283,15 +1280,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             match parent.node {
                 hir::ItemTrait(_, _, ref generics, ..)
                 | hir::ItemImpl(_, _, _, ref generics, ..) => {
-                    index += (generics.lifetimes.len() + generics.ty_params.len()) as u32;
+                    index += generics.params.len() as u32;
                 }
                 _ => {}
             }
         }
 
         let lifetimes = generics
-            .lifetimes
-            .iter()
+            .lifetimes()
             .map(|def| {
                 if self.map.late_bound.contains(&def.lifetime.id) {
                     Region::late(&self.tcx.hir, def)
@@ -1301,7 +1297,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             })
             .collect();
 
-        let next_early_index = index + generics.ty_params.len() as u32;
+        let next_early_index = index + generics.ty_params().count() as u32;
 
         let scope = Scope::Binder {
             lifetimes,
@@ -1309,7 +1305,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             s: self.scope,
         };
         self.with(scope, move |old_scope, this| {
-            this.check_lifetime_defs(old_scope, &generics.lifetimes);
+            this.check_lifetime_params(old_scope, &generics.params);
             this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
         });
     }
@@ -1769,6 +1765,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 }
             }
 
+            fn visit_generic_param(&mut self, param: &hir::GenericParam) {
+                if let hir::GenericParam::Lifetime(ref lifetime_def) = *param {
+                    for l in &lifetime_def.bounds {
+                        self.visit_lifetime(l);
+                    }
+                }
+
+                intravisit::walk_generic_param(self, param);
+            }
+
             fn visit_poly_trait_ref(
                 &mut self,
                 trait_ref: &hir::PolyTraitRef,
@@ -1779,12 +1785,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 self.binder_depth -= 1;
             }
 
-            fn visit_lifetime_def(&mut self, lifetime_def: &hir::LifetimeDef) {
-                for l in &lifetime_def.bounds {
-                    self.visit_lifetime(l);
-                }
-            }
-
             fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
                 if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) {
                     match lifetime {
@@ -1980,11 +1980,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
     }
 
-    fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &'tcx [hir::LifetimeDef]) {
-        for i in 0..lifetimes.len() {
-            let lifetime_i = &lifetimes[i];
-
-            for lifetime in lifetimes {
+    fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::GenericParam]) {
+        for (i, lifetime_i) in params.lifetimes().enumerate() {
+            for lifetime in params.lifetimes() {
                 match lifetime.lifetime.name {
                     hir::LifetimeName::Static | hir::LifetimeName::Underscore => {
                         let lifetime = lifetime.lifetime;
@@ -2007,9 +2005,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
 
             // It is a hard error to shadow a lifetime within the same scope.
-            for j in i + 1..lifetimes.len() {
-                let lifetime_j = &lifetimes[j];
-
+            for lifetime_j in params.lifetimes().skip(i + 1) {
                 if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
                     struct_span_err!(
                         self.tcx.sess,
@@ -2200,24 +2196,30 @@ fn insert_late_bound_lifetimes(
     let mut appears_in_where_clause = AllCollector {
         regions: FxHashSet(),
     };
-    for ty_param in generics.ty_params.iter() {
-        walk_list!(
-            &mut appears_in_where_clause,
-            visit_ty_param_bound,
-            &ty_param.bounds
-        );
+
+    for param in &generics.params {
+        match *param {
+            hir::GenericParam::Lifetime(ref lifetime_def) => {
+                if !lifetime_def.bounds.is_empty() {
+                    // `'a: 'b` means both `'a` and `'b` are referenced
+                    appears_in_where_clause.visit_generic_param(param);
+                }
+            }
+            hir::GenericParam::Type(ref ty_param) => {
+                walk_list!(
+                    &mut appears_in_where_clause,
+                    visit_ty_param_bound,
+                    &ty_param.bounds
+                );
+            }
+        }
     }
+
     walk_list!(
         &mut appears_in_where_clause,
         visit_where_predicate,
         &generics.where_clause.predicates
     );
-    for lifetime_def in &generics.lifetimes {
-        if !lifetime_def.bounds.is_empty() {
-            // `'a: 'b` means both `'a` and `'b` are referenced
-            appears_in_where_clause.visit_lifetime_def(lifetime_def);
-        }
-    }
 
     debug!(
         "insert_late_bound_lifetimes: appears_in_where_clause={:?}",
@@ -2228,7 +2230,7 @@ fn insert_late_bound_lifetimes(
     // - appear in the inputs
     // - do not appear in the where-clauses
     // - are not implicitly captured by `impl Trait`
-    for lifetime in &generics.lifetimes {
+    for lifetime in generics.lifetimes() {
         let name = lifetime.lifetime.name;
 
         // appears in the where clauses? early-bound.