about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2018-05-26 00:27:54 +0100
committervarkor <github@varkor.com>2018-06-20 12:21:07 +0100
commit82dba3d419d3cfac00cc90bc8d078e6ae0a724f5 (patch)
treea9957cd9109080725a5ffd4e8615901ed16443b8
parentd643946550fa349729184a4f70abc01e21ceddc0 (diff)
downloadrust-82dba3d419d3cfac00cc90bc8d078e6ae0a724f5.tar.gz
rust-82dba3d419d3cfac00cc90bc8d078e6ae0a724f5.zip
Refactor hir::GenericParam as a struct
-rw-r--r--src/librustc/hir/intravisit.rs25
-rw-r--r--src/librustc/hir/lowering.rs211
-rw-r--r--src/librustc/hir/map/collector.rs12
-rw-r--r--src/librustc/hir/map/mod.rs69
-rw-r--r--src/librustc/hir/mod.rs197
-rw-r--r--src/librustc/hir/print.rs59
-rw-r--r--src/librustc/ich/impls_hir.rs42
-rw-r--r--src/librustc/infer/error_reporting/mod.rs12
-rw-r--r--src/librustc/middle/resolve_lifetime.rs295
-rw-r--r--src/librustc_lint/bad_style.rs23
-rw-r--r--src/librustc_lint/builtin.rs12
-rw-r--r--src/librustc_metadata/encoder.rs15
-rw-r--r--src/librustc_privacy/lib.rs13
-rw-r--r--src/librustc_typeck/check/compare_method.rs18
-rw-r--r--src/librustc_typeck/check/mod.rs5
-rw-r--r--src/librustc_typeck/check/wfcheck.rs7
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs14
-rw-r--r--src/librustc_typeck/collect.rs155
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustdoc/clean/mod.rs71
-rw-r--r--src/libsyntax/visit.rs4
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs3
-rw-r--r--src/libsyntax_ext/deriving/generic/ty.rs7
23 files changed, 704 insertions, 566 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index fef33939fac..4c24c7afd73 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -743,26 +743,25 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyPar
 }
 
 pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam) {
-    match *param {
-        GenericParam::Lifetime(ref ld) => {
-            visitor.visit_id(ld.lifetime.id);
-            match ld.lifetime.name {
+    visitor.visit_id(param.id);
+    match param.kind {
+        GenericParamKind::Lifetime { ref bounds, ref lifetime_deprecated, .. } => {
+            match lifetime_deprecated.name {
                 LifetimeName::Name(name) => {
-                    visitor.visit_name(ld.lifetime.span, name);
+                    visitor.visit_name(param.span, name);
                 }
                 LifetimeName::Fresh(_) |
                 LifetimeName::Static |
                 LifetimeName::Implicit |
                 LifetimeName::Underscore => {}
             }
-            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_attribute, ty_param.attrs.iter());
+            walk_list!(visitor, visit_lifetime, bounds);
+        }
+        GenericParamKind::Type { name, ref bounds, ref default, ref attrs, .. } => {
+            visitor.visit_name(param.span, name);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_ty, default);
+            walk_list!(visitor, visit_attribute, attrs.iter());
         }
     }
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 4660352b28b..0c5c79e8e60 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -116,7 +116,7 @@ pub struct LoweringContext<'a> {
     // When traversing a signature such as `fn foo(x: impl Trait)`,
     // we record `impl Trait` as a new type parameter, then later
     // add it on to `foo`s generics.
-    in_band_ty_params: Vec<hir::TyParam>,
+    in_band_ty_params: Vec<hir::GenericParam>,
 
     // Used to create lifetime definitions from in-band lifetime usages.
     // e.g. `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8`
@@ -695,22 +695,23 @@ impl<'a> LoweringContext<'a> {
                     span,
                 );
 
-                hir::GenericParam::Lifetime(hir::LifetimeDef {
-                    lifetime: hir::Lifetime {
-                        id: def_node_id,
-                        span,
-                        name: hir_name,
-                    },
-                    bounds: Vec::new().into(),
+                hir::GenericParam {
+                    id: def_node_id,
+                    span,
                     pure_wrt_drop: false,
-                    in_band: true,
-                })
+                    kind: hir::GenericParamKind::Lifetime {
+                        name: hir_name,
+                        bounds: vec![].into(),
+                        in_band: true,
+                        lifetime_deprecated: hir::Lifetime {
+                            id: def_node_id,
+                            span,
+                            name: hir_name,
+                        }
+                    }
+                }
             })
-            .chain(
-                in_band_ty_params
-                    .into_iter()
-                    .map(|tp| hir::GenericParam::Type(tp)),
-            )
+            .chain(in_band_ty_params.into_iter())
             .collect();
 
         (params, res)
@@ -778,12 +779,12 @@ impl<'a> LoweringContext<'a> {
     // This should only be used with generics that have already had their
     // in-band lifetimes added. In practice, this means that this function is
     // only used when lowering a child item of a trait or impl.
-    fn with_parent_impl_lifetime_defs<T, F>(&mut self, lt_defs: &[hir::LifetimeDef], f: F) -> T
+    fn with_parent_impl_lifetime_defs<T, F>(&mut self, params: &[hir::GenericParam], f: F) -> T
     where
         F: FnOnce(&mut LoweringContext) -> T,
     {
         let old_len = self.in_scope_lifetimes.len();
-        let lt_def_names = lt_defs.iter().map(|lt_def| lt_def.lifetime.name.name());
+        let lt_def_names = params.iter().map(|param| param.name());
         self.in_scope_lifetimes.extend(lt_def_names);
 
         let res = f(self);
@@ -1252,15 +1253,17 @@ impl<'a> LoweringContext<'a> {
                         let hir_bounds = self.lower_bounds(bounds, itctx);
                         // Set the name to `impl Bound1 + Bound2`
                         let name = Symbol::intern(&pprust::ty_to_string(t));
-                        self.in_band_ty_params.push(hir::TyParam {
-                            name,
+                        self.in_band_ty_params.push(hir::GenericParam {
                             id: def_node_id,
-                            bounds: hir_bounds,
-                            default: None,
                             span,
                             pure_wrt_drop: false,
-                            synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
-                            attrs: P::new(),
+                            kind: hir::GenericParamKind::Type {
+                                name,
+                                bounds: hir_bounds,
+                                default: None,
+                                synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+                                attrs: P::new(),
+                            }
                         });
 
                         hir::TyPath(hir::QPath::Resolved(
@@ -1367,10 +1370,10 @@ impl<'a> LoweringContext<'a> {
 
             fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
                 // Record the introduction of 'a in `for<'a> ...`
-                if let hir::GenericParam::Lifetime(ref lt_def) = *param {
+                if let hir::GenericParamKind::Lifetime { name, .. } = param.kind {
                     // 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);
+                    self.currently_bound_lifetimes.push(name);
                 }
 
                 hir::intravisit::walk_generic_param(self, param);
@@ -1416,18 +1419,22 @@ impl<'a> LoweringContext<'a> {
                         Mark::root(),
                         lifetime.span,
                     );
-                    let def_lifetime = hir::Lifetime {
+
+                    self.output_lifetime_params.push(hir::GenericParam {
                         id: def_node_id,
                         span: lifetime.span,
-                        name,
-                    };
-                    self.output_lifetime_params
-                        .push(hir::GenericParam::Lifetime(hir::LifetimeDef {
-                            lifetime: def_lifetime,
-                            bounds: Vec::new().into(),
-                            pure_wrt_drop: false,
+                        pure_wrt_drop: false,
+                        kind: hir::GenericParamKind::Lifetime {
+                            name,
+                            bounds: vec![].into(),
                             in_band: false,
-                        }));
+                            lifetime_deprecated: hir::Lifetime {
+                                id: def_node_id,
+                                span: lifetime.span,
+                                name,
+                            }
+                        }
+                    });
                 }
             }
         }
@@ -1887,47 +1894,6 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_ty_param(
-        &mut self,
-        tp: &TyParam,
-        add_bounds: &[TyParamBound],
-        itctx: ImplTraitContext,
-    ) -> hir::TyParam {
-        let mut name = self.lower_ident(tp.ident);
-
-        // Don't expose `Self` (recovered "keyword used as ident" parse error).
-        // `rustc::ty` expects `Self` to be only used for a trait's `Self`.
-        // Instead, use gensym("Self") to create a distinct name that looks the same.
-        if name == keywords::SelfType.name() {
-            name = Symbol::gensym("Self");
-        }
-
-        let mut bounds = self.lower_bounds(&tp.bounds, itctx);
-        if !add_bounds.is_empty() {
-            bounds = bounds
-                .into_iter()
-                .chain(self.lower_bounds(add_bounds, itctx).into_iter())
-                .collect();
-        }
-
-        hir::TyParam {
-            id: self.lower_node_id(tp.id).node_id,
-            name,
-            bounds,
-            default: tp.default
-                .as_ref()
-                .map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
-            span: tp.ident.span,
-            pure_wrt_drop: attr::contains_name(&tp.attrs, "may_dangle"),
-            synthetic: tp.attrs
-                .iter()
-                .filter(|attr| attr.check_name("rustc_synthetic"))
-                .map(|_| hir::SyntheticTyParamKind::ImplTrait)
-                .nth(0),
-            attrs: self.lower_attrs(&tp.attrs),
-        }
-    }
-
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         let span = l.ident.span;
         match self.lower_ident(l.ident) {
@@ -1962,20 +1928,75 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_lifetime_def(&mut self, l: &LifetimeDef) -> hir::LifetimeDef {
-        let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
-        self.is_collecting_in_band_lifetimes = false;
+    fn lower_generic_param(&mut self,
+                           param: &GenericParamAST,
+                           add_bounds: &NodeMap<Vec<TyParamBound>>,
+                           itctx: ImplTraitContext)
+                           -> hir::GenericParam {
+        match param {
+            GenericParamAST::Lifetime(ref lifetime_def) => {
+                let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
+                self.is_collecting_in_band_lifetimes = false;
+
+                let lifetime = self.lower_lifetime(&lifetime_def.lifetime);
+                let param = hir::GenericParam {
+                    id: lifetime.id,
+                    span: lifetime.span,
+                    pure_wrt_drop: attr::contains_name(&lifetime_def.attrs, "may_dangle"),
+                    kind: hir::GenericParamKind::Lifetime {
+                        name: lifetime.name,
+                        bounds: lifetime_def.bounds
+                                            .iter()
+                                            .map(|lt| self.lower_lifetime(lt)).collect(),
+                        in_band: false,
+                        lifetime_deprecated: lifetime,
+                    }
+                };
 
-        let def = hir::LifetimeDef {
-            lifetime: self.lower_lifetime(&l.lifetime),
-            bounds: l.bounds.iter().map(|l| self.lower_lifetime(l)).collect(),
-            pure_wrt_drop: attr::contains_name(&l.attrs, "may_dangle"),
-            in_band: false,
-        };
+                self.is_collecting_in_band_lifetimes = was_collecting_in_band;
 
-        self.is_collecting_in_band_lifetimes = was_collecting_in_band;
+                param
+            }
+            GenericParamAST::Type(ref ty_param) => {
+                let mut name = self.lower_ident(ty_param.ident);
+
+                // Don't expose `Self` (recovered "keyword used as ident" parse error).
+                // `rustc::ty` expects `Self` to be only used for a trait's `Self`.
+                // Instead, use gensym("Self") to create a distinct name that looks the same.
+                if name == keywords::SelfType.name() {
+                    name = Symbol::gensym("Self");
+                }
+
+                let mut bounds = self.lower_bounds(&ty_param.bounds, itctx);
+                let add_bounds = add_bounds.get(&ty_param.id).map_or(&[][..], |x| &x);
+                if !add_bounds.is_empty() {
+                    bounds = bounds
+                        .into_iter()
+                        .chain(self.lower_bounds(add_bounds, itctx).into_iter())
+                        .collect();
+                }
 
-        def
+                hir::GenericParam {
+                    id: self.lower_node_id(ty_param.id).node_id,
+                    span: ty_param.ident.span,
+                    pure_wrt_drop: attr::contains_name(&ty_param.attrs, "may_dangle"),
+                    kind: hir::GenericParamKind::Type {
+                        name,
+                        bounds,
+                        default: ty_param.default.as_ref()
+                                         .map(|x| {
+                                             self.lower_ty(x, ImplTraitContext::Disallowed)
+                                         }),
+                        synthetic: ty_param.attrs
+                                           .iter()
+                                           .filter(|attr| attr.check_name("rustc_synthetic"))
+                                           .map(|_| hir::SyntheticTyParamKind::ImplTrait)
+                                           .nth(0),
+                        attrs: self.lower_attrs(&ty_param.attrs),
+                    }
+                }
+            }
+        }
     }
 
     fn lower_generic_params(
@@ -1984,19 +2005,7 @@ impl<'a> LoweringContext<'a> {
         add_bounds: &NodeMap<Vec<TyParamBound>>,
         itctx: ImplTraitContext,
     ) -> hir::HirVec<hir::GenericParam> {
-        params
-            .iter()
-            .map(|param| match *param {
-                GenericParamAST::Lifetime(ref lifetime_def) => {
-                    hir::GenericParam::Lifetime(self.lower_lifetime_def(lifetime_def))
-                }
-                GenericParamAST::Type(ref ty_param) => hir::GenericParam::Type(self.lower_ty_param(
-                    ty_param,
-                    add_bounds.get(&ty_param.id).map_or(&[][..], |x| &x),
-                    itctx,
-                )),
-            })
-            .collect()
+        params.iter().map(|param| self.lower_generic_param(param, add_bounds, itctx)).collect()
     }
 
     fn lower_generics(&mut self, g: &Generics, itctx: ImplTraitContext) -> hir::Generics {
@@ -2175,8 +2184,8 @@ impl<'a> LoweringContext<'a> {
         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()),
+                .filter_map(|param| match param.kind {
+                    hir::GenericParamKind::Lifetime { .. } => Some(param.clone()),
                     _ => None,
                 })
                 .collect::<Vec<_>>(),
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 7835d4e782c..d34924547ed 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -212,7 +212,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
             NodeBlock(n) => EntryBlock(parent, dep_node_index, n),
             NodeStructCtor(n) => EntryStructCtor(parent, dep_node_index, n),
             NodeLifetime(n) => EntryLifetime(parent, dep_node_index, n),
-            NodeTyParam(n) => EntryTyParam(parent, dep_node_index, n),
+            NodeGenericParam(n) => EntryGenericParam(parent, dep_node_index, n),
             NodeVisibility(n) => EntryVisibility(parent, dep_node_index, n),
             NodeLocal(n) => EntryLocal(parent, dep_node_index, n),
             NodeMacroDef(n) => EntryMacroDef(dep_node_index, n),
@@ -347,12 +347,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_generic_param(&mut self, param: &'hir GenericParam) {
-        match *param {
-            GenericParam::Lifetime(ref ld) => {
-                self.insert(ld.lifetime.id, NodeLifetime(&ld.lifetime));
+        match param.kind {
+            GenericParamKind::Lifetime { ref lifetime_deprecated, .. } => {
+                self.insert(param.id, NodeLifetime(lifetime_deprecated));
             }
-            GenericParam::Type(ref ty_param) => {
-                self.insert(ty_param.id, NodeTyParam(ty_param));
+            GenericParamKind::Type { .. } => {
+                self.insert(param.id, NodeGenericParam(param));
             }
         }
         intravisit::walk_generic_param(self, param);
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index d2e04ef31c8..c46f5813754 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -68,7 +68,7 @@ pub enum Node<'hir> {
     NodeStructCtor(&'hir VariantData),
 
     NodeLifetime(&'hir Lifetime),
-    NodeTyParam(&'hir TyParam),
+    NodeGenericParam(&'hir GenericParam),
     NodeVisibility(&'hir Visibility),
 }
 
@@ -96,7 +96,7 @@ enum MapEntry<'hir> {
     EntryBlock(NodeId, DepNodeIndex, &'hir Block),
     EntryStructCtor(NodeId, DepNodeIndex, &'hir VariantData),
     EntryLifetime(NodeId, DepNodeIndex, &'hir Lifetime),
-    EntryTyParam(NodeId, DepNodeIndex, &'hir TyParam),
+    EntryGenericParam(NodeId, DepNodeIndex, &'hir GenericParam),
     EntryVisibility(NodeId, DepNodeIndex, &'hir Visibility),
     EntryLocal(NodeId, DepNodeIndex, &'hir Local),
 
@@ -132,7 +132,7 @@ impl<'hir> MapEntry<'hir> {
             EntryBlock(id, _, _) => id,
             EntryStructCtor(id, _, _) => id,
             EntryLifetime(id, _, _) => id,
-            EntryTyParam(id, _, _) => id,
+            EntryGenericParam(id, _, _) => id,
             EntryVisibility(id, _, _) => id,
             EntryLocal(id, _, _) => id,
 
@@ -160,7 +160,7 @@ impl<'hir> MapEntry<'hir> {
             EntryBlock(_, _, n) => NodeBlock(n),
             EntryStructCtor(_, _, n) => NodeStructCtor(n),
             EntryLifetime(_, _, n) => NodeLifetime(n),
-            EntryTyParam(_, _, n) => NodeTyParam(n),
+            EntryGenericParam(_, _, n) => NodeGenericParam(n),
             EntryVisibility(_, _, n) => NodeVisibility(n),
             EntryLocal(_, _, n) => NodeLocal(n),
             EntryMacroDef(_, n) => NodeMacroDef(n),
@@ -328,7 +328,7 @@ impl<'hir> Map<'hir> {
             EntryBlock(_, dep_node_index, _) |
             EntryStructCtor(_, dep_node_index, _) |
             EntryLifetime(_, dep_node_index, _) |
-            EntryTyParam(_, dep_node_index, _) |
+            EntryGenericParam(_, dep_node_index, _) |
             EntryVisibility(_, dep_node_index, _) |
             EntryAnonConst(_, dep_node_index, _) |
             EntryExpr(_, dep_node_index, _) |
@@ -494,7 +494,7 @@ impl<'hir> Map<'hir> {
                 Some(Def::Macro(self.local_def_id(macro_def.id),
                                 MacroKind::Bang))
             }
-            NodeTyParam(param) => {
+            NodeGenericParam(param) => {
                 Some(Def::TyParam(self.local_def_id(param.id)))
             }
         }
@@ -600,7 +600,7 @@ impl<'hir> Map<'hir> {
     pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
         match self.get(id) {
             NodeItem(&Item { node: ItemTrait(..), .. }) => id,
-            NodeTyParam(_) => self.get_parent_node(id),
+            NodeGenericParam(_) => self.get_parent_node(id),
             _ => {
                 bug!("ty_param_owner: {} not a type parameter",
                     self.node_to_string(id))
@@ -613,7 +613,7 @@ impl<'hir> Map<'hir> {
             NodeItem(&Item { node: ItemTrait(..), .. }) => {
                 keywords::SelfType.name()
             }
-            NodeTyParam(tp) => tp.name,
+            NodeGenericParam(param) => param.name(),
             _ => {
                 bug!("ty_param_name: {} not a type parameter",
                     self.node_to_string(id))
@@ -954,7 +954,7 @@ impl<'hir> Map<'hir> {
             NodeVariant(v) => v.node.name,
             NodeField(f) => f.ident.name,
             NodeLifetime(lt) => lt.name.name(),
-            NodeTyParam(tp) => tp.name,
+            NodeGenericParam(param) => param.name(),
             NodeBinding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.node,
             NodeStructCtor(_) => self.name(self.get_parent(id)),
             _ => bug!("no name for {}", self.node_to_string(id))
@@ -974,7 +974,12 @@ impl<'hir> Map<'hir> {
             Some(NodeField(ref f)) => Some(&f.attrs[..]),
             Some(NodeExpr(ref e)) => Some(&*e.attrs),
             Some(NodeStmt(ref s)) => Some(s.node.attrs()),
-            Some(NodeTyParam(tp)) => Some(&tp.attrs[..]),
+            Some(NodeGenericParam(param)) => {
+                match param.kind {
+                    GenericParamKind::Type { ref attrs, .. } => Some(&attrs[..]),
+                    _ => bug!("unexpected non-type NodeGenericParam")
+                }
+            }
             // unit/tuple structs take the attributes straight from
             // the struct definition.
             Some(NodeStructCtor(_)) => {
@@ -1021,7 +1026,7 @@ impl<'hir> Map<'hir> {
             Some(EntryBlock(_, _, block)) => block.span,
             Some(EntryStructCtor(_, _, _)) => self.expect_item(self.get_parent(id)).span,
             Some(EntryLifetime(_, _, lifetime)) => lifetime.span,
-            Some(EntryTyParam(_, _, ty_param)) => ty_param.span,
+            Some(EntryGenericParam(_, _, param)) => param.span,
             Some(EntryVisibility(_, _, &Visibility::Restricted { ref path, .. })) => path.span,
             Some(EntryVisibility(_, _, v)) => bug!("unexpected Visibility {:?}", v),
             Some(EntryLocal(_, _, local)) => local.span,
@@ -1226,19 +1231,19 @@ impl<'hir> print::PpAnn for Map<'hir> {
 impl<'a> print::State<'a> {
     pub fn print_node(&mut self, node: Node) -> io::Result<()> {
         match node {
-            NodeItem(a)        => self.print_item(&a),
-            NodeForeignItem(a) => self.print_foreign_item(&a),
-            NodeTraitItem(a)   => self.print_trait_item(a),
-            NodeImplItem(a)    => self.print_impl_item(a),
-            NodeVariant(a)     => self.print_variant(&a),
-            NodeAnonConst(a)   => self.print_anon_const(&a),
-            NodeExpr(a)        => self.print_expr(&a),
-            NodeStmt(a)        => self.print_stmt(&a),
-            NodeTy(a)          => self.print_type(&a),
-            NodeTraitRef(a)    => self.print_trait_ref(&a),
+            NodeItem(a)         => self.print_item(&a),
+            NodeForeignItem(a)  => self.print_foreign_item(&a),
+            NodeTraitItem(a)    => self.print_trait_item(a),
+            NodeImplItem(a)     => self.print_impl_item(a),
+            NodeVariant(a)      => self.print_variant(&a),
+            NodeAnonConst(a)    => self.print_anon_const(&a),
+            NodeExpr(a)         => self.print_expr(&a),
+            NodeStmt(a)         => self.print_stmt(&a),
+            NodeTy(a)           => self.print_type(&a),
+            NodeTraitRef(a)     => self.print_trait_ref(&a),
             NodeBinding(a)       |
-            NodePat(a)         => self.print_pat(&a),
-            NodeBlock(a)       => {
+            NodePat(a)          => self.print_pat(&a),
+            NodeBlock(a)        => {
                 use syntax::print::pprust::PrintState;
 
                 // containing cbox, will be closed by print-block at }
@@ -1247,16 +1252,16 @@ impl<'a> print::State<'a> {
                 self.ibox(0)?;
                 self.print_block(&a)
             }
-            NodeLifetime(a)    => self.print_lifetime(&a),
-            NodeVisibility(a)  => self.print_visibility(&a),
-            NodeTyParam(_)     => bug!("cannot print TyParam"),
-            NodeField(_)       => bug!("cannot print StructField"),
+            NodeLifetime(a)     => self.print_lifetime(&a),
+            NodeVisibility(a)   => self.print_visibility(&a),
+            NodeGenericParam(_) => bug!("cannot print NodeGenericParam"),
+            NodeField(_)        => bug!("cannot print StructField"),
             // these cases do not carry enough information in the
             // hir_map to reconstruct their full structure for pretty
             // printing.
-            NodeStructCtor(_)  => bug!("cannot print isolated StructCtor"),
-            NodeLocal(a)       => self.print_local_decl(&a),
-            NodeMacroDef(_)    => bug!("cannot print MacroDef"),
+            NodeStructCtor(_)   => bug!("cannot print isolated StructCtor"),
+            NodeLocal(a)        => self.print_local_decl(&a),
+            NodeMacroDef(_)     => bug!("cannot print MacroDef"),
         }
     }
 }
@@ -1371,8 +1376,8 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         Some(NodeLifetime(_)) => {
             format!("lifetime {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeTyParam(ref ty_param)) => {
-            format!("typaram {:?}{}", ty_param, id_str)
+        Some(NodeGenericParam(ref param)) => {
+            format!("genericparam {:?}{}", param, id_str)
         }
         Some(NodeVisibility(ref vis)) => {
             format!("visibility {:?}{}", vis, id_str)
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d4785e40b1f..6a0301a556f 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -53,8 +53,6 @@ use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}
 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
@@ -242,6 +240,24 @@ impl LifetimeName {
             Name(name) => name,
         }
     }
+
+    fn is_elided(&self) -> bool {
+        use self::LifetimeName::*;
+        match self {
+            Implicit | Underscore => true,
+
+            // It might seem surprising that `Fresh(_)` counts as
+            // *not* elided -- but this is because, as far as the code
+            // in the compiler is concerned -- `Fresh(_)` variants act
+            // equivalently to "some fresh name". They correspond to
+            // early-bound regions on an impl, in other words.
+            Fresh(_) | Static | Name(_) => false,
+        }
+    }
+
+    fn is_static(&self) -> bool {
+        self == &LifetimeName::Static
+    }
 }
 
 impl fmt::Debug for Lifetime {
@@ -255,36 +271,14 @@ impl fmt::Debug for Lifetime {
 
 impl Lifetime {
     pub fn is_elided(&self) -> bool {
-        use self::LifetimeName::*;
-        match self.name {
-            Implicit | Underscore => true,
-
-            // It might seem surprising that `Fresh(_)` counts as
-            // *not* elided -- but this is because, as far as the code
-            // in the compiler is concerned -- `Fresh(_)` variants act
-            // equivalently to "some fresh name". They correspond to
-            // early-bound regions on an impl, in other words.
-            Fresh(_) | Static | Name(_) => false,
-        }
+        self.name.is_elided()
     }
 
     pub fn is_static(&self) -> bool {
-        self.name == LifetimeName::Static
+        self.name.is_static()
     }
 }
 
-/// A lifetime definition, eg `'a: 'b+'c+'d`
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct LifetimeDef {
-    pub lifetime: Lifetime,
-    pub bounds: HirVec<Lifetime>,
-    pub pure_wrt_drop: bool,
-    // Indicates that the lifetime definition was synthetically added
-    // as a result of an in-band lifetime usage like
-    // `fn foo(x: &'a u8) -> &'a u8 { x }`
-    pub in_band: bool,
-}
-
 /// A "Path" is essentially Rust's notion of a name; for instance:
 /// `std::cmp::PartialEq`. It's represented as a sequence of identifiers,
 /// along with a bunch of supporting information.
@@ -466,70 +460,62 @@ pub enum TraitBoundModifier {
 pub type TyParamBounds = HirVec<TyParamBound>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct TyParam {
-    pub name: Name,
+pub enum GenericParamKind {
+    /// A lifetime definition, eg `'a: 'b + 'c + 'd`.
+    Lifetime {
+        /// Either "'a", referring to a named lifetime definition,
+        /// or "" (aka keywords::Invalid), for elision placeholders.
+        ///
+        /// HIR lowering inserts these placeholders in type paths that
+        /// refer to type definitions needing lifetime parameters,
+        /// `&T` and `&mut T`, and trait objects without `... + 'a`.
+        name: LifetimeName,
+        bounds: HirVec<Lifetime>,
+        // Indicates that the lifetime definition was synthetically added
+        // as a result of an in-band lifetime usage like:
+        // `fn foo(x: &'a u8) -> &'a u8 { x }`
+        in_band: bool,
+        // We keep a `Lifetime` around for now just so we can `visit_lifetime`.
+        lifetime_deprecated: Lifetime,
+    },
+    Type {
+        name: Name,
+        bounds: TyParamBounds,
+        default: Option<P<Ty>>,
+        synthetic: Option<SyntheticTyParamKind>,
+        attrs: HirVec<Attribute>,
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct GenericParam {
     pub id: NodeId,
-    pub bounds: TyParamBounds,
-    pub default: Option<P<Ty>>,
     pub span: Span,
     pub pure_wrt_drop: bool,
-    pub synthetic: Option<SyntheticTyParamKind>,
-    pub attrs: HirVec<Attribute>,
-}
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum GenericParam {
-    Lifetime(LifetimeDef),
-    Type(TyParam),
+    pub kind: GenericParamKind,
 }
 
 impl GenericParam {
     pub fn is_lifetime_param(&self) -> bool {
-        match *self {
-            GenericParam::Lifetime(_) => true,
+        match self.kind {
+            GenericParamKind::Lifetime { .. } => true,
             _ => false,
         }
     }
 
     pub fn is_type_param(&self) -> bool {
-        match *self {
-            GenericParam::Type(_) => true,
+        match self.kind {
+            GenericParamKind::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,
-        })
+    pub fn name(&self) -> Name {
+        match self.kind {
+            GenericParamKind::Lifetime { name, .. } => name.name(),
+            GenericParamKind::Type { name, .. } => name,
+        }
     }
 }
 
@@ -555,54 +541,39 @@ impl Generics {
     }
 
     pub fn is_lt_parameterized(&self) -> bool {
-        self.params.iter().any(|param| param.is_lifetime_param())
+        self.params.iter().any(|param| {
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => true,
+                _ => false,
+            }
+        })
     }
 
     pub fn is_type_parameterized(&self) -> bool {
-        self.params.iter().any(|param| param.is_type_param())
-    }
-
-    pub fn lifetimes<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a LifetimeDef> {
-        self.params.lifetimes()
-    }
-
-    pub fn ty_params<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a TyParam> {
-        self.params.ty_params()
+        self.params.iter().any(|param| {
+            match param.kind {
+                GenericParamKind::Type { .. } => true,
+                _ => false,
+            }
+        })
     }
-}
-
-pub enum UnsafeGeneric {
-    Region(LifetimeDef, &'static str),
-    Type(TyParam, &'static str),
-}
 
-impl UnsafeGeneric {
-    pub fn attr_name(&self) -> &'static str {
-        match *self {
-            UnsafeGeneric::Region(_, s) => s,
-            UnsafeGeneric::Type(_, s) => s,
-        }
+    pub fn lifetimes<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a GenericParam> {
+        self.params.iter().filter(|param| {
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => true,
+                _ => false,
+            }
+        })
     }
-}
 
-impl Generics {
-    pub fn carries_unsafe_attr(&self) -> Option<UnsafeGeneric> {
-        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"));
-                    }
-                }
+    pub fn ty_params<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a GenericParam> {
+        self.params.iter().filter(|param| {
+            match param.kind {
+                GenericParamKind::Type { .. } => true,
+                _ => false,
             }
-        }
-
-        None
+        })
     }
 }
 
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 5420be64ca4..afb3a6d0e6c 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -25,7 +25,7 @@ use syntax_pos::{self, BytePos, FileName};
 
 use hir;
 use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd};
-use hir::GenericArg;
+use hir::{GenericParam, GenericParamKind, GenericArg};
 
 use std::cell::Cell;
 use std::io::{self, Write, Read};
@@ -2094,30 +2094,12 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
-        self.print_name(lifetime.name.name())
-    }
-
-    pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> {
-        self.print_lifetime(&lifetime.lifetime)?;
-        let mut sep = ":";
-        for v in &lifetime.bounds {
-            self.s.word(sep)?;
-            self.print_lifetime(v)?;
-            sep = "+";
-        }
-        Ok(())
-    }
-
-    pub fn print_generic_params(&mut self, generic_params: &[hir::GenericParam]) -> io::Result<()> {
+    pub fn print_generic_params(&mut self, generic_params: &[GenericParam]) -> io::Result<()> {
         if !generic_params.is_empty() {
             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),
-                }
+                s.print_generic_param(param)
             })?;
 
             self.s.word(">")?;
@@ -2125,19 +2107,36 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_ty_param(&mut self, param: &hir::TyParam) -> io::Result<()> {
-        self.print_name(param.name)?;
-        self.print_bounds(":", &param.bounds)?;
-        match param.default {
-            Some(ref default) => {
-                self.s.space()?;
-                self.word_space("=")?;
-                self.print_type(&default)
+    pub fn print_generic_param(&mut self, param: &GenericParam) -> io::Result<()> {
+        self.print_name(param.name())?;
+        match param.kind {
+            GenericParamKind::Lifetime { ref bounds, .. } => {
+                let mut sep = ":";
+                for bound in bounds {
+                    self.s.word(sep)?;
+                    self.print_lifetime(bound)?;
+                    sep = "+";
+                }
+                Ok(())
+            }
+            GenericParamKind::Type { ref bounds, ref default, .. } => {
+                self.print_bounds(":", bounds)?;
+                match default {
+                    Some(default) => {
+                        self.s.space()?;
+                        self.word_space("=")?;
+                        self.print_type(&default)
+                    }
+                    _ => Ok(()),
+                }
             }
-            _ => Ok(()),
         }
     }
 
+    pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
+        self.print_name(lifetime.name.name())
+    }
+
     pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) -> io::Result<()> {
         if where_clause.predicates.is_empty() {
             return Ok(());
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 871e399b4f2..ea12db8681c 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -161,13 +161,6 @@ impl_stable_hash_for!(struct hir::Lifetime {
     name
 });
 
-impl_stable_hash_for!(struct hir::LifetimeDef {
-    lifetime,
-    bounds,
-    pure_wrt_drop,
-    in_band
-});
-
 impl_stable_hash_for!(struct hir::Path {
     span,
     def,
@@ -201,21 +194,36 @@ impl_stable_hash_for!(enum hir::TraitBoundModifier {
     Maybe
 });
 
-impl_stable_hash_for!(struct hir::TyParam {
-    name,
+impl_stable_hash_for!(struct hir::GenericParam {
     id,
-    bounds,
-    default,
     span,
     pure_wrt_drop,
-    synthetic,
-    attrs
+    kind
 });
 
-impl_stable_hash_for!(enum hir::GenericParam {
-    Lifetime(lifetime_def),
-    Type(ty_param)
-});
+impl<'a> HashStable<StableHashingContext<'a>> for hir::GenericParamKind {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            hir::GenericParamKind::Lifetime { name, ref bounds, in_band,
+                                              ref lifetime_deprecated } => {
+                name.hash_stable(hcx, hasher);
+                bounds.hash_stable(hcx, hasher);
+                in_band.hash_stable(hcx, hasher);
+                lifetime_deprecated.hash_stable(hcx, hasher);
+            }
+            hir::GenericParamKind::Type { name, ref bounds, ref default, synthetic, attrs } => {
+                name.hash_stable(hcx, hasher);
+                bounds.hash_stable(hcx, hasher);
+                default.hash_stable(hcx, hasher);
+                synthetic.hash_stable(hcx, hasher);
+                attrs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
 
 impl_stable_hash_for!(struct hir::Generics {
     params,
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 4bde363672d..af38e8ba2d4 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -61,7 +61,7 @@ use super::region_constraints::GenericKind;
 use super::lexical_region_resolve::RegionResolutionError;
 
 use std::fmt;
-use hir;
+use hir::{self, GenericParamKind};
 use hir::map as hir_map;
 use hir::def_id::DefId;
 use middle::region;
@@ -1036,8 +1036,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             // Get the `hir::TyParam` to verify whether it already has any bounds.
                             // We do this to avoid suggesting code that ends up as `T: 'a'b`,
                             // instead we suggest `T: 'a + 'b` in that case.
-                            let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) {
-                                p.bounds.len() > 0
+                            let has_lifetimes =
+                                if let hir_map::NodeGenericParam(ref param) = hir.get(id) {
+                                match param.kind {
+                                    GenericParamKind::Type { ref bounds, .. } => {
+                                        !bounds.is_empty()
+                                    }
+                                    _ => bug!("unexpected non-type NodeGenericParam"),
+                                }
                             } else {
                                 false
                             };
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 8f1cd9bb30e..76680b20535 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -35,7 +35,7 @@ use syntax_pos::Span;
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
 
 use hir::intravisit::{self, NestedVisitorMap, Visitor};
-use hir::{self, GenericParamsExt};
+use hir::{self, GenericParamKind};
 
 /// The origin of a named lifetime definition.
 ///
@@ -86,20 +86,30 @@ impl Region {
     fn early(
         hir_map: &Map,
         index: &mut u32,
-        def: &hir::LifetimeDef,
+        param: &hir::GenericParam,
     ) -> (hir::LifetimeName, Region) {
         let i = *index;
         *index += 1;
-        let def_id = hir_map.local_def_id(def.lifetime.id);
-        let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
+        let def_id = hir_map.local_def_id(param.id);
+        let (name, origin) = match param.kind {
+            GenericParamKind::Lifetime { name, in_band, .. } => {
+                (name, LifetimeDefOrigin::from_is_in_band(in_band))
+            }
+            _ => bug!("expected a lifetime param"),
+        };
         debug!("Region::early: index={} def_id={:?}", i, def_id);
-        (def.lifetime.name, Region::EarlyBound(i, def_id, origin))
+        (name, Region::EarlyBound(i, def_id, origin))
     }
 
-    fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) {
+    fn late(hir_map: &Map, param: &hir::GenericParam) -> (hir::LifetimeName, Region) {
         let depth = ty::INNERMOST;
-        let def_id = hir_map.local_def_id(def.lifetime.id);
-        let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
+        let def_id = hir_map.local_def_id(param.id);
+        let (name, origin) = match param.kind {
+            GenericParamKind::Lifetime { name, in_band, .. } => {
+                (name, LifetimeDefOrigin::from_is_in_band(in_band))
+            }
+            _ => bug!("expected a lifetime param"),
+        };
         debug!(
             "Region::late: def={:?} depth={:?} def_id={:?} origin={:?}",
             def,
@@ -107,7 +117,7 @@ impl Region {
             def_id,
             origin,
         );
-        (def.lifetime.name, Region::LateBound(depth, def_id, origin))
+        (name, Region::LateBound(depth, def_id, origin))
     }
 
     fn late_anon(index: &Cell<u32>) -> Region {
@@ -567,9 +577,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 self.is_in_fn_syntax = true;
                 let scope = Scope::Binder {
                     lifetimes: c.generic_params
-                        .lifetimes()
-                        .map(|def| Region::late(&self.tcx.hir, def))
-                        .collect(),
+                                .iter()
+                                .filter_map(|param| {
+                                    match param.kind {
+                                        GenericParamKind::Lifetime { .. } => {
+                                            Some(Region::late(&self.tcx.hir, param))
+                                        }
+                                        _ => None,
+                                    }
+                                })
+                                .collect(),
                     s: self.scope,
                     next_early_index,
                     track_lifetime_uses: true,
@@ -850,10 +867,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             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);
+        for param in &generics.params {
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => {}
+                GenericParamKind::Type { ref bounds, ref default, .. } => {
+                    walk_list!(self, visit_ty_param_bound, bounds);
+                    if let Some(ref ty) = default {
+                        self.visit_ty(&ty);
+                    }
+                }
             }
         }
         for predicate in &generics.where_clause.predicates {
@@ -869,8 +891,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         let next_early_index = self.next_early_index();
                         let scope = Scope::Binder {
                             lifetimes: bound_generic_params
-                                .lifetimes()
-                                .map(|def| Region::late(&self.tcx.hir, def))
+                                .iter()
+                                .filter_map(|param| {
+                                    match param.kind {
+                                        GenericParamKind::Lifetime { .. } => {
+                                            Some(Region::late(&self.tcx.hir, param))
+                                        }
+                                        _ => None,
+                                    }
+                                })
                                 .collect(),
                             s: self.scope,
                             next_early_index,
@@ -936,8 +965,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             let scope = Scope::Binder {
                 lifetimes: trait_ref
                     .bound_generic_params
-                    .lifetimes()
-                    .map(|def| Region::late(&self.tcx.hir, def))
+                    .iter()
+                    .filter_map(|param| {
+                        match param.kind {
+                            GenericParamKind::Lifetime { .. } => {
+                                Some(Region::late(&self.tcx.hir, param))
+                            }
+                            _ => None,
+                        }
+                    })
                     .collect(),
                 s: self.scope,
                 next_early_index,
@@ -987,10 +1023,10 @@ fn original_lifetime(span: Span) -> Original {
         span: span,
     }
 }
-fn shadower_lifetime(l: &hir::Lifetime) -> Shadower {
+fn shadower_lifetime(param: &hir::GenericParam) -> Shadower {
     Shadower {
         kind: ShadowKind::Lifetime,
-        span: l.span,
+        span: param.span,
     }
 }
 
@@ -1005,23 +1041,29 @@ impl ShadowKind {
 
 fn check_mixed_explicit_and_in_band_defs(
     tcx: TyCtxt<'_, '_, '_>,
-    lifetime_defs: &[hir::LifetimeDef],
+    params: &[hir::GenericParam],
 ) {
-    let oob_def = lifetime_defs.iter().find(|lt| !lt.in_band);
-    let in_band_def = lifetime_defs.iter().find(|lt| lt.in_band);
+    let in_bands: Vec<_> = params.iter().map(|param| {
+        match param.kind {
+            GenericParamKind::Lifetime { in_band, .. } => (in_band, param.span),
+            _ => bug!("expected lifetime param"),
+        }
+    }).collect();
+    let out_of_band = in_bands.iter().find(|(in_band, _)| !in_band);
+    let in_band = in_bands.iter().find(|(in_band, _)| *in_band);
 
-    if let (Some(oob_def), Some(in_band_def)) = (oob_def, in_band_def) {
+    if let (Some((_, out_of_band_span)), Some((_, in_band_span)))
+        = (out_of_band, in_band) {
         struct_span_err!(
             tcx.sess,
-            in_band_def.lifetime.span,
+            *in_band_span,
             E0688,
             "cannot mix in-band and explicit lifetime definitions"
         ).span_label(
-            in_band_def.lifetime.span,
+            *in_band_span,
             "in-band lifetime definition here",
-        )
-            .span_label(oob_def.lifetime.span, "explicit lifetime definition here")
-            .emit();
+        ).span_label(*out_of_band_span, "explicit lifetime definition here")
+        .emit();
     }
 }
 
@@ -1178,8 +1220,6 @@ fn compute_object_lifetime_defaults(
                                 .lifetimes()
                                 .nth(i as usize)
                                 .unwrap()
-                                .lifetime
-                                .name
                                 .name()
                                 .to_string(),
                             Set1::One(_) => bug!(),
@@ -1213,58 +1253,67 @@ fn object_lifetime_defaults_for_item(
         }
     }
 
-    generics
-        .ty_params()
-        .map(|param| {
-            let mut set = Set1::Empty;
+    generics.params.iter().filter_map(|param| {
+        match param.kind {
+            GenericParamKind::Lifetime { .. } => None,
+            GenericParamKind::Type { ref bounds, .. } => {
+                let mut set = Set1::Empty;
 
-            add_bounds(&mut set, &param.bounds);
+                add_bounds(&mut set, &bounds);
 
-            let param_def_id = tcx.hir.local_def_id(param.id);
-            for predicate in &generics.where_clause.predicates {
-                // Look for `type: ...` where clauses.
-                let data = match *predicate {
-                    hir::WherePredicate::BoundPredicate(ref data) => data,
-                    _ => continue,
-                };
+                let param_def_id = tcx.hir.local_def_id(param.id);
+                for predicate in &generics.where_clause.predicates {
+                    // Look for `type: ...` where clauses.
+                    let data = match *predicate {
+                        hir::WherePredicate::BoundPredicate(ref data) => data,
+                        _ => continue,
+                    };
 
-                // Ignore `for<'a> type: ...` as they can change what
-                // lifetimes mean (although we could "just" handle it).
-                if !data.bound_generic_params.is_empty() {
-                    continue;
-                }
+                    // Ignore `for<'a> type: ...` as they can change what
+                    // lifetimes mean (although we could "just" handle it).
+                    if !data.bound_generic_params.is_empty() {
+                        continue;
+                    }
 
-                let def = match data.bounded_ty.node {
-                    hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def,
-                    _ => continue,
-                };
+                    let def = match data.bounded_ty.node {
+                        hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def,
+                        _ => continue,
+                    };
 
-                if def == Def::TyParam(param_def_id) {
-                    add_bounds(&mut set, &data.bounds);
+                    if def == Def::TyParam(param_def_id) {
+                        add_bounds(&mut set, &data.bounds);
+                    }
                 }
-            }
 
-            match set {
-                Set1::Empty => Set1::Empty,
-                Set1::One(name) => {
-                    if name == hir::LifetimeName::Static {
-                        Set1::One(Region::Static)
-                    } else {
-                        generics
-                            .lifetimes()
+                Some(match set {
+                    Set1::Empty => Set1::Empty,
+                    Set1::One(name) => {
+                        if name == hir::LifetimeName::Static {
+                            Set1::One(Region::Static)
+                        } else {
+                            generics.params.iter().filter_map(|param| {
+                                match param.kind {
+                                    GenericParamKind::Lifetime { name, in_band, .. } => {
+                                       Some((param.id, name, in_band))
+                                    }
+                                    _ => None,
+                                }
+                            })
                             .enumerate()
-                            .find(|&(_, def)| def.lifetime.name == name)
-                            .map_or(Set1::Many, |(i, def)| {
-                                let def_id = tcx.hir.local_def_id(def.lifetime.id);
-                                let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
+                            .find(|&(_, (_, lt_name, _))| lt_name == name)
+                            .map_or(Set1::Many, |(i, (id, _, in_band))| {
+                                let def_id = tcx.hir.local_def_id(id);
+                                let origin = LifetimeDefOrigin::from_is_in_band(in_band);
                                 Set1::One(Region::EarlyBound(i as u32, def_id, origin))
                             })
+                        }
                     }
-                }
-                Set1::Many => Set1::Many,
+                    Set1::Many => Set1::Many,
+                })
             }
-        })
-        .collect()
+        }
+    })
+    .collect()
 }
 
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
@@ -1438,11 +1487,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
         let lifetimes = generics
             .lifetimes()
-            .map(|def| {
-                if self.map.late_bound.contains(&def.lifetime.id) {
-                    Region::late(&self.tcx.hir, def)
+            .map(|param| {
+                if self.map.late_bound.contains(&param.id) {
+                    Region::late(&self.tcx.hir, param)
                 } else {
-                    Region::early(&self.tcx.hir, &mut index, def)
+                    Region::early(&self.tcx.hir, &mut index, param)
                 }
             })
             .collect();
@@ -1943,7 +1992,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
 
             fn visit_generic_param(&mut self, param: &hir::GenericParam) {
-                if let hir::GenericParam::Lifetime(_) = *param {
+                if let hir::GenericParamKind::Lifetime { .. } = param.kind {
                     // FIXME(eddyb) Do we want this? It only makes a difference
                     // if this `for<'a>` lifetime parameter is never used.
                     self.have_bound_regions = true;
@@ -2160,20 +2209,26 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     }
 
     fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::GenericParam]) {
-        for (i, lifetime_i) in params.lifetimes().enumerate() {
-            match lifetime_i.lifetime.name {
+        let lifetimes: Vec<_> = params.iter().filter_map(|param| {
+            match param.kind {
+                GenericParamKind::Lifetime { name, .. } => Some((param, name)),
+                _ => None,
+            }
+        }).collect();
+        for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() {
+            match lifetime_i_name {
                 hir::LifetimeName::Static | hir::LifetimeName::Underscore => {
                     let lifetime = lifetime_i.lifetime;
-                    let name = lifetime.name.name();
+                    let name = lifetime_i.name();
                     let mut err = struct_span_err!(
                         self.tcx.sess,
-                        lifetime.span,
+                        lifetime_i.span,
                         E0262,
                         "invalid lifetime parameter name: `{}`",
                         name
                     );
                     err.span_label(
-                        lifetime.span,
+                        lifetime_i.span,
                         format!("{} is a reserved lifetime name", name),
                     );
                     err.emit();
@@ -2184,24 +2239,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
 
             // It is a hard error to shadow a lifetime within the same scope.
-            for lifetime_j in params.lifetimes().skip(i + 1) {
-                if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
+            for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) {
+                if lifetime_i_name == lifetime_j_name {
                     struct_span_err!(
                         self.tcx.sess,
-                        lifetime_j.lifetime.span,
+                        lifetime_j.span,
                         E0263,
                         "lifetime name `{}` declared twice in the same scope",
-                        lifetime_j.lifetime.name.name()
-                    ).span_label(lifetime_j.lifetime.span, "declared twice")
-                        .span_label(lifetime_i.lifetime.span, "previous declaration here")
+                        lifetime_j.name()
+                    ).span_label(lifetime_j.span, "declared twice")
+                        .span_label(lifetime_i.span, "previous declaration here")
                         .emit();
                 }
             }
 
             // It is a soft error to shadow a lifetime within a parent scope.
-            self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
+            self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
 
-            for bound in &lifetime_i.bounds {
+            let bounds = match lifetime_i.kind {
+                GenericParamKind::Lifetime { ref bounds, .. } => bounds,
+                _ => bug!(),
+            };
+            for bound in bounds {
                 match bound.name {
                     hir::LifetimeName::Underscore => {
                         let mut err = struct_span_err!(
@@ -2218,16 +2277,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         self.tcx
                             .sess
                             .struct_span_warn(
-                                lifetime_i.lifetime.span.to(bound.span),
+                                lifetime_i.span.to(bound.span),
                                 &format!(
                                     "unnecessary lifetime parameter `{}`",
-                                    lifetime_i.lifetime.name.name()
+                                    lifetime_i.name()
                                 ),
                             )
                             .help(&format!(
                                 "you can use the `'static` lifetime directly, in place \
                                  of `{}`",
-                                lifetime_i.lifetime.name.name()
+                                lifetime_i.name()
                             ))
                             .emit();
                     }
@@ -2241,24 +2300,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn check_lifetime_def_for_shadowing(
+    fn check_lifetime_param_for_shadowing(
         &self,
         mut old_scope: ScopeRef,
-        lifetime: &'tcx hir::Lifetime,
+        param: &'tcx hir::GenericParam,
     ) {
         for &(label, label_span) in &self.labels_in_fn {
             // FIXME (#24278): non-hygienic comparison
-            if lifetime.name.name() == label {
+            if param.name() == label {
                 signal_shadowing_problem(
                     self.tcx,
                     label,
                     original_label(label_span),
-                    shadower_lifetime(&lifetime),
+                    shadower_lifetime(&param),
                 );
                 return;
             }
         }
 
+        let name = match param.kind {
+            GenericParamKind::Lifetime { name, .. } => name,
+            _ => bug!("expected lifetime param"),
+        };
+
         loop {
             match *old_scope {
                 Scope::Body { s, .. }
@@ -2274,14 +2338,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 Scope::Binder {
                     ref lifetimes, s, ..
                 } => {
-                    if let Some(&def) = lifetimes.get(&lifetime.name) {
+                    if let Some(&def) = lifetimes.get(&name) {
                         let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
 
                         signal_shadowing_problem(
                             self.tcx,
-                            lifetime.name.name(),
+                            param.name(),
                             original_lifetime(self.tcx.hir.span(node_id)),
-                            shadower_lifetime(&lifetime),
+                            shadower_lifetime(&param),
                         );
                         return;
                     }
@@ -2429,14 +2493,14 @@ fn insert_late_bound_lifetimes(
     appears_in_where_clause.visit_generics(generics);
 
     for param in &generics.params {
-        match *param {
-            hir::GenericParam::Lifetime(ref lifetime_def) => {
-                if !lifetime_def.bounds.is_empty() {
+        match param.kind {
+            hir::GenericParamKind::Lifetime { ref bounds, .. } => {
+                if !bounds.is_empty() {
                     // `'a: 'b` means both `'a` and `'b` are referenced
                     appears_in_where_clause.regions.insert(lifetime_def.lifetime.name);
                 }
             }
-            hir::GenericParam::Type(_) => {}
+            hir::GenericParamKind::Type { .. } => {}
         }
     }
 
@@ -2450,7 +2514,10 @@ fn insert_late_bound_lifetimes(
     // - do not appear in the where-clauses
     // - are not implicitly captured by `impl Trait`
     for lifetime in generics.lifetimes() {
-        let name = lifetime.lifetime.name;
+        let name = match lifetime.kind {
+            GenericParamKind::Lifetime { name, .. } => name,
+            _ => bug!(),
+        };
 
         // appears in the where clauses? early-bound.
         if appears_in_where_clause.regions.contains(&name) {
@@ -2464,18 +2531,12 @@ fn insert_late_bound_lifetimes(
             continue;
         }
 
-        debug!(
-            "insert_late_bound_lifetimes: \
-             lifetime {:?} with id {:?} is late-bound",
-            lifetime.lifetime.name, lifetime.lifetime.id
-        );
+        debug!("insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound",
+               name,
+               lifetime.id);
 
-        let inserted = map.late_bound.insert(lifetime.lifetime.id);
-        assert!(
-            inserted,
-            "visited lifetime {:?} twice",
-            lifetime.lifetime.id
-        );
+        let inserted = map.late_bound.insert(lifetime.id);
+        assert!(inserted, "visited lifetime {:?} twice", lifetime.id);
     }
 
     return;
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index dbf756f80ca..f456ab36799 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -18,7 +18,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax_pos::Span;
 
-use rustc::hir::{self, PatKind};
+use rustc::hir::{self, GenericParamKind, PatKind};
 use rustc::hir::intravisit::FnKind;
 
 #[derive(PartialEq)]
@@ -147,9 +147,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes {
     }
 
     fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
-        if let hir::GenericParam::Type(ref gen) = *param {
-            if gen.synthetic.is_none() {
-                self.check_case(cx, "type parameter", gen.name, gen.span);
+        match param.kind {
+            GenericParamKind::Lifetime { .. } => {}
+            GenericParamKind::Type { synthetic, .. } => {
+                if synthetic.is_none() {
+                    self.check_case(cx, "type parameter", param.name(), param.span);
+                }
             }
         }
     }
@@ -253,13 +256,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
     }
 
     fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
-        if let hir::GenericParam::Lifetime(ref ld) = *param {
-            self.check_snake_case(
-                cx,
-                "lifetime",
-                &ld.lifetime.name.name().as_str(),
-                Some(ld.lifetime.span)
-            );
+        match param.kind {
+            GenericParamKind::Lifetime { .. } => {
+                self.check_snake_case(cx, "lifetime", &param.name().as_str(), Some(param.span));
+            }
+            GenericParamKind::Type { .. } => {}
         }
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 79796d78871..b981d075d53 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -49,7 +49,7 @@ use syntax_pos::{BytePos, Span, SyntaxContext};
 use syntax::symbol::keywords;
 use syntax::errors::{Applicability, DiagnosticBuilder};
 
-use rustc::hir::{self, PatKind};
+use rustc::hir::{self, GenericParamKind, PatKind};
 use rustc::hir::intravisit::FnKind;
 
 use bad_style::{MethodLateContext, method_context};
@@ -1531,9 +1531,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
         }
         // The parameters must not have bounds
         for param in type_alias_generics.params.iter() {
-            let spans : Vec<_> = match param {
-                &hir::GenericParam::Lifetime(ref l) => l.bounds.iter().map(|b| b.span).collect(),
-                &hir::GenericParam::Type(ref ty) => ty.bounds.iter().map(|b| b.span()).collect(),
+            let spans: Vec<_> = match param.kind {
+                GenericParamKind::Lifetime { ref bounds, .. } => {
+                    bounds.iter().map(|b| b.span).collect()
+                }
+                GenericParamKind::Type { ref bounds, .. } => {
+                    bounds.iter().map(|b| b.span()).collect()
+                }
             };
             if !spans.is_empty() {
                 let mut err = cx.struct_span_lint(
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 33d4df1c3a5..c1a22c353c7 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1645,10 +1645,17 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     }
 
     fn encode_info_for_generics(&mut self, generics: &hir::Generics) {
-        for ty_param in generics.ty_params() {
-            let def_id = self.tcx.hir.local_def_id(ty_param.id);
-            let has_default = Untracked(ty_param.default.is_some());
-            self.record(def_id, IsolatedEncoder::encode_info_for_ty_param, (def_id, has_default));
+        for param in &generics.params {
+            match param.kind {
+                hir::GenericParamKind::Lifetime { .. } => {}
+                hir::GenericParamKind::Type { ref default, .. } => {
+                    let def_id = self.tcx.hir.local_def_id(param.id);
+                    let has_default = Untracked(default.is_some());
+                    self.record(def_id,
+                                IsolatedEncoder::encode_info_for_ty_param,
+                                (def_id, has_default));
+                }
+            }
         }
     }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 291092015b5..19ed04a7968 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -22,7 +22,7 @@ extern crate rustc_typeck;
 extern crate syntax_pos;
 extern crate rustc_data_structures;
 
-use rustc::hir::{self, PatKind};
+use rustc::hir::{self, GenericParamKind, PatKind};
 use rustc::hir::def::Def;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -1268,9 +1268,14 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
-        for ty_param in generics.ty_params() {
-            for bound in ty_param.bounds.iter() {
-                self.check_ty_param_bound(bound)
+        for param in &generics.params {
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => {}
+                GenericParamKind::Type { ref bounds, .. } => {
+                    for bound in bounds {
+                        self.check_ty_param_bound(bound);
+                    }
+                }
             }
         }
         for predicate in &generics.where_clause.predicates {
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 808c134e994..f573ad7ef27 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir::{self, ImplItemKind, TraitItemKind};
+use rustc::hir::{self, GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc::infer::{self, InferOk};
 use rustc::ty::{self, TyCtxt, GenericParamDefKind};
 use rustc::ty::util::ExplicitSelf;
@@ -843,19 +843,19 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         }
                         let span = visitor.0?;
 
-                        let param = impl_m.generics.params.iter().filter_map(|param| {
-                            match param {
-                                hir::GenericParam::Type(param) => {
+                        let bounds = impl_m.generics.params.iter().find_map(|param| {
+                            match param.kind {
+                                GenericParamKind::Lifetime { .. } => None,
+                                GenericParamKind::Type { ref bounds, .. } => {
                                     if param.id == impl_node_id {
-                                        Some(param)
+                                        Some(bounds)
                                     } else {
                                         None
                                     }
-                                },
-                                hir::GenericParam::Lifetime(..) => None,
+                                }
                             }
-                        }).next()?;
-                        let bounds = param.bounds.first()?.span().to(param.bounds.last()?.span());
+                        })?;
+                        let bounds = bounds.first()?.span().to(bounds.last()?.span());
                         let bounds = tcx
                             .sess
                             .codemap()
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c0779235e89..0066e3ce846 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5188,9 +5188,8 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     for (&used, param) in tps_used.iter().zip(generics.ty_params()) {
         if !used {
-            struct_span_err!(tcx.sess, param.span, E0091,
-                "type parameter `{}` is unused",
-                param.name)
+            struct_span_err!(tcx.sess, param.span, E0091, "type parameter `{}` is unused",
+                             param.name())
                 .span_label(param.span, "unused type parameter")
                 .emit();
         }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7a2c38468e0..8d2c1e07ec8 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -631,11 +631,8 @@ fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             continue;
         }
 
-        let (span, name) = match ast_generics.params[index] {
-            hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()),
-            hir::GenericParam::Type(ref tp) => (tp.span, tp.name),
-        };
-        report_bivariance(tcx, span, name);
+        let param = &ast_generics.params[index];
+        report_bivariance(tcx, param.span, param.name());
     }
 }
 
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index 4aa876e85b6..007ef4dee55 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -35,7 +35,14 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
 
             Some(trait_ref) => {
                 let trait_def = self.tcx.trait_def(trait_ref.def_id);
-                let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr());
+                let unsafe_attr = impl_generics.and_then(|g| {
+                    for param in &g.params {
+                        if param.pure_wrt_drop {
+                            return Some("may_dangle");
+                        }
+                    }
+                    None
+                });
                 match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
                     (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
                         span_err!(self.tcx.sess,
@@ -53,13 +60,14 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
                                   trait_ref);
                     }
 
-                    (Unsafety::Normal, Some(g), Unsafety::Normal, hir::ImplPolarity::Positive) =>
+                    (Unsafety::Normal, Some(attr_name), Unsafety::Normal,
+                        hir::ImplPolarity::Positive) =>
                     {
                         span_err!(self.tcx.sess,
                                   item.span,
                                   E0569,
                                   "requires an `unsafe impl` declaration due to `#[{}]` attribute",
-                                  g.attr_name());
+                                  attr_name);
                     }
 
                     (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 58e804fc13f..36436d95e9f 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -49,6 +49,7 @@ use syntax::feature_gate;
 use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir::{self, map as hir_map, CodegenFnAttrs, CodegenFnAttrFlags, Unsafety};
+use rustc::hir::GenericParamKind;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
@@ -113,10 +114,15 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
-        for param in generics.ty_params() {
-            if param.default.is_some() {
-                let def_id = self.tcx.hir.local_def_id(param.id);
-                self.tcx.type_of(def_id);
+        for param in &generics.params {
+            match param.kind {
+                hir::GenericParamKind::Lifetime { .. } => {}
+                hir::GenericParamKind::Type { ref default, .. } => {
+                    if default.is_some() {
+                        let def_id = self.tcx.hir.local_def_id(param.id);
+                        self.tcx.type_of(def_id);
+                    }
+                }
             }
         }
         intravisit::walk_generics(self, generics);
@@ -308,9 +314,20 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
                                          -> Vec<ty::Predicate<'tcx>>
     {
         let from_ty_params =
-            ast_generics.ty_params()
-                .filter(|p| p.id == param_id)
-                .flat_map(|p| p.bounds.iter())
+            ast_generics.params.iter()
+                .filter_map(|param| {
+                    match param.kind {
+                        GenericParamKind::Type { ref bounds, .. } => {
+                            if param.id == param_id {
+                                Some(bounds)
+                            } else {
+                                None
+                            }
+                        }
+                        _ => None
+                    }
+                })
+                .flat_map(|bounds| bounds.iter())
                 .flat_map(|b| predicates_from_bound(self, ty, b));
 
         let from_where_clauses =
@@ -740,9 +757,9 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             has_late_bound_regions: None,
         };
         for lifetime in generics.lifetimes() {
-            let hir_id = tcx.hir.node_to_hir_id(lifetime.lifetime.id);
+            let hir_id = tcx.hir.node_to_hir_id(lifetime.id);
             if tcx.is_late_bound(hir_id) {
-                return Some(lifetime.lifetime.span);
+                return Some(lifetime.span);
             }
         }
         visitor.visit_fn_decl(decl);
@@ -883,12 +900,12 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut params: Vec<_> = opt_self.into_iter().collect();
 
     let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
-    params.extend(early_lifetimes.enumerate().map(|(i, l)| {
+    params.extend(early_lifetimes.enumerate().map(|(i, param)| {
         ty::GenericParamDef {
-            name: l.lifetime.name.name().as_interned_str(),
+            name: param.name().as_interned_str(),
             index: own_start + i as u32,
-            def_id: tcx.hir.local_def_id(l.lifetime.id),
-            pure_wrt_drop: l.pure_wrt_drop,
+            def_id: tcx.hir.local_def_id(param.id),
+            pure_wrt_drop: param.pure_wrt_drop,
             kind: ty::GenericParamDefKind::Lifetime,
         }
     }));
@@ -898,33 +915,39 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Now create the real type parameters.
     let type_start = own_start - has_self as u32 + params.len() as u32;
-    params.extend(ast_generics.ty_params().enumerate().map(|(i, p)| {
-        if p.name == keywords::SelfType.name() {
-            span_bug!(p.span, "`Self` should not be the name of a regular parameter");
-        }
-
-        if !allow_defaults && p.default.is_some() {
-            if !tcx.features().default_type_parameter_fallback {
-                tcx.lint_node(
-                    lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                    p.id,
-                    p.span,
-                    &format!("defaults for type parameters are only allowed in `struct`, \
-                              `enum`, `type`, or `trait` definitions."));
-            }
-        }
+    params.extend(ast_generics.ty_params().enumerate().map(|(i, param)| {
+        match param.kind {
+            GenericParamKind::Type { ref default, synthetic, .. } => {
+                if param.name() == keywords::SelfType.name() {
+                    span_bug!(param.span,
+                              "`Self` should not be the name of a regular parameter");
+                }
 
-        ty::GenericParamDef {
-            index: type_start + i as u32,
-            name: p.name.as_interned_str(),
-            def_id: tcx.hir.local_def_id(p.id),
-            pure_wrt_drop: p.pure_wrt_drop,
-            kind: ty::GenericParamDefKind::Type {
-                has_default: p.default.is_some(),
-                object_lifetime_default:
-                    object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]),
-                synthetic: p.synthetic,
-            },
+                if !allow_defaults && default.is_some() {
+                    if !tcx.features().default_type_parameter_fallback {
+                        tcx.lint_node(
+                            lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                            param.id,
+                            param.span,
+                            &format!("defaults for type parameters are only allowed in \
+                                      `struct`, `enum`, `type`, or `trait` definitions."));
+                    }
+                }
+
+                ty::GenericParamDef {
+                    index: type_start + i as u32,
+                    name: param.name().as_interned_str(),
+                    def_id: tcx.hir.local_def_id(param.id),
+                    pure_wrt_drop: param.pure_wrt_drop,
+                    kind: ty::GenericParamDefKind::Type {
+                        has_default: default.is_some(),
+                        object_lifetime_default:
+                            object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]),
+                        synthetic,
+                    },
+                }
+            }
+            _ => bug!()
         }
     }));
 
@@ -1119,8 +1142,13 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         },
 
-        NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => {
-            icx.to_ty(ty)
+        NodeGenericParam(param) => {
+            match param.kind {
+                hir::GenericParamKind::Type { default: Some(ref ty), .. } => {
+                    icx.to_ty(ty)
+                }
+                _ => bug!("unexpected non-type NodeGenericParam"),
+            }
         }
 
         x => {
@@ -1274,15 +1302,18 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
 /// `resolve_lifetime::early_bound_lifetimes`.
 fn early_bound_lifetimes_from_generics<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    ast_generics: &'a hir::Generics)
-    -> impl Iterator<Item=&'a hir::LifetimeDef> + Captures<'tcx>
+    generics: &'a hir::Generics)
+    -> impl Iterator<Item=&'a hir::GenericParam> + Captures<'tcx>
 {
-    ast_generics
-        .lifetimes()
-        .filter(move |l| {
-            let hir_id = tcx.hir.node_to_hir_id(l.lifetime.id);
-            !tcx.is_late_bound(hir_id)
-        })
+    generics.params.iter().filter(move |param| {
+        match param.kind {
+            GenericParamKind::Lifetime { .. } => {
+                let hir_id = tcx.hir.node_to_hir_id(param.id);
+                !tcx.is_late_bound(hir_id)
+            }
+            _ => false,
+        }
+    })
 }
 
 fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1410,28 +1441,38 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut index = parent_count + has_own_self as u32;
     for param in early_bound_lifetimes_from_generics(tcx, ast_generics) {
         let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
-            def_id: tcx.hir.local_def_id(param.lifetime.id),
+            def_id: tcx.hir.local_def_id(param.id),
             index,
-            name: param.lifetime.name.name().as_interned_str(),
+            name: param.name().as_interned_str(),
         }));
         index += 1;
 
-        for bound in &param.bounds {
-            let bound_region = AstConv::ast_region_to_region(&icx, bound, None);
-            let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound_region));
-            predicates.push(outlives.to_predicate());
+        match param.kind {
+            GenericParamKind::Lifetime { ref bounds, .. } => {
+                for bound in bounds {
+                    let bound_region = AstConv::ast_region_to_region(&icx, bound, None);
+                    let outlives =
+                        ty::Binder::bind(ty::OutlivesPredicate(region, bound_region));
+                    predicates.push(outlives.to_predicate());
+                }
+            },
+            _ => bug!(),
         }
     }
 
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T:Foo>`).
     for param in ast_generics.ty_params() {
-        let param_ty = ty::ParamTy::new(index, param.name.as_interned_str()).to_ty(tcx);
+        let param_ty = ty::ParamTy::new(index, param.name().as_interned_str()).to_ty(tcx);
         index += 1;
 
+        let bounds = match param.kind {
+            GenericParamKind::Type { ref bounds, .. } => bounds,
+            _ => bug!(),
+        };
         let bounds = compute_bounds(&icx,
                                     param_ty,
-                                    &param.bounds,
+                                    bounds,
                                     SizedByDefault::Yes,
                                     param.span);
         predicates.extend(bounds.predicates(tcx, param_ty));
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 80f57adf580..fb005ba18e9 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -76,6 +76,7 @@ This API is completely unstable and subject to change.
 #![feature(crate_visibility_modifier)]
 #![feature(from_ref)]
 #![feature(exhaustive_patterns)]
+#![feature(iterator_find_map)]
 #![feature(quote)]
 #![feature(refcell_replace_swap)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0d44c583cff..40fdd6d8d2d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1466,14 +1466,19 @@ pub struct TyParam {
     pub synthetic: Option<hir::SyntheticTyParamKind>,
 }
 
-impl Clean<TyParam> for hir::TyParam {
+impl Clean<TyParam> for hir::GenericParam {
     fn clean(&self, cx: &DocContext) -> TyParam {
-        TyParam {
-            name: self.name.clean(cx),
-            did: cx.tcx.hir.local_def_id(self.id),
-            bounds: self.bounds.clean(cx),
-            default: self.default.clean(cx),
-            synthetic: self.synthetic,
+        match self.kind {
+            hir::GenericParamKind::Type { ref bounds, ref default, synthetic, .. } => {
+                TyParam {
+                    name: self.name().clean(cx),
+                    did: cx.tcx.hir.local_def_id(self.id),
+                    bounds: bounds.clean(cx),
+                    default: default.clean(cx),
+                    synthetic: synthetic,
+                }
+            }
+            _ => panic!(),
         }
     }
 }
@@ -1707,18 +1712,21 @@ impl Clean<Lifetime> for hir::Lifetime {
     }
 }
 
-impl Clean<Lifetime> for hir::LifetimeDef {
+impl Clean<Lifetime> for hir::GenericParam {
     fn clean(&self, _: &DocContext) -> Lifetime {
-        if self.bounds.len() > 0 {
-            let mut s = format!("{}: {}",
-                                self.lifetime.name.name(),
-                                self.bounds[0].name.name());
-            for bound in self.bounds.iter().skip(1) {
-                s.push_str(&format!(" + {}", bound.name.name()));
+        match self.kind {
+            hir::GenericParamKind::Lifetime { ref bounds, .. } => {
+                if bounds.len() > 0 {
+                    let mut s = format!("{}: {}", self.name(), bounds[0].name.name());
+                    for bound in bounds.iter().skip(1) {
+                        s.push_str(&format!(" + {}", bound.name.name()));
+                    }
+                    Lifetime(s)
+                } else {
+                    Lifetime(self.name().to_string())
+                }
             }
-            Lifetime(s)
-        } else {
-            Lifetime(self.lifetime.name.name().to_string())
+            _ => panic!(),
         }
     }
 }
@@ -1880,9 +1888,11 @@ impl GenericParamDef {
 
 impl Clean<GenericParamDef> for hir::GenericParam {
     fn clean(&self, cx: &DocContext) -> GenericParamDef {
-        match *self {
-            hir::GenericParam::Lifetime(ref l) => GenericParamDef::Lifetime(l.clean(cx)),
-            hir::GenericParam::Type(ref t) => GenericParamDef::Type(t.clean(cx)),
+        match self.kind {
+            hir::GenericParamKind::Lifetime { .. } => {
+                GenericParamDef::Lifetime(self.clean(cx))
+            }
+            hir::GenericParamKind::Type { .. } => GenericParamDef::Type(self.clean(cx)),
         }
     }
 }
@@ -1900,10 +1910,11 @@ impl Clean<Generics> for hir::Generics {
         // In order for normal parameters to be able to refer to synthetic ones,
         // scans them first.
         fn is_impl_trait(param: &hir::GenericParam) -> bool {
-            if let hir::GenericParam::Type(ref tp) = param {
-                tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait)
-            } else {
-                false
+            match param.kind {
+                hir::GenericParamKind::Type { synthetic, .. } => {
+                    synthetic == Some(hir::SyntheticTyParamKind::ImplTrait)
+                }
+                _ => false,
             }
         }
         let impl_trait_params = self.params
@@ -2857,25 +2868,25 @@ impl Clean<Type> for hir::Ty {
                             types: 0
                         };
                         for param in generics.params.iter() {
-                            match param {
-                                hir::GenericParam::Lifetime(lt_param) => {
+                            match param.kind {
+                                hir::GenericParamKind::Lifetime { .. } => {
                                     if let Some(lt) = generic_args.lifetimes()
                                         .nth(indices.lifetimes).cloned() {
                                         if !lt.is_elided() {
                                             let lt_def_id =
-                                                cx.tcx.hir.local_def_id(lt_param.lifetime.id);
+                                                cx.tcx.hir.local_def_id(param.id);
                                             lt_substs.insert(lt_def_id, lt.clean(cx));
                                         }
                                     }
                                     indices.lifetimes += 1;
                                 }
-                                hir::GenericParam::Type(ty_param) => {
+                                hir::GenericParamKind::Type { ref default, .. } => {
                                     let ty_param_def =
-                                        Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
+                                        Def::TyParam(cx.tcx.hir.local_def_id(param.id));
                                     if let Some(ty) = generic_args.types()
                                         .nth(indices.types).cloned() {
                                         ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
-                                    } else if let Some(default) = ty_param.default.clone() {
+                                    } else if let Some(default) = default.clone() {
                                         ty_substs.insert(ty_param_def,
                                                          default.into_inner().clean(cx));
                                     }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 8a4fde21e63..091673bfba9 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -73,7 +73,9 @@ pub trait Visitor<'ast>: Sized {
     fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) }
     fn visit_expr_post(&mut self, _ex: &'ast Expr) { }
     fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) }
-    fn visit_generic_param(&mut self, param: &'ast GenericParamAST) { walk_generic_param(self, param) }
+    fn visit_generic_param(&mut self, param: &'ast GenericParamAST) {
+        walk_generic_param(self, param)
+    }
     fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) }
     fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
         walk_where_predicate(self, p)
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index f85091b0e71..4bc8d208bab 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -568,7 +568,8 @@ impl<'a> TraitDef<'a> {
                         bounds.push((*declared_bound).clone());
                     }
 
-                    GenericParamAST::Type(cx.typaram(self.span, ty_param.ident, vec![], bounds, None))
+                    let ty_param = cx.typaram(self.span, ty_param.ident, vec![], bounds, None);
+                    GenericParamAST::Type(ty_param)
                 }
             }
         }));
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index 92046262ed2..22487e7bfe3 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -192,7 +192,9 @@ impl<'a> Ty<'a> {
                 let ty_params: Vec<P<ast::Ty>> = self_generics.params
                     .iter()
                     .filter_map(|param| match *param {
-                        GenericParamAST::Type(ref ty_param) => Some(cx.ty_ident(span, ty_param.ident)),
+                        GenericParamAST::Type(ref ty_param) => {
+                            Some(cx.ty_ident(span, ty_param.ident))
+                        }
                         _ => None,
                     })
                     .collect();
@@ -280,7 +282,8 @@ impl<'a> LifetimeBounds<'a> {
                 let bounds = bounds.iter()
                     .map(|b| cx.lifetime(span, Ident::from_str(b)))
                     .collect();
-                GenericParamAST::Lifetime(cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds))
+                let lifetime_def = cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds);
+                GenericParamAST::Lifetime(lifetime_def)
             })
             .chain(self.bounds
                 .iter()