about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/intravisit.rs84
-rw-r--r--src/librustc/hir/lowering.rs535
-rw-r--r--src/librustc/hir/map/collector.rs11
-rw-r--r--src/librustc/hir/map/def_collector.rs24
-rw-r--r--src/librustc/hir/map/definitions.rs6
-rw-r--r--src/librustc/hir/map/mod.rs74
-rw-r--r--src/librustc/hir/mod.rs324
-rw-r--r--src/librustc/hir/print.rs170
-rw-r--r--src/librustc/ich/impls_hir.rs64
-rw-r--r--src/librustc/infer/error_reporting/mod.rs13
-rw-r--r--src/librustc/middle/reachable.rs41
-rw-r--r--src/librustc/middle/resolve_lifetime.rs647
-rw-r--r--src/librustc/traits/auto_trait.rs8
-rw-r--r--src/librustc/ty/item_path.rs2
-rw-r--r--src/librustc/util/ppaux.rs12
-rw-r--r--src/librustc_driver/pretty.rs18
-rw-r--r--src/librustc_lint/bad_style.rs24
-rw-r--r--src/librustc_lint/builtin.rs31
-rw-r--r--src/librustc_lint/types.rs99
-rw-r--r--src/librustc_metadata/encoder.rs24
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs2
-rw-r--r--src/librustc_mir/monomorphize/collector.rs14
-rw-r--r--src/librustc_passes/ast_validation.rs142
-rw-r--r--src/librustc_passes/hir_stats.rs12
-rw-r--r--src/librustc_privacy/lib.rs22
-rw-r--r--src/librustc_resolve/lib.rs60
-rw-r--r--src/librustc_resolve/macros.rs4
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs108
-rw-r--r--src/librustc_save_analysis/lib.rs9
-rw-r--r--src/librustc_save_analysis/sig.rs61
-rw-r--r--src/librustc_typeck/astconv.rs111
-rw-r--r--src/librustc_typeck/check/compare_method.rs26
-rw-r--r--src/librustc_typeck/check/method/confirm.rs49
-rw-r--r--src/librustc_typeck/check/mod.rs228
-rw-r--r--src/librustc_typeck/check/wfcheck.rs28
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs9
-rw-r--r--src/librustc_typeck/collect.rs209
-rw-r--r--src/librustc_typeck/diagnostics.rs6
-rw-r--r--src/librustc_typeck/lib.rs14
-rw-r--r--src/librustdoc/clean/auto_trait.rs100
-rw-r--r--src/librustdoc/clean/inline.rs14
-rw-r--r--src/librustdoc/clean/mod.rs463
-rw-r--r--src/librustdoc/clean/simplify.rs19
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/doctree.rs2
-rw-r--r--src/librustdoc/html/format.rs52
-rw-r--r--src/librustdoc/html/render.rs14
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/libsyntax/ast.rs164
-rw-r--r--src/libsyntax/attr.rs15
-rw-r--r--src/libsyntax/ext/build.rs75
-rw-r--r--src/libsyntax/feature_gate.rs4
-rw-r--r--src/libsyntax/fold.rs159
-rw-r--r--src/libsyntax/parse/parser.rs125
-rw-r--r--src/libsyntax/print/pprust.rs159
-rw-r--r--src/libsyntax/test.rs2
-rw-r--r--src/libsyntax/util/node_count.rs8
-rw-r--r--src/libsyntax/visit.rs77
-rw-r--r--src/libsyntax_ext/deriving/clone.rs8
-rw-r--r--src/libsyntax_ext/deriving/cmp/eq.rs4
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs95
-rw-r--r--src/libsyntax_ext/deriving/generic/ty.rs64
-rw-r--r--src/libsyntax_ext/deriving/mod.rs9
-rw-r--r--src/libsyntax_ext/env.rs9
-rw-r--r--src/test/compile-fail/issue-1900.rs2
-rw-r--r--src/test/run-pass/issue-22777.rs4
-rw-r--r--src/test/ui/error-codes/E0110.stderr2
-rw-r--r--src/test/ui/error-codes/E0131.stderr4
-rw-r--r--src/test/ui/issue-51022.rs2
-rw-r--r--src/test/ui/issue-51022.stderr4
-rw-r--r--src/test/ui/rfc1598-generic-associated-types/collections.stderr4
-rw-r--r--src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr6
-rw-r--r--src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr6
-rw-r--r--src/test/ui/rfc1598-generic-associated-types/iterable.stderr12
-rw-r--r--src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr24
-rw-r--r--src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr10
76 files changed, 2565 insertions, 2484 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 12ccb329e06..ed86ef70564 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -314,8 +314,8 @@ pub trait Visitor<'v> : Sized {
     fn visit_trait_ref(&mut self, t: &'v TraitRef) {
         walk_trait_ref(self, t)
     }
-    fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) {
-        walk_ty_param_bound(self, bounds)
+    fn visit_param_bound(&mut self, bounds: &'v GenericBound) {
+        walk_param_bound(self, bounds)
     }
     fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) {
         walk_poly_trait_ref(self, t, m)
@@ -344,6 +344,12 @@ pub trait Visitor<'v> : Sized {
     fn visit_label(&mut self, label: &'v Label) {
         walk_label(self, label)
     }
+    fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg) {
+        match generic_arg {
+            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
+            GenericArg::Type(ty) => self.visit_ty(ty),
+        }
+    }
     fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
         walk_lifetime(self, lifetime)
     }
@@ -356,8 +362,8 @@ pub trait Visitor<'v> : Sized {
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) {
         walk_path_segment(self, path_span, path_segment)
     }
-    fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) {
-        walk_path_parameters(self, path_span, path_parameters)
+    fn visit_generic_args(&mut self, path_span: Span, generic_args: &'v GenericArgs) {
+        walk_generic_args(self, path_span, generic_args)
     }
     fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) {
         walk_assoc_type_binding(self, type_binding)
@@ -427,10 +433,10 @@ pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
 pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
     visitor.visit_id(lifetime.id);
     match lifetime.name {
-        LifetimeName::Name(name) => {
+        LifetimeName::Param(ParamName::Plain(name)) => {
             visitor.visit_name(lifetime.span, name);
         }
-        LifetimeName::Fresh(_) |
+        LifetimeName::Param(ParamName::Fresh(_)) |
         LifetimeName::Static |
         LifetimeName::Implicit |
         LifetimeName::Underscore => {}
@@ -505,7 +511,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
         ItemExistential(ExistTy {ref generics, ref bounds, impl_trait_fn}) => {
             visitor.visit_id(item.id);
             walk_generics(visitor, generics);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
             if let Some(impl_trait_fn) = impl_trait_fn {
                 visitor.visit_def_mention(Def::Fn(impl_trait_fn))
             }
@@ -531,13 +537,13 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
         ItemTrait(.., ref generics, ref bounds, ref trait_item_refs) => {
             visitor.visit_id(item.id);
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
         }
         ItemTraitAlias(ref generics, ref bounds) => {
             visitor.visit_id(item.id);
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
         }
     }
     walk_list!(visitor, visit_attribute, &item.attrs);
@@ -642,17 +648,16 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
                                              path_span: Span,
                                              segment: &'v PathSegment) {
     visitor.visit_name(path_span, segment.name);
-    if let Some(ref parameters) = segment.parameters {
-        visitor.visit_path_parameters(path_span, parameters);
+    if let Some(ref args) = segment.args {
+        visitor.visit_generic_args(path_span, args);
     }
 }
 
-pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
-                                                _path_span: Span,
-                                                path_parameters: &'v PathParameters) {
-    walk_list!(visitor, visit_lifetime, &path_parameters.lifetimes);
-    walk_list!(visitor, visit_ty, &path_parameters.types);
-    walk_list!(visitor, visit_assoc_type_binding, &path_parameters.bindings);
+pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V,
+                                             _path_span: Span,
+                                             generic_args: &'v GenericArgs) {
+    walk_list!(visitor, visit_generic_arg, &generic_args.args);
+    walk_list!(visitor, visit_assoc_type_binding, &generic_args.bindings);
 }
 
 pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
@@ -726,40 +731,27 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
     walk_list!(visitor, visit_attribute, &foreign_item.attrs);
 }
 
-pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) {
+pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound) {
     match *bound {
-        TraitTyParamBound(ref typ, modifier) => {
+        GenericBound::Trait(ref typ, modifier) => {
             visitor.visit_poly_trait_ref(typ, modifier);
         }
-        RegionTyParamBound(ref lifetime) => {
-            visitor.visit_lifetime(lifetime);
-        }
+        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
     }
 }
 
 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 {
-                LifetimeName::Name(name) => {
-                    visitor.visit_name(ld.lifetime.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());
-        }
+    visitor.visit_id(param.id);
+    walk_list!(visitor, visit_attribute, &param.attrs);
+    match param.name {
+        ParamName::Plain(name) => visitor.visit_name(param.span, name),
+        ParamName::Fresh(_) => {}
+    }
+    match param.kind {
+        GenericParamKind::Lifetime { .. } => {}
+        GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
     }
+    walk_list!(visitor, visit_param_bound, &param.bounds);
 }
 
 pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
@@ -778,14 +770,14 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
                                                             ref bound_generic_params,
                                                             ..}) => {
             visitor.visit_ty(bounded_ty);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_generic_param, bound_generic_params);
         }
         &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
                                                               ref bounds,
                                                               ..}) => {
             visitor.visit_lifetime(lifetime);
-            walk_list!(visitor, visit_lifetime, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
         }
         &WherePredicate::EqPredicate(WhereEqPredicate{id,
                                                       ref lhs_ty,
@@ -862,7 +854,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
         }
         TraitItemKind::Type(ref bounds, ref default) => {
             visitor.visit_id(trait_item.id);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
         }
     }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index dd12edb7302..6291e0eb113 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -41,11 +41,12 @@
 //! in the HIR, especially for multiple identifiers.
 
 use dep_graph::DepGraph;
-use hir;
+use hir::{self, ParamName};
 use hir::HirVec;
 use hir::map::{DefKey, DefPathData, Definitions};
 use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
 use hir::def::{Def, PathResolution, PerNS};
+use hir::GenericArg;
 use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
 use middle::cstore::CrateStore;
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -58,6 +59,7 @@ use std::fmt::Debug;
 use std::iter;
 use std::mem;
 use syntax::attr;
+use syntax::ast;
 use syntax::ast::*;
 use syntax::errors;
 use syntax::ext::hygiene::{Mark, SyntaxContext};
@@ -114,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`
@@ -123,7 +125,7 @@ pub struct LoweringContext<'a> {
     // (i.e. it doesn't appear in the in_scope_lifetimes list), it is added
     // to this list. The results of this list are then added to the list of
     // lifetime definitions in the corresponding impl or function generics.
-    lifetimes_to_define: Vec<(Span, hir::LifetimeName)>,
+    lifetimes_to_define: Vec<(Span, ParamName)>,
 
     // Whether or not in-band lifetimes are being collected. This is used to
     // indicate whether or not we're in a place where new lifetimes will result
@@ -322,7 +324,10 @@ impl<'a> LoweringContext<'a> {
                         let count = generics
                             .params
                             .iter()
-                            .filter(|param| param.is_lifetime_param())
+                            .filter(|param| match param.kind {
+                                ast::GenericParamKind::Lifetime { .. } => true,
+                                _ => false,
+                            })
                             .count();
                         self.lctx.type_def_lifetime_params.insert(def_id, count);
                     }
@@ -374,25 +379,24 @@ impl<'a> LoweringContext<'a> {
                 });
 
                 if item_lowered {
-                    let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node {
+                    let item_generics = match self.lctx.items.get(&item.id).unwrap().node {
                         hir::Item_::ItemImpl(_, _, _, ref generics, ..)
                         | hir::Item_::ItemTrait(_, _, ref generics, ..) => {
-                            generics.lifetimes().cloned().collect::<Vec<_>>()
+                            generics.params.clone()
                         }
-                        _ => Vec::new(),
+                        _ => HirVec::new(),
                     };
 
-                    self.lctx
-                        .with_parent_impl_lifetime_defs(&item_lifetimes, |this| {
-                            let this = &mut ItemLowerer { lctx: this };
-                            if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node {
-                                this.with_trait_impl_ref(opt_trait_ref, |this| {
-                                    visit::walk_item(this, item)
-                                });
-                            } else {
-                                visit::walk_item(this, item);
-                            }
-                        });
+                    self.lctx.with_parent_impl_lifetime_defs(&item_generics, |this| {
+                        let this = &mut ItemLowerer { lctx: this };
+                        if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node {
+                            this.with_trait_impl_ref(opt_trait_ref, |this| {
+                                visit::walk_item(this, item)
+                            });
+                        } else {
+                            visit::walk_item(this, item);
+                        }
+                    });
                 }
             }
 
@@ -674,41 +678,31 @@ impl<'a> LoweringContext<'a> {
                 // that collisions are ok here and this shouldn't
                 // really show up for end-user.
                 let str_name = match hir_name {
-                    hir::LifetimeName::Name(n) => n.as_str(),
-                    hir::LifetimeName::Fresh(_) => keywords::UnderscoreLifetime.name().as_str(),
-                    hir::LifetimeName::Implicit
-                    | hir::LifetimeName::Underscore
-                    | hir::LifetimeName::Static => {
-                        span_bug!(span, "unexpected in-band lifetime name: {:?}", hir_name)
-                    }
+                    ParamName::Plain(name) => name.as_str(),
+                    ParamName::Fresh(_) => keywords::UnderscoreLifetime.name().as_str(),
                 };
 
                 // Add a definition for the in-band lifetime def
                 self.resolver.definitions().create_def_with_parent(
                     parent_id.index,
                     def_node_id,
-                    DefPathData::LifetimeDef(str_name.as_interned_str()),
+                    DefPathData::LifetimeParam(str_name.as_interned_str()),
                     DefIndexAddressSpace::High,
                     Mark::root(),
                     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,
+                    name: hir_name,
+                    attrs: hir_vec![],
+                    bounds: hir_vec![],
+                    span,
                     pure_wrt_drop: false,
-                    in_band: true,
-                })
+                    kind: hir::GenericParamKind::Lifetime { in_band: true }
+                }
             })
-            .chain(
-                in_band_ty_params
-                    .into_iter()
-                    .map(|tp| hir::GenericParam::Type(tp)),
-            )
+            .chain(in_band_ty_params.into_iter())
             .collect();
 
         (params, res)
@@ -727,12 +721,9 @@ impl<'a> LoweringContext<'a> {
             return;
         }
 
-        let hir_name = hir::LifetimeName::Name(name);
+        let hir_name = ParamName::Plain(name);
 
-        if self.lifetimes_to_define
-            .iter()
-            .any(|(_, lt_name)| *lt_name == hir_name)
-        {
+        if self.lifetimes_to_define.iter().any(|(_, lt_name)| *lt_name == hir_name) {
             return;
         }
 
@@ -741,28 +732,27 @@ impl<'a> LoweringContext<'a> {
 
     /// When we have either an elided or `'_` lifetime in an impl
     /// header, we convert it to
-    fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> hir::LifetimeName {
+    fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName {
         assert!(self.is_collecting_in_band_lifetimes);
         let index = self.lifetimes_to_define.len();
-        let hir_name = hir::LifetimeName::Fresh(index);
+        let hir_name = ParamName::Fresh(index);
         self.lifetimes_to_define.push((span, hir_name));
         hir_name
     }
 
-    // Evaluates `f` with the lifetimes in `lt_defs` in-scope.
+    // Evaluates `f` with the lifetimes in `params` in-scope.
     // This is used to track which lifetimes have already been defined, and
     // which are new in-band lifetimes that need to have a definition created
     // for them.
-    fn with_in_scope_lifetime_defs<'l, T, F>(
-        &mut self,
-        lt_defs: impl Iterator<Item = &'l LifetimeDef>,
-        f: F,
-    ) -> T
+    fn with_in_scope_lifetime_defs<T, F>(&mut self, params: &Vec<GenericParam>, f: F) -> T
     where
         F: FnOnce(&mut LoweringContext) -> T,
     {
         let old_len = self.in_scope_lifetimes.len();
-        let lt_def_names = lt_defs.map(|lt_def| lt_def.lifetime.ident.name);
+        let lt_def_names = params.iter().filter_map(|param| match param.kind {
+            GenericParamKind::Lifetime { .. } => Some(param.ident.name),
+            _ => None,
+        });
         self.in_scope_lifetimes.extend(lt_def_names);
 
         let res = f(self);
@@ -771,17 +761,22 @@ impl<'a> LoweringContext<'a> {
         res
     }
 
-    // Same as the method above, but accepts `hir::LifetimeDef`s
-    // instead of `ast::LifetimeDef`s.
+    // Same as the method above, but accepts `hir::GenericParam`s
+    // instead of `ast::GenericParam`s.
     // 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
-    where
+    fn with_parent_impl_lifetime_defs<T, F>(&mut self,
+        params: &HirVec<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().filter_map(|param| match param.kind {
+            hir::GenericParamKind::Lifetime { .. } => Some(param.name.name()),
+            _ => None,
+        });
         self.in_scope_lifetimes.extend(lt_def_names);
 
         let res = f(self);
@@ -807,10 +802,7 @@ impl<'a> LoweringContext<'a> {
         F: FnOnce(&mut LoweringContext) -> T,
     {
         let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(
-            generics.params.iter().filter_map(|p| match p {
-                GenericParam::Lifetime(ld) => Some(ld),
-                _ => None,
-            }),
+            &generics.params,
             |this| {
                 let itctx = ImplTraitContext::Universal(parent_id);
                 this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
@@ -1037,6 +1029,16 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
+    fn lower_generic_arg(&mut self,
+                        arg: &ast::GenericArg,
+                        itctx: ImplTraitContext)
+                        -> hir::GenericArg {
+        match arg {
+            ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
+            ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty(&ty, itctx)),
+        }
+    }
+
     fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
         let kind = match t.node {
             TyKind::Infer => hir::TyInfer,
@@ -1052,10 +1054,7 @@ impl<'a> LoweringContext<'a> {
                 hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(
-                f.generic_params.iter().filter_map(|p| match p {
-                    GenericParam::Lifetime(ld) => Some(ld),
-                    _ => None,
-                }),
+                &f.generic_params,
                 |this| {
                     this.with_anonymous_lifetime_mode(
                         AnonymousLifetimeMode::PassThrough,
@@ -1110,11 +1109,11 @@ impl<'a> LoweringContext<'a> {
                 let bounds = bounds
                     .iter()
                     .filter_map(|bound| match *bound {
-                        TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
+                        GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
                             Some(self.lower_poly_trait_ref(ty, itctx))
                         }
-                        TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
-                        RegionTyParamBound(ref lifetime) => {
+                        GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
+                        GenericBound::Outlives(ref lifetime) => {
                             if lifetime_bound.is_none() {
                                 lifetime_bound = Some(self.lower_lifetime(lifetime));
                             }
@@ -1166,7 +1165,7 @@ impl<'a> LoweringContext<'a> {
                         self.allocate_hir_id_counter(exist_ty_node_id, t);
 
                         let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| {
-                            lctx.lower_bounds(bounds, itctx)
+                            lctx.lower_param_bounds(bounds, itctx)
                         });
 
                         let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
@@ -1233,18 +1232,20 @@ impl<'a> LoweringContext<'a> {
                             span,
                         );
 
-                        let hir_bounds = self.lower_bounds(bounds, itctx);
+                        let hir_bounds = self.lower_param_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,
+                            name: ParamName::Plain(name),
                             span,
                             pure_wrt_drop: false,
-                            synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
-                            attrs: P::new(),
+                            attrs: hir_vec![],
+                            bounds: hir_bounds,
+                            kind: hir::GenericParamKind::Type {
+                                default: None,
+                                synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+                            }
                         });
 
                         hir::TyPath(hir::QPath::Resolved(
@@ -1284,7 +1285,7 @@ impl<'a> LoweringContext<'a> {
         &mut self,
         exist_ty_id: NodeId,
         parent_index: DefIndex,
-        bounds: &hir::TyParamBounds,
+        bounds: &hir::GenericBounds,
     ) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
         // This visitor walks over impl trait bounds and creates defs for all lifetimes which
         // appear in the bounds, excluding lifetimes that are created within the bounds.
@@ -1307,15 +1308,15 @@ impl<'a> LoweringContext<'a> {
                 hir::intravisit::NestedVisitorMap::None
             }
 
-            fn visit_path_parameters(&mut self, span: Span, parameters: &'v hir::PathParameters) {
+            fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
                 // Don't collect elided lifetimes used inside of `Fn()` syntax.
                 if parameters.parenthesized {
                     let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
                     self.collect_elided_lifetimes = false;
-                    hir::intravisit::walk_path_parameters(self, span, parameters);
+                    hir::intravisit::walk_generic_args(self, span, parameters);
                     self.collect_elided_lifetimes = old_collect_elided_lifetimes;
                 } else {
-                    hir::intravisit::walk_path_parameters(self, span, parameters);
+                    hir::intravisit::walk_generic_args(self, span, parameters);
                 }
             }
 
@@ -1351,10 +1352,11 @@ 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 { .. } = 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);
+                    let lt_name = hir::LifetimeName::Param(param.name);
+                    self.currently_bound_lifetimes.push(lt_name);
                 }
 
                 hir::intravisit::walk_generic_param(self, param);
@@ -1371,14 +1373,12 @@ impl<'a> LoweringContext<'a> {
                             return;
                         }
                     }
-                    name @ hir::LifetimeName::Fresh(_) => name,
-                    name @ hir::LifetimeName::Name(_) => name,
+                    hir::LifetimeName::Param(_) => lifetime.name,
                     hir::LifetimeName::Static => return,
                 };
 
                 if !self.currently_bound_lifetimes.contains(&name)
-                    && !self.already_defined_lifetimes.contains(&name)
-                {
+                    && !self.already_defined_lifetimes.contains(&name) {
                     self.already_defined_lifetimes.insert(name);
 
                     self.output_lifetimes.push(hir::Lifetime {
@@ -1395,23 +1395,31 @@ impl<'a> LoweringContext<'a> {
                     self.context.resolver.definitions().create_def_with_parent(
                         self.parent,
                         def_node_id,
-                        DefPathData::LifetimeDef(name.name().as_interned_str()),
+                        DefPathData::LifetimeParam(name.name().as_interned_str()),
                         DefIndexAddressSpace::High,
                         Mark::root(),
                         lifetime.span,
                     );
-                    let def_lifetime = hir::Lifetime {
+
+                    let name = match name {
+                        hir::LifetimeName::Underscore => {
+                            hir::ParamName::Plain(keywords::UnderscoreLifetime.name())
+                        }
+                        hir::LifetimeName::Param(param_name) => param_name,
+                        _ => bug!("expected LifetimeName::Param or ParamName::Plain"),
+                    };
+
+                    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,
+                        span: lifetime.span,
+                        pure_wrt_drop: false,
+                        attrs: hir_vec![],
+                        bounds: hir_vec![],
+                        kind: hir::GenericParamKind::Lifetime {
                             in_band: false,
-                        }));
+                        }
+                    });
                 }
             }
         }
@@ -1428,7 +1436,7 @@ impl<'a> LoweringContext<'a> {
         };
 
         for bound in bounds {
-            hir::intravisit::walk_ty_param_bound(&mut lifetime_collector, &bound);
+            hir::intravisit::walk_param_bound(&mut lifetime_collector, &bound);
         }
 
         (
@@ -1669,13 +1677,13 @@ impl<'a> LoweringContext<'a> {
         parenthesized_generic_args: ParenthesizedGenericArgs,
         itctx: ImplTraitContext,
     ) -> hir::PathSegment {
-        let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters {
+        let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
             let msg = "parenthesized parameters may only be used with a trait";
-            match **parameters {
-                PathParameters::AngleBracketed(ref data) => {
+            match **generic_args {
+                GenericArgs::AngleBracketed(ref data) => {
                     self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
-                PathParameters::Parenthesized(ref data) => match parenthesized_generic_args {
+                GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
                     ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
                     ParenthesizedGenericArgs::Warn => {
                         self.sess.buffer_lint(
@@ -1684,13 +1692,13 @@ impl<'a> LoweringContext<'a> {
                             data.span,
                             msg.into(),
                         );
-                        (hir::PathParameters::none(), true)
+                        (hir::GenericArgs::none(), true)
                     }
                     ParenthesizedGenericArgs::Err => {
                         struct_span_err!(self.sess, data.span, E0214, "{}", msg)
                             .span_label(data.span, "only traits may use parentheses")
                             .emit();
-                        (hir::PathParameters::none(), true)
+                        (hir::GenericArgs::none(), true)
                     }
                 },
             }
@@ -1698,47 +1706,49 @@ impl<'a> LoweringContext<'a> {
             self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
         };
 
-        if !parameters.parenthesized && parameters.lifetimes.is_empty() {
-            parameters.lifetimes = self.elided_path_lifetimes(path_span, expected_lifetimes);
+        let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
+            GenericArg::Lifetime(_) => true,
+            _ => false,
+        });
+        if !generic_args.parenthesized && !has_lifetimes {
+            generic_args.args =
+                self.elided_path_lifetimes(path_span, expected_lifetimes)
+                    .into_iter()
+                    .map(|lt| GenericArg::Lifetime(lt))
+                    .chain(generic_args.args.into_iter())
+                    .collect();
         }
 
         hir::PathSegment::new(
             self.lower_ident(segment.ident),
-            parameters,
+            generic_args,
             infer_types,
         )
     }
 
     fn lower_angle_bracketed_parameter_data(
         &mut self,
-        data: &AngleBracketedParameterData,
+        data: &AngleBracketedArgs,
         param_mode: ParamMode,
         itctx: ImplTraitContext,
-    ) -> (hir::PathParameters, bool) {
-        let &AngleBracketedParameterData {
-            ref lifetimes,
-            ref types,
-            ref bindings,
-            ..
-        } = data;
-        (
-            hir::PathParameters {
-                lifetimes: self.lower_lifetimes(lifetimes),
-                types: types.iter().map(|ty| self.lower_ty(ty, itctx)).collect(),
-                bindings: bindings
-                    .iter()
-                    .map(|b| self.lower_ty_binding(b, itctx))
-                    .collect(),
-                parenthesized: false,
-            },
-            types.is_empty() && param_mode == ParamMode::Optional,
-        )
+    ) -> (hir::GenericArgs, bool) {
+        let &AngleBracketedArgs { ref args, ref bindings, .. } = data;
+        let has_types = args.iter().any(|arg| match arg {
+            ast::GenericArg::Type(_) => true,
+            _ => false,
+        });
+        (hir::GenericArgs {
+            args: args.iter().map(|a| self.lower_generic_arg(a, itctx)).collect(),
+            bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx)).collect(),
+            parenthesized: false,
+        },
+        !has_types && param_mode == ParamMode::Optional)
     }
 
     fn lower_parenthesized_parameter_data(
         &mut self,
-        data: &ParenthesizedParameterData,
-    ) -> (hir::PathParameters, bool) {
+        data: &ParenthesisedArgs,
+    ) -> (hir::GenericArgs, bool) {
         // Switch to `PassThrough` mode for anonymous lifetimes: this
         // means that we permit things like `&Ref<T>`, where `Ref` has
         // a hidden lifetime parameter. This is needed for backwards
@@ -1748,29 +1758,16 @@ impl<'a> LoweringContext<'a> {
             AnonymousLifetimeMode::PassThrough,
             |this| {
                 const DISALLOWED: ImplTraitContext = ImplTraitContext::Disallowed;
-                let &ParenthesizedParameterData {
-                    ref inputs,
-                    ref output,
-                    span,
-                } = data;
-                let inputs = inputs
-                    .iter()
-                    .map(|ty| this.lower_ty(ty, DISALLOWED))
-                    .collect();
+                let &ParenthesisedArgs { ref inputs, ref output, span } = data;
+                let inputs = inputs.iter().map(|ty| this.lower_ty(ty, DISALLOWED)).collect();
                 let mk_tup = |this: &mut Self, tys, span| {
                     let LoweredNodeId { node_id, hir_id } = this.next_id();
-                    P(hir::Ty {
-                        node: hir::TyTup(tys),
-                        id: node_id,
-                        hir_id,
-                        span,
-                    })
+                    P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span })
                 };
 
                 (
-                    hir::PathParameters {
-                        lifetimes: hir::HirVec::new(),
-                        types: hir_vec![mk_tup(this, inputs, span)],
+                    hir::GenericArgs {
+                        args: hir_vec![GenericArg::Type(mk_tup(this, inputs, span))],
                         bindings: hir_vec![
                             hir::TypeBinding {
                                 id: this.next_id().node_id,
@@ -1874,63 +1871,22 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn lower_ty_param_bound(
+    fn lower_param_bound(
         &mut self,
-        tpb: &TyParamBound,
+        tpb: &GenericBound,
         itctx: ImplTraitContext,
-    ) -> hir::TyParamBound {
+    ) -> hir::GenericBound {
         match *tpb {
-            TraitTyParamBound(ref ty, modifier) => hir::TraitTyParamBound(
+            GenericBound::Trait(ref ty, modifier) => hir::GenericBound::Trait(
                 self.lower_poly_trait_ref(ty, itctx),
                 self.lower_trait_bound_modifier(modifier),
             ),
-            RegionTyParamBound(ref lifetime) => {
-                hir::RegionTyParamBound(self.lower_lifetime(lifetime))
+            GenericBound::Outlives(ref lifetime) => {
+                hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
             }
         }
     }
 
-    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) {
@@ -1938,7 +1894,7 @@ impl<'a> LoweringContext<'a> {
             x if x == "'_" => match self.anonymous_lifetime_mode {
                 AnonymousLifetimeMode::CreateParameter => {
                     let fresh_name = self.collect_fresh_in_band_lifetime(span);
-                    self.new_named_lifetime(l.id, span, fresh_name)
+                    self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name))
                 }
 
                 AnonymousLifetimeMode::PassThrough => {
@@ -1947,7 +1903,8 @@ impl<'a> LoweringContext<'a> {
             },
             name => {
                 self.maybe_collect_in_band_lifetime(span, name);
-                self.new_named_lifetime(l.id, span, hir::LifetimeName::Name(name))
+                let param_name = ParamName::Plain(name);
+                self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name))
             }
         }
     }
@@ -1965,57 +1922,98 @@ 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;
-
-        let def = hir::LifetimeDef {
-            lifetime: self.lower_lifetime(&l.lifetime),
-            bounds: self.lower_lifetimes(&l.bounds),
-            pure_wrt_drop: attr::contains_name(&l.attrs, "may_dangle"),
-            in_band: false,
-        };
-
-        self.is_collecting_in_band_lifetimes = was_collecting_in_band;
-
-        def
-    }
-
-    fn lower_lifetimes(&mut self, lts: &Vec<Lifetime>) -> hir::HirVec<hir::Lifetime> {
-        lts.iter().map(|l| self.lower_lifetime(l)).collect()
-    }
-
     fn lower_generic_params(
         &mut self,
         params: &Vec<GenericParam>,
-        add_bounds: &NodeMap<Vec<TyParamBound>>,
+        add_bounds: &NodeMap<Vec<GenericBound>>,
         itctx: ImplTraitContext,
     ) -> hir::HirVec<hir::GenericParam> {
-        params
-            .iter()
-            .map(|param| match *param {
-                GenericParam::Lifetime(ref lifetime_def) => {
-                    hir::GenericParam::Lifetime(self.lower_lifetime_def(lifetime_def))
+        params.iter().map(|param| self.lower_generic_param(param, add_bounds, itctx)).collect()
+    }
+
+    fn lower_generic_param(&mut self,
+                           param: &GenericParam,
+                           add_bounds: &NodeMap<Vec<GenericBound>>,
+                           itctx: ImplTraitContext)
+                           -> hir::GenericParam {
+        let mut bounds = self.lower_param_bounds(&param.bounds, itctx);
+        match param.kind {
+            GenericParamKind::Lifetime => {
+                let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
+                self.is_collecting_in_band_lifetimes = false;
+
+                let lt = self.lower_lifetime(&Lifetime { id: param.id, ident: param.ident });
+                let param_name = match lt.name {
+                    hir::LifetimeName::Param(param_name) => param_name,
+                    _ => hir::ParamName::Plain(lt.name.name()),
+                };
+                let param = hir::GenericParam {
+                    id: lt.id,
+                    name: param_name,
+                    span: lt.span,
+                    pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
+                    attrs: self.lower_attrs(&param.attrs),
+                    bounds,
+                    kind: hir::GenericParamKind::Lifetime { in_band: false }
+                };
+
+                self.is_collecting_in_band_lifetimes = was_collecting_in_band;
+
+                param
+            }
+            GenericParamKind::Type { ref default, .. } => {
+                let mut name = self.lower_ident(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");
                 }
-                GenericParam::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()
+
+                let add_bounds = add_bounds.get(&param.id).map_or(&[][..], |x| &x);
+                if !add_bounds.is_empty() {
+                    bounds = bounds.into_iter()
+                                   .chain(self.lower_param_bounds(add_bounds, itctx).into_iter())
+                                   .collect();
+                }
+
+                hir::GenericParam {
+                    id: self.lower_node_id(param.id).node_id,
+                    name: hir::ParamName::Plain(name),
+                    span: param.ident.span,
+                    pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
+                    attrs: self.lower_attrs(&param.attrs),
+                    bounds,
+                    kind: hir::GenericParamKind::Type {
+                        default: default.as_ref().map(|x| {
+                            self.lower_ty(x, ImplTraitContext::Disallowed)
+                        }),
+                        synthetic: param.attrs.iter()
+                                              .filter(|attr| attr.check_name("rustc_synthetic"))
+                                              .map(|_| hir::SyntheticTyParamKind::ImplTrait)
+                                              .next(),
+                    }
+                }
+            }
+        }
     }
 
-    fn lower_generics(&mut self, g: &Generics, itctx: ImplTraitContext) -> hir::Generics {
+    fn lower_generics(
+        &mut self,
+        generics: &Generics,
+        itctx: ImplTraitContext)
+        -> hir::Generics
+    {
         // Collect `?Trait` bounds in where clause and move them to parameter definitions.
         // FIXME: This could probably be done with less rightward drift. Also looks like two control
         //        paths where report_error is called are also the only paths that advance to after
         //        the match statement, so the error reporting could probably just be moved there.
         let mut add_bounds = NodeMap();
-        for pred in &g.where_clause.predicates {
+        for pred in &generics.where_clause.predicates {
             if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
                 'next_bound: for bound in &bound_pred.bounds {
-                    if let TraitTyParamBound(_, TraitBoundModifier::Maybe) = *bound {
+                    if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound {
                         let report_error = |this: &mut Self| {
                             this.diagnostic().span_err(
                                 bound_pred.bounded_ty.span,
@@ -2036,15 +2034,17 @@ impl<'a> LoweringContext<'a> {
                                     if let Some(node_id) =
                                         self.resolver.definitions().as_local_node_id(def_id)
                                     {
-                                        for param in &g.params {
-                                            if let GenericParam::Type(ref ty_param) = *param {
-                                                if node_id == ty_param.id {
-                                                    add_bounds
-                                                        .entry(ty_param.id)
-                                                        .or_insert(Vec::new())
-                                                        .push(bound.clone());
-                                                    continue 'next_bound;
+                                        for param in &generics.params {
+                                            match param.kind {
+                                                GenericParamKind::Type { .. } => {
+                                                    if node_id == param.id {
+                                                        add_bounds.entry(param.id)
+                                                            .or_insert(Vec::new())
+                                                            .push(bound.clone());
+                                                        continue 'next_bound;
+                                                    }
                                                 }
+                                                _ => {}
                                             }
                                         }
                                     }
@@ -2059,9 +2059,9 @@ impl<'a> LoweringContext<'a> {
         }
 
         hir::Generics {
-            params: self.lower_generic_params(&g.params, &add_bounds, itctx),
-            where_clause: self.lower_where_clause(&g.where_clause),
-            span: g.span,
+            params: self.lower_generic_params(&generics.params, &add_bounds, itctx),
+            where_clause: self.lower_where_clause(&generics.where_clause),
+            span: generics.span,
         }
     }
 
@@ -2084,10 +2084,7 @@ impl<'a> LoweringContext<'a> {
                 span,
             }) => {
                 self.with_in_scope_lifetime_defs(
-                    bound_generic_params.iter().filter_map(|p| match p {
-                        GenericParam::Lifetime(ld) => Some(ld),
-                        _ => None,
-                    }),
+                    &bound_generic_params,
                     |this| {
                         hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                             bound_generic_params: this.lower_generic_params(
@@ -2101,8 +2098,8 @@ impl<'a> LoweringContext<'a> {
                                 .filter_map(|bound| match *bound {
                                     // Ignore `?Trait` bounds.
                                     // Tthey were copied into type parameters already.
-                                    TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
-                                    _ => Some(this.lower_ty_param_bound(
+                                    GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
+                                    _ => Some(this.lower_param_bound(
                                         bound,
                                         ImplTraitContext::Disallowed,
                                     )),
@@ -2120,10 +2117,7 @@ impl<'a> LoweringContext<'a> {
             }) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
                 span,
                 lifetime: self.lower_lifetime(lifetime),
-                bounds: bounds
-                    .iter()
-                    .map(|bound| self.lower_lifetime(bound))
-                    .collect(),
+                bounds: self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
             }),
             WherePredicate::EqPredicate(WhereEqPredicate {
                 id,
@@ -2180,13 +2174,7 @@ impl<'a> LoweringContext<'a> {
         let bound_generic_params =
             self.lower_generic_params(&p.bound_generic_params, &NodeMap(), itctx);
         let trait_ref = self.with_parent_impl_lifetime_defs(
-            &bound_generic_params
-                .iter()
-                .filter_map(|p| match *p {
-                    hir::GenericParam::Lifetime(ref ld) => Some(ld.clone()),
-                    _ => None,
-                })
-                .collect::<Vec<_>>(),
+            &bound_generic_params,
             |this| this.lower_trait_ref(&p.trait_ref, itctx),
         );
 
@@ -2229,15 +2217,9 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_bounds(
-        &mut self,
-        bounds: &[TyParamBound],
-        itctx: ImplTraitContext,
-    ) -> hir::TyParamBounds {
-        bounds
-            .iter()
-            .map(|bound| self.lower_ty_param_bound(bound, itctx))
-            .collect()
+    fn lower_param_bounds(&mut self, bounds: &[GenericBound], itctx: ImplTraitContext)
+        -> hir::GenericBounds {
+        bounds.iter().map(|bound| self.lower_param_bound(bound, itctx)).collect()
     }
 
     fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
@@ -2403,10 +2385,7 @@ impl<'a> LoweringContext<'a> {
                 );
 
                 let new_impl_items = self.with_in_scope_lifetime_defs(
-                    ast_generics.params.iter().filter_map(|p| match p {
-                        GenericParam::Lifetime(ld) => Some(ld),
-                        _ => None,
-                    }),
+                    &ast_generics.params,
                     |this| {
                         impl_items
                             .iter()
@@ -2426,7 +2405,7 @@ impl<'a> LoweringContext<'a> {
                 )
             }
             ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
-                let bounds = self.lower_bounds(bounds, ImplTraitContext::Disallowed);
+                let bounds = self.lower_param_bounds(bounds, ImplTraitContext::Disallowed);
                 let items = items
                     .iter()
                     .map(|item| self.lower_trait_item_ref(item))
@@ -2441,7 +2420,7 @@ impl<'a> LoweringContext<'a> {
             }
             ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemTraitAlias(
                 self.lower_generics(generics, ImplTraitContext::Disallowed),
-                self.lower_bounds(bounds, ImplTraitContext::Disallowed),
+                self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
             ),
             ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
         }
@@ -2668,7 +2647,7 @@ impl<'a> LoweringContext<'a> {
             TraitItemKind::Type(ref bounds, ref default) => (
                 self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
                 hir::TraitItemKind::Type(
-                    self.lower_bounds(bounds, ImplTraitContext::Disallowed),
+                    self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
                     default
                         .as_ref()
                         .map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
@@ -4217,7 +4196,7 @@ impl<'a> LoweringContext<'a> {
                 hir::Lifetime {
                     id: self.next_id().node_id,
                     span,
-                    name: fresh_name,
+                    name: hir::LifetimeName::Param(fresh_name),
                 }
             }
 
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 7835d4e782c..14cecba490d 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,14 +347,7 @@ 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));
-            }
-            GenericParam::Type(ref ty_param) => {
-                self.insert(ty_param.id, NodeTyParam(ty_param));
-            }
-        }
+        self.insert(param.id, NodeGenericParam(param));
         intravisit::walk_generic_param(self, param);
     }
 
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 48d959b4f8e..8aa5dd4ad80 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -171,24 +171,12 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
     }
 
     fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        match *param {
-            GenericParam::Lifetime(ref lifetime_def) => {
-                self.create_def(
-                    lifetime_def.lifetime.id,
-                    DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_interned_str()),
-                    REGULAR_SPACE,
-                    lifetime_def.lifetime.ident.span
-                );
-            }
-            GenericParam::Type(ref ty_param) => {
-                self.create_def(
-                    ty_param.id,
-                    DefPathData::TypeParam(ty_param.ident.name.as_interned_str()),
-                    REGULAR_SPACE,
-                    ty_param.ident.span
-                );
-            }
-        }
+        let name = param.ident.name.as_interned_str();
+        let def_path_data = match param.kind {
+            GenericParamKind::Lifetime { .. } => DefPathData::LifetimeParam(name),
+            GenericParamKind::Type { .. } => DefPathData::TypeParam(name),
+        };
+        self.create_def(param.id, def_path_data, REGULAR_SPACE, param.ident.span);
 
         visit::walk_generic_param(self, param);
     }
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 99023a16867..b1cb9d7fbd4 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -360,7 +360,7 @@ pub enum DefPathData {
     /// A type parameter (generic parameter)
     TypeParam(InternedString),
     /// A lifetime definition
-    LifetimeDef(InternedString),
+    LifetimeParam(InternedString),
     /// A variant of a enum
     EnumVariant(InternedString),
     /// A struct field
@@ -625,7 +625,7 @@ impl DefPathData {
             Module(name) |
             MacroDef(name) |
             TypeParam(name) |
-            LifetimeDef(name) |
+            LifetimeParam(name) |
             EnumVariant(name) |
             Field(name) |
             GlobalMetaData(name) => Some(name),
@@ -652,7 +652,7 @@ impl DefPathData {
             Module(name) |
             MacroDef(name) |
             TypeParam(name) |
-            LifetimeDef(name) |
+            LifetimeParam(name) |
             EnumVariant(name) |
             Field(name) |
             GlobalMetaData(name) => {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index d2e04ef31c8..c2c8c7a391b 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,8 +494,11 @@ impl<'hir> Map<'hir> {
                 Some(Def::Macro(self.local_def_id(macro_def.id),
                                 MacroKind::Bang))
             }
-            NodeTyParam(param) => {
-                Some(Def::TyParam(self.local_def_id(param.id)))
+            NodeGenericParam(param) => {
+                Some(match param.kind {
+                    GenericParamKind::Lifetime { .. } => Def::Local(param.id),
+                    GenericParamKind::Type { .. } => Def::TyParam(self.local_def_id(param.id)),
+                })
             }
         }
     }
@@ -600,7 +603,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,11 +616,8 @@ impl<'hir> Map<'hir> {
             NodeItem(&Item { node: ItemTrait(..), .. }) => {
                 keywords::SelfType.name()
             }
-            NodeTyParam(tp) => tp.name,
-            _ => {
-                bug!("ty_param_name: {} not a type parameter",
-                    self.node_to_string(id))
-            }
+            NodeGenericParam(param) => param.name.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.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,7 @@ 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)) => Some(&param.attrs[..]),
             // unit/tuple structs take the attributes straight from
             // the struct definition.
             Some(NodeStructCtor(_)) => {
@@ -1021,7 +1021,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 +1226,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 +1247,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 +1371,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!("generic_param {:?}{}", 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 833090c3ee0..f6876113c11 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -22,7 +22,6 @@ pub use self::Mutability::*;
 pub use self::PrimTy::*;
 pub use self::Stmt_::*;
 pub use self::Ty_::*;
-pub use self::TyParamBound::*;
 pub use self::UnOp::*;
 pub use self::UnsafeSource::*;
 pub use self::Visibility::{Public, Inherited};
@@ -53,8 +52,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
@@ -203,12 +200,9 @@ pub struct Lifetime {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
-pub enum LifetimeName {
-    /// User typed nothing. e.g. the lifetime in `&u32`.
-    Implicit,
-
-    /// User typed `'_`.
-    Underscore,
+pub enum ParamName {
+    /// Some user-given name like `T` or `'x`.
+    Plain(Name),
 
     /// Synthetic name generated when user elided a lifetime in an impl header,
     /// e.g. the lifetimes in cases like these:
@@ -224,12 +218,30 @@ pub enum LifetimeName {
     /// where `'f` is something like `Fresh(0)`. The indices are
     /// unique per impl, but not necessarily continuous.
     Fresh(usize),
+}
+
+impl ParamName {
+    pub fn name(&self) -> Name {
+        match *self {
+            ParamName::Plain(name) => name,
+            ParamName::Fresh(_) => keywords::UnderscoreLifetime.name(),
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+pub enum LifetimeName {
+    /// User-given names or fresh (synthetic) names.
+    Param(ParamName),
+
+    /// User typed nothing. e.g. the lifetime in `&u32`.
+    Implicit,
+
+    /// User typed `'_`.
+    Underscore,
 
     /// User wrote `'static`
     Static,
-
-    /// Some user-given name like `'x`
-    Name(Name),
 }
 
 impl LifetimeName {
@@ -237,11 +249,29 @@ impl LifetimeName {
         use self::LifetimeName::*;
         match *self {
             Implicit => keywords::Invalid.name(),
-            Fresh(_) | Underscore => keywords::UnderscoreLifetime.name(),
+            Underscore => keywords::UnderscoreLifetime.name(),
             Static => keywords::StaticLifetime.name(),
-            Name(name) => name,
+            Param(param_name) => param_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.
+            Param(_) | Static => false,
+        }
+    }
+
+    fn is_static(&self) -> bool {
+        self == &LifetimeName::Static
+    }
 }
 
 impl fmt::Debug for Lifetime {
@@ -255,36 +285,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.
@@ -327,7 +335,7 @@ pub struct PathSegment {
     /// this is more than just simple syntactic sugar; the use of
     /// parens affects the region binding rules, so we preserve the
     /// distinction.
-    pub parameters: Option<P<PathParameters>>,
+    pub args: Option<P<GenericArgs>>,
 
     /// Whether to infer remaining type parameters, if any.
     /// This only applies to expression and pattern paths, and
@@ -342,30 +350,30 @@ impl PathSegment {
         PathSegment {
             name,
             infer_types: true,
-            parameters: None
+            args: None,
         }
     }
 
-    pub fn new(name: Name, parameters: PathParameters, infer_types: bool) -> Self {
+    pub fn new(name: Name, args: GenericArgs, infer_types: bool) -> Self {
         PathSegment {
             name,
             infer_types,
-            parameters: if parameters.is_empty() {
+            args: if args.is_empty() {
                 None
             } else {
-                Some(P(parameters))
+                Some(P(args))
             }
         }
     }
 
     // FIXME: hack required because you can't create a static
-    // PathParameters, so you can't just return a &PathParameters.
-    pub fn with_parameters<F, R>(&self, f: F) -> R
-        where F: FnOnce(&PathParameters) -> R
+    // GenericArgs, so you can't just return a &GenericArgs.
+    pub fn with_generic_args<F, R>(&self, f: F) -> R
+        where F: FnOnce(&GenericArgs) -> R
     {
-        let dummy = PathParameters::none();
-        f(if let Some(ref params) = self.parameters {
-            &params
+        let dummy = GenericArgs::none();
+        f(if let Some(ref args) = self.args {
+            &args
         } else {
             &dummy
         })
@@ -373,142 +381,114 @@ impl PathSegment {
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct PathParameters {
-    /// The lifetime parameters for this path segment.
-    pub lifetimes: HirVec<Lifetime>,
-    /// The type parameters for this path segment, if present.
-    pub types: HirVec<P<Ty>>,
+pub enum GenericArg {
+    Lifetime(Lifetime),
+    Type(P<Ty>),
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct GenericArgs {
+    /// The generic arguments for this path segment.
+    pub args: HirVec<GenericArg>,
     /// Bindings (equality constraints) on associated types, if present.
     /// E.g., `Foo<A=Bar>`.
     pub bindings: HirVec<TypeBinding>,
-    /// Were parameters written in parenthesized form `Fn(T) -> U`?
+    /// Were arguments written in parenthesized form `Fn(T) -> U`?
     /// This is required mostly for pretty-printing and diagnostics,
     /// but also for changing lifetime elision rules to be "function-like".
     pub parenthesized: bool,
 }
 
-impl PathParameters {
+impl GenericArgs {
     pub fn none() -> Self {
         Self {
-            lifetimes: HirVec::new(),
-            types: HirVec::new(),
+            args: HirVec::new(),
             bindings: HirVec::new(),
             parenthesized: false,
         }
     }
 
     pub fn is_empty(&self) -> bool {
-        self.lifetimes.is_empty() && self.types.is_empty() &&
-            self.bindings.is_empty() && !self.parenthesized
+        self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized
     }
 
     pub fn inputs(&self) -> &[P<Ty>] {
         if self.parenthesized {
-            if let Some(ref ty) = self.types.get(0) {
-                if let TyTup(ref tys) = ty.node {
-                    return tys;
+            for arg in &self.args {
+                match arg {
+                    GenericArg::Lifetime(_) => {}
+                    GenericArg::Type(ref ty) => {
+                        if let TyTup(ref tys) = ty.node {
+                            return tys;
+                        }
+                        break;
+                    }
                 }
             }
         }
-        bug!("PathParameters::inputs: not a `Fn(T) -> U`");
+        bug!("GenericArgs::inputs: not a `Fn(T) -> U`");
     }
 }
 
+/// A modifier on a bound, currently this is only used for `?Sized`, where the
+/// modifier is `Maybe`. Negative bounds should also be handled here.
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitBoundModifier {
+    None,
+    Maybe,
+}
+
 /// The AST represents all type param bounds as types.
 /// typeck::collect::compute_bounds matches these against
 /// the "special" built-in traits (see middle::lang_items) and
 /// detects Copy, Send and Sync.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TyParamBound {
-    TraitTyParamBound(PolyTraitRef, TraitBoundModifier),
-    RegionTyParamBound(Lifetime),
+pub enum GenericBound {
+    Trait(PolyTraitRef, TraitBoundModifier),
+    Outlives(Lifetime),
 }
 
-impl TyParamBound {
+impl GenericBound {
     pub fn span(&self) -> Span {
         match self {
-            &TraitTyParamBound(ref t, ..) => t.span,
-            &RegionTyParamBound(ref l) => l.span,
+            &GenericBound::Trait(ref t, ..) => t.span,
+            &GenericBound::Outlives(ref l) => l.span,
         }
     }
 }
 
-/// A modifier on a bound, currently this is only used for `?Sized`, where the
-/// modifier is `Maybe`. Negative bounds should also be handled here.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TraitBoundModifier {
-    None,
-    Maybe,
-}
+pub type GenericBounds = HirVec<GenericBound>;
 
-pub type TyParamBounds = HirVec<TyParamBound>;
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum GenericParamKind {
+    /// A lifetime definition, eg `'a: 'b + 'c + 'd`.
+    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,
+    },
+    Type {
+        default: Option<P<Ty>>,
+        synthetic: Option<SyntheticTyParamKind>,
+    }
+}
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct TyParam {
-    pub name: Name,
+pub struct GenericParam {
     pub id: NodeId,
-    pub bounds: TyParamBounds,
-    pub default: Option<P<Ty>>,
+    pub name: ParamName,
+    pub attrs: HirVec<Attribute>,
+    pub bounds: GenericBounds,
     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,
-            _ => false,
-        }
-    }
-
-    pub fn is_type_param(&self) -> bool {
-        match *self {
-            GenericParam::Type(_) => true,
-            _ => false,
-        }
-    }
-}
-
-pub trait GenericParamsExt {
-    fn lifetimes<'a>(&'a self) -> iter::FilterMap<
-        slice::Iter<GenericParam>,
-        fn(&GenericParam) -> Option<&LifetimeDef>,
-    >;
-
-    fn ty_params<'a>(&'a self) -> iter::FilterMap<
-        slice::Iter<GenericParam>,
-        fn(&GenericParam) -> Option<&TyParam>,
-    >;
-}
-
-impl GenericParamsExt for [GenericParam] {
-    fn lifetimes<'a>(&'a self) -> iter::FilterMap<
-        slice::Iter<GenericParam>,
-        fn(&GenericParam) -> Option<&LifetimeDef>,
-    > {
-        self.iter().filter_map(|param| match *param {
-            GenericParam::Lifetime(ref l) => Some(l),
-            _ => None,
-        })
-    }
-
-    fn ty_params<'a>(&'a self) -> iter::FilterMap<
-        slice::Iter<GenericParam>,
-        fn(&GenericParam) -> Option<&TyParam>,
-    > {
-        self.iter().filter_map(|param| match *param {
-            GenericParam::Type(ref t) => Some(t),
-            _ => None,
-        })
-    }
+pub struct GenericParamCount {
+    pub lifetimes: usize,
+    pub types: usize,
 }
 
 /// Represents lifetimes and type parameters attached to a declaration
@@ -532,55 +512,23 @@ impl Generics {
         }
     }
 
-    pub fn is_lt_parameterized(&self) -> bool {
-        self.params.iter().any(|param| param.is_lifetime_param())
-    }
-
-    pub fn is_type_parameterized(&self) -> bool {
-        self.params.iter().any(|param| param.is_type_param())
-    }
-
-    pub fn lifetimes<'a>(&'a self) -> impl Iterator<Item = &'a LifetimeDef> {
-        self.params.lifetimes()
-    }
-
-    pub fn ty_params<'a>(&'a self) -> impl Iterator<Item = &'a TyParam> {
-        self.params.ty_params()
-    }
-}
-
-pub enum UnsafeGeneric {
-    Region(LifetimeDef, &'static str),
-    Type(TyParam, &'static str),
-}
+    pub fn own_counts(&self) -> GenericParamCount {
+        // We could cache this as a property of `GenericParamCount`, but
+        // the aim is to refactor this away entirely eventually and the
+        // presence of this method will be a constant reminder.
+        let mut own_counts = GenericParamCount {
+            lifetimes: 0,
+            types: 0,
+        };
 
-impl UnsafeGeneric {
-    pub fn attr_name(&self) -> &'static str {
-        match *self {
-            UnsafeGeneric::Region(_, s) => s,
-            UnsafeGeneric::Type(_, s) => s,
-        }
-    }
-}
-
-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"));
-                    }
-                }
-            }
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => own_counts.lifetimes += 1,
+                GenericParamKind::Type { .. } => own_counts.types += 1,
+            };
         }
 
-        None
+        own_counts
     }
 }
 
@@ -640,7 +588,7 @@ pub struct WhereBoundPredicate {
     /// The type being bounded
     pub bounded_ty: P<Ty>,
     /// Trait and lifetime bounds (`Clone+Send+'static`)
-    pub bounds: TyParamBounds,
+    pub bounds: GenericBounds,
 }
 
 /// A lifetime predicate, e.g. `'a: 'b+'c`
@@ -648,7 +596,7 @@ pub struct WhereBoundPredicate {
 pub struct WhereRegionPredicate {
     pub span: Span,
     pub lifetime: Lifetime,
-    pub bounds: HirVec<Lifetime>,
+    pub bounds: GenericBounds,
 }
 
 /// An equality predicate (unsupported), e.g. `T=int`
@@ -1607,7 +1555,7 @@ pub enum TraitItemKind {
     Method(MethodSig, TraitMethod),
     /// An associated type with (possibly empty) bounds and optional concrete
     /// type
-    Type(TyParamBounds, Option<P<Ty>>),
+    Type(GenericBounds, Option<P<Ty>>),
 }
 
 // The bodies for items are stored "out of line", in a separate
@@ -1692,7 +1640,7 @@ pub struct BareFnTy {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct ExistTy {
     pub generics: Generics,
-    pub bounds: TyParamBounds,
+    pub bounds: GenericBounds,
     pub impl_trait_fn: Option<DefId>,
 }
 
@@ -2101,9 +2049,9 @@ pub enum Item_ {
     /// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
     ItemUnion(VariantData, Generics),
     /// Represents a Trait Declaration
-    ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
+    ItemTrait(IsAuto, Unsafety, Generics, GenericBounds, HirVec<TraitItemRef>),
     /// Represents a Trait Alias Declaration
-    ItemTraitAlias(Generics, TyParamBounds),
+    ItemTraitAlias(Generics, GenericBounds),
 
     /// An implementation, eg `impl<A> Trait for Foo { .. }`
     ItemImpl(Unsafety,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 1beef3f715e..14f780fab7f 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -24,7 +24,8 @@ use syntax::util::parser::{self, AssocOp, Fixity};
 use syntax_pos::{self, BytePos, FileName};
 
 use hir;
-use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd};
+use hir::{PatKind, GenericBound, TraitBoundModifier, RangeEnd};
+use hir::{GenericParam, GenericParamKind, GenericArg};
 
 use std::cell::Cell;
 use std::io::{self, Write, Read};
@@ -513,7 +514,7 @@ impl<'a> State<'a> {
 
     fn print_associated_type(&mut self,
                              name: ast::Name,
-                             bounds: Option<&hir::TyParamBounds>,
+                             bounds: Option<&hir::GenericBounds>,
                              ty: Option<&hir::Ty>)
                              -> io::Result<()> {
         self.word_space("type")?;
@@ -661,7 +662,7 @@ impl<'a> State<'a> {
                 self.word_space(":")?;
                 let mut real_bounds = Vec::with_capacity(exist.bounds.len());
                 for b in exist.bounds.iter() {
-                    if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                    if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
                         self.s.space()?;
                         self.word_space("for ?")?;
                         self.print_trait_ref(&ptr.trait_ref)?;
@@ -739,7 +740,7 @@ impl<'a> State<'a> {
                 self.print_generic_params(&generics.params)?;
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 for b in bounds.iter() {
-                    if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                    if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
                         self.s.space()?;
                         self.word_space("for ?")?;
                         self.print_trait_ref(&ptr.trait_ref)?;
@@ -765,7 +766,7 @@ impl<'a> State<'a> {
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 // FIXME(durka) this seems to be some quite outdated syntax
                 for b in bounds.iter() {
-                    if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                    if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
                         self.s.space()?;
                         self.word_space("for ?")?;
                         self.print_trait_ref(&ptr.trait_ref)?;
@@ -1268,15 +1269,11 @@ impl<'a> State<'a> {
         self.s.word(".")?;
         self.print_name(segment.name)?;
 
-        segment.with_parameters(|parameters| {
-            if !parameters.lifetimes.is_empty() ||
-                !parameters.types.is_empty() ||
-                !parameters.bindings.is_empty()
-            {
-                self.print_path_parameters(&parameters, segment.infer_types, true)
-            } else {
-                Ok(())
+        segment.with_generic_args(|generic_args| {
+            if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() {
+                return self.print_generic_args(&generic_args, segment.infer_types, true);
             }
+            Ok(())
         })?;
         self.print_call_post(base_args)
     }
@@ -1641,10 +1638,9 @@ impl<'a> State<'a> {
             if segment.name != keywords::CrateRoot.name() &&
                segment.name != keywords::DollarCrate.name() {
                self.print_name(segment.name)?;
-               segment.with_parameters(|parameters| {
-                   self.print_path_parameters(parameters,
-                                              segment.infer_types,
-                                              colons_before_params)
+               segment.with_generic_args(|generic_args| {
+                   self.print_generic_args(generic_args, segment.infer_types,
+                                           colons_before_params)
                })?;
             }
         }
@@ -1673,10 +1669,10 @@ impl<'a> State<'a> {
                     if segment.name != keywords::CrateRoot.name() &&
                        segment.name != keywords::DollarCrate.name() {
                         self.print_name(segment.name)?;
-                        segment.with_parameters(|parameters| {
-                            self.print_path_parameters(parameters,
-                                                       segment.infer_types,
-                                                       colons_before_params)
+                        segment.with_generic_args(|generic_args| {
+                            self.print_generic_args(generic_args,
+                                                    segment.infer_types,
+                                                    colons_before_params)
                         })?;
                     }
                 }
@@ -1685,10 +1681,10 @@ impl<'a> State<'a> {
                 self.s.word("::")?;
                 let item_segment = path.segments.last().unwrap();
                 self.print_name(item_segment.name)?;
-                item_segment.with_parameters(|parameters| {
-                    self.print_path_parameters(parameters,
-                                               item_segment.infer_types,
-                                               colons_before_params)
+                item_segment.with_generic_args(|generic_args| {
+                    self.print_generic_args(generic_args,
+                                            item_segment.infer_types,
+                                            colons_before_params)
                 })
             }
             hir::QPath::TypeRelative(ref qself, ref item_segment) => {
@@ -1697,28 +1693,28 @@ impl<'a> State<'a> {
                 self.s.word(">")?;
                 self.s.word("::")?;
                 self.print_name(item_segment.name)?;
-                item_segment.with_parameters(|parameters| {
-                    self.print_path_parameters(parameters,
-                                               item_segment.infer_types,
-                                               colons_before_params)
+                item_segment.with_generic_args(|generic_args| {
+                    self.print_generic_args(generic_args,
+                                            item_segment.infer_types,
+                                            colons_before_params)
                 })
             }
         }
     }
 
-    fn print_path_parameters(&mut self,
-                             parameters: &hir::PathParameters,
+    fn print_generic_args(&mut self,
+                             generic_args: &hir::GenericArgs,
                              infer_types: bool,
                              colons_before_params: bool)
                              -> io::Result<()> {
-        if parameters.parenthesized {
+        if generic_args.parenthesized {
             self.s.word("(")?;
-            self.commasep(Inconsistent, parameters.inputs(), |s, ty| s.print_type(&ty))?;
+            self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(&ty))?;
             self.s.word(")")?;
 
             self.space_if_not_bol()?;
             self.word_space("->")?;
-            self.print_type(&parameters.bindings[0].ty)?;
+            self.print_type(&generic_args.bindings[0].ty)?;
         } else {
             let start = if colons_before_params { "::<" } else { "<" };
             let empty = Cell::new(true);
@@ -1731,16 +1727,31 @@ impl<'a> State<'a> {
                 }
             };
 
-            if !parameters.lifetimes.iter().all(|lt| lt.is_elided()) {
-                for lifetime in &parameters.lifetimes {
-                    start_or_comma(self)?;
-                    self.print_lifetime(lifetime)?;
+            let mut types = vec![];
+            let mut elide_lifetimes = true;
+            for arg in &generic_args.args {
+                match arg {
+                    GenericArg::Lifetime(lt) => {
+                        if !lt.is_elided() {
+                            elide_lifetimes = false;
+                        }
+                    }
+                    GenericArg::Type(ty) => {
+                        types.push(ty);
+                    }
                 }
             }
-
-            if !parameters.types.is_empty() {
+            if !elide_lifetimes {
+                start_or_comma(self)?;
+                self.commasep(Inconsistent, &generic_args.args, |s, generic_arg| {
+                    match generic_arg {
+                        GenericArg::Lifetime(lt) => s.print_lifetime(lt),
+                        GenericArg::Type(ty) => s.print_type(ty),
+                    }
+                })?;
+            } else if !types.is_empty() {
                 start_or_comma(self)?;
-                self.commasep(Inconsistent, &parameters.types, |s, ty| s.print_type(&ty))?;
+                self.commasep(Inconsistent, &types, |s, ty| s.print_type(&ty))?;
             }
 
             // FIXME(eddyb) This would leak into error messages, e.g.:
@@ -1750,7 +1761,7 @@ impl<'a> State<'a> {
                 self.s.word("..")?;
             }
 
-            for binding in parameters.bindings.iter() {
+            for binding in generic_args.bindings.iter() {
                 start_or_comma(self)?;
                 self.print_name(binding.name)?;
                 self.s.space()?;
@@ -2060,7 +2071,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io::Result<()> {
+    pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::GenericBound]) -> io::Result<()> {
         if !bounds.is_empty() {
             self.s.word(prefix)?;
             let mut first = true;
@@ -2075,13 +2086,13 @@ impl<'a> State<'a> {
                 }
 
                 match bound {
-                    TraitTyParamBound(tref, modifier) => {
+                    GenericBound::Trait(tref, modifier) => {
                         if modifier == &TraitBoundModifier::Maybe {
                             self.s.word("?")?;
                         }
                         self.print_poly_trait_ref(tref)?;
                     }
-                    RegionTyParamBound(lt) => {
+                    GenericBound::Outlives(lt) => {
                         self.print_lifetime(lt)?;
                     }
                 }
@@ -2090,30 +2101,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(">")?;
@@ -2121,19 +2114,41 @@ 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.name())?;
+        match param.kind {
+            GenericParamKind::Lifetime { .. } => {
+                let mut sep = ":";
+                for bound in &param.bounds {
+                    match bound {
+                        GenericBound::Outlives(lt) => {
+                            self.s.word(sep)?;
+                            self.print_lifetime(lt)?;
+                            sep = "+";
+                        }
+                        _ => bug!(),
+                    }
+                }
+                Ok(())
+            }
+            GenericParamKind::Type { ref default, .. } => {
+                self.print_bounds(":", &param.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(());
@@ -2165,7 +2180,12 @@ impl<'a> State<'a> {
                     self.s.word(":")?;
 
                     for (i, bound) in bounds.iter().enumerate() {
-                        self.print_lifetime(bound)?;
+                        match bound {
+                            GenericBound::Outlives(lt) => {
+                                self.print_lifetime(lt)?;
+                            }
+                            _ => bug!(),
+                        }
 
                         if i != 0 {
                             self.s.word(":")?;
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index ed259b28545..882194ae64e 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -142,12 +142,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
     }
 }
 
+impl_stable_hash_for!(enum hir::ParamName {
+    Plain(name),
+    Fresh(index)
+});
+
 impl_stable_hash_for!(enum hir::LifetimeName {
+    Param(param_name),
     Implicit,
     Underscore,
-    Fresh(index),
     Static,
-    Name(name)
 });
 
 impl_stable_hash_for!(struct hir::Label {
@@ -161,13 +165,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,
@@ -177,19 +174,23 @@ impl_stable_hash_for!(struct hir::Path {
 impl_stable_hash_for!(struct hir::PathSegment {
     name,
     infer_types,
-    parameters
+    args
 });
 
-impl_stable_hash_for!(struct hir::PathParameters {
-    lifetimes,
-    types,
+impl_stable_hash_for!(enum hir::GenericArg {
+    Lifetime(lt),
+    Type(ty)
+});
+
+impl_stable_hash_for!(struct hir::GenericArgs {
+    args,
     bindings,
     parenthesized
 });
 
-impl_stable_hash_for!(enum hir::TyParamBound {
-    TraitTyParamBound(poly_trait_ref, trait_bound_modifier),
-    RegionTyParamBound(lifetime)
+impl_stable_hash_for!(enum hir::GenericBound {
+    Trait(poly_trait_ref, trait_bound_modifier),
+    Outlives(lifetime)
 });
 
 impl_stable_hash_for!(enum hir::TraitBoundModifier {
@@ -197,21 +198,32 @@ 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,
+    name,
     span,
     pure_wrt_drop,
-    synthetic,
-    attrs
+    attrs,
+    bounds,
+    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 { in_band } => {
+                in_band.hash_stable(hcx, hasher);
+            }
+            hir::GenericParamKind::Type { ref default, synthetic } => {
+                default.hash_stable(hcx, hasher);
+                synthetic.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..4d6f2fb41b0 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -1036,15 +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
-                            } else {
-                                false
-                            };
+                            let mut has_bounds = false;
+                            if let hir_map::NodeGenericParam(ref param) = hir.get(id) {
+                                has_bounds = !param.bounds.is_empty();
+                            }
                             let sp = hir.span(id);
                             // `sp` only covers `T`, change it so that it covers
                             // `T:` when appropriate
-                            let sp = if has_lifetimes {
+                            let sp = if has_bounds {
                                 sp.to(self.tcx
                                     .sess
                                     .codemap()
@@ -1052,7 +1051,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             } else {
                                 sp
                             };
-                            (sp, has_lifetimes)
+                            (sp, has_bounds)
                         })
                     } else {
                         None
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 40cf78edaec..7f81af7e46c 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -20,7 +20,7 @@ use hir::map as hir_map;
 use hir::def::Def;
 use hir::def_id::{DefId, CrateNum};
 use rustc_data_structures::sync::Lrc;
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, GenericParamDefKind};
 use ty::query::Providers;
 use middle::privacy;
 use session::config;
@@ -37,21 +37,30 @@ use hir::intravisit;
 
 // Returns true if the given set of generics implies that the item it's
 // associated with must be inlined.
-fn generics_require_inlining(generics: &hir::Generics) -> bool {
-    generics.params.iter().any(|param| param.is_type_param())
+fn generics_require_inlining(generics: &ty::Generics) -> bool {
+    for param in &generics.params {
+        match param.kind {
+            GenericParamDefKind::Lifetime { .. } => {}
+            GenericParamDefKind::Type { .. } => return true,
+        }
+    }
+    false
 }
 
 // Returns true if the given item must be inlined because it may be
 // monomorphized or it was marked with `#[inline]`. This will only return
 // true for functions.
-fn item_might_be_inlined(item: &hir::Item, attrs: CodegenFnAttrs) -> bool {
+fn item_might_be_inlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                         item: &hir::Item,
+                         attrs: CodegenFnAttrs) -> bool {
     if attrs.requests_inline() {
         return true
     }
 
     match item.node {
-        hir::ItemImpl(_, _, _, ref generics, ..) |
-        hir::ItemFn(.., ref generics, _) => {
+        hir::ItemImpl(..) |
+        hir::ItemFn(..) => {
+            let generics = tcx.generics_of(tcx.hir.local_def_id(item.id));
             generics_require_inlining(generics)
         }
         _ => false,
@@ -62,14 +71,14 @@ fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      impl_item: &hir::ImplItem,
                                      impl_src: DefId) -> bool {
     let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id.owner_def_id());
-    if codegen_fn_attrs.requests_inline() ||
-        generics_require_inlining(&impl_item.generics) {
+    let generics = tcx.generics_of(tcx.hir.local_def_id(impl_item.id));
+    if codegen_fn_attrs.requests_inline() || generics_require_inlining(generics) {
         return true
     }
     if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) {
         match tcx.hir.find(impl_node_id) {
             Some(hir_map::NodeItem(item)) =>
-                item_might_be_inlined(&item, codegen_fn_attrs),
+                item_might_be_inlined(tcx, &item, codegen_fn_attrs),
             Some(..) | None =>
                 span_bug!(impl_item.span, "impl did is not an item")
         }
@@ -163,7 +172,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             Some(hir_map::NodeItem(item)) => {
                 match item.node {
                     hir::ItemFn(..) =>
-                        item_might_be_inlined(&item, self.tcx.codegen_fn_attrs(def_id)),
+                        item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id)),
                     _ => false,
                 }
             }
@@ -180,7 +189,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ImplItemKind::Const(..) => true,
                     hir::ImplItemKind::Method(..) => {
                         let attrs = self.tcx.codegen_fn_attrs(def_id);
-                        if generics_require_inlining(&impl_item.generics) ||
+                        let generics = self.tcx.generics_of(def_id);
+                        if generics_require_inlining(&generics) ||
                                 attrs.requests_inline() {
                             true
                         } else {
@@ -192,8 +202,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                             // does too.
                             let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap();
                             match self.tcx.hir.expect_item(impl_node_id).node {
-                                hir::ItemImpl(_, _, _, ref generics, ..) => {
-                                    generics_require_inlining(generics)
+                                hir::ItemImpl(..) => {
+                                    let generics = self.tcx.generics_of(impl_did);
+                                    generics_require_inlining(&generics)
                                 }
                                 _ => false
                             }
@@ -251,7 +262,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                 match item.node {
                     hir::ItemFn(.., body) => {
                         let def_id = self.tcx.hir.local_def_id(item.id);
-                        if item_might_be_inlined(&item, self.tcx.codegen_fn_attrs(def_id)) {
+                        if item_might_be_inlined(self.tcx,
+                                                 &item,
+                                                 self.tcx.codegen_fn_attrs(def_id)) {
                             self.visit_nested_body(body);
                         }
                     }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index f251a3d5f38..091662966ea 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -18,8 +18,7 @@
 use hir::def::Def;
 use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use hir::map::Map;
-use hir::ItemLocalId;
-use hir::LifetimeName;
+use hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, ParamName};
 use ty::{self, TyCtxt, GenericParamDefKind};
 
 use errors::DiagnosticBuilder;
@@ -28,15 +27,15 @@ use rustc_data_structures::sync::Lrc;
 use session::Session;
 use std::cell::Cell;
 use std::mem::replace;
-use std::slice;
 use syntax::ast;
 use syntax::attr;
 use syntax::ptr::P;
+use syntax::symbol::keywords;
 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.
 ///
@@ -50,11 +49,16 @@ pub enum LifetimeDefOrigin {
 }
 
 impl LifetimeDefOrigin {
-    fn from_is_in_band(is_in_band: bool) -> Self {
-        if is_in_band {
-            LifetimeDefOrigin::InBand
-        } else {
-            LifetimeDefOrigin::Explicit
+    fn from_param(param: &GenericParam) -> Self {
+        match param.kind {
+            GenericParamKind::Lifetime { in_band } => {
+                if in_band {
+                    LifetimeDefOrigin::InBand
+                } else {
+                    LifetimeDefOrigin::Explicit
+                }
+            }
+            _ => bug!("expected a lifetime param"),
         }
     }
 }
@@ -84,31 +88,27 @@ pub enum Region {
 }
 
 impl Region {
-    fn early(
-        hir_map: &Map,
-        index: &mut u32,
-        def: &hir::LifetimeDef,
-    ) -> (hir::LifetimeName, Region) {
+    fn early(hir_map: &Map, index: &mut u32, param: &GenericParam) -> (ParamName, 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 origin = LifetimeDefOrigin::from_param(param);
         debug!("Region::early: index={} def_id={:?}", i, def_id);
-        (def.lifetime.name, Region::EarlyBound(i, def_id, origin))
+        (param.name, Region::EarlyBound(i, def_id, origin))
     }
 
-    fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) {
+    fn late(hir_map: &Map, param: &GenericParam) -> (ParamName, 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 origin = LifetimeDefOrigin::from_param(param);
         debug!(
-            "Region::late: def={:?} depth={:?} def_id={:?} origin={:?}",
-            def,
+            "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}",
+            param,
             depth,
             def_id,
             origin,
         );
-        (def.lifetime.name, Region::LateBound(depth, def_id, origin))
+        (param.name, Region::LateBound(depth, def_id, origin))
     }
 
     fn late_anon(index: &Cell<u32>) -> Region {
@@ -155,11 +155,10 @@ impl Region {
         }
     }
 
-    fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap) -> Option<Region> {
+    fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option<Region>
+            where L: Iterator<Item = &'a hir::Lifetime>  {
         if let Region::EarlyBound(index, _, _) = self {
-            params
-                .get(index as usize)
-                .and_then(|lifetime| map.defs.get(&lifetime.id).cloned())
+            params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.id).cloned())
         } else {
             Some(self)
         }
@@ -270,7 +269,7 @@ enum Scope<'a> {
     /// it should be shifted by the number of `Binder`s in between the
     /// declaration `Binder` and the location it's referenced from.
     Binder {
-        lifetimes: FxHashMap<hir::LifetimeName, Region>,
+        lifetimes: FxHashMap<hir::ParamName, Region>,
 
         /// if we extend this scope with another scope, what is the next index
         /// we should use for an early-bound region?
@@ -524,14 +523,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 } else {
                     0
                 };
-                let lifetimes = generics
-                    .lifetimes()
-                    .map(|def| Region::early(&self.tcx.hir, &mut index, def))
-                    .collect();
-                let next_early_index = index + generics.ty_params().count() as u32;
+                let mut type_count = 0;
+                let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        Some(Region::early(&self.tcx.hir, &mut index, param))
+                    }
+                    GenericParamKind::Type { .. } => {
+                        type_count += 1;
+                        None
+                    }
+                }).collect();
                 let scope = Scope::Binder {
                     lifetimes,
-                    next_early_index,
+                    next_early_index: index + type_count,
                     abstract_type_parent: true,
                     track_lifetime_uses,
                     s: ROOT_SCOPE,
@@ -568,10 +572,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let was_in_fn_syntax = self.is_in_fn_syntax;
                 self.is_in_fn_syntax = true;
                 let scope = Scope::Binder {
-                    lifetimes: c.generic_params
-                        .lifetimes()
-                        .map(|def| Region::late(&self.tcx.hir, def))
-                        .collect(),
+                    lifetimes: c.generic_params.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,
@@ -603,9 +609,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         // resolved the same as the `'_` in `&'_ Foo`.
                         //
                         // cc #48468
-                        self.resolve_elided_lifetimes(slice::from_ref(lifetime), false)
+                        self.resolve_elided_lifetimes(vec![lifetime], false)
                     }
-                    LifetimeName::Fresh(_) | LifetimeName::Static | LifetimeName::Name(_) => {
+                    LifetimeName::Param(_) | LifetimeName::Static => {
                         // If the user wrote an explicit name, use that.
                         self.visit_lifetime(lifetime);
                     }
@@ -676,18 +682,29 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
                 let mut elision = None;
                 let mut lifetimes = FxHashMap();
-                for lt_def in generics.lifetimes() {
-                    let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, &lt_def);
-                    if let hir::LifetimeName::Underscore = lt_name {
-                        // Pick the elided lifetime "definition" if one exists and use it to make
-                        // an elision scope.
-                        elision = Some(region);
-                    } else {
-                        lifetimes.insert(lt_name, region);
+                let mut type_count = 0;
+                for param in &generics.params {
+                    match param.kind {
+                        GenericParamKind::Lifetime { .. } => {
+                            let (name, reg) = Region::early(&self.tcx.hir, &mut index, &param);
+                            if let hir::ParamName::Plain(param_name) = name {
+                                if param_name == keywords::UnderscoreLifetime.name() {
+                                    // Pick the elided lifetime "definition" if one exists
+                                    // and use it to make an elision scope.
+                                    elision = Some(reg);
+                                } else {
+                                    lifetimes.insert(name, reg);
+                                }
+                            } else {
+                                lifetimes.insert(name, reg);
+                            }
+                        }
+                        GenericParamKind::Type { .. } => {
+                            type_count += 1;
+                        }
                     }
                 }
-
-                let next_early_index = index + generics.ty_params().count() as u32;
+                let next_early_index = index + type_count;
 
                 if let Some(elision_region) = elision {
                     let scope = Scope::Elision {
@@ -705,7 +722,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         this.with(scope, |_old_scope, this| {
                             this.visit_generics(generics);
                             for bound in bounds {
-                                this.visit_ty_param_bound(bound);
+                                this.visit_param_bound(bound);
                             }
                         });
                     });
@@ -720,7 +737,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     self.with(scope, |_old_scope, this| {
                         this.visit_generics(generics);
                         for bound in bounds {
-                            this.visit_ty_param_bound(bound);
+                            this.visit_param_bound(bound);
                         }
                     });
                 }
@@ -745,15 +762,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let generics = &trait_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics
-                    .lifetimes()
-                    .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
-                    .collect();
-
-                let next_early_index = index + generics.ty_params().count() as u32;
+                let mut type_count = 0;
+                let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        Some(Region::early(&self.tcx.hir, &mut index, param))
+                    }
+                    GenericParamKind::Type { .. } => {
+                        type_count += 1;
+                        None
+                    }
+                }).collect();
                 let scope = Scope::Binder {
                     lifetimes,
-                    next_early_index,
+                    next_early_index: index + type_count,
                     s: self.scope,
                     track_lifetime_uses: true,
                     abstract_type_parent: true,
@@ -761,7 +782,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 self.with(scope, |_old_scope, this| {
                     this.visit_generics(generics);
                     for bound in bounds {
-                        this.visit_ty_param_bound(bound);
+                        this.visit_param_bound(bound);
                     }
                     if let Some(ty) = ty {
                         this.visit_ty(ty);
@@ -791,13 +812,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             Type(ref ty) => {
                 let generics = &impl_item.generics;
                 let mut index = self.next_early_index();
+                let mut next_early_index = index;
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics
-                    .lifetimes()
-                    .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
-                    .collect();
-
-                let next_early_index = index + generics.ty_params().count() as u32;
+                let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        Some(Region::early(&self.tcx.hir, &mut index, param))
+                    }
+                    GenericParamKind::Type { .. } => {
+                        next_early_index += 1;
+                        None
+                    }
+                }).collect();
                 let scope = Scope::Binder {
                     lifetimes,
                     next_early_index,
@@ -820,7 +845,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         if lifetime_ref.is_elided() {
-            self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref), false);
+            self.resolve_elided_lifetimes(vec![lifetime_ref], false);
             return;
         }
         if lifetime_ref.is_static() {
@@ -833,8 +858,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
         for (i, segment) in path.segments.iter().enumerate() {
             let depth = path.segments.len() - i - 1;
-            if let Some(ref parameters) = segment.parameters {
-                self.visit_segment_parameters(path.def, depth, parameters);
+            if let Some(ref args) = segment.args {
+                self.visit_segment_args(path.def, depth, args);
             }
         }
     }
@@ -848,14 +873,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
-        check_mixed_explicit_and_in_band_defs(
-            self.tcx,
-            &generics.lifetimes().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);
+        check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params);
+        for param in &generics.params {
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => {}
+                GenericParamKind::Type { ref default, .. } => {
+                    walk_list!(self, visit_param_bound, &param.bounds);
+                    if let Some(ref ty) = default {
+                        self.visit_ty(&ty);
+                    }
+                }
             }
         }
         for predicate in &generics.where_clause.predicates {
@@ -866,14 +893,18 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     ref bound_generic_params,
                     ..
                 }) => {
-                    if bound_generic_params.iter().any(|p| p.is_lifetime_param()) {
+                    let lifetimes: FxHashMap<_, _> = bound_generic_params.iter()
+                        .filter_map(|param| match param.kind {
+                            GenericParamKind::Lifetime { .. } => {
+                                Some(Region::late(&self.tcx.hir, param))
+                            }
+                            _ => None,
+                        }).collect();
+                    if !lifetimes.is_empty() {
                         self.trait_ref_hack = true;
                         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))
-                                .collect(),
+                            lifetimes,
                             s: self.scope,
                             next_early_index,
                             track_lifetime_uses: true,
@@ -882,13 +913,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         let result = self.with(scope, |old_scope, this| {
                             this.check_lifetime_params(old_scope, &bound_generic_params);
                             this.visit_ty(&bounded_ty);
-                            walk_list!(this, visit_ty_param_bound, bounds);
+                            walk_list!(this, visit_param_bound, bounds);
                         });
                         self.trait_ref_hack = false;
                         result
                     } else {
                         self.visit_ty(&bounded_ty);
-                        walk_list!(self, visit_ty_param_bound, bounds);
+                        walk_list!(self, visit_param_bound, bounds);
                     }
                 }
                 &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
@@ -897,9 +928,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     ..
                 }) => {
                     self.visit_lifetime(lifetime);
-                    for bound in bounds {
-                        self.visit_lifetime(bound);
-                    }
+                    walk_list!(self, visit_param_bound, bounds);
                 }
                 &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                     ref lhs_ty,
@@ -924,7 +953,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             || trait_ref
                 .bound_generic_params
                 .iter()
-                .any(|p| p.is_lifetime_param())
+                .any(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => true,
+                    _ => false,
+                })
         {
             if self.trait_ref_hack {
                 span_err!(
@@ -936,11 +968,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             }
             let next_early_index = self.next_early_index();
             let scope = Scope::Binder {
-                lifetimes: trait_ref
-                    .bound_generic_params
-                    .lifetimes()
-                    .map(|def| Region::late(&self.tcx.hir, def))
-                    .collect(),
+                lifetimes: trait_ref.bound_generic_params.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,
@@ -989,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,
     }
 }
 
@@ -1007,23 +1041,27 @@ impl ShadowKind {
 
 fn check_mixed_explicit_and_in_band_defs(
     tcx: TyCtxt<'_, '_, '_>,
-    lifetime_defs: &[hir::LifetimeDef],
+    params: &P<[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);
-
-    if let (Some(oob_def), Some(in_band_def)) = (oob_def, in_band_def) {
+    let in_bands: Vec<_> = params.iter().filter_map(|param| match param.kind {
+        GenericParamKind::Lifetime { in_band, .. } => Some((in_band, param.span)),
+        _ => None,
+    }).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((_, 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();
     }
 }
 
@@ -1138,7 +1176,8 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
                     ref lifetimes, s, ..
                 } => {
                     // FIXME (#24278): non-hygienic comparison
-                    if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
+                    let param_name = hir::ParamName::Plain(label);
+                    if let Some(def) = lifetimes.get(&param_name) {
                         let node_id = tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
 
                         signal_shadowing_problem(
@@ -1176,14 +1215,18 @@ fn compute_object_lifetime_defaults(
                         .map(|set| match *set {
                             Set1::Empty => "BaseDefault".to_string(),
                             Set1::One(Region::Static) => "'static".to_string(),
-                            Set1::One(Region::EarlyBound(i, _, _)) => generics
-                                .lifetimes()
-                                .nth(i as usize)
-                                .unwrap()
-                                .lifetime
-                                .name
-                                .name()
-                                .to_string(),
+                            Set1::One(Region::EarlyBound(mut i, _, _)) => {
+                                generics.params.iter().find_map(|param| match param.kind {
+                                        GenericParamKind::Lifetime { .. } => {
+                                            if i == 0 {
+                                                return Some(param.name.name().to_string());
+                                            }
+                                            i -= 1;
+                                            None
+                                        }
+                                        _ => None,
+                                    }).unwrap()
+                            }
                             Set1::One(_) => bug!(),
                             Set1::Many => "Ambiguous".to_string(),
                         })
@@ -1207,17 +1250,17 @@ fn object_lifetime_defaults_for_item(
     tcx: TyCtxt<'_, '_, '_>,
     generics: &hir::Generics,
 ) -> Vec<ObjectLifetimeDefault> {
-    fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::TyParamBound]) {
+    fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound]) {
         for bound in bounds {
-            if let hir::RegionTyParamBound(ref lifetime) = *bound {
+            if let hir::GenericBound::Outlives(ref lifetime) = *bound {
                 set.insert(lifetime.name);
             }
         }
     }
 
-    generics
-        .ty_params()
-        .map(|param| {
+    generics.params.iter().filter_map(|param| match param.kind {
+        GenericParamKind::Lifetime { .. } => None,
+        GenericParamKind::Type { .. } => {
             let mut set = Set1::Empty;
 
             add_bounds(&mut set, &param.bounds);
@@ -1246,27 +1289,35 @@ fn object_lifetime_defaults_for_item(
                 }
             }
 
-            match set {
+            Some(match set {
                 Set1::Empty => Set1::Empty,
                 Set1::One(name) => {
                     if name == hir::LifetimeName::Static {
                         Set1::One(Region::Static)
                     } else {
-                        generics
-                            .lifetimes()
-                            .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);
-                                Set1::One(Region::EarlyBound(i as u32, def_id, origin))
-                            })
+                        generics.params.iter().filter_map(|param| match param.kind {
+                            GenericParamKind::Lifetime { .. } => {
+                                Some((
+                                    param.id,
+                                    hir::LifetimeName::Param(param.name),
+                                    LifetimeDefOrigin::from_param(param),
+                                ))
+                            }
+                            _ => None,
+                        })
+                        .enumerate()
+                        .find(|&(_, (_, lt_name, _))| lt_name == name)
+                        .map_or(Set1::Many, |(i, (id, _, origin))| {
+                            let def_id = tcx.hir.local_def_id(id);
+                            Set1::One(Region::EarlyBound(i as u32, def_id, origin))
+                        })
                     }
                 }
                 Set1::Many => Set1::Many,
-            }
-        })
-        .collect()
+            })
+        }
+    })
+    .collect()
 }
 
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
@@ -1346,25 +1397,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 Some(LifetimeUseSet::One(_)) => {
                     let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                     debug!("node id first={:?}", node_id);
-                    if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
-                        let span = hir_lifetime.span;
-                        let id = hir_lifetime.id;
-                        debug!(
-                            "id ={:?} span = {:?} hir_lifetime = {:?}",
-                            node_id, span, hir_lifetime
-                        );
-
-                        self.tcx
-                            .struct_span_lint_node(
-                                lint::builtin::SINGLE_USE_LIFETIMES,
-                                id,
-                                span,
-                                &format!(
-                                    "lifetime parameter `{}` only used once",
-                                    hir_lifetime.name.name()
-                                ),
-                            )
-                            .emit();
+                    if let Some((id, span, name)) = match self.tcx.hir.get(node_id) {
+                        hir::map::NodeLifetime(hir_lifetime) => {
+                            Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.name()))
+                        }
+                        hir::map::NodeGenericParam(param) => {
+                            Some((param.id, param.span, param.name.name()))
+                        }
+                        _ => None,
+                    } {
+                        debug!("id = {:?} span = {:?} name = {:?}", node_id, span, name);
+                        self.tcx.struct_span_lint_node(
+                            lint::builtin::SINGLE_USE_LIFETIMES,
+                            id,
+                            span,
+                            &format!("lifetime parameter `{}` only used once", name),
+                        ).emit();
                     }
                 }
                 Some(LifetimeUseSet::Many) => {
@@ -1372,21 +1420,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 }
                 None => {
                     let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
-                    if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
-                        let span = hir_lifetime.span;
-                        let id = hir_lifetime.id;
-
-                        self.tcx
-                            .struct_span_lint_node(
-                                lint::builtin::UNUSED_LIFETIMES,
-                                id,
-                                span,
-                                &format!(
-                                    "lifetime parameter `{}` never used",
-                                    hir_lifetime.name.name()
-                                ),
-                            )
-                            .emit();
+                    if let Some((id, span, name)) = match self.tcx.hir.get(node_id) {
+                        hir::map::NodeLifetime(hir_lifetime) => {
+                            Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.name()))
+                        }
+                        hir::map::NodeGenericParam(param) => {
+                            Some((param.id, param.span, param.name.name()))
+                        }
+                        _ => None,
+                    } {
+                        debug!("id ={:?} span = {:?} name = {:?}", node_id, span, name);
+                        self.tcx.struct_span_lint_node(
+                            lint::builtin::UNUSED_LIFETIMES,
+                            id,
+                            span,
+                            &format!("lifetime parameter `{}` never used", name)
+                        ).emit();
                     }
                 }
             }
@@ -1438,18 +1487,21 @@ 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)
+        let mut type_count = 0;
+        let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+            GenericParamKind::Lifetime { .. } => {
+                if self.map.late_bound.contains(&param.id) {
+                    Some(Region::late(&self.tcx.hir, param))
                 } else {
-                    Region::early(&self.tcx.hir, &mut index, def)
+                    Some(Region::early(&self.tcx.hir, &mut index, param))
                 }
-            })
-            .collect();
-
-        let next_early_index = index + generics.ty_params().count() as u32;
+            }
+            GenericParamKind::Type { .. } => {
+                type_count += 1;
+                None
+            }
+        }).collect();
+        let next_early_index = index + type_count;
 
         let scope = Scope::Binder {
             lifetimes,
@@ -1521,10 +1573,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     break None;
                 }
 
-                Scope::Binder {
-                    ref lifetimes, s, ..
-                } => {
-                    if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
+                Scope::Binder { ref lifetimes, s, .. } => {
+                    let name = match lifetime_ref.name {
+                        LifetimeName::Param(param_name) => param_name,
+                        _ => bug!("expected LifetimeName::Param"),
+                    };
+                    if let Some(&def) = lifetimes.get(&name) {
                         break Some(def.shifted(late_depth));
                     } else {
                         late_depth += 1;
@@ -1599,26 +1653,35 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn visit_segment_parameters(
+    fn visit_segment_args(
         &mut self,
         def: Def,
         depth: usize,
-        params: &'tcx hir::PathParameters,
+        generic_args: &'tcx hir::GenericArgs,
     ) {
-        if params.parenthesized {
+        if generic_args.parenthesized {
             let was_in_fn_syntax = self.is_in_fn_syntax;
             self.is_in_fn_syntax = true;
-            self.visit_fn_like_elision(params.inputs(), Some(&params.bindings[0].ty));
+            self.visit_fn_like_elision(generic_args.inputs(),
+                                       Some(&generic_args.bindings[0].ty));
             self.is_in_fn_syntax = was_in_fn_syntax;
             return;
         }
 
-        if params.lifetimes.iter().all(|l| l.is_elided()) {
-            self.resolve_elided_lifetimes(&params.lifetimes, true);
-        } else {
-            for l in &params.lifetimes {
-                self.visit_lifetime(l);
+        let mut elide_lifetimes = true;
+        let lifetimes = generic_args.args.iter().filter_map(|arg| match arg {
+            hir::GenericArg::Lifetime(lt) => {
+                if !lt.is_elided() {
+                    elide_lifetimes = false;
+                }
+                Some(lt)
             }
+            _ => None,
+        }).collect();
+        if elide_lifetimes {
+            self.resolve_elided_lifetimes(lifetimes, true);
+        } else {
+            lifetimes.iter().for_each(|lt| self.visit_lifetime(lt));
         }
 
         // Figure out if this is a type/trait segment,
@@ -1680,33 +1743,45 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         }).collect()
                     })
             };
-            unsubst
-                .iter()
-                .map(|set| match *set {
-                    Set1::Empty => if in_body {
-                        None
-                    } else {
-                        Some(Region::Static)
-                    },
-                    Set1::One(r) => r.subst(&params.lifetimes, map),
-                    Set1::Many => None,
-                })
-                .collect()
+            unsubst.iter()
+                   .map(|set| match *set {
+                       Set1::Empty => if in_body {
+                           None
+                       } else {
+                           Some(Region::Static)
+                       },
+                       Set1::One(r) => {
+                           let lifetimes = generic_args.args.iter().filter_map(|arg| match arg {
+                               GenericArg::Lifetime(lt) => Some(lt),
+                               _ => None,
+                           });
+                           r.subst(lifetimes, map)
+                       }
+                       Set1::Many => None,
+                   })
+                   .collect()
         });
 
-        for (i, ty) in params.types.iter().enumerate() {
-            if let Some(&lt) = object_lifetime_defaults.get(i) {
-                let scope = Scope::ObjectLifetimeDefault {
-                    lifetime: lt,
-                    s: self.scope,
-                };
-                self.with(scope, |_, this| this.visit_ty(ty));
-            } else {
-                self.visit_ty(ty);
+        let mut i = 0;
+        for arg in &generic_args.args {
+            match arg {
+                GenericArg::Lifetime(_) => {}
+                GenericArg::Type(ty) => {
+                    if let Some(&lt) = object_lifetime_defaults.get(i) {
+                        let scope = Scope::ObjectLifetimeDefault {
+                            lifetime: lt,
+                            s: self.scope,
+                        };
+                        self.with(scope, |_, this| this.visit_ty(ty));
+                    } else {
+                        self.visit_ty(ty);
+                    }
+                    i += 1;
+                }
             }
         }
 
-        for b in &params.bindings {
+        for b in &generic_args.bindings {
             self.visit_assoc_type_binding(b);
         }
     }
@@ -1944,7 +2019,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;
@@ -1981,7 +2056,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime], deprecated: bool) {
+    fn resolve_elided_lifetimes(&mut self,
+                                lifetime_refs: Vec<&'tcx hir::Lifetime>,
+                                deprecated: bool) {
         if lifetime_refs.is_empty() {
             return;
         }
@@ -2159,100 +2236,99 @@ 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 {
-                hir::LifetimeName::Static | hir::LifetimeName::Underscore => {
-                    let lifetime = lifetime_i.lifetime;
-                    let name = lifetime.name.name();
+        let lifetimes: Vec<_> = params.iter().filter_map(|param| match param.kind {
+            GenericParamKind::Lifetime { .. } => Some((param, param.name)),
+            _ => None,
+        }).collect();
+        for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() {
+            if let hir::ParamName::Plain(_) = lifetime_i_name {
+                let name = lifetime_i_name.name();
+                if name == keywords::UnderscoreLifetime.name() ||
+                   name == keywords::StaticLifetime.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();
                 }
-                hir::LifetimeName::Fresh(_)
-                | hir::LifetimeName::Implicit
-                | hir::LifetimeName::Name(_) => {}
             }
 
             // 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")
-                        .emit();
+                        lifetime_j.name.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 {
-                match bound.name {
-                    hir::LifetimeName::Underscore => {
-                        let mut err = struct_span_err!(
-                            self.tcx.sess,
-                            bound.span,
-                            E0637,
-                            "invalid lifetime bound name: `'_`"
-                        );
-                        err.span_label(bound.span, "`'_` is a reserved lifetime name");
-                        err.emit();
-                    }
-                    hir::LifetimeName::Static => {
-                        self.insert_lifetime(bound, Region::Static);
-                        self.tcx
-                            .sess
-                            .struct_span_warn(
-                                lifetime_i.lifetime.span.to(bound.span),
+                match bound {
+                    hir::GenericBound::Outlives(lt) => match lt.name {
+                        hir::LifetimeName::Underscore => {
+                            let mut err = struct_span_err!(
+                                self.tcx.sess,
+                                lt.span,
+                                E0637,
+                                "invalid lifetime bound name: `'_`"
+                            );
+                            err.span_label(lt.span, "`'_` is a reserved lifetime name");
+                            err.emit();
+                        }
+                        hir::LifetimeName::Static => {
+                            self.insert_lifetime(lt, Region::Static);
+                            self.tcx.sess.struct_span_warn(
+                                lifetime_i.span.to(lt.span),
                                 &format!(
                                     "unnecessary lifetime parameter `{}`",
-                                    lifetime_i.lifetime.name.name()
+                                    lifetime_i.name.name(),
                                 ),
-                            )
-                            .help(&format!(
+                            ).help(&format!(
                                 "you can use the `'static` lifetime directly, in place \
-                                 of `{}`",
-                                lifetime_i.lifetime.name.name()
-                            ))
-                            .emit();
-                    }
-                    hir::LifetimeName::Fresh(_)
-                    | hir::LifetimeName::Implicit
-                    | hir::LifetimeName::Name(_) => {
-                        self.resolve_lifetime_ref(bound);
+                                    of `{}`",
+                                lifetime_i.name.name(),
+                            )).emit();
+                        }
+                        hir::LifetimeName::Param(_)
+                        | hir::LifetimeName::Implicit => {
+                            self.resolve_lifetime_ref(lt);
+                        }
                     }
+                    _ => bug!(),
                 }
             }
         }
     }
 
-    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.name() == label {
                 signal_shadowing_problem(
                     self.tcx,
                     label,
                     original_label(label_span),
-                    shadower_lifetime(&lifetime),
+                    shadower_lifetime(&param),
                 );
                 return;
             }
@@ -2273,14 +2349,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(&param.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.name(),
                             original_lifetime(self.tcx.hir.span(node_id)),
-                            shadower_lifetime(&lifetime),
+                            shadower_lifetime(&param),
                         );
                         return;
                     }
@@ -2428,14 +2504,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 { .. } => {
+                if !param.bounds.is_empty() {
                     // `'a: 'b` means both `'a` and `'b` are referenced
-                    appears_in_where_clause.regions.insert(lifetime_def.lifetime.name);
+                    appears_in_where_clause.regions.insert(hir::LifetimeName::Param(param.name));
                 }
             }
-            hir::GenericParam::Type(_) => {}
+            hir::GenericParamKind::Type { .. } => {}
         }
     }
 
@@ -2448,33 +2524,26 @@ fn insert_late_bound_lifetimes(
     // - appear in the inputs
     // - do not appear in the where-clauses
     // - are not implicitly captured by `impl Trait`
-    for lifetime in generics.lifetimes() {
-        let name = lifetime.lifetime.name;
-
+    for param in &generics.params {
+        let lt_name = hir::LifetimeName::Param(param.name);
         // appears in the where clauses? early-bound.
-        if appears_in_where_clause.regions.contains(&name) {
+        if appears_in_where_clause.regions.contains(&lt_name) {
             continue;
         }
 
         // does not appear in the inputs, but appears in the return type? early-bound.
-        if !constrained_by_input.regions.contains(&name)
-            && appears_in_output.regions.contains(&name)
+        if !constrained_by_input.regions.contains(&lt_name)
+            && appears_in_output.regions.contains(&lt_name)
         {
             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",
+               param.name.name(),
+               param.id);
 
-        let inserted = map.late_bound.insert(lifetime.lifetime.id);
-        assert!(
-            inserted,
-            "visited lifetime {:?} twice",
-            lifetime.lifetime.id
-        );
+        let inserted = map.late_bound.insert(param.id);
+        assert!(inserted, "visited lifetime {:?} twice", param.id);
     }
 
     return;
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index 227cba40d14..f4873979920 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -224,11 +224,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
             let names_map: FxHashSet<String> = generics
                 .params
                 .iter()
-                .filter_map(|param| {
-                    match param.kind {
-                        ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
-                        _ => None
-                    }
+                .filter_map(|param| match param.kind {
+                    ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
+                    _ => None
                 })
                 .collect();
 
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index d858ba7acf7..479fbe2673b 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -215,7 +215,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             data @ DefPathData::ValueNs(..) |
             data @ DefPathData::Module(..) |
             data @ DefPathData::TypeParam(..) |
-            data @ DefPathData::LifetimeDef(..) |
+            data @ DefPathData::LifetimeParam(..) |
             data @ DefPathData::EnumVariant(..) |
             data @ DefPathData::Field(..) |
             data @ DefPathData::AnonConst |
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 883882dfe68..3252a2cd6ab 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -287,7 +287,7 @@ impl PrintContext {
                     DefPathData::MacroDef(_) |
                     DefPathData::ClosureExpr |
                     DefPathData::TypeParam(_) |
-                    DefPathData::LifetimeDef(_) |
+                    DefPathData::LifetimeParam(_) |
                     DefPathData::Field(_) |
                     DefPathData::StructCtor |
                     DefPathData::AnonConst |
@@ -336,12 +336,10 @@ impl PrintContext {
 
             if !verbose {
                 let mut type_params =
-                    generics.params.iter().rev().filter_map(|param| {
-                        match param.kind {
-                            GenericParamDefKind::Type { has_default, .. } => {
-                                Some((param.def_id, has_default))
-                            }
-                            GenericParamDefKind::Lifetime => None,
+                    generics.params.iter().rev().filter_map(|param| match param.kind {
+                        GenericParamDefKind::Lifetime => None,
+                        GenericParamDefKind::Type { has_default, .. } => {
+                            Some((param.def_id, has_default))
                         }
                     }).peekable();
                 let has_default = {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index f1ad14237ee..67720e61e91 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -677,14 +677,20 @@ impl<'a> ReplaceBodyWithLoop<'a> {
                     ast::TyKind::Paren(ref subty) => involves_impl_trait(subty),
                     ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()),
                     ast::TyKind::Path(_, ref path) => path.segments.iter().any(|seg| {
-                        match seg.parameters.as_ref().map(|p| &**p) {
+                        match seg.args.as_ref().map(|generic_arg| &**generic_arg) {
                             None => false,
-                            Some(&ast::PathParameters::AngleBracketed(ref data)) =>
-                                any_involves_impl_trait(data.types.iter()) ||
-                                any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty)),
-                            Some(&ast::PathParameters::Parenthesized(ref data)) =>
+                            Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
+                                let types = data.args.iter().filter_map(|arg| match arg {
+                                    ast::GenericArg::Type(ty) => Some(ty),
+                                    _ => None,
+                                });
+                                any_involves_impl_trait(types.into_iter()) ||
+                                any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty))
+                            },
+                            Some(&ast::GenericArgs::Parenthesized(ref data)) => {
                                 any_involves_impl_trait(data.inputs.iter()) ||
-                                any_involves_impl_trait(data.output.iter()),
+                                any_involves_impl_trait(data.output.iter())
+                            }
                         }
                     }),
                     _ => false,
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index dbf756f80ca..8f8fe04fd8e 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.name(), param.span);
+                }
             }
         }
     }
@@ -253,13 +256,12 @@ 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 { .. } => {
+                let name = param.name.name().as_str();
+                self.check_snake_case(cx, "lifetime", &name, Some(param.span));
+            }
+            GenericParamKind::Type { .. } => {}
         }
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 79796d78871..941fabe26a6 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};
@@ -1196,15 +1196,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
                         }
                         err.emit();
                     }
-                    if generics.is_type_parameterized() {
-                        let mut err = cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS,
-                                                          it.span,
-                                                          "functions generic over \
-                                                           types must be mangled");
-                        err.span_suggestion_short(no_mangle_attr.span,
-                                                  "remove this attribute",
-                                                  "".to_owned());
-                        err.emit();
+                    for param in &generics.params {
+                        match param.kind {
+                            GenericParamKind::Lifetime { .. } => {}
+                            GenericParamKind::Type { .. } => {
+                                let mut err = cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS,
+                                                                  it.span,
+                                                                  "functions generic over \
+                                                                   types must be mangled");
+                                err.span_suggestion_short(no_mangle_attr.span,
+                                                          "remove this attribute",
+                                                          "".to_owned());
+                                err.emit();
+                                break;
+                            }
+                        }
                     }
                 }
             }
@@ -1531,10 +1537,7 @@ 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<_> = param.bounds.iter().map(|b| b.span()).collect();
             if !spans.is_empty() {
                 let mut err = cx.struct_span_lint(
                     TYPE_ALIAS_BOUNDS,
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 2abe361233f..50492ae0737 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -810,52 +810,63 @@ impl LintPass for VariantSizeDifferences {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
-        if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
-            if gens.params.iter().all(|param| param.is_lifetime_param()) {
-                // sizes only make sense for non-generic types
-                let item_def_id = cx.tcx.hir.local_def_id(it.id);
-                let t = cx.tcx.type_of(item_def_id);
-                let ty = cx.tcx.erase_regions(&t);
-                let layout = cx.layout_of(ty).unwrap_or_else(|e| {
-                    bug!("failed to get layout for `{}`: {}", t, e)
-                });
-
-                if let layout::Variants::Tagged { ref variants, ref tag, .. } = layout.variants {
-                    let discr_size = tag.value.size(cx.tcx).bytes();
-
-                    debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
-                      t, layout.size.bytes(), layout);
-
-                    let (largest, slargest, largest_index) = enum_definition.variants
-                        .iter()
-                        .zip(variants)
-                        .map(|(variant, variant_layout)| {
-                            // Subtract the size of the enum discriminant
-                            let bytes = variant_layout.size.bytes()
-                                .saturating_sub(discr_size);
-
-                            debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
-                            bytes
-                        })
-                        .enumerate()
-                        .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
-                            (size, l, idx)
-                        } else if size > s {
-                            (l, size, li)
-                        } else {
-                            (l, s, li)
-                        });
-
-                    // we only warn if the largest variant is at least thrice as large as
-                    // the second-largest.
-                    if largest > slargest * 3 && slargest > 0 {
-                        cx.span_lint(VARIANT_SIZE_DIFFERENCES,
-                                     enum_definition.variants[largest_index].span,
-                                     &format!("enum variant is more than three times larger \
-                                               ({} bytes) than the next largest",
-                                              largest));
+        if let hir::ItemEnum(ref enum_definition, _) = it.node {
+            let item_def_id = cx.tcx.hir.local_def_id(it.id);
+            let generics = cx.tcx.generics_of(item_def_id);
+            for param in &generics.params {
+                match param.kind {
+                    ty::GenericParamDefKind::Lifetime { .. } => {},
+                    ty::GenericParamDefKind::Type { .. } => return,
+                }
+            }
+            // Sizes only make sense for non-generic types.
+            let t = cx.tcx.type_of(item_def_id);
+            let ty = cx.tcx.erase_regions(&t);
+            match cx.layout_of(ty) {
+                Ok(layout) => {
+                    let variants = &layout.variants;
+                    if let layout::Variants::Tagged { ref variants, ref tag, .. } = variants {
+                        let discr_size = tag.value.size(cx.tcx).bytes();
+
+                        debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
+                               t, layout.size.bytes(), layout);
+
+                        let (largest, slargest, largest_index) = enum_definition.variants
+                            .iter()
+                            .zip(variants)
+                            .map(|(variant, variant_layout)| {
+                                // Subtract the size of the enum discriminant.
+                                let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
+
+                                debug!("- variant `{}` is {} bytes large",
+                                       variant.node.name,
+                                       bytes);
+                                bytes
+                            })
+                            .enumerate()
+                            .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
+                                (size, l, idx)
+                            } else if size > s {
+                                (l, size, li)
+                            } else {
+                                (l, s, li)
+                            });
+
+                        // We only warn if the largest variant is at least thrice as large as
+                        // the second-largest.
+                        if largest > slargest * 3 && slargest > 0 {
+                            cx.span_lint(VARIANT_SIZE_DIFFERENCES,
+                                            enum_definition.variants[largest_index].span,
+                                            &format!("enum variant is more than three times \
+                                                      larger ({} bytes) than the next largest",
+                                                     largest));
+                        }
                     }
                 }
+                Err(ty::layout::LayoutError::Unknown(_)) => return,
+                Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => {
+                    bug!("failed to get layout for `{}`: {}", t, err);
+                }
             }
         }
     }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 33d4df1c3a5..cbe9615c693 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1235,10 +1235,14 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                     self.encode_optimized_mir(def_id)
                 }
                 hir::ItemConst(..) => self.encode_optimized_mir(def_id),
-                hir::ItemFn(_, _, constness, _, ref generics, _) => {
-                    let has_tps = generics.ty_params().next().is_some();
+                hir::ItemFn(_, _, constness, ..) => {
+                    let generics = tcx.generics_of(def_id);
+                    let has_types = generics.params.iter().any(|param| match param.kind {
+                        ty::GenericParamDefKind::Type { .. } => true,
+                        _ => false,
+                    });
                     let needs_inline =
-                        (has_tps || tcx.codegen_fn_attrs(def_id).requests_inline()) &&
+                        (has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) &&
                             !self.metadata_output_only();
                     let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
                     if needs_inline || constness == hir::Constness::Const || always_encode_mir {
@@ -1645,11 +1649,15 @@ 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));
-        }
+        generics.params.iter().for_each(|param| 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());
+                let encode_info = IsolatedEncoder::encode_info_for_ty_param;
+                self.record(def_id, encode_info, (def_id, has_default));
+            }
+        });
     }
 
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 7cef8a75aa6..2c58bd8e79b 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -295,7 +295,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
             );
             let label_msg = match pat.node {
                 PatKind::Path(hir::QPath::Resolved(None, ref path))
-                        if path.segments.len() == 1 && path.segments[0].parameters.is_none() => {
+                        if path.segments.len() == 1 && path.segments[0].args.is_none() => {
                     format!("interpreted as a {} pattern, not new variable", path.def.kind_name())
                 }
                 _ => format!("pattern `{}` not covered", pattern_string),
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 96aeb969d89..ef69cb574e0 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1099,14 +1099,12 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                  item: &'tcx hir::Item,
                                                  output: &mut Vec<MonoItem<'tcx>>) {
     match item.node {
-        hir::ItemImpl(_,
-                      _,
-                      _,
-                      ref generics,
-                      ..,
-                      ref impl_item_refs) => {
-            if generics.is_type_parameterized() {
-                return
+        hir::ItemImpl(_, _, _, ref generics, .., ref impl_item_refs) => {
+            for param in &generics.params {
+                match param.kind {
+                    hir::GenericParamKind::Lifetime { .. } => {}
+                    hir::GenericParamKind::Type { .. } => return,
+                }
             }
 
             let impl_def_id = tcx.hir.local_def_id(item.id);
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 39e0a539258..fc54d323b0f 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -99,9 +99,9 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait: bool) {
+    fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
         for bound in bounds {
-            if let TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) = *bound {
+            if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
                 let mut err = self.err_handler().struct_span_err(poly.span,
                                     &format!("`?Trait` is not permitted in {}", where_));
                 if is_trait {
@@ -139,29 +139,22 @@ impl<'a> AstValidator<'a> {
     }
 
     fn check_late_bound_lifetime_defs(&self, params: &Vec<GenericParam>) {
-        // Check: Only lifetime parameters
-        let non_lifetime_param_spans : Vec<_> = params.iter()
-            .filter_map(|param| match *param {
-                GenericParam::Lifetime(_) => None,
-                GenericParam::Type(ref t) => Some(t.ident.span),
-            }).collect();
-        if !non_lifetime_param_spans.is_empty() {
-            self.err_handler().span_err(non_lifetime_param_spans,
-                "only lifetime parameters can be used in this context");
-        }
-
-        // Check: No bounds on lifetime parameters
-        for param in params.iter() {
-            match *param {
-                GenericParam::Lifetime(ref l) => {
-                    if !l.bounds.is_empty() {
-                        let spans: Vec<_> = l.bounds.iter().map(|b| b.ident.span).collect();
-                        self.err_handler().span_err(spans,
-                            "lifetime bounds cannot be used in this context");
+        // Check only lifetime parameters are present and that the lifetime
+        // parameters that are present have no bounds.
+        let non_lt_param_spans: Vec<_> = params.iter().filter_map(|param| match param.kind {
+                GenericParamKind::Lifetime { .. } => {
+                    if !param.bounds.is_empty() {
+                        let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
+                        self.err_handler()
+                            .span_err(spans, "lifetime bounds cannot be used in this context");
                     }
+                    None
                 }
-                GenericParam::Type(_) => {}
-            }
+                _ => Some(param.ident.span),
+            }).collect();
+        if !non_lt_param_spans.is_empty() {
+            self.err_handler().span_err(non_lt_param_spans,
+                "only lifetime parameters can be used in this context");
         }
     }
 }
@@ -197,7 +190,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             TyKind::TraitObject(ref bounds, ..) => {
                 let mut any_lifetime_bounds = false;
                 for bound in bounds {
-                    if let RegionTyParamBound(ref lifetime) = *bound {
+                    if let GenericBound::Outlives(ref lifetime) = *bound {
                         if any_lifetime_bounds {
                             span_err!(self.session, lifetime.ident.span, E0226,
                                       "only a single explicit lifetime bound is permitted");
@@ -210,7 +203,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             TyKind::ImplTrait(ref bounds) => {
                 if !bounds.iter()
-                          .any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
+                          .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) {
                     self.err_handler().span_err(ty.span, "at least one trait must be specified");
                 }
             }
@@ -230,9 +223,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         // }
         // foo!(bar::baz<T>);
         use_tree.prefix.segments.iter().find(|segment| {
-            segment.parameters.is_some()
+            segment.args.is_some()
         }).map(|segment| {
-            self.err_handler().span_err(segment.parameters.as_ref().unwrap().span(),
+            self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
                                         "generic arguments in import path");
         });
 
@@ -300,7 +293,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
                 if is_auto == IsAuto::Yes {
                     // Auto traits cannot have generics, super traits nor contain items.
-                    if generics.is_parameterized() {
+                    if !generics.params.is_empty() {
                         struct_span_err!(self.session, item.span, E0567,
                                         "auto traits cannot have generic parameters").emit();
                     }
@@ -335,22 +328,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::TraitAlias(Generics { ref params, .. }, ..) => {
                 for param in params {
-                    if let GenericParam::Type(TyParam {
-                        ident,
-                        ref bounds,
-                        ref default,
-                        ..
-                    }) = *param
-                    {
-                        if !bounds.is_empty() {
-                            self.err_handler().span_err(ident.span,
-                                                        "type parameters on the left side of a \
-                                                         trait alias cannot be bounded");
-                        }
-                        if !default.is_none() {
-                            self.err_handler().span_err(ident.span,
-                                                        "type parameters on the left side of a \
-                                                         trait alias cannot have defaults");
+                    match param.kind {
+                        GenericParamKind::Lifetime { .. } => {}
+                        GenericParamKind::Type { ref default, .. } => {
+                            if !param.bounds.is_empty() {
+                                self.err_handler()
+                                    .span_err(param.ident.span, "type parameters on the left \
+                                        side of a trait alias cannot be bounded");
+                            }
+                            if !default.is_none() {
+                                self.err_handler()
+                                    .span_err(param.ident.span, "type parameters on the left \
+                                        side of a trait alias cannot have defaults");
+                            }
                         }
                     }
                 }
@@ -398,8 +388,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_vis(&mut self, vis: &'a Visibility) {
         match vis.node {
             VisibilityKind::Restricted { ref path, .. } => {
-                path.segments.iter().find(|segment| segment.parameters.is_some()).map(|segment| {
-                    self.err_handler().span_err(segment.parameters.as_ref().unwrap().span(),
+                path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
+                    self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
                                                 "generic arguments in visibility path");
                 });
             }
@@ -409,41 +399,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_vis(self, vis)
     }
 
-    fn visit_generics(&mut self, g: &'a Generics) {
+    fn visit_generics(&mut self, generics: &'a Generics) {
         let mut seen_non_lifetime_param = false;
         let mut seen_default = None;
-        for param in &g.params {
-            match (param, seen_non_lifetime_param) {
-                (&GenericParam::Lifetime(ref ld), true) => {
+        for param in &generics.params {
+            match (&param.kind, seen_non_lifetime_param) {
+                (GenericParamKind::Lifetime { .. }, true) => {
                     self.err_handler()
-                        .span_err(ld.lifetime.ident.span, "lifetime parameters must be leading");
+                        .span_err(param.ident.span, "lifetime parameters must be leading");
                 },
-                (&GenericParam::Lifetime(_), false) => {}
-                _ => {
+                (GenericParamKind::Lifetime { .. }, false) => {}
+                (GenericParamKind::Type { ref default, .. }, _) => {
                     seen_non_lifetime_param = true;
+                    if default.is_some() {
+                        seen_default = Some(param.ident.span);
+                    } else if let Some(span) = seen_default {
+                        self.err_handler()
+                            .span_err(span, "type parameters with a default must be trailing");
+                        break;
+                    }
                 }
             }
-
-            if let GenericParam::Type(ref ty_param @ TyParam { default: Some(_), .. }) = *param {
-                seen_default = Some(ty_param.ident.span);
-            } else if let Some(span) = seen_default {
-                self.err_handler()
-                    .span_err(span, "type parameters with a default must be trailing");
-                break
-            }
         }
-        for predicate in &g.where_clause.predicates {
+        for predicate in &generics.where_clause.predicates {
             if let WherePredicate::EqPredicate(ref predicate) = *predicate {
                 self.err_handler().span_err(predicate.span, "equality constraints are not yet \
                                                              supported in where clauses (#20041)");
             }
         }
-        visit::walk_generics(self, g)
+        visit::walk_generics(self, generics)
     }
 
     fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        if let GenericParam::Lifetime(ref ld) = *param {
-            self.check_lifetime(ld.lifetime.ident);
+        if let GenericParamKind::Lifetime { .. } = param.kind {
+            self.check_lifetime(param.ident);
         }
         visit::walk_generic_param(self, param);
     }
@@ -521,23 +510,24 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
             visit::walk_ty(self, t);
         }
     }
-    fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a PathParameters) {
-        match *path_parameters {
-            PathParameters::AngleBracketed(ref params) => {
-                for type_ in &params.types {
-                    self.visit_ty(type_);
-                }
-                for type_binding in &params.bindings {
+    fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
+        match *generic_args {
+            GenericArgs::AngleBracketed(ref data) => {
+                data.args.iter().for_each(|arg| match arg {
+                    GenericArg::Type(ty) => self.visit_ty(ty),
+                    _ => {}
+                });
+                for type_binding in &data.bindings {
                     // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
                     // are allowed to contain nested `impl Trait`.
                     self.with_impl_trait(None, |this| visit::walk_ty(this, &type_binding.ty));
                 }
             }
-            PathParameters::Parenthesized(ref params) => {
-                for type_ in &params.inputs {
+            GenericArgs::Parenthesized(ref data) => {
+                for type_ in &data.inputs {
                     self.visit_ty(type_);
                 }
-                if let Some(ref type_) = params.output {
+                if let Some(ref type_) = data.output {
                     // `-> Foo` syntax is essentially an associated type binding,
                     // so it is also allowed to contain nested `impl Trait`.
                     self.with_impl_trait(None, |this| visit::walk_ty(this, type_));
@@ -590,7 +580,7 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
                 //
                 // To implement this, we disallow `impl Trait` from `qself`
                 // (for cases like `<impl Trait>::Foo>`)
-                // but we allow `impl Trait` in `PathParameters`
+                // but we allow `impl Trait` in `GenericArgs`
                 // iff there are no more PathSegments.
                 if let Some(ref qself) = *qself {
                     // `impl Trait` in `qself` is always illegal
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index ba0be974b27..e7b2869dfe6 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -203,9 +203,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_impl_item(self, ii)
     }
 
-    fn visit_ty_param_bound(&mut self, bounds: &'v hir::TyParamBound) {
-        self.record("TyParamBound", Id::None, bounds);
-        hir_visit::walk_ty_param_bound(self, bounds)
+    fn visit_param_bound(&mut self, bounds: &'v hir::GenericBound) {
+        self.record("GenericBound", Id::None, bounds);
+        hir_visit::walk_param_bound(self, bounds)
     }
 
     fn visit_struct_field(&mut self, s: &'v hir::StructField) {
@@ -322,9 +322,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_impl_item(self, ii)
     }
 
-    fn visit_ty_param_bound(&mut self, bounds: &'v ast::TyParamBound) {
-        self.record("TyParamBound", Id::None, bounds);
-        ast_visit::walk_ty_param_bound(self, bounds)
+    fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) {
+        self.record("GenericBound", Id::None, bounds);
+        ast_visit::walk_param_bound(self, bounds)
     }
 
     fn visit_struct_field(&mut self, s: &'v ast::StructField) {
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 291092015b5..de087049267 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};
@@ -1037,9 +1037,8 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
         self.access_levels.is_public(trait_id)
     }
 
-    fn check_ty_param_bound(&mut self,
-                            ty_param_bound: &hir::TyParamBound) {
-        if let hir::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
+    fn check_generic_bound(&mut self, bound: &hir::GenericBound) {
+        if let hir::GenericBound::Trait(ref trait_ref, _) = *bound {
             if self.path_is_private_type(&trait_ref.trait_ref.path) {
                 self.old_error_set.insert(trait_ref.trait_ref.ref_id);
             }
@@ -1101,7 +1100,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                 }
 
                 for bound in bounds.iter() {
-                    self.check_ty_param_bound(bound)
+                    self.check_generic_bound(bound)
                 }
             }
 
@@ -1268,16 +1267,19 @@ 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)
+        generics.params.iter().for_each(|param| match param.kind {
+            GenericParamKind::Lifetime { .. } => {}
+            GenericParamKind::Type { .. } => {
+                for bound in &param.bounds {
+                    self.check_generic_bound(bound);
+                }
             }
-        }
+        });
         for predicate in &generics.where_clause.predicates {
             match predicate {
                 &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
                     for bound in bound_pred.bounds.iter() {
-                        self.check_ty_param_bound(bound)
+                        self.check_generic_bound(bound)
                     }
                 }
                 &hir::WherePredicate::RegionPredicate(_) => {}
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index a2b2096ccaa..e311701ac05 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -56,7 +56,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::visit::{self, FnKind, Visitor};
 use syntax::attr;
 use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
-use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParam, Generics};
+use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
 use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
 use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
 use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
@@ -797,31 +797,41 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         // put all the parameters on the ban list and then remove
         // them one by one as they are processed and become available.
         let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
+        let mut found_default = false;
         default_ban_rib.bindings.extend(generics.params.iter()
-            .filter_map(|p| if let GenericParam::Type(ref tp) = *p { Some(tp) } else { None })
-            .skip_while(|p| p.default.is_none())
-            .map(|p| (Ident::with_empty_ctxt(p.ident.name), Def::Err)));
+            .filter_map(|param| match param.kind {
+                GenericParamKind::Lifetime { .. } => None,
+                GenericParamKind::Type { ref default, .. } => {
+                    if found_default || default.is_some() {
+                        found_default = true;
+                        return Some((Ident::with_empty_ctxt(param.ident.name), Def::Err));
+                    }
+                    None
+                }
+            }));
 
         for param in &generics.params {
-            match *param {
-                GenericParam::Lifetime(_) => self.visit_generic_param(param),
-                GenericParam::Type(ref ty_param) => {
-                    for bound in &ty_param.bounds {
-                        self.visit_ty_param_bound(bound);
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
+                GenericParamKind::Type { ref default, .. } => {
+                    for bound in &param.bounds {
+                        self.visit_param_bound(bound);
                     }
 
-                    if let Some(ref ty) = ty_param.default {
+                    if let Some(ref ty) = default {
                         self.ribs[TypeNS].push(default_ban_rib);
                         self.visit_ty(ty);
                         default_ban_rib = self.ribs[TypeNS].pop().unwrap();
                     }
 
                     // Allow all following defaults to refer to this type parameter.
-                    default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(ty_param.ident.name));
+                    default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
                 }
             }
         }
-        for p in &generics.where_clause.predicates { self.visit_where_predicate(p); }
+        for p in &generics.where_clause.predicates {
+            self.visit_where_predicate(p);
+        }
     }
 }
 
@@ -2066,7 +2076,7 @@ impl<'a> Resolver<'a> {
                     let local_def_id = this.definitions.local_def_id(item.id);
                     this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
-                        walk_list!(this, visit_ty_param_bound, bounds);
+                        walk_list!(this, visit_param_bound, bounds);
 
                         for trait_item in trait_items {
                             this.check_proc_macro_attrs(&trait_item.attrs);
@@ -2109,7 +2119,7 @@ impl<'a> Resolver<'a> {
                     let local_def_id = this.definitions.local_def_id(item.id);
                     this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
-                        walk_list!(this, visit_ty_param_bound, bounds);
+                        walk_list!(this, visit_param_bound, bounds);
                     });
                 });
             }
@@ -2197,10 +2207,11 @@ impl<'a> Resolver<'a> {
             HasTypeParameters(generics, rib_kind) => {
                 let mut function_type_rib = Rib::new(rib_kind);
                 let mut seen_bindings = FxHashMap();
-                for param in &generics.params {
-                    if let GenericParam::Type(ref type_parameter) = *param {
-                        let ident = type_parameter.ident.modern();
-                        debug!("with_type_parameter_rib: {}", type_parameter.id);
+                generics.params.iter().for_each(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {}
+                    GenericParamKind::Type { .. } => {
+                        let ident = param.ident.modern();
+                        debug!("with_type_parameter_rib: {}", param.id);
 
                         if seen_bindings.contains_key(&ident) {
                             let span = seen_bindings.get(&ident).unwrap();
@@ -2208,17 +2219,16 @@ impl<'a> Resolver<'a> {
                                 ident.name,
                                 span,
                             );
-                            resolve_error(self, type_parameter.ident.span, err);
+                            resolve_error(self, param.ident.span, err);
                         }
-                        seen_bindings.entry(ident).or_insert(type_parameter.ident.span);
+                        seen_bindings.entry(ident).or_insert(param.ident.span);
 
-                        // plain insert (no renaming)
-                        let def_id = self.definitions.local_def_id(type_parameter.id);
-                        let def = Def::TyParam(def_id);
+                    // Plain insert (no renaming).
+                    let def = Def::TyParam(self.definitions.local_def_id(param.id));
                         function_type_rib.bindings.insert(ident, def);
-                        self.record_def(type_parameter.id, PathResolution::new(def));
+                        self.record_def(param.id, PathResolution::new(def));
                     }
-                }
+                });
                 self.ribs[TypeNS].push(function_type_rib);
             }
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index de7a3dc5cee..649e8858b09 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -437,8 +437,8 @@ impl<'a> Resolver<'a> {
         let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
         if def != Err(Determinacy::Undetermined) {
             // Do not report duplicated errors on every undetermined resolution.
-            path.segments.iter().find(|segment| segment.parameters.is_some()).map(|segment| {
-                self.session.span_err(segment.parameters.as_ref().unwrap().span(),
+            path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
+                self.session.span_err(segment.args.as_ref().unwrap().span(),
                                       "generic arguments in macro path");
             });
         }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 279ee403cc6..7da5b1668b3 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -370,35 +370,38 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         id: NodeId,
     ) {
         for param in &generics.params {
-            if let ast::GenericParam::Type(ref ty_param) = *param {
-                let param_ss = ty_param.ident.span;
-                let name = escape(self.span.snippet(param_ss));
-                // Append $id to name to make sure each one is unique
-                let qualname = format!("{}::{}${}", prefix, name, id);
-                if !self.span.filter_generated(Some(param_ss), full_span) {
-                    let id = ::id_from_node_id(ty_param.id, &self.save_ctxt);
-                    let span = self.span_from_span(param_ss);
+            match param.kind {
+                ast::GenericParamKind::Lifetime { .. } => {}
+                ast::GenericParamKind::Type { .. } => {
+                    let param_ss = param.ident.span;
+                    let name = escape(self.span.snippet(param_ss));
+                    // Append $id to name to make sure each one is unique.
+                    let qualname = format!("{}::{}${}", prefix, name, id);
+                    if !self.span.filter_generated(Some(param_ss), full_span) {
+                        let id = ::id_from_node_id(param.id, &self.save_ctxt);
+                        let span = self.span_from_span(param_ss);
 
-                    self.dumper.dump_def(
-                        &Access {
-                            public: false,
-                            reachable: false,
-                        },
-                        Def {
-                            kind: DefKind::Type,
-                            id,
-                            span,
-                            name,
-                            qualname,
-                            value: String::new(),
-                            parent: None,
-                            children: vec![],
-                            decl_id: None,
-                            docs: String::new(),
-                            sig: None,
-                            attributes: vec![],
-                        },
-                    );
+                        self.dumper.dump_def(
+                            &Access {
+                                public: false,
+                                reachable: false,
+                            },
+                            Def {
+                                kind: DefKind::Type,
+                                id,
+                                span,
+                                name,
+                                qualname,
+                                value: String::new(),
+                                parent: None,
+                                children: vec![],
+                                decl_id: None,
+                                docs: String::new(),
+                                sig: None,
+                                attributes: vec![],
+                            },
+                        );
+                    }
                 }
             }
         }
@@ -715,7 +718,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         &mut self,
         item: &'l ast::Item,
         generics: &'l ast::Generics,
-        trait_refs: &'l ast::TyParamBounds,
+        trait_refs: &'l ast::GenericBounds,
         methods: &'l [ast::TraitItem],
     ) {
         let name = item.ident.to_string();
@@ -758,10 +761,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         // super-traits
         for super_bound in trait_refs.iter() {
             let trait_ref = match *super_bound {
-                ast::TraitTyParamBound(ref trait_ref, _) => trait_ref,
-                ast::RegionTyParamBound(..) => {
-                    continue;
-                }
+                ast::GenericBound::Trait(ref trait_ref, _) => trait_ref,
+                ast::GenericBound::Outlives(..) => continue,
             };
 
             let trait_ref = &trait_ref.trait_ref;
@@ -818,14 +819,17 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         }
         self.dump_path_ref(id, path);
 
-        // Type parameters
+        // Type arguments
         for seg in &path.segments {
-            if let Some(ref params) = seg.parameters {
-                match **params {
-                    ast::PathParameters::AngleBracketed(ref data) => for t in &data.types {
-                        self.visit_ty(t);
-                    },
-                    ast::PathParameters::Parenthesized(ref data) => {
+            if let Some(ref generic_args) = seg.args {
+                match **generic_args {
+                    ast::GenericArgs::AngleBracketed(ref data) => {
+                        data.args.iter().for_each(|arg| match arg {
+                            ast::GenericArg::Type(ty) => self.visit_ty(ty),
+                            _ => {}
+                        });
+                    }
+                    ast::GenericArgs::Parenthesized(ref data) => {
                         for t in &data.inputs {
                             self.visit_ty(t);
                         }
@@ -905,11 +909,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         }
 
         // Explicit types in the turbo-fish.
-        if let Some(ref params) = seg.parameters {
-            if let ast::PathParameters::AngleBracketed(ref data) = **params {
-                for t in &data.types {
-                    self.visit_ty(t);
-                }
+        if let Some(ref generic_args) = seg.args {
+            if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
+                data.args.iter().for_each(|arg| match arg {
+                    ast::GenericArg::Type(ty) => self.visit_ty(ty),
+                    _ => {}
+                });
             }
         }
 
@@ -1478,18 +1483,19 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
     }
 
     fn visit_generics(&mut self, generics: &'l ast::Generics) {
-        for param in &generics.params {
-            if let ast::GenericParam::Type(ref ty_param) = *param {
-                for bound in ty_param.bounds.iter() {
-                    if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
+        generics.params.iter().for_each(|param| match param.kind {
+            ast::GenericParamKind::Lifetime { .. } => {}
+            ast::GenericParamKind::Type { ref default, .. } => {
+                for bound in &param.bounds {
+                    if let ast::GenericBound::Trait(ref trait_ref, _) = *bound {
                         self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
                     }
                 }
-                if let Some(ref ty) = ty_param.default {
+                if let Some(ref ty) = default {
                     self.visit_ty(&ty);
                 }
             }
-        }
+        });
     }
 
     fn visit_ty(&mut self, t: &'l ast::Ty) {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index f9510970e43..453500d5ab7 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -692,8 +692,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             if path.segments.len() != 1 {
                 return false;
             }
-            if let Some(ref params) = path.segments[0].parameters {
-                if let ast::PathParameters::Parenthesized(_) = **params {
+            if let Some(ref generic_args) = path.segments[0].args {
+                if let ast::GenericArgs::Parenthesized(_) = **generic_args {
                     return true;
                 }
             }
@@ -934,10 +934,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
         sig.push_str(&generics
             .params
             .iter()
-            .map(|param| match *param {
-                ast::GenericParam::Lifetime(ref l) => l.lifetime.ident.name.to_string(),
-                ast::GenericParam::Type(ref t) => t.ident.to_string(),
-            })
+            .map(|param| param.ident.to_string())
             .collect::<Vec<_>>()
             .join(", "));
         sig.push_str("> ");
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index e3545e8f1a9..7f2f0b0c837 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -104,7 +104,7 @@ pub fn assoc_const_signature(
 pub fn assoc_type_signature(
     id: NodeId,
     ident: ast::Ident,
-    bounds: Option<&ast::TyParamBounds>,
+    bounds: Option<&ast::GenericBounds>,
     default: Option<&ast::Ty>,
     scx: &SaveContext,
 ) -> Option<Signature> {
@@ -223,9 +223,9 @@ impl Sig for ast::Ty {
                     text.push_str("for<");
                     text.push_str(&f.generic_params
                         .iter()
-                        .filter_map(|p| match *p {
-                            ast::GenericParam::Lifetime(ref l) => {
-                                Some(l.lifetime.ident.to_string())
+                        .filter_map(|param| match param.kind {
+                            ast::GenericParamKind::Lifetime { .. } => {
+                                Some(param.ident.to_string())
                             }
                             _ => None,
                         })
@@ -617,45 +617,34 @@ impl Sig for ast::Generics {
 
         let mut defs = vec![];
         for param in &self.params {
-            match *param {
-                ast::GenericParam::Lifetime(ref l) => {
-                    let mut l_text = l.lifetime.ident.to_string();
-                    defs.push(SigElement {
-                        id: id_from_node_id(l.lifetime.id, scx),
-                        start: offset + text.len(),
-                        end: offset + text.len() + l_text.len(),
-                    });
-
-                    if !l.bounds.is_empty() {
-                        l_text.push_str(": ");
-                        let bounds = l.bounds
-                            .iter()
-                            .map(|l| l.ident.to_string())
+            let mut param_text = param.ident.to_string();
+            defs.push(SigElement {
+                id: id_from_node_id(param.id, scx),
+                start: offset + text.len(),
+                end: offset + text.len() + param_text.len(),
+            });
+            if !param.bounds.is_empty() {
+                param_text.push_str(": ");
+                match param.kind {
+                    ast::GenericParamKind::Lifetime { .. } => {
+                        let bounds = param.bounds.iter()
+                            .map(|bound| match bound {
+                                ast::GenericBound::Outlives(lt) => lt.ident.to_string(),
+                                _ => panic!(),
+                            })
                             .collect::<Vec<_>>()
                             .join(" + ");
-                        l_text.push_str(&bounds);
+                        param_text.push_str(&bounds);
                         // FIXME add lifetime bounds refs.
                     }
-                    text.push_str(&l_text);
-                    text.push(',');
-                }
-                ast::GenericParam::Type(ref t) => {
-                    let mut t_text = t.ident.to_string();
-                    defs.push(SigElement {
-                        id: id_from_node_id(t.id, scx),
-                        start: offset + text.len(),
-                        end: offset + text.len() + t_text.len(),
-                    });
-
-                    if !t.bounds.is_empty() {
-                        t_text.push_str(": ");
-                        t_text.push_str(&pprust::bounds_to_string(&t.bounds));
+                    ast::GenericParamKind::Type { .. } => {
+                        param_text.push_str(&pprust::bounds_to_string(&param.bounds));
                         // FIXME descend properly into bounds.
                     }
-                    text.push_str(&t_text);
-                    text.push(',');
                 }
             }
+            text.push_str(&param_text);
+            text.push(',');
         }
 
         text.push('>');
@@ -852,7 +841,7 @@ fn name_and_generics(
 fn make_assoc_type_signature(
     id: NodeId,
     ident: ast::Ident,
-    bounds: Option<&ast::TyParamBounds>,
+    bounds: Option<&ast::GenericBounds>,
     default: Option<&ast::Ty>,
     scx: &SaveContext,
 ) -> Result {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 18911b47ed1..f3912c3042d 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -13,7 +13,7 @@
 //! is parameterized by an instance of `AstConv`.
 
 use rustc_data_structures::accumulate_vec::AccumulateVec;
-use hir;
+use hir::{self, GenericArg};
 use hir::def::Def;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
@@ -177,11 +177,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     {
 
         let (substs, assoc_bindings) =
-            item_segment.with_parameters(|parameters| {
+            item_segment.with_generic_args(|generic_args| {
                 self.create_substs_for_ast_path(
                     span,
                     def_id,
-                    parameters,
+                    generic_args,
                     item_segment.infer_types,
                     None)
             });
@@ -199,7 +199,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     fn create_substs_for_ast_path(&self,
         span: Span,
         def_id: DefId,
-        parameters: &hir::PathParameters,
+        generic_args: &hir::GenericArgs,
         infer_types: bool,
         self_ty: Option<Ty<'tcx>>)
         -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
@@ -207,16 +207,26 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let tcx = self.tcx();
 
         debug!("create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \
-               parameters={:?})",
-               def_id, self_ty, parameters);
+               generic_args={:?})",
+               def_id, self_ty, generic_args);
 
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
         // whatever & would get replaced with).
-        let decl_generics = tcx.generics_of(def_id);
-        let ty_provided = parameters.types.len();
-        let lt_provided = parameters.lifetimes.len();
 
+        // FIXME(varkor): Separating out the parameters is messy.
+        let lifetimes: Vec<_> = generic_args.args.iter().filter_map(|arg| match arg {
+            GenericArg::Lifetime(lt) => Some(lt),
+            _ => None,
+        }).collect();
+        let types: Vec<_> = generic_args.args.iter().filter_map(|arg| match arg {
+            GenericArg::Type(ty) => Some(ty),
+            _ => None,
+        }).collect();
+        let lt_provided = lifetimes.len();
+        let ty_provided = types.len();
+
+        let decl_generics = tcx.generics_of(def_id);
         let mut lt_accepted = 0;
         let mut ty_params = ParamRange { required: 0, accepted: 0 };
         for param in &decl_generics.params {
@@ -269,8 +279,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             match param.kind {
                 GenericParamDefKind::Lifetime => {
                     let i = param.index as usize - own_self;
-                    if let Some(lifetime) = parameters.lifetimes.get(i) {
-                        self.ast_region_to_region(lifetime, Some(param)).into()
+                    if let Some(lt) = lifetimes.get(i) {
+                        self.ast_region_to_region(lt, Some(param)).into()
                     } else {
                         tcx.types.re_static.into()
                     }
@@ -286,7 +296,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     let i = i - (lt_accepted + own_self);
                     if i < ty_provided {
                         // A provided type parameter.
-                        self.ast_ty_to_ty(&parameters.types[i]).into()
+                        self.ast_ty_to_ty(&types[i]).into()
                     } else if infer_types {
                         // No type parameters were provided, we can infer all.
                         if !default_needs_object_self(param) {
@@ -330,7 +340,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
         });
 
-        let assoc_bindings = parameters.bindings.iter().map(|binding| {
+        let assoc_bindings = generic_args.bindings.iter().map(|binding| {
             ConvertedBinding {
                 item_name: binding.name,
                 ty: self.ast_ty_to_ty(&binding.ty),
@@ -355,7 +365,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         self_ty: Ty<'tcx>)
         -> ty::TraitRef<'tcx>
     {
-        self.prohibit_type_params(trait_ref.path.segments.split_last().unwrap().1);
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
 
         let trait_def_id = self.trait_def_id(trait_ref);
         self.ast_path_to_mono_trait_ref(trait_ref.path.span,
@@ -389,7 +399,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
 
-        self.prohibit_type_params(trait_ref.path.segments.split_last().unwrap().1);
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
 
         let (substs, assoc_bindings) =
             self.create_substs_for_ast_trait_ref(trait_ref.path.span,
@@ -451,7 +461,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let trait_def = self.tcx().trait_def(trait_def_id);
 
         if !self.tcx().features().unboxed_closures &&
-           trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar {
+            trait_segment.with_generic_args(|generic_args| generic_args.parenthesized)
+            != trait_def.paren_sugar {
             // For now, require that parenthetical notation be used only with `Fn()` etc.
             let msg = if trait_def.paren_sugar {
                 "the precise format of `Fn`-family traits' type parameters is subject to change. \
@@ -463,10 +474,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                              span, GateIssue::Language, msg);
         }
 
-        trait_segment.with_parameters(|parameters| {
+        trait_segment.with_generic_args(|generic_args| {
             self.create_substs_for_ast_path(span,
                                             trait_def_id,
-                                            parameters,
+                                            generic_args,
                                             trait_segment.infer_types,
                                             Some(self_ty))
         })
@@ -866,7 +877,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
 
-        self.prohibit_type_params(slice::from_ref(item_segment));
+        self.prohibit_generics(slice::from_ref(item_segment));
 
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
@@ -943,7 +954,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let tcx = self.tcx();
         let trait_def_id = tcx.parent_def_id(item_def_id).unwrap();
 
-        self.prohibit_type_params(slice::from_ref(item_segment));
+        self.prohibit_generics(slice::from_ref(item_segment));
 
         let self_ty = if let Some(ty) = opt_self_ty {
             ty
@@ -968,25 +979,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         self.normalize_ty(span, tcx.mk_projection(item_def_id, trait_ref.substs))
     }
 
-    pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
+    pub fn prohibit_generics(&self, segments: &[hir::PathSegment]) {
         for segment in segments {
-            segment.with_parameters(|parameters| {
-                for typ in &parameters.types {
-                    struct_span_err!(self.tcx().sess, typ.span, E0109,
-                                     "type parameters are not allowed on this type")
-                        .span_label(typ.span, "type parameter not allowed")
-                        .emit();
-                    break;
-                }
-                for lifetime in &parameters.lifetimes {
-                    struct_span_err!(self.tcx().sess, lifetime.span, E0110,
-                                     "lifetime parameters are not allowed on this type")
-                        .span_label(lifetime.span,
-                                    "lifetime parameter not allowed on this type")
-                        .emit();
-                    break;
+            segment.with_generic_args(|generic_args| {
+                let (mut err_for_lt, mut err_for_ty) = (false, false);
+                for arg in &generic_args.args {
+                    let (mut span_err, span, kind) = match arg {
+                        hir::GenericArg::Lifetime(lt) => {
+                            if err_for_lt { continue }
+                            err_for_lt = true;
+                            (struct_span_err!(self.tcx().sess, lt.span, E0110,
+                                            "lifetime parameters are not allowed on \
+                                                this type"),
+                             lt.span,
+                             "lifetime")
+                        }
+                        hir::GenericArg::Type(ty) => {
+                            if err_for_ty { continue }
+                            err_for_ty = true;
+                            (struct_span_err!(self.tcx().sess, ty.span, E0109,
+                                            "type parameters are not allowed on this type"),
+                             ty.span,
+                             "type")
+                        }
+                    };
+                    span_err.span_label(span, format!("{} parameter not allowed", kind))
+                            .emit();
+                    if err_for_lt && err_for_ty {
+                        break;
+                    }
                 }
-                for binding in &parameters.bindings {
+                for binding in &generic_args.bindings {
                     self.prohibit_projection(binding.span);
                     break;
                 }
@@ -1016,21 +1039,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) |
             Def::Union(did) | Def::TyForeign(did) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_generics(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Def::Variant(did) if permit_variants => {
                 // Convert "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_generics(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span,
                                     tcx.parent_def_id(did).unwrap(),
                                     path.segments.last().unwrap())
             }
             Def::TyParam(did) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_type_params(&path.segments);
+                self.prohibit_generics(&path.segments);
 
                 let node_id = tcx.hir.as_local_node_id(did).unwrap();
                 let item_id = tcx.hir.get_parent_node(node_id);
@@ -1043,18 +1066,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // Self in impl (we know the concrete type).
 
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_type_params(&path.segments);
+                self.prohibit_generics(&path.segments);
 
                 tcx.at(span).type_of(def_id)
             }
             Def::SelfTy(Some(_), None) => {
                 // Self in trait.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_type_params(&path.segments);
+                self.prohibit_generics(&path.segments);
                 tcx.mk_self_type()
             }
             Def::AssociatedTy(def_id) => {
-                self.prohibit_type_params(&path.segments[..path.segments.len()-2]);
+                self.prohibit_generics(&path.segments[..path.segments.len()-2]);
                 self.qpath_to_ty(span,
                                  opt_self_ty,
                                  def_id,
@@ -1063,7 +1086,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             Def::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_type_params(&path.segments);
+                self.prohibit_generics(&path.segments);
                 match prim_ty {
                     hir::TyBool => tcx.types.bool,
                     hir::TyChar => tcx.types.char,
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 808c134e994..5f8955612e1 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;
@@ -728,11 +728,9 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut error_found = false;
     let impl_m_generics = tcx.generics_of(impl_m.def_id);
     let trait_m_generics = tcx.generics_of(trait_m.def_id);
-    let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| {
-        match param.kind {
-            GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
-            GenericParamDefKind::Lifetime => None,
-        }
+    let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
+        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
+        GenericParamDefKind::Lifetime => None,
     });
     let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| {
         match param.kind {
@@ -843,19 +841,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 { .. } => {
                                     if param.id == impl_node_id {
-                                        Some(param)
+                                        Some(&param.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/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index f3a3c30fe5a..36ce01bcd08 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -12,6 +12,7 @@ use super::{probe, MethodCallee};
 
 use astconv::AstConv;
 use check::{FnCtxt, PlaceOp, callee, Needs};
+use hir::GenericArg;
 use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
@@ -59,7 +60,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})",
             unadjusted_self_ty,
             pick,
-            segment.parameters,
+            segment.args,
         );
 
         let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
@@ -316,36 +317,44 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         let method_generics = self.tcx.generics_of(pick.item.def_id);
         let mut fn_segment = Some((segment, method_generics));
         let supress_mismatch = self.fcx.check_impl_trait(self.span, fn_segment);
-        self.fcx.check_path_parameter_count(self.span, &mut fn_segment, true, supress_mismatch);
+        self.fcx.check_generic_arg_count(self.span, &mut fn_segment, true, supress_mismatch);
 
         // Create subst for early-bound lifetime parameters, combining
         // parameters from the type and those from the method.
         assert_eq!(method_generics.parent_count, parent_substs.len());
-        let provided = &segment.parameters;
+        let provided = &segment.args;
         let own_counts = method_generics.own_counts();
         Substs::for_item(self.tcx, pick.item.def_id, |param, _| {
-            let i = param.index as usize;
+            let mut i = param.index as usize;
             if i < parent_substs.len() {
                 parent_substs[i]
             } else {
-                match param.kind {
-                    GenericParamDefKind::Lifetime => {
-                        if let Some(lifetime) = provided.as_ref().and_then(|p| {
-                            p.lifetimes.get(i - parent_substs.len())
-                        }) {
-                            return AstConv::ast_region_to_region(
-                                self.fcx, lifetime, Some(param)).into();
-                        }
-                    }
-                    GenericParamDefKind::Type {..} => {
-                        if let Some(ast_ty) = provided.as_ref().and_then(|p| {
-                            p.types.get(i - parent_substs.len() - own_counts.lifetimes)
-                        }) {
-                            return self.to_ty(ast_ty).into();
+                let (is_lt, is_ty) = match param.kind {
+                    GenericParamDefKind::Lifetime => (true, false),
+                    GenericParamDefKind::Type { .. } => (false, true),
+                };
+                provided.as_ref().and_then(|data| {
+                    for arg in &data.args {
+                        match arg {
+                            GenericArg::Lifetime(lt) if is_lt => {
+                                if i == parent_substs.len() {
+                                    return Some(AstConv::ast_region_to_region(
+                                        self.fcx, lt, Some(param)).into());
+                                }
+                                i -= 1;
+                            }
+                            GenericArg::Lifetime(_) => {}
+                            GenericArg::Type(ty) if is_ty => {
+                                if i == parent_substs.len() + own_counts.lifetimes {
+                                    return Some(self.to_ty(ty).into());
+                                }
+                                i -= 1;
+                            }
+                            GenericArg::Type(_) => {}
                         }
                     }
-                }
-                self.var_for_def(self.span, param)
+                    None
+                }).unwrap_or_else(|| self.var_for_def(self.span, param))
             }
         })
     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b70b61d1915..366420cfcab 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -85,6 +85,7 @@ use self::method::MethodCallee;
 use self::TupleArgumentsFlag::*;
 
 use astconv::AstConv;
+use hir::GenericArg;
 use hir::def::Def;
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use std::slice;
@@ -1260,10 +1261,11 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
       hir::ItemUnion(..) => {
         check_union(tcx, it.id, it.span);
       }
-      hir::ItemTy(_, ref generics) => {
+      hir::ItemTy(..) => {
         let def_id = tcx.hir.local_def_id(it.id);
         let pty_ty = tcx.type_of(def_id);
-        check_bounds_are_used(tcx, generics, pty_ty);
+        let generics = tcx.generics_of(def_id);
+        check_bounds_are_used(tcx, &generics, pty_ty);
       }
       hir::ItemForeignMod(ref m) => {
         check_abi(tcx, it.span, m.abi);
@@ -4740,8 +4742,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::Fn(def_id) |
             Def::Const(def_id) |
             Def::Static(def_id, _) => {
-                fn_segment = Some((segments.last().unwrap(),
-                                   self.tcx.generics_of(def_id)));
+                fn_segment = Some((segments.last().unwrap(), self.tcx.generics_of(def_id)));
             }
 
             // Case 3. Reference to a method or associated const.
@@ -4781,7 +4782,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // errors if type parameters are provided in an inappropriate place.
         let poly_segments = type_segment.is_some() as usize +
                             fn_segment.is_some() as usize;
-        AstConv::prohibit_type_params(self, &segments[..segments.len() - poly_segments]);
+        AstConv::prohibit_generics(self, &segments[..segments.len() - poly_segments]);
 
         match def {
             Def::Local(nid) | Def::Upvar(nid, ..) => {
@@ -4800,8 +4801,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // to add defaults. If the user provided *too many* types, that's
         // a problem.
         let supress_mismatch = self.check_impl_trait(span, fn_segment);
-        self.check_path_parameter_count(span, &mut type_segment, false, supress_mismatch);
-        self.check_path_parameter_count(span, &mut fn_segment, false, supress_mismatch);
+        self.check_generic_arg_count(span, &mut type_segment, false, supress_mismatch);
+        self.check_generic_arg_count(span, &mut fn_segment, false, supress_mismatch);
 
         let (fn_start, has_self) = match (type_segment, fn_segment) {
             (_, Some((_, generics))) => {
@@ -4812,11 +4813,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             (None, None) => (0, false)
         };
+        // FIXME(varkor): Separating out the parameters is messy.
+        let mut lifetimes_type_seg = vec![];
+        let mut types_type_seg = vec![];
+        let mut infer_types_type_seg = true;
+        if let Some((seg, _)) = type_segment {
+            if let Some(ref data) = seg.args {
+                for arg in &data.args {
+                    match arg {
+                        GenericArg::Lifetime(lt) => lifetimes_type_seg.push(lt),
+                        GenericArg::Type(ty) => types_type_seg.push(ty),
+                    }
+                }
+            }
+            infer_types_type_seg = seg.infer_types;
+        }
+
+        let mut lifetimes_fn_seg = vec![];
+        let mut types_fn_seg = vec![];
+        let mut infer_types_fn_seg = true;
+        if let Some((seg, _)) = fn_segment {
+            if let Some(ref data) = seg.args {
+                for arg in &data.args {
+                    match arg {
+                        GenericArg::Lifetime(lt) => lifetimes_fn_seg.push(lt),
+                        GenericArg::Type(ty) => types_fn_seg.push(ty),
+                    }
+                }
+            }
+            infer_types_fn_seg = seg.infer_types;
+        }
+
         let substs = Substs::for_item(self.tcx, def.def_id(), |param, substs| {
             let mut i = param.index as usize;
 
-            let segment = if i < fn_start {
-                if let GenericParamDefKind::Type {..} = param.kind {
+            let (segment, lifetimes, types, infer_types) = if i < fn_start {
+                if let GenericParamDefKind::Type { .. } = param.kind {
                     // Handle Self first, so we can adjust the index to match the AST.
                     if has_self && i == 0 {
                         return opt_self_ty.map(|ty| ty.into()).unwrap_or_else(|| {
@@ -4825,29 +4857,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
                 i -= has_self as usize;
-                type_segment
+                (type_segment, &lifetimes_type_seg, &types_type_seg, infer_types_type_seg)
             } else {
                 i -= fn_start;
-                fn_segment
+                (fn_segment, &lifetimes_fn_seg, &types_fn_seg, infer_types_fn_seg)
             };
 
             match param.kind {
                 GenericParamDefKind::Lifetime => {
-                    let lifetimes = segment.map_or(&[][..], |(s, _)| {
-                        s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
-                    });
-
                     if let Some(lifetime) = lifetimes.get(i) {
                         AstConv::ast_region_to_region(self, lifetime, Some(param)).into()
                     } else {
                         self.re_infer(span, Some(param)).unwrap().into()
                     }
                 }
-                GenericParamDefKind::Type {..} => {
-                    let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
-                        (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
-                    });
-
+                GenericParamDefKind::Type { .. } => {
                     // Skip over the lifetimes in the same segment.
                     if let Some((_, generics)) = segment {
                         i -= generics.own_counts().lifetimes;
@@ -4955,25 +4979,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Report errors if the provided parameters are too few or too many.
-    fn check_path_parameter_count(&self,
-                                  span: Span,
-                                  segment: &mut Option<(&hir::PathSegment, &ty::Generics)>,
-                                  is_method_call: bool,
-                                  supress_mismatch_error: bool) {
+    fn check_generic_arg_count(&self,
+                               span: Span,
+                               segment: &mut Option<(&hir::PathSegment, &ty::Generics)>,
+                               is_method_call: bool,
+                               supress_mismatch_error: bool) {
         let (lifetimes, types, infer_types, bindings) = segment.map_or(
-            (&[][..], &[][..], true, &[][..]),
-            |(s, _)| s.parameters.as_ref().map_or(
-                (&[][..], &[][..], s.infer_types, &[][..]),
-                |p| (&p.lifetimes[..], &p.types[..],
-                     s.infer_types, &p.bindings[..])));
-        let infer_lifetimes = lifetimes.len() == 0;
-
-        let count_lifetime_params = |n| {
-            format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
-        };
-        let count_type_params = |n| {
-            format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
-        };
+            (vec![], vec![], true, &[][..]),
+            |(s, _)| {
+                s.args.as_ref().map_or(
+                    (vec![], vec![], s.infer_types, &[][..]),
+                    |data| {
+                        let (mut lifetimes, mut types) = (vec![], vec![]);
+                        data.args.iter().for_each(|arg| match arg {
+                            GenericArg::Lifetime(lt) => lifetimes.push(lt),
+                            GenericArg::Type(ty) => types.push(ty),
+                        });
+                        (lifetimes, types, s.infer_types, &data.bindings[..])
+                    }
+                )
+            });
 
         // Check provided parameters.
         let ((ty_required, ty_accepted), lt_accepted) =
@@ -4987,9 +5012,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let mut ty_params = ParamRange { required: 0, accepted: 0 };
                 for param in &generics.params {
                     match param.kind {
-                        GenericParamDefKind::Lifetime => {
-                            lt_accepted += 1;
-                        }
+                        GenericParamDefKind::Lifetime => lt_accepted += 1,
                         GenericParamDefKind::Type { has_default, .. } => {
                             ty_params.accepted += 1;
                             if !has_default {
@@ -5006,36 +5029,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 ((ty_params.required, ty_params.accepted), lt_accepted)
             });
 
-        if types.len() > ty_accepted {
-            let span = types[ty_accepted].span;
-            let expected_text = count_type_params(ty_accepted);
-            let actual_text = count_type_params(types.len());
-            struct_span_err!(self.tcx.sess, span, E0087,
-                             "too many type parameters provided: \
-                              expected at most {}, found {}",
-                             expected_text, actual_text)
-                .span_label(span, format!("expected {}", expected_text))
-                .emit();
-
+        let count_type_params = |n| {
+            format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
+        };
+        let expected_text = count_type_params(ty_accepted);
+        let actual_text = count_type_params(types.len());
+        if let Some((mut err, span)) = if types.len() > ty_accepted {
             // To prevent derived errors to accumulate due to extra
             // type parameters, we force instantiate_value_path to
             // use inference variables instead of the provided types.
             *segment = None;
+            let span = types[ty_accepted].span;
+            Some((struct_span_err!(self.tcx.sess, span, E0087,
+                                  "too many type parameters provided: \
+                                  expected at most {}, found {}",
+                                  expected_text, actual_text), span))
         } else if types.len() < ty_required && !infer_types && !supress_mismatch_error {
-            let expected_text = count_type_params(ty_required);
-            let actual_text = count_type_params(types.len());
-            struct_span_err!(self.tcx.sess, span, E0089,
-                             "too few type parameters provided: \
-                              expected {}, found {}",
-                             expected_text, actual_text)
-                .span_label(span, format!("expected {}", expected_text))
-                .emit();
+            Some((struct_span_err!(self.tcx.sess, span, E0089,
+                                  "too few type parameters provided: \
+                                  expected {}, found {}",
+                                  expected_text, actual_text), span))
+        } else {
+            None
+        } {
+            err.span_label(span, format!("expected {}", expected_text)).emit();
         }
 
         if !bindings.is_empty() {
             AstConv::prohibit_projection(self, bindings[0].span);
         }
 
+        let infer_lifetimes = lifetimes.len() == 0;
         // Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
         let has_late_bound_lifetime_defs =
             segment.map_or(None, |(_, generics)| generics.has_late_bound_regions);
@@ -5059,25 +5083,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             return;
         }
 
-        if lifetimes.len() > lt_accepted {
+        let count_lifetime_params = |n| {
+            format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
+        };
+        let expected_text = count_lifetime_params(lt_accepted);
+        let actual_text = count_lifetime_params(lifetimes.len());
+        if let Some((mut err, span)) = if lifetimes.len() > lt_accepted {
             let span = lifetimes[lt_accepted].span;
-            let expected_text = count_lifetime_params(lt_accepted);
-            let actual_text = count_lifetime_params(lifetimes.len());
-            struct_span_err!(self.tcx.sess, span, E0088,
-                             "too many lifetime parameters provided: \
-                              expected at most {}, found {}",
-                             expected_text, actual_text)
-                .span_label(span, format!("expected {}", expected_text))
-                .emit();
+            Some((struct_span_err!(self.tcx.sess, span, E0088,
+                                  "too many lifetime parameters provided: \
+                                  expected at most {}, found {}",
+                                  expected_text, actual_text), span))
         } else if lifetimes.len() < lt_accepted && !infer_lifetimes {
-            let expected_text = count_lifetime_params(lt_accepted);
-            let actual_text = count_lifetime_params(lifetimes.len());
-            struct_span_err!(self.tcx.sess, span, E0090,
-                             "too few lifetime parameters provided: \
-                              expected {}, found {}",
-                             expected_text, actual_text)
-                .span_label(span, format!("expected {}", expected_text))
-                .emit();
+            Some((struct_span_err!(self.tcx.sess, span, E0090,
+                                  "too few lifetime parameters provided: \
+                                  expected {}, found {}",
+                                  expected_text, actual_text), span))
+        } else {
+            None
+        } {
+            err.span_label(span, format!("expected {}", expected_text)).emit();
         }
     }
 
@@ -5088,13 +5113,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         -> bool {
         let segment = segment.map(|(path_segment, generics)| {
             let explicit = !path_segment.infer_types;
-            let impl_trait = generics.params.iter().any(|param| {
-                match param.kind {
-                    ty::GenericParamDefKind::Type {
-                        synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
-                    } => true,
-                    _ => false,
-                }
+            let impl_trait = generics.params.iter().any(|param| match param.kind {
+                ty::GenericParamDefKind::Type {
+                    synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
+                } => true,
+                _ => false,
             });
 
             if explicit && impl_trait {
@@ -5155,34 +5178,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 }
 
 pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       generics: &hir::Generics,
+                                       generics: &ty::Generics,
                                        ty: Ty<'tcx>) {
-    debug!("check_bounds_are_used(n_tps={}, ty={:?})",
-           generics.ty_params().count(),  ty);
-
-    // make a vector of booleans initially false, set to true when used
-    if generics.ty_params().next().is_none() { return; }
-    let mut tps_used = vec![false; generics.ty_params().count()];
+    let own_counts = generics.own_counts();
+    debug!("check_bounds_are_used(n_tps={}, ty={:?})", own_counts.types, ty);
 
-    let lifetime_count = generics.lifetimes().count();
+    if own_counts.types == 0 {
+        return;
+    }
+    // Make a vector of booleans initially false, set to true when used.
+    let mut types_used = vec![false; own_counts.types];
 
     for leaf_ty in ty.walk() {
-        if let ty::TyParam(ty::ParamTy {idx, ..}) = leaf_ty.sty {
+        if let ty::TyParam(ty::ParamTy { idx, .. }) = leaf_ty.sty {
             debug!("Found use of ty param num {}", idx);
-            tps_used[idx as usize - lifetime_count] = true;
+            types_used[idx as usize - own_counts.lifetimes] = true;
         } else if let ty::TyError = leaf_ty.sty {
-            // If there already another error, do not emit an error for not using a type Parameter
+            // If there is already another error, do not emit
+            // an error for not using a type Parameter.
             assert!(tcx.sess.err_count() > 0);
             return;
         }
     }
 
-    for (&used, param) in tps_used.iter().zip(generics.ty_params()) {
+    let types = generics.params.iter().filter(|param| match param.kind {
+        ty::GenericParamDefKind::Type { .. } => true,
+        _ => false,
+    });
+    for (&used, param) in types_used.iter().zip(types) {
         if !used {
-            struct_span_err!(tcx.sess, param.span, E0091,
-                "type parameter `{}` is unused",
-                param.name)
-                .span_label(param.span, "unused type parameter")
+            let id = tcx.hir.as_local_node_id(param.def_id).unwrap();
+            let span = tcx.hir.span(id);
+            struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name)
+                .span_label(span, "unused type parameter")
                 .emit();
         }
     }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7a2c38468e0..b61f09cbaea 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -602,8 +602,8 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
 }
 
 fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    item: &hir::Item,
-                                    ast_generics: &hir::Generics)
+                                           item: &hir::Item,
+                                           hir_generics: &hir::Generics)
 {
     let item_def_id = tcx.hir.local_def_id(item.id);
     let ty = tcx.type_of(item_def_id);
@@ -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 = &hir_generics.params[index];
+        report_bivariance(tcx, param.span, param.name.name());
     }
 }
 
@@ -663,17 +660,12 @@ fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn reject_shadowing_parameters(tcx: TyCtxt, def_id: DefId) {
     let generics = tcx.generics_of(def_id);
     let parent = tcx.generics_of(generics.parent.unwrap());
-    let impl_params: FxHashMap<_, _> =
-        parent.params.iter()
-                     .flat_map(|param| {
-                         match param.kind {
-                             GenericParamDefKind::Lifetime => None,
-                             GenericParamDefKind::Type {..} => Some((param.name, param.def_id)),
-                         }
-                     })
-                     .collect();
-
-    for method_param in generics.params.iter() {
+    let impl_params: FxHashMap<_, _> = parent.params.iter().flat_map(|param| match param.kind {
+        GenericParamDefKind::Lifetime => None,
+        GenericParamDefKind::Type {..} => Some((param.name, param.def_id)),
+    }).collect();
+
+    for method_param in &generics.params {
         match method_param.kind {
             // Shadowing is checked in resolve_lifetime.
             GenericParamDefKind::Lifetime => continue,
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index 4aa876e85b6..5a442881a63 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -35,7 +35,9 @@ 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(|generics| {
+                    generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle")
+                });
                 match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
                     (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
                         span_err!(self.tcx.sess,
@@ -53,13 +55,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..7a4fbc73c2e 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,14 @@ 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 { default: Some(_), .. } => {
+                    let def_id = self.tcx.hir.local_def_id(param.id);
+                    self.tcx.type_of(def_id);
+                }
+                hir::GenericParamKind::Type { .. } => {}
             }
         }
         intravisit::walk_generics(self, generics);
@@ -308,9 +313,12 @@ 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 { .. } if param.id == param_id => Some(&param.bounds),
+                    _ => None
+                })
+                .flat_map(|bounds| bounds.iter())
                 .flat_map(|b| predicates_from_bound(self, ty, b));
 
         let from_where_clauses =
@@ -739,10 +747,15 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             outer_index: ty::INNERMOST,
             has_late_bound_regions: None,
         };
-        for lifetime in generics.lifetimes() {
-            let hir_id = tcx.hir.node_to_hir_id(lifetime.lifetime.id);
-            if tcx.is_late_bound(hir_id) {
-                return Some(lifetime.lifetime.span);
+        for param in &generics.params {
+            match param.kind {
+                GenericParamKind::Lifetime { .. } => {
+                    let hir_id = tcx.hir.node_to_hir_id(param.id);
+                    if tcx.is_late_bound(hir_id) {
+                        return Some(param.span);
+                    }
+                }
+                _ => {},
             }
         }
         visitor.visit_fn_decl(decl);
@@ -883,12 +896,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.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,34 +911,40 @@ 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."));
+    let mut i = 0;
+    params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
+        GenericParamKind::Type { ref default, synthetic, .. } => {
+            if param.name.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."));
+                }
+            }
+
+            let ty_param = ty::GenericParamDef {
+                index: type_start + i as u32,
+                name: param.name.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,
+                },
+            };
+            i += 1;
+            Some(ty_param)
         }
+        _ => None,
     }));
 
     // provide junk type parameter defs - the only place that
@@ -1119,8 +1138,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 => {
@@ -1225,7 +1249,7 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 // Is it marked with ?Sized
 fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
-                                ast_bounds: &[hir::TyParamBound],
+                                ast_bounds: &[hir::GenericBound],
                                 span: Span) -> bool
 {
     let tcx = astconv.tcx();
@@ -1233,7 +1257,7 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
     // Try to find an unbound in bounds.
     let mut unbound = None;
     for ab in ast_bounds {
-        if let &hir::TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = ab  {
+        if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab  {
             if unbound.is_none() {
                 unbound = Some(ptr.trait_ref.clone());
             } else {
@@ -1274,15 +1298,16 @@ 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);
+    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,31 +1435,42 @@ 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.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 { .. } => {
+                param.bounds.iter().for_each(|bound| match bound {
+                    hir::GenericBound::Outlives(lt) => {
+                        let bound = AstConv::ast_region_to_region(&icx, &lt, None);
+                        let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound));
+                        predicates.push(outlives.to_predicate());
+                    }
+                    _ => bug!(),
+                });
+            },
+            _ => 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);
-        index += 1;
-
-        let bounds = compute_bounds(&icx,
-                                    param_ty,
-                                    &param.bounds,
-                                    SizedByDefault::Yes,
-                                    param.span);
-        predicates.extend(bounds.predicates(tcx, param_ty));
+    for param in &ast_generics.params {
+        match param.kind {
+            GenericParamKind::Type { .. } => {
+                let name = param.name.name().as_interned_str();
+                let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
+                index += 1;
+
+                let sized = SizedByDefault::Yes;
+                let bounds = compute_bounds(&icx, param_ty, &param.bounds, sized, param.span);
+                predicates.extend(bounds.predicates(tcx, param_ty));
+            }
+            _ => {}
+        }
     }
 
     // Add in the bounds that appear in the where-clause
@@ -1446,7 +1482,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                 for bound in bound_pred.bounds.iter() {
                     match bound {
-                        &hir::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => {
+                        &hir::GenericBound::Trait(ref poly_trait_ref, _) => {
                             let mut projections = Vec::new();
 
                             let trait_ref =
@@ -1462,7 +1498,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             }
                         }
 
-                        &hir::TyParamBound::RegionTyParamBound(ref lifetime) => {
+                        &hir::GenericBound::Outlives(ref lifetime) => {
                             let region = AstConv::ast_region_to_region(&icx,
                                                                        lifetime,
                                                                        None);
@@ -1476,7 +1512,12 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             &hir::WherePredicate::RegionPredicate(ref region_pred) => {
                 let r1 = AstConv::ast_region_to_region(&icx, &region_pred.lifetime, None);
                 for bound in &region_pred.bounds {
-                    let r2 = AstConv::ast_region_to_region(&icx, bound, None);
+                    let r2 = match bound {
+                        hir::GenericBound::Outlives(lt) => {
+                            AstConv::ast_region_to_region(&icx, lt, None)
+                        }
+                        _ => bug!(),
+                    };
                     let pred = ty::Binder::bind(ty::OutlivesPredicate(r1, r2));
                     predicates.push(ty::Predicate::RegionOutlives(pred))
                 }
@@ -1541,7 +1582,7 @@ pub enum SizedByDefault { Yes, No, }
 /// built-in trait (formerly known as kind): Send.
 pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
                                         param_ty: Ty<'tcx>,
-                                        ast_bounds: &[hir::TyParamBound],
+                                        ast_bounds: &[hir::GenericBound],
                                         sized_by_default: SizedByDefault,
                                         span: Span)
                                         -> Bounds<'tcx>
@@ -1550,22 +1591,16 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
     let mut trait_bounds = vec![];
     for ast_bound in ast_bounds {
         match *ast_bound {
-            hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
-                trait_bounds.push(b);
-            }
-            hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {}
-            hir::RegionTyParamBound(ref l) => {
-                region_bounds.push(l);
-            }
+            hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => trait_bounds.push(b),
+            hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
+            hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
         }
     }
 
     let mut projection_bounds = vec![];
 
     let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
-        astconv.instantiate_poly_trait_ref(bound,
-                                           param_ty,
-                                           &mut projection_bounds)
+        astconv.instantiate_poly_trait_ref(bound, param_ty, &mut projection_bounds)
     }).collect();
 
     let region_bounds = region_bounds.into_iter().map(|r| {
@@ -1588,18 +1623,18 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
     }
 }
 
-/// Converts a specific TyParamBound from the AST into a set of
+/// Converts a specific GenericBound from the AST into a set of
 /// predicates that apply to the self-type. A vector is returned
 /// because this can be anywhere from 0 predicates (`T:?Sized` adds no
 /// predicates) to 1 (`T:Foo`) to many (`T:Bar<X=i32>` adds `T:Bar`
 /// and `<T as Bar>::X == i32`).
 fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
                                param_ty: Ty<'tcx>,
-                               bound: &hir::TyParamBound)
+                               bound: &hir::GenericBound)
                                -> Vec<ty::Predicate<'tcx>>
 {
     match *bound {
-        hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => {
+        hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
             let mut projections = Vec::new();
             let pred = astconv.instantiate_poly_trait_ref(tr,
                                                           param_ty,
@@ -1609,14 +1644,12 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
                        .chain(Some(pred.to_predicate()))
                        .collect()
         }
-        hir::RegionTyParamBound(ref lifetime) => {
+        hir::GenericBound::Outlives(ref lifetime) => {
             let region = astconv.ast_region_to_region(lifetime, None);
             let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region));
             vec![ty::Predicate::TypeOutlives(pred)]
         }
-        hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {
-            Vec::new()
-        }
+        hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => vec![],
     }
 }
 
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index da54eeabdb9..3f7e3529e96 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1501,12 +1501,12 @@ struct Foo {
 "##,
 
 E0131: r##"
-It is not possible to define `main` with type parameters, or even with function
-parameters. When `main` is present, it must take no arguments and return `()`.
+It is not possible to define `main` with generic parameters.
+When `main` is present, it must take no arguments and return `()`.
 Erroneous code example:
 
 ```compile_fail,E0131
-fn main<T>() { // error: main function is not allowed to have type parameters
+fn main<T>() { // error: main function is not allowed to have generic parameters
 }
 ```
 "##,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 80f57adf580..dcc5fa53d2f 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)]
@@ -190,16 +191,9 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         hir::ItemFn(.., ref generics, _) => {
                             let mut error = false;
                             if !generics.params.is_empty() {
-                                let param_type = if generics.is_lt_parameterized() {
-                                    "lifetime"
-                                } else {
-                                    "type"
-                                };
-                                let msg =
-                                    format!("`main` function is not allowed to have {} parameters",
-                                            param_type);
-                                let label =
-                                    format!("`main` cannot have {} parameters", param_type);
+                                let msg = format!("`main` function is not allowed to have generic \
+                                                   parameters");
+                                let label = format!("`main` cannot have generic parameters");
                                 struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
                                     .span_label(generics.span, label)
                                     .emit();
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index da749fca2a9..5c09da90491 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -244,34 +244,32 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
         None
     }
 
-    fn generics_to_path_params(&self, generics: ty::Generics) -> hir::PathParameters {
-        let mut lifetimes = vec![];
-        let mut types = vec![];
+    fn generics_to_path_params(&self, generics: ty::Generics) -> hir::GenericArgs {
+        let mut args = vec![];
 
         for param in generics.params.iter() {
             match param.kind {
                 ty::GenericParamDefKind::Lifetime => {
                     let name = if param.name == "" {
-                        hir::LifetimeName::Static
+                        hir::ParamName::Plain(keywords::StaticLifetime.name())
                     } else {
-                        hir::LifetimeName::Name(param.name.as_symbol())
+                        hir::ParamName::Plain(param.name.as_symbol())
                     };
 
-                    lifetimes.push(hir::Lifetime {
+                    args.push(hir::GenericArg::Lifetime(hir::Lifetime {
                         id: ast::DUMMY_NODE_ID,
                         span: DUMMY_SP,
-                        name,
-                    });
+                        name: hir::LifetimeName::Param(name),
+                    }));
                 }
                 ty::GenericParamDefKind::Type {..} => {
-                    types.push(P(self.ty_param_to_ty(param.clone())));
+                    args.push(hir::GenericArg::Type(P(self.ty_param_to_ty(param.clone()))));
                 }
             }
         }
 
-        hir::PathParameters {
-            lifetimes: HirVec::from_vec(lifetimes),
-            types: HirVec::from_vec(types),
+        hir::GenericArgs {
+            args: HirVec::from_vec(args),
             bindings: HirVec::new(),
             parenthesized: false,
         }
@@ -488,11 +486,8 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
             .iter()
             .flat_map(|(name, lifetime)| {
                 let empty = Vec::new();
-                let bounds: FxHashSet<Lifetime> = finished
-                    .get(name)
-                    .unwrap_or(&empty)
-                    .iter()
-                    .map(|region| self.get_lifetime(region, names_map))
+                let bounds: FxHashSet<GenericBound> = finished.get(name).unwrap_or(&empty).iter()
+                    .map(|region| GenericBound::Outlives(self.get_lifetime(region, names_map)))
                     .collect();
 
                 if bounds.is_empty() {
@@ -523,7 +518,10 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                         // We only care about late bound regions, as we need to add them
                         // to the 'for<>' section
                         &ty::ReLateBound(_, ty::BoundRegion::BrNamed(_, name)) => {
-                            Some(GenericParamDef::Lifetime(Lifetime(name.to_string())))
+                            Some(GenericParamDef {
+                                name: name.to_string(),
+                                kind: GenericParamDefKind::Lifetime,
+                            })
                         }
                         &ty::ReVar(_) | &ty::ReEarlyBound(_) => None,
                         _ => panic!("Unexpected region type {:?}", r),
@@ -535,9 +533,9 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
 
     fn make_final_bounds<'b, 'c, 'cx>(
         &self,
-        ty_to_bounds: FxHashMap<Type, FxHashSet<TyParamBound>>,
+        ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>,
         ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)>,
-        lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<Lifetime>>,
+        lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>,
     ) -> Vec<WherePredicate> {
         ty_to_bounds
             .into_iter()
@@ -555,9 +553,9 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                             let mut new_path = path.clone();
                             let last_segment = new_path.segments.pop().unwrap();
 
-                            let (old_input, old_output) = match last_segment.params {
-                                PathParameters::AngleBracketed { types, .. } => (types, None),
-                                PathParameters::Parenthesized { inputs, output, .. } => {
+                            let (old_input, old_output) = match last_segment.args {
+                                GenericArgs::AngleBracketed { types, .. } => (types, None),
+                                GenericArgs::Parenthesized { inputs, output, .. } => {
                                     (inputs, output)
                                 }
                             };
@@ -569,14 +567,14 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                                 );
                             }
 
-                            let new_params = PathParameters::Parenthesized {
+                            let new_params = GenericArgs::Parenthesized {
                                 inputs: old_input,
                                 output,
                             };
 
                             new_path.segments.push(PathSegment {
                                 name: last_segment.name,
-                                params: new_params,
+                                args: new_params,
                             });
 
                             Type::ResolvedPath {
@@ -588,7 +586,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                         }
                         _ => panic!("Unexpected data: {:?}, {:?}", ty, data),
                     };
-                    bounds.insert(TyParamBound::TraitBound(
+                    bounds.insert(GenericBound::TraitBound(
                         PolyTrait {
                             trait_: new_ty,
                             generic_params: poly_trait.generic_params,
@@ -614,7 +612,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                     .filter(|&(_, ref bounds)| !bounds.is_empty())
                     .map(|(lifetime, bounds)| {
                         let mut bounds_vec = bounds.into_iter().collect();
-                        self.sort_where_lifetimes(&mut bounds_vec);
+                        self.sort_where_bounds(&mut bounds_vec);
                         WherePredicate::RegionPredicate {
                             lifetime,
                             bounds: bounds_vec,
@@ -731,7 +729,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                         // later
 
                         let is_fn = match &mut b {
-                            &mut TyParamBound::TraitBound(ref mut p, _) => {
+                            &mut GenericBound::TraitBound(ref mut p, _) => {
                                 // Insert regions into the for_generics hash map first, to ensure
                                 // that we don't end up with duplicate bounds (e.g. for<'b, 'b>)
                                 for_generics.extend(p.generic_params.clone());
@@ -793,13 +791,13 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
 
                                     // FIXME: Remove this scope when NLL lands
                                     {
-                                        let params =
-                                            &mut new_trait_path.segments.last_mut().unwrap().params;
+                                        let args =
+                                            &mut new_trait_path.segments.last_mut().unwrap().args;
 
-                                        match params {
+                                        match args {
                                             // Convert somethiung like '<T as Iterator::Item> = u8'
                                             // to 'T: Iterator<Item=u8>'
-                                            &mut PathParameters::AngleBracketed {
+                                            &mut GenericArgs::AngleBracketed {
                                                 ref mut bindings,
                                                 ..
                                             } => {
@@ -808,7 +806,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                                                     ty: rhs,
                                                 });
                                             }
-                                            &mut PathParameters::Parenthesized { .. } => {
+                                            &mut GenericArgs::Parenthesized { .. } => {
                                                 existing_predicates.push(
                                                     WherePredicate::EqPredicate {
                                                         lhs: lhs.clone(),
@@ -825,7 +823,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                                         .entry(*ty.clone())
                                         .or_insert_with(|| FxHashSet());
 
-                                    bounds.insert(TyParamBound::TraitBound(
+                                    bounds.insert(GenericBound::TraitBound(
                                         PolyTrait {
                                             trait_: Type::ResolvedPath {
                                                 path: new_trait_path,
@@ -842,7 +840,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                                     // that we don't see a
                                     // duplicate bound like `T: Iterator + Iterator<Item=u8>`
                                     // on the docs page.
-                                    bounds.remove(&TyParamBound::TraitBound(
+                                    bounds.remove(&GenericBound::TraitBound(
                                         PolyTrait {
                                             trait_: *trait_.clone(),
                                             generic_params: Vec::new(),
@@ -869,19 +867,17 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
 
         existing_predicates.extend(final_bounds);
 
-        for p in generic_params.iter_mut() {
-            match p {
-                &mut GenericParamDef::Type(ref mut ty) => {
-                    // We never want something like 'impl<T=Foo>'
-                    ty.default.take();
-
-                    let generic_ty = Type::Generic(ty.name.clone());
-
+        for param in generic_params.iter_mut() {
+            match param.kind {
+                GenericParamDefKind::Type { ref mut default, ref mut bounds, .. } => {
+                    // We never want something like `impl<T=Foo>`.
+                    default.take();
+                    let generic_ty = Type::Generic(param.name.clone());
                     if !has_sized.contains(&generic_ty) {
-                        ty.bounds.insert(0, TyParamBound::maybe_sized(self.cx));
+                        bounds.insert(0, GenericBound::maybe_sized(self.cx));
                     }
                 }
-                GenericParamDef::Lifetime(_) => {}
+                GenericParamDefKind::Lifetime => {}
             }
         }
 
@@ -912,15 +908,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
     // both for visual consistency between 'rustdoc' runs, and to
     // make writing tests much easier
     #[inline]
-    fn sort_where_bounds(&self, mut bounds: &mut Vec<TyParamBound>) {
-        // We should never have identical bounds - and if we do,
-        // they're visually identical as well. Therefore, using
-        // an unstable sort is fine.
-        self.unstable_debug_sort(&mut bounds);
-    }
-
-    #[inline]
-    fn sort_where_lifetimes(&self, mut bounds: &mut Vec<Lifetime>) {
+    fn sort_where_bounds(&self, mut bounds: &mut Vec<GenericBound>) {
         // We should never have identical bounds - and if we do,
         // they're visually identical as well. Therefore, using
         // an unstable sort is fine.
@@ -940,7 +928,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
     // to end users, it makes writing tests much more difficult, as predicates
     // can appear in any order in the final result.
     //
-    // To solve this problem, we sort WherePredicates and TyParamBounds
+    // To solve this problem, we sort WherePredicates and GenericBounds
     // by their Debug string. The thing to keep in mind is that we don't really
     // care what the final order is - we're synthesizing an impl or bound
     // ourselves, so any order can be considered equally valid. By sorting the
@@ -950,7 +938,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
     // Using the Debug impementation for sorting prevents us from needing to
     // write quite a bit of almost entirely useless code (e.g. how should two
     // Types be sorted relative to each other). It also allows us to solve the
-    // problem for both WherePredicates and TyParamBounds at the same time. This
+    // problem for both WherePredicates and GenericBounds at the same time. This
     // approach is probably somewhat slower, but the small number of items
     // involved (impls rarely have more than a few bounds) means that it
     // shouldn't matter in practice.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 80eb2d1e214..114cb0e455d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -374,8 +374,8 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
     let polarity = tcx.impl_polarity(did);
     let trait_ = associated_trait.clean(cx).map(|bound| {
         match bound {
-            clean::TraitBound(polyt, _) => polyt.trait_,
-            clean::RegionBound(..) => unreachable!(),
+            clean::GenericBound::TraitBound(polyt, _) => polyt.trait_,
+            clean::GenericBound::Outlives(..) => unreachable!(),
         }
     });
     if trait_.def_id() == tcx.lang_items().deref_trait() {
@@ -387,9 +387,9 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
 
     let provided = trait_.def_id().map(|did| {
         tcx.provided_trait_methods(did)
-            .into_iter()
-            .map(|meth| meth.name.to_string())
-            .collect()
+           .into_iter()
+           .map(|meth| meth.name.to_string())
+           .collect()
     }).unwrap_or(FxHashSet());
 
     ret.push(clean::Item {
@@ -474,7 +474,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
             } if *s == "Self" => {
                 bounds.retain(|bound| {
                     match *bound {
-                        clean::TyParamBound::TraitBound(clean::PolyTrait {
+                        clean::GenericBound::TraitBound(clean::PolyTrait {
                             trait_: clean::ResolvedPath { did, .. },
                             ..
                         }, _) => did != trait_did,
@@ -505,7 +505,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
 /// the metadata for a crate, so we want to separate those out and create a new
 /// list of explicit supertrait bounds to render nicely.
 fn separate_supertrait_bounds(mut g: clean::Generics)
-                              -> (clean::Generics, Vec<clean::TyParamBound>) {
+                              -> (clean::Generics, Vec<clean::GenericBound>) {
     let mut ty_bounds = Vec::new();
     g.where_predicates.retain(|pred| {
         match *pred {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 852a4479199..0979c3d8558 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -14,7 +14,6 @@
 pub use self::Type::*;
 pub use self::Mutability::*;
 pub use self::ItemEnum::*;
-pub use self::TyParamBound::*;
 pub use self::SelfTy::*;
 pub use self::FunctionRetTy::*;
 pub use self::Visibility::{Public, Inherited};
@@ -36,12 +35,12 @@ use rustc::middle::resolve_lifetime as rl;
 use rustc::ty::fold::TypeFolder;
 use rustc::middle::lang_items;
 use rustc::mir::interpret::GlobalId;
-use rustc::hir::{self, HirVec};
+use rustc::hir::{self, GenericArg, HirVec};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::hir::def_id::DefIndexAddressSpace;
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind, GenericParamCount};
+use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind};
 use rustc::middle::stability;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_typeck::hir_ty_to_ty;
@@ -532,7 +531,7 @@ pub enum ItemEnum {
     MacroItem(Macro),
     PrimitiveItem(PrimitiveType),
     AssociatedConstItem(Type, Option<String>),
-    AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
+    AssociatedTypeItem(Vec<GenericBound>, Option<Type>),
     /// An item that has been stripped by a rustdoc pass
     StrippedItem(Box<ItemEnum>),
     KeywordItem(String),
@@ -1458,61 +1457,19 @@ impl Clean<Attributes> for [ast::Attribute] {
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
-pub struct TyParam {
-    pub name: String,
-    pub did: DefId,
-    pub bounds: Vec<TyParamBound>,
-    pub default: Option<Type>,
-    pub synthetic: Option<hir::SyntheticTyParamKind>,
-}
-
-impl Clean<TyParam> for hir::TyParam {
-    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,
-        }
-    }
+pub enum GenericBound {
+    TraitBound(PolyTrait, hir::TraitBoundModifier),
+    Outlives(Lifetime),
 }
 
-impl<'tcx> Clean<TyParam> for ty::GenericParamDef {
-    fn clean(&self, cx: &DocContext) -> TyParam {
-        cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
-        let has_default = match self.kind {
-            ty::GenericParamDefKind::Type { has_default, .. } => has_default,
-            _ => panic!("tried to convert a non-type GenericParamDef as a type")
-        };
-        TyParam {
-            name: self.name.clean(cx),
-            did: self.def_id,
-            bounds: vec![], // these are filled in from the where-clauses
-            default: if has_default {
-                Some(cx.tcx.type_of(self.def_id).clean(cx))
-            } else {
-                None
-            },
-            synthetic: None,
-        }
-    }
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
-pub enum TyParamBound {
-    RegionBound(Lifetime),
-    TraitBound(PolyTrait, hir::TraitBoundModifier)
-}
-
-impl TyParamBound {
-    fn maybe_sized(cx: &DocContext) -> TyParamBound {
+impl GenericBound {
+    fn maybe_sized(cx: &DocContext) -> GenericBound {
         let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
         let empty = cx.tcx.intern_substs(&[]);
         let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
             Some(did), false, vec![], empty);
         inline::record_extern_fqn(cx, did, TypeKind::Trait);
-        TraitBound(PolyTrait {
+        GenericBound::TraitBound(PolyTrait {
             trait_: ResolvedPath {
                 path,
                 typarams: None,
@@ -1525,7 +1482,7 @@ impl TyParamBound {
 
     fn is_sized_bound(&self, cx: &DocContext) -> bool {
         use rustc::hir::TraitBoundModifier as TBM;
-        if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
+        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
             if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
                 return true;
             }
@@ -1534,7 +1491,7 @@ impl TyParamBound {
     }
 
     fn get_poly_trait(&self) -> Option<PolyTrait> {
-        if let TyParamBound::TraitBound(ref p, _) = *self {
+        if let GenericBound::TraitBound(ref p, _) = *self {
             return Some(p.clone())
         }
         None
@@ -1542,24 +1499,26 @@ impl TyParamBound {
 
     fn get_trait_type(&self) -> Option<Type> {
 
-        if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
+        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
             return Some(trait_.clone());
         }
         None
     }
 }
 
-impl Clean<TyParamBound> for hir::TyParamBound {
-    fn clean(&self, cx: &DocContext) -> TyParamBound {
+impl Clean<GenericBound> for hir::GenericBound {
+    fn clean(&self, cx: &DocContext) -> GenericBound {
         match *self {
-            hir::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
-            hir::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
+            hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
+            hir::GenericBound::Trait(ref t, modifier) => {
+                GenericBound::TraitBound(t.clean(cx), modifier)
+            }
         }
     }
 }
 
-fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
-                        bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
+fn external_generic_args(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
+                        bindings: Vec<TypeBinding>, substs: &Substs) -> GenericArgs {
     let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
     let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
 
@@ -1570,7 +1529,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: boo
             let inputs = match types[0].sty {
                 ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
                 _ => {
-                    return PathParameters::AngleBracketed {
+                    return GenericArgs::AngleBracketed {
                         lifetimes,
                         types: types.clean(cx),
                         bindings,
@@ -1583,13 +1542,13 @@ fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: boo
             //     ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
             //     _ => Some(types[1].clean(cx))
             // };
-            PathParameters::Parenthesized {
+            GenericArgs::Parenthesized {
                 inputs,
                 output,
             }
         },
         _ => {
-            PathParameters::AngleBracketed {
+            GenericArgs::AngleBracketed {
                 lifetimes,
                 types: types.clean(cx),
                 bindings,
@@ -1607,13 +1566,13 @@ fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self
         def: Def::Err,
         segments: vec![PathSegment {
             name: name.to_string(),
-            params: external_path_params(cx, trait_did, has_self, bindings, substs)
+            args: external_generic_args(cx, trait_did, has_self, bindings, substs)
         }],
     }
 }
 
-impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
-    fn clean(&self, cx: &DocContext) -> TyParamBound {
+impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
+    fn clean(&self, cx: &DocContext) -> GenericBound {
         let (trait_ref, ref bounds) = *self;
         inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
         let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(),
@@ -1629,8 +1588,11 @@ impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>
                     if let ty::TyRef(ref reg, _, _) = ty_s.sty {
                         if let &ty::RegionKind::ReLateBound(..) = *reg {
                             debug!("  hit an ReLateBound {:?}", reg);
-                            if let Some(lt) = reg.clean(cx) {
-                                late_bounds.push(GenericParamDef::Lifetime(lt));
+                            if let Some(Lifetime(name)) = reg.clean(cx) {
+                                late_bounds.push(GenericParamDef {
+                                    name,
+                                    kind: GenericParamDefKind::Lifetime,
+                                });
                             }
                         }
                     }
@@ -1638,7 +1600,7 @@ impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>
             }
         }
 
-        TraitBound(
+        GenericBound::TraitBound(
             PolyTrait {
                 trait_: ResolvedPath {
                     path,
@@ -1653,18 +1615,17 @@ impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>
     }
 }
 
-impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
-    fn clean(&self, cx: &DocContext) -> TyParamBound {
+impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
+    fn clean(&self, cx: &DocContext) -> GenericBound {
         (self, vec![]).clean(cx)
     }
 }
 
-impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
-    fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
+impl<'tcx> Clean<Option<Vec<GenericBound>>> for Substs<'tcx> {
+    fn clean(&self, cx: &DocContext) -> Option<Vec<GenericBound>> {
         let mut v = Vec::new();
-        v.extend(self.regions().filter_map(|r| r.clean(cx))
-                     .map(RegionBound));
-        v.extend(self.types().map(|t| TraitBound(PolyTrait {
+        v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
+        v.extend(self.types().map(|t| GenericBound::TraitBound(PolyTrait {
             trait_: t.clean(cx),
             generic_params: Vec::new(),
         }, hir::TraitBoundModifier::None)));
@@ -1707,18 +1668,26 @@ 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 { .. } => {
+                if self.bounds.len() > 0 {
+                    let mut bounds = self.bounds.iter().map(|bound| match bound {
+                        hir::GenericBound::Outlives(lt) => lt,
+                        _ => panic!(),
+                    });
+                    let name = bounds.next().unwrap().name.name();
+                    let mut s = format!("{}: {}", self.name.name(), name);
+                    for bound in bounds {
+                        s.push_str(&format!(" + {}", bound.name.name()));
+                    }
+                    Lifetime(s)
+                } else {
+                    Lifetime(self.name.name().to_string())
+                }
             }
-            Lifetime(s)
-        } else {
-            Lifetime(self.lifetime.name.name().to_string())
+            _ => panic!(),
         }
     }
 }
@@ -1751,8 +1720,8 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub enum WherePredicate {
-    BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
-    RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
+    BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
+    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
     EqPredicate { lhs: Type, rhs: Type },
 }
 
@@ -1822,7 +1791,7 @@ impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region<'tcx>, ty:
         let ty::OutlivesPredicate(ref a, ref b) = *self;
         WherePredicate::RegionPredicate {
             lifetime: a.clean(cx).unwrap(),
-            bounds: vec![b.clean(cx).unwrap()]
+            bounds: vec![GenericBound::Outlives(b.clean(cx).unwrap())]
         }
     }
 }
@@ -1833,7 +1802,7 @@ impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<
 
         WherePredicate::BoundPredicate {
             ty: ty.clean(cx),
-            bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
+            bounds: vec![GenericBound::Outlives(lt.clean(cx).unwrap())]
         }
     }
 }
@@ -1850,10 +1819,8 @@ impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
     fn clean(&self, cx: &DocContext) -> Type {
         let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
-            TyParamBound::TraitBound(t, _) => t.trait_,
-            TyParamBound::RegionBound(_) => {
-                panic!("cleaning a trait got a region")
-            }
+            GenericBound::TraitBound(t, _) => t.trait_,
+            GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
         };
         Type::QPath {
             name: cx.tcx.associated_item(self.item_def_id).name.clean(cx),
@@ -1864,25 +1831,95 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
-pub enum GenericParamDef {
-    Lifetime(Lifetime),
-    Type(TyParam),
+pub enum GenericParamDefKind {
+    Lifetime,
+    Type {
+        did: DefId,
+        bounds: Vec<GenericBound>,
+        default: Option<Type>,
+        synthetic: Option<hir::SyntheticTyParamKind>,
+    },
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
+pub struct GenericParamDef {
+    pub name: String,
+
+    pub kind: GenericParamDefKind,
 }
 
 impl GenericParamDef {
     pub fn is_synthetic_type_param(&self) -> bool {
-        match self {
-            GenericParamDef::Type(ty) => ty.synthetic.is_some(),
-            GenericParamDef::Lifetime(_) => false,
+        match self.kind {
+            GenericParamDefKind::Lifetime => false,
+            GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
+        }
+    }
+}
+
+impl<'tcx> Clean<GenericParamDef> for ty::GenericParamDef {
+    fn clean(&self, cx: &DocContext) -> GenericParamDef {
+        let (name, kind) = match self.kind {
+            ty::GenericParamDefKind::Lifetime => {
+                (self.name.to_string(), GenericParamDefKind::Lifetime)
+            }
+            ty::GenericParamDefKind::Type { has_default, .. } => {
+                cx.renderinfo.borrow_mut().external_typarams
+                             .insert(self.def_id, self.name.clean(cx));
+                let default = if has_default {
+                    Some(cx.tcx.type_of(self.def_id).clean(cx))
+                } else {
+                    None
+                };
+                (self.name.clean(cx), GenericParamDefKind::Type {
+                    did: self.def_id,
+                    bounds: vec![], // These are filled in from the where-clauses.
+                    default,
+                    synthetic: None,
+                })
+            }
+        };
+
+        GenericParamDef {
+            name,
+            kind,
         }
     }
 }
 
 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)),
+        let (name, kind) = match self.kind {
+            hir::GenericParamKind::Lifetime { .. } => {
+                let name = if self.bounds.len() > 0 {
+                    let mut bounds = self.bounds.iter().map(|bound| match bound {
+                        hir::GenericBound::Outlives(lt) => lt,
+                        _ => panic!(),
+                    });
+                    let name = bounds.next().unwrap().name.name();
+                    let mut s = format!("{}: {}", self.name.name(), name);
+                    for bound in bounds {
+                        s.push_str(&format!(" + {}", bound.name.name()));
+                    }
+                    s
+                } else {
+                    self.name.name().to_string()
+                };
+                (name, GenericParamDefKind::Lifetime)
+            }
+            hir::GenericParamKind::Type { ref default, synthetic, .. } => {
+                (self.name.name().clean(cx), GenericParamDefKind::Type {
+                    did: cx.tcx.hir.local_def_id(self.id),
+                    bounds: self.bounds.clean(cx),
+                    default: default.clean(cx),
+                    synthetic: synthetic,
+                })
+            }
+        };
+
+        GenericParamDef {
+            name,
+            kind,
         }
     }
 }
@@ -1900,25 +1937,25 @@ 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
             .iter()
-            .filter(|p| is_impl_trait(p))
-            .map(|p| {
-                let p = p.clean(cx);
-                if let GenericParamDef::Type(ref tp) = p {
-                    cx.impl_trait_bounds
-                        .borrow_mut()
-                        .insert(tp.did, tp.bounds.clone());
-                } else {
-                    unreachable!()
+            .filter(|param| is_impl_trait(param))
+            .map(|param| {
+                let param: GenericParamDef = param.clean(cx);
+                match param.kind {
+                    GenericParamDefKind::Lifetime => unreachable!(),
+                    GenericParamDefKind::Type { did, ref bounds, .. } => {
+                        cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone());
+                    }
                 }
-                p
+                param
             })
             .collect::<Vec<_>>();
 
@@ -1929,23 +1966,26 @@ impl Clean<Generics> for hir::Generics {
         }
         params.extend(impl_trait_params);
 
-        let mut g = Generics {
+        let mut generics = Generics {
             params,
-            where_predicates: self.where_clause.predicates.clean(cx)
+            where_predicates: self.where_clause.predicates.clean(cx),
         };
 
         // Some duplicates are generated for ?Sized bounds between type params and where
         // predicates. The point in here is to move the bounds definitions from type params
         // to where predicates when such cases occur.
-        for where_pred in &mut g.where_predicates {
+        for where_pred in &mut generics.where_predicates {
             match *where_pred {
                 WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
                     if bounds.is_empty() {
-                        for param in &mut g.params {
-                            if let GenericParamDef::Type(ref mut type_param) = *param {
-                                if &type_param.name == name {
-                                    mem::swap(bounds, &mut type_param.bounds);
-                                    break
+                        for param in &mut generics.params {
+                            match param.kind {
+                                GenericParamDefKind::Lifetime => {}
+                                GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
+                                    if &param.name == name {
+                                        mem::swap(bounds, ty_bounds);
+                                        break
+                                    }
                                 }
                             }
                         }
@@ -1954,7 +1994,7 @@ impl Clean<Generics> for hir::Generics {
                 _ => continue,
             }
         }
-        g
+        generics
     }
 }
 
@@ -1968,18 +2008,16 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
         // Bounds in the type_params and lifetimes fields are repeated in the
         // predicates field (see rustc_typeck::collect::ty_generics), so remove
         // them.
-        let stripped_typarams = gens.params.iter().filter_map(|param| {
-            if let ty::GenericParamDefKind::Type {..} = param.kind {
+        let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime => None,
+            ty::GenericParamDefKind::Type { .. } => {
                 if param.name == keywords::SelfType.name().as_str() {
                     assert_eq!(param.index, 0);
-                    None
-                } else {
-                    Some(param.clean(cx))
+                    return None;
                 }
-            } else {
-                None
+                Some(param.clean(cx))
             }
-        }).collect::<Vec<TyParam>>();
+        }).collect::<Vec<GenericParamDef>>();
 
         let mut where_predicates = preds.predicates.to_vec().clean(cx);
 
@@ -2011,7 +2049,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
             if !sized_params.contains(&tp.name) {
                 where_predicates.push(WP::BoundPredicate {
                     ty: Type::Generic(tp.name.clone()),
-                    bounds: vec![TyParamBound::maybe_sized(cx)],
+                    bounds: vec![GenericBound::maybe_sized(cx)],
                 })
             }
         }
@@ -2023,17 +2061,10 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
         Generics {
             params: gens.params
                         .iter()
-                        .flat_map(|param| {
-                            if let ty::GenericParamDefKind::Lifetime = param.kind {
-                                Some(GenericParamDef::Lifetime(param.clean(cx)))
-                            } else {
-                                None
-                            }
-                        }).chain(
-                            simplify::ty_params(stripped_typarams)
-                                .into_iter()
-                                .map(|tp| GenericParamDef::Type(tp))
-                        )
+                        .flat_map(|param| match param.kind {
+                            ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
+                            ty::GenericParamDefKind::Type { .. } => None,
+                        }).chain(simplify::ty_params(stripped_typarams).into_iter())
                         .collect(),
             where_predicates: simplify::where_clauses(cx, where_predicates),
         }
@@ -2259,7 +2290,7 @@ pub struct Trait {
     pub unsafety: hir::Unsafety,
     pub items: Vec<Item>,
     pub generics: Generics,
-    pub bounds: Vec<TyParamBound>,
+    pub bounds: Vec<GenericBound>,
     pub is_spotlight: bool,
     pub is_auto: bool,
 }
@@ -2481,7 +2512,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                     // at the end.
                     match bounds.iter().position(|b| b.is_sized_bound(cx)) {
                         Some(i) => { bounds.remove(i); }
-                        None => bounds.push(TyParamBound::maybe_sized(cx)),
+                        None => bounds.push(GenericBound::maybe_sized(cx)),
                     }
 
                     let ty = if self.defaultness.has_value() {
@@ -2536,7 +2567,7 @@ pub enum Type {
     /// structs/enums/traits (most that'd be an hir::TyPath)
     ResolvedPath {
         path: Path,
-        typarams: Option<Vec<TyParamBound>>,
+        typarams: Option<Vec<GenericBound>>,
         did: DefId,
         /// true if is a `T::Name` path for associated types
         is_generic: bool,
@@ -2572,7 +2603,7 @@ pub enum Type {
     Infer,
 
     // impl TraitA+TraitB
-    ImplTrait(Vec<TyParamBound>),
+    ImplTrait(Vec<GenericBound>),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
@@ -2656,7 +2687,7 @@ impl Type {
         match *self {
             ResolvedPath { ref path, .. } => {
                 path.segments.last().and_then(|seg| {
-                    if let PathParameters::AngleBracketed { ref types, .. } = seg.params {
+                    if let GenericArgs::AngleBracketed { ref types, .. } = seg.args {
                         Some(&**types)
                     } else {
                         None
@@ -2851,31 +2882,55 @@ impl Clean<Type> for hir::Ty {
                     let provided_params = &path.segments.last().unwrap();
                     let mut ty_substs = FxHashMap();
                     let mut lt_substs = FxHashMap();
-                    provided_params.with_parameters(|provided_params| {
-                        let mut indices = GenericParamCount {
+                    provided_params.with_generic_args(|generic_args| {
+                        let mut indices = ty::GenericParamCount {
                             lifetimes: 0,
                             types: 0
                         };
                         for param in generics.params.iter() {
-                            match param {
-                                hir::GenericParam::Lifetime(lt_param) => {
-                                    if let Some(lt) = provided_params.lifetimes
-                                        .get(indices.lifetimes).cloned() {
+                            match param.kind {
+                                hir::GenericParamKind::Lifetime { .. } => {
+                                    let mut j = 0;
+                                    let lifetime = generic_args.args.iter().find_map(|arg| {
+                                        match arg {
+                                            GenericArg::Lifetime(lt) => {
+                                                if indices.lifetimes == j {
+                                                    return Some(lt);
+                                                }
+                                                j += 1;
+                                                None
+                                            }
+                                            _ => None,
+                                        }
+                                    });
+                                    if let Some(lt) = lifetime.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));
-                                    if let Some(ty) = provided_params.types
-                                        .get(indices.types).cloned() {
+                                        Def::TyParam(cx.tcx.hir.local_def_id(param.id));
+                                    let mut j = 0;
+                                    let type_ = generic_args.args.iter().find_map(|arg| {
+                                        match arg {
+                                            GenericArg::Type(ty) => {
+                                                if indices.types == j {
+                                                    return Some(ty);
+                                                }
+                                                j += 1;
+                                                None
+                                            }
+                                            _ => None,
+                                        }
+                                    });
+                                    if let Some(ty) = type_.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));
                                     }
@@ -2922,18 +2977,14 @@ impl Clean<Type> for hir::Ty {
             TyTraitObject(ref bounds, ref lifetime) => {
                 match bounds[0].clean(cx).trait_ {
                     ResolvedPath { path, typarams: None, did, is_generic } => {
-                        let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| {
-                            TraitBound(bound.clean(cx), hir::TraitBoundModifier::None)
+                        let mut bounds: Vec<self::GenericBound> = bounds[1..].iter().map(|bound| {
+                            self::GenericBound::TraitBound(bound.clean(cx),
+                                                           hir::TraitBoundModifier::None)
                         }).collect();
                         if !lifetime.is_elided() {
-                            bounds.push(RegionBound(lifetime.clean(cx)));
-                        }
-                        ResolvedPath {
-                            path,
-                            typarams: Some(bounds),
-                            did,
-                            is_generic,
+                            bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
                         }
+                        ResolvedPath { path, typarams: Some(bounds), did, is_generic, }
                     }
                     _ => Infer // shouldn't happen
                 }
@@ -3030,13 +3081,13 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     inline::record_extern_fqn(cx, did, TypeKind::Trait);
 
                     let mut typarams = vec![];
-                    reg.clean(cx).map(|b| typarams.push(RegionBound(b)));
+                    reg.clean(cx).map(|b| typarams.push(GenericBound::Outlives(b)));
                     for did in obj.auto_traits() {
                         let empty = cx.tcx.intern_substs(&[]);
                         let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
                             Some(did), false, vec![], empty);
                         inline::record_extern_fqn(cx, did, TypeKind::Trait);
-                        let bound = TraitBound(PolyTrait {
+                        let bound = GenericBound::TraitBound(PolyTrait {
                             trait_: ResolvedPath {
                                 path,
                                 typarams: None,
@@ -3087,7 +3138,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                         tr
                     } else if let ty::Predicate::TypeOutlives(pred) = *predicate {
                         // these should turn up at the end
-                        pred.skip_binder().1.clean(cx).map(|r| regions.push(RegionBound(r)));
+                        pred.skip_binder().1.clean(cx).map(|r| {
+                            regions.push(GenericBound::Outlives(r))
+                        });
                         return None;
                     } else {
                         return None;
@@ -3100,7 +3153,6 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                         }
                     }
 
-
                     let bounds = bounds.predicates.iter().filter_map(|pred|
                         if let ty::Predicate::Projection(proj) = *pred {
                             let proj = proj.skip_binder();
@@ -3122,7 +3174,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 }).collect::<Vec<_>>();
                 bounds.extend(regions);
                 if !has_sized && !bounds.is_empty() {
-                    bounds.insert(0, TyParamBound::maybe_sized(cx));
+                    bounds.insert(0, GenericBound::maybe_sized(cx));
                 }
                 ImplTrait(bounds)
             }
@@ -3447,7 +3499,7 @@ impl Path {
             def: Def::Err,
             segments: vec![PathSegment {
                 name,
-                params: PathParameters::AngleBracketed {
+                args: GenericArgs::AngleBracketed {
                     lifetimes: Vec::new(),
                     types: Vec::new(),
                     bindings: Vec::new(),
@@ -3472,7 +3524,7 @@ impl Clean<Path> for hir::Path {
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
-pub enum PathParameters {
+pub enum GenericArgs {
     AngleBracketed {
         lifetimes: Vec<Lifetime>,
         types: Vec<Type>,
@@ -3484,22 +3536,33 @@ pub enum PathParameters {
     }
 }
 
-impl Clean<PathParameters> for hir::PathParameters {
-    fn clean(&self, cx: &DocContext) -> PathParameters {
+impl Clean<GenericArgs> for hir::GenericArgs {
+    fn clean(&self, cx: &DocContext) -> GenericArgs {
         if self.parenthesized {
             let output = self.bindings[0].ty.clean(cx);
-            PathParameters::Parenthesized {
+            GenericArgs::Parenthesized {
                 inputs: self.inputs().clean(cx),
                 output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
             }
         } else {
-            PathParameters::AngleBracketed {
-                lifetimes: if self.lifetimes.iter().all(|lt| lt.is_elided()) {
-                    vec![]
-                } else {
-                    self.lifetimes.clean(cx)
-                },
-                types: self.types.clean(cx),
+            let (mut lifetimes, mut types) = (vec![], vec![]);
+            let mut elided_lifetimes = true;
+            for arg in &self.args {
+                match arg {
+                    GenericArg::Lifetime(lt) => {
+                        if !lt.is_elided() {
+                            elided_lifetimes = false;
+                        }
+                        lifetimes.push(lt.clean(cx));
+                    }
+                    GenericArg::Type(ty) => {
+                        types.push(ty.clean(cx));
+                    }
+                }
+            }
+            GenericArgs::AngleBracketed {
+                lifetimes: if elided_lifetimes { vec![] } else { lifetimes },
+                types,
                 bindings: self.bindings.clean(cx),
             }
         }
@@ -3509,14 +3572,14 @@ impl Clean<PathParameters> for hir::PathParameters {
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub struct PathSegment {
     pub name: String,
-    pub params: PathParameters,
+    pub args: GenericArgs,
 }
 
 impl Clean<PathSegment> for hir::PathSegment {
     fn clean(&self, cx: &DocContext) -> PathSegment {
         PathSegment {
             name: self.name.clean(cx),
-            params: self.with_parameters(|parameters| parameters.clean(cx))
+            args: self.with_generic_args(|generic_args| generic_args.clean(cx))
         }
     }
 }
@@ -3550,7 +3613,7 @@ fn strip_path(path: &Path) -> Path {
     let segments = path.segments.iter().map(|s| {
         PathSegment {
             name: s.name.clone(),
-            params: PathParameters::AngleBracketed {
+            args: GenericArgs::AngleBracketed {
                 lifetimes: Vec::new(),
                 types: Vec::new(),
                 bindings: Vec::new(),
@@ -4365,7 +4428,7 @@ where F: Fn(DefId) -> Def {
         def: def_ctor(def_id),
         segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment {
             name: ast::Name::intern(&s),
-            parameters: None,
+            args: None,
             infer_types: false,
         }).collect())
     }
@@ -4388,8 +4451,8 @@ struct RegionDeps<'tcx> {
 
 #[derive(Eq, PartialEq, Hash, Debug)]
 enum SimpleBound {
-    RegionBound(Lifetime),
-    TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier)
+    TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier),
+    Outlives(Lifetime),
 }
 
 enum AutoTraitResult {
@@ -4407,11 +4470,11 @@ impl AutoTraitResult {
     }
 }
 
-impl From<TyParamBound> for SimpleBound {
-    fn from(bound: TyParamBound) -> Self {
+impl From<GenericBound> for SimpleBound {
+    fn from(bound: GenericBound) -> Self {
         match bound.clone() {
-            TyParamBound::RegionBound(l) => SimpleBound::RegionBound(l),
-            TyParamBound::TraitBound(t, mod_) => match t.trait_ {
+            GenericBound::Outlives(l) => SimpleBound::Outlives(l),
+            GenericBound::TraitBound(t, mod_) => match t.trait_ {
                 Type::ResolvedPath { path, typarams, .. } => {
                     SimpleBound::TraitBound(path.segments,
                                             typarams
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index b7767606a6a..30a55bf0d18 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -27,7 +27,7 @@ use std::collections::BTreeMap;
 use rustc::hir::def_id::DefId;
 use rustc::ty;
 
-use clean::PathParameters as PP;
+use clean::GenericArgs as PP;
 use clean::WherePredicate as WP;
 use clean;
 use core::DocContext;
@@ -83,8 +83,8 @@ pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> {
         };
         !bounds.iter_mut().any(|b| {
             let trait_ref = match *b {
-                clean::TraitBound(ref mut tr, _) => tr,
-                clean::RegionBound(..) => return false,
+                clean::GenericBound::TraitBound(ref mut tr, _) => tr,
+                clean::GenericBound::Outlives(..) => return false,
             };
             let (did, path) = match trait_ref.trait_ {
                 clean::ResolvedPath { did, ref mut path, ..} => (did, path),
@@ -97,7 +97,7 @@ pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> {
                 return false
             }
             let last = path.segments.last_mut().unwrap();
-            match last.params {
+            match last.args {
                 PP::AngleBracketed { ref mut bindings, .. } => {
                     bindings.push(clean::TypeBinding {
                         name: name.clone(),
@@ -135,14 +135,19 @@ pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> {
     clauses
 }
 
-pub fn ty_params(mut params: Vec<clean::TyParam>) -> Vec<clean::TyParam> {
+pub fn ty_params(mut params: Vec<clean::GenericParamDef>) -> Vec<clean::GenericParamDef> {
     for param in &mut params {
-        param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new()));
+        match param.kind {
+            clean::GenericParamDefKind::Type { ref mut bounds, .. } => {
+                *bounds = ty_bounds(mem::replace(bounds, Vec::new()));
+            }
+            _ => panic!("expected only type parameters"),
+        }
     }
     params
 }
 
-fn ty_bounds(bounds: Vec<clean::TyParamBound>) -> Vec<clean::TyParamBound> {
+fn ty_bounds(bounds: Vec<clean::GenericBound>) -> Vec<clean::GenericBound> {
     bounds
 }
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index e858f10860b..53ebb3a12f5 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -77,7 +77,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
     /// Table node id of lifetime parameter definition -> substituted lifetime
     pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
     /// Table DefId of `impl Trait` in argument position -> bounds
-    pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::TyParamBound>>>,
+    pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::GenericBound>>>,
     pub send_trait: Option<DefId>,
     pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
     pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index f85a70a6d40..16d14bc56d6 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -201,7 +201,7 @@ pub struct Trait {
     pub name: Name,
     pub items: hir::HirVec<hir::TraitItem>,
     pub generics: hir::Generics,
-    pub bounds: hir::HirVec<hir::TyParamBound>,
+    pub bounds: hir::HirVec<hir::GenericBound>,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub id: ast::NodeId,
     pub whence: Span,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 40dcd6e891f..3d360f2f344 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -46,7 +46,7 @@ pub struct MutableSpace(pub clean::Mutability);
 #[derive(Copy, Clone)]
 pub struct RawMutableSpace(pub clean::Mutability);
 /// Wrapper struct for emitting type parameter bounds.
-pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
+pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
 /// Wrapper struct for emitting a comma-separated list of items
 pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
 pub struct AbiSpace(pub Abi);
@@ -104,9 +104,9 @@ impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
     }
 }
 
-impl<'a> fmt::Display for TyParamBounds<'a> {
+impl<'a> fmt::Display for GenericBounds<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let &TyParamBounds(bounds) = self;
+        let &GenericBounds(bounds) = self;
         for (i, bound) in bounds.iter().enumerate() {
             if i > 0 {
                 f.write_str(" + ")?;
@@ -119,20 +119,20 @@ impl<'a> fmt::Display for TyParamBounds<'a> {
 
 impl fmt::Display for clean::GenericParamDef {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            clean::GenericParamDef::Lifetime(ref lp) => write!(f, "{}", lp),
-            clean::GenericParamDef::Type(ref tp) => {
-                f.write_str(&tp.name)?;
+        match self.kind {
+            clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
+            clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
+                f.write_str(&self.name)?;
 
-                if !tp.bounds.is_empty() {
+                if !bounds.is_empty() {
                     if f.alternate() {
-                        write!(f, ": {:#}", TyParamBounds(&tp.bounds))?;
+                        write!(f, ": {:#}", GenericBounds(bounds))?;
                     } else {
-                        write!(f, ":&nbsp;{}", TyParamBounds(&tp.bounds))?;
+                        write!(f, ":&nbsp;{}", GenericBounds(bounds))?;
                     }
                 }
 
-                if let Some(ref ty) = tp.default {
+                if let Some(ref ty) = default {
                     if f.alternate() {
                         write!(f, " = {:#}", ty)?;
                     } else {
@@ -190,9 +190,9 @@ impl<'a> fmt::Display for WhereClause<'a> {
                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
                     let bounds = bounds;
                     if f.alternate() {
-                        clause.push_str(&format!("{:#}: {:#}", ty, TyParamBounds(bounds)));
+                        clause.push_str(&format!("{:#}: {:#}", ty, GenericBounds(bounds)));
                     } else {
-                        clause.push_str(&format!("{}: {}", ty, TyParamBounds(bounds)));
+                        clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds)));
                     }
                 }
                 &clean::WherePredicate::RegionPredicate { ref lifetime,
@@ -267,13 +267,13 @@ impl fmt::Display for clean::PolyTrait {
     }
 }
 
-impl fmt::Display for clean::TyParamBound {
+impl fmt::Display for clean::GenericBound {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            clean::RegionBound(ref lt) => {
+            clean::GenericBound::Outlives(ref lt) => {
                 write!(f, "{}", *lt)
             }
-            clean::TraitBound(ref ty, modifier) => {
+            clean::GenericBound::TraitBound(ref ty, modifier) => {
                 let modifier_str = match modifier {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
@@ -288,10 +288,10 @@ impl fmt::Display for clean::TyParamBound {
     }
 }
 
-impl fmt::Display for clean::PathParameters {
+impl fmt::Display for clean::GenericArgs {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            clean::PathParameters::AngleBracketed {
+            clean::GenericArgs::AngleBracketed {
                 ref lifetimes, ref types, ref bindings
             } => {
                 if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
@@ -337,7 +337,7 @@ impl fmt::Display for clean::PathParameters {
                     }
                 }
             }
-            clean::PathParameters::Parenthesized { ref inputs, ref output } => {
+            clean::GenericArgs::Parenthesized { ref inputs, ref output } => {
                 f.write_str("(")?;
                 let mut comma = false;
                 for ty in inputs {
@@ -369,9 +369,9 @@ impl fmt::Display for clean::PathSegment {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(&self.name)?;
         if f.alternate() {
-            write!(f, "{:#}", self.params)
+            write!(f, "{:#}", self.args)
         } else {
-            write!(f, "{}", self.params)
+            write!(f, "{}", self.args)
         }
     }
 }
@@ -447,7 +447,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
         }
     }
     if w.alternate() {
-        write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
+        write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.args)?;
     } else {
         let path = if use_absolute {
             match href(did) {
@@ -461,7 +461,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
         } else {
             format!("{}", HRef::new(did, &last.name))
         };
-        write!(w, "{}{}", path, last.params)?;
+        write!(w, "{}{}", path, last.args)?;
     }
     Ok(())
 }
@@ -512,7 +512,7 @@ fn primitive_link(f: &mut fmt::Formatter,
 
 /// Helper to render type parameters
 fn tybounds(w: &mut fmt::Formatter,
-            typarams: &Option<Vec<clean::TyParamBound>>) -> fmt::Result {
+            typarams: &Option<Vec<clean::GenericBound>>) -> fmt::Result {
     match *typarams {
         Some(ref params) => {
             for param in params {
@@ -667,7 +667,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
             }
         }
         clean::ImplTrait(ref bounds) => {
-            write!(f, "impl {}", TyParamBounds(bounds))
+            write!(f, "impl {}", GenericBounds(bounds))
         }
         clean::QPath { ref name, ref self_type, ref trait_ } => {
             let should_show_cast = match *trait_ {
@@ -757,7 +757,7 @@ fn fmt_impl(i: &clean::Impl,
                 clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
                     let last = path.segments.last().unwrap();
                     fmt::Display::fmt(&last.name, f)?;
-                    fmt::Display::fmt(&last.params, f)?;
+                    fmt::Display::fmt(&last.args, f)?;
                 }
                 _ => unreachable!(),
             }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 5c2ec2058ee..180591b3532 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -69,7 +69,7 @@ use doctree;
 use fold::DocFolder;
 use html::escape::Escape;
 use html::format::{ConstnessSpace};
-use html::format::{TyParamBounds, WhereClause, href, AbiSpace};
+use html::format::{GenericBounds, WhereClause, href, AbiSpace};
 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
 use html::format::fmt_impl_for_trait_page;
 use html::item_type::ItemType;
@@ -1453,11 +1453,11 @@ impl DocFolder for Cache {
 impl<'a> Cache {
     fn generics(&mut self, generics: &clean::Generics) {
         for param in &generics.params {
-            match *param {
-                clean::GenericParamDef::Type(ref typ) => {
-                    self.typarams.insert(typ.did, typ.name.clone());
+            match param.kind {
+                clean::GenericParamDefKind::Lifetime => {}
+                clean::GenericParamDefKind::Type { did, .. } => {
+                    self.typarams.insert(did, param.name.clone());
                 }
-                clean::GenericParamDef::Lifetime(_) => {}
             }
         }
     }
@@ -2960,14 +2960,14 @@ fn assoc_const(w: &mut fmt::Formatter,
 }
 
 fn assoc_type<W: fmt::Write>(w: &mut W, it: &clean::Item,
-                             bounds: &Vec<clean::TyParamBound>,
+                             bounds: &Vec<clean::GenericBound>,
                              default: Option<&clean::Type>,
                              link: AssocItemLink) -> fmt::Result {
     write!(w, "type <a href='{}' class=\"type\">{}</a>",
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap())?;
     if !bounds.is_empty() {
-        write!(w, ": {}", TyParamBounds(bounds))?
+        write!(w, ": {}", GenericBounds(bounds))?
     }
     if let Some(default) = default {
         write!(w, " = {}", default)?;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 3a38a8c29d7..566e2f1ed49 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -18,6 +18,7 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(fs_read_write)]
+#![feature(iterator_find_map)]
 #![feature(set_stdio)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(test)]
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 76fa463a631..c6de2c4da39 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -10,9 +10,8 @@
 
 // The Rust abstract syntax tree.
 
-pub use self::TyParamBound::*;
 pub use self::UnsafeSource::*;
-pub use self::PathParameters::*;
+pub use self::GenericArgs::*;
 pub use symbol::{Ident, Symbol as Name};
 pub use util::ThinVec;
 pub use util::parser::ExprPrecedence;
@@ -58,14 +57,6 @@ impl fmt::Debug for Lifetime {
     }
 }
 
-/// A lifetime definition, e.g. `'a: 'b+'c+'d`
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct LifetimeDef {
-    pub attrs: ThinVec<Attribute>,
-    pub lifetime: Lifetime,
-    pub bounds: Vec<Lifetime>
-}
-
 /// A "Path" is essentially Rust's notion of a name.
 ///
 /// It's represented as a sequence of identifiers,
@@ -135,30 +126,30 @@ pub struct PathSegment {
     /// `Some` means that parameter list is supplied (`Path<X, Y>`)
     /// but it can be empty (`Path<>`).
     /// `P` is used as a size optimization for the common case with no parameters.
-    pub parameters: Option<P<PathParameters>>,
+    pub args: Option<P<GenericArgs>>,
 }
 
 impl PathSegment {
     pub fn from_ident(ident: Ident) -> Self {
-        PathSegment { ident, parameters: None }
+        PathSegment { ident, args: None }
     }
     pub fn crate_root(span: Span) -> Self {
         PathSegment::from_ident(Ident::new(keywords::CrateRoot.name(), span))
     }
 }
 
-/// Parameters of a path segment.
+/// Arguments of a path segment.
 ///
 /// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum PathParameters {
+pub enum GenericArgs {
     /// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>`
-    AngleBracketed(AngleBracketedParameterData),
+    AngleBracketed(AngleBracketedArgs),
     /// The `(A,B)` and `C` in `Foo(A,B) -> C`
-    Parenthesized(ParenthesizedParameterData),
+    Parenthesized(ParenthesisedArgs),
 }
 
-impl PathParameters {
+impl GenericArgs {
     pub fn span(&self) -> Span {
         match *self {
             AngleBracketed(ref data) => data.span,
@@ -167,36 +158,40 @@ impl PathParameters {
     }
 }
 
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum GenericArg {
+    Lifetime(Lifetime),
+    Type(P<Ty>),
+}
+
 /// A path like `Foo<'a, T>`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Default)]
-pub struct AngleBracketedParameterData {
+pub struct AngleBracketedArgs {
     /// Overall span
     pub span: Span,
-    /// The lifetime parameters for this path segment.
-    pub lifetimes: Vec<Lifetime>,
-    /// The type parameters for this path segment, if present.
-    pub types: Vec<P<Ty>>,
+    /// The arguments for this path segment.
+    pub args: Vec<GenericArg>,
     /// Bindings (equality constraints) on associated types, if present.
     ///
     /// E.g., `Foo<A=Bar>`.
     pub bindings: Vec<TypeBinding>,
 }
 
-impl Into<Option<P<PathParameters>>> for AngleBracketedParameterData {
-    fn into(self) -> Option<P<PathParameters>> {
-        Some(P(PathParameters::AngleBracketed(self)))
+impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
+    fn into(self) -> Option<P<GenericArgs>> {
+        Some(P(GenericArgs::AngleBracketed(self)))
     }
 }
 
-impl Into<Option<P<PathParameters>>> for ParenthesizedParameterData {
-    fn into(self) -> Option<P<PathParameters>> {
-        Some(P(PathParameters::Parenthesized(self)))
+impl Into<Option<P<GenericArgs>>> for ParenthesisedArgs {
+    fn into(self) -> Option<P<GenericArgs>> {
+        Some(P(GenericArgs::Parenthesized(self)))
     }
 }
 
 /// A path like `Foo(A,B) -> C`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct ParenthesizedParameterData {
+pub struct ParenthesisedArgs {
     /// Overall span
     pub span: Span,
 
@@ -273,64 +268,52 @@ pub const CRATE_NODE_ID: NodeId = NodeId(0);
 /// small, positive ids.
 pub const DUMMY_NODE_ID: NodeId = NodeId(!0);
 
+/// A modifier on a bound, currently this is only used for `?Sized`, where the
+/// modifier is `Maybe`. Negative bounds should also be handled here.
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitBoundModifier {
+    None,
+    Maybe,
+}
+
 /// The AST represents all type param bounds as types.
 /// typeck::collect::compute_bounds matches these against
 /// the "special" built-in traits (see middle::lang_items) and
 /// detects Copy, Send and Sync.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TyParamBound {
-    TraitTyParamBound(PolyTraitRef, TraitBoundModifier),
-    RegionTyParamBound(Lifetime)
+pub enum GenericBound {
+    Trait(PolyTraitRef, TraitBoundModifier),
+    Outlives(Lifetime)
 }
 
-impl TyParamBound {
+impl GenericBound {
     pub fn span(&self) -> Span {
         match self {
-            &TraitTyParamBound(ref t, ..) => t.span,
-            &RegionTyParamBound(ref l) => l.ident.span,
+            &GenericBound::Trait(ref t, ..) => t.span,
+            &GenericBound::Outlives(ref l) => l.ident.span,
         }
     }
 }
 
-/// A modifier on a bound, currently this is only used for `?Sized`, where the
-/// modifier is `Maybe`. Negative bounds should also be handled here.
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TraitBoundModifier {
-    None,
-    Maybe,
-}
-
-pub type TyParamBounds = Vec<TyParamBound>;
+pub type GenericBounds = Vec<GenericBound>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct TyParam {
-    pub attrs: ThinVec<Attribute>,
-    pub ident: Ident,
-    pub id: NodeId,
-    pub bounds: TyParamBounds,
-    pub default: Option<P<Ty>>,
+pub enum GenericParamKind {
+    /// A lifetime definition, e.g. `'a: 'b+'c+'d`.
+    Lifetime,
+    Type {
+        default: Option<P<Ty>>,
+    }
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum GenericParam {
-    Lifetime(LifetimeDef),
-    Type(TyParam),
-}
-
-impl GenericParam {
-    pub fn is_lifetime_param(&self) -> bool {
-        match *self {
-            GenericParam::Lifetime(_) => true,
-            _ => false,
-        }
-    }
+pub struct GenericParam {
+    pub id: NodeId,
+    pub ident: Ident,
+    pub attrs: ThinVec<Attribute>,
+    pub bounds: GenericBounds,
 
-    pub fn is_type_param(&self) -> bool {
-        match *self {
-            GenericParam::Type(_) => true,
-            _ => false,
-        }
-    }
+    pub kind: GenericParamKind,
 }
 
 /// Represents lifetime, type and const parameters attached to a declaration of
@@ -342,31 +325,6 @@ pub struct Generics {
     pub span: Span,
 }
 
-impl Generics {
-    pub fn is_lt_parameterized(&self) -> bool {
-        self.params.iter().any(|param| param.is_lifetime_param())
-    }
-
-    pub fn is_type_parameterized(&self) -> bool {
-        self.params.iter().any(|param| param.is_type_param())
-    }
-
-    pub fn is_parameterized(&self) -> bool {
-        !self.params.is_empty()
-    }
-
-    pub fn span_for_name(&self, name: &str) -> Option<Span> {
-        for param in &self.params {
-            if let GenericParam::Type(ref t) = *param {
-                if t.ident.name == name {
-                    return Some(t.ident.span);
-                }
-            }
-        }
-        None
-    }
-}
-
 impl Default for Generics {
     /// Creates an instance of `Generics`.
     fn default() ->  Generics {
@@ -422,7 +380,7 @@ pub struct WhereBoundPredicate {
     /// The type being bounded
     pub bounded_ty: P<Ty>,
     /// Trait and lifetime bounds (`Clone+Send+'static`)
-    pub bounds: TyParamBounds,
+    pub bounds: GenericBounds,
 }
 
 /// A lifetime predicate.
@@ -432,7 +390,7 @@ pub struct WhereBoundPredicate {
 pub struct WhereRegionPredicate {
     pub span: Span,
     pub lifetime: Lifetime,
-    pub bounds: Vec<Lifetime>,
+    pub bounds: GenericBounds,
 }
 
 /// An equality predicate (unsupported).
@@ -968,11 +926,11 @@ impl Expr {
         }
     }
 
-    fn to_bound(&self) -> Option<TyParamBound> {
+    fn to_bound(&self) -> Option<GenericBound> {
         match &self.node {
             ExprKind::Path(None, path) =>
-                Some(TraitTyParamBound(PolyTraitRef::new(Vec::new(), path.clone(), self.span),
-                                       TraitBoundModifier::None)),
+                Some(GenericBound::Trait(PolyTraitRef::new(Vec::new(), path.clone(), self.span),
+                                         TraitBoundModifier::None)),
             _ => None,
         }
     }
@@ -1393,7 +1351,7 @@ pub struct TraitItem {
 pub enum TraitItemKind {
     Const(P<Ty>, Option<P<Expr>>),
     Method(MethodSig, Option<P<Block>>),
-    Type(TyParamBounds, Option<P<Ty>>),
+    Type(GenericBounds, Option<P<Ty>>),
     Macro(Mac),
 }
 
@@ -1578,10 +1536,10 @@ pub enum TyKind {
     Path(Option<QSelf>, Path),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
-    TraitObject(TyParamBounds, TraitObjectSyntax),
+    TraitObject(GenericBounds, TraitObjectSyntax),
     /// An `impl Bound1 + Bound2 + Bound3` type
     /// where `Bound` is a trait or a lifetime.
-    ImplTrait(TyParamBounds),
+    ImplTrait(GenericBounds),
     /// No-op; kept solely so that we can pretty-print faithfully
     Paren(P<Ty>),
     /// Unused for now
@@ -2102,11 +2060,11 @@ pub enum ItemKind {
     /// A Trait declaration (`trait` or `pub trait`).
     ///
     /// E.g. `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`
-    Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
+    Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec<TraitItem>),
     /// Trait alias
     ///
     /// E.g. `trait Foo = Bar + Quux;`
-    TraitAlias(Generics, TyParamBounds),
+    TraitAlias(Generics, GenericBounds),
     /// An implementation.
     ///
     /// E.g. `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 2389ed799cf..ded493fe395 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -1446,17 +1446,12 @@ impl HasAttrs for Stmt {
 
 impl HasAttrs for GenericParam {
     fn attrs(&self) -> &[ast::Attribute] {
-        match self {
-            GenericParam::Lifetime(lifetime) => lifetime.attrs(),
-            GenericParam::Type(ty) => ty.attrs(),
-        }
+        &self.attrs
     }
 
-    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
-        match self {
-            GenericParam::Lifetime(lifetime) => GenericParam::Lifetime(lifetime.map_attrs(f)),
-            GenericParam::Type(ty) => GenericParam::Type(ty.map_attrs(f)),
-        }
+    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(mut self, f: F) -> Self {
+        self.attrs = self.attrs.map_attrs(f);
+        self
     }
 }
 
@@ -1479,5 +1474,5 @@ macro_rules! derive_has_attrs {
 
 derive_has_attrs! {
     Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
-    ast::Field, ast::FieldPat, ast::Variant_, ast::LifetimeDef, ast::TyParam
+    ast::Field, ast::FieldPat, ast::Variant_
 }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 4a6f06dcc17..9044cab05d6 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -30,10 +30,9 @@ pub trait AstBuilder {
     fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path;
     fn path_all(&self, sp: Span,
                 global: bool,
-                idents: Vec<ast::Ident> ,
-                lifetimes: Vec<ast::Lifetime>,
-                types: Vec<P<ast::Ty>>,
-                bindings: Vec<ast::TypeBinding> )
+                idents: Vec<ast::Ident>,
+                args: Vec<ast::GenericArg>,
+                bindings: Vec<ast::TypeBinding>)
         -> ast::Path;
 
     fn qpath(&self, self_type: P<ast::Ty>,
@@ -43,8 +42,7 @@ pub trait AstBuilder {
     fn qpath_all(&self, self_type: P<ast::Ty>,
                 trait_path: ast::Path,
                 ident: ast::Ident,
-                lifetimes: Vec<ast::Lifetime>,
-                types: Vec<P<ast::Ty>>,
+                args: Vec<ast::GenericArg>,
                 bindings: Vec<ast::TypeBinding>)
                 -> (ast::QSelf, ast::Path);
 
@@ -70,19 +68,19 @@ pub trait AstBuilder {
                span: Span,
                id: ast::Ident,
                attrs: Vec<ast::Attribute>,
-               bounds: ast::TyParamBounds,
-               default: Option<P<ast::Ty>>) -> ast::TyParam;
+               bounds: ast::GenericBounds,
+               default: Option<P<ast::Ty>>) -> ast::GenericParam;
 
     fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
     fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef;
-    fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
+    fn trait_bound(&self, path: ast::Path) -> ast::GenericBound;
     fn lifetime(&self, span: Span, ident: ast::Ident) -> ast::Lifetime;
     fn lifetime_def(&self,
                     span: Span,
                     ident: ast::Ident,
                     attrs: Vec<ast::Attribute>,
-                    bounds: Vec<ast::Lifetime>)
-                    -> ast::LifetimeDef;
+                    bounds: ast::GenericBounds)
+                    -> ast::GenericParam;
 
     // statements
     fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt;
@@ -304,34 +302,33 @@ pub trait AstBuilder {
 
 impl<'a> AstBuilder for ExtCtxt<'a> {
     fn path(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path {
-        self.path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new())
+        self.path_all(span, false, strs, vec![], vec![])
     }
     fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path {
         self.path(span, vec![id])
     }
     fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path {
-        self.path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new())
+        self.path_all(span, true, strs, vec![], vec![])
     }
     fn path_all(&self,
                 span: Span,
                 global: bool,
                 mut idents: Vec<ast::Ident> ,
-                lifetimes: Vec<ast::Lifetime>,
-                types: Vec<P<ast::Ty>>,
+                args: Vec<ast::GenericArg>,
                 bindings: Vec<ast::TypeBinding> )
                 -> ast::Path {
         let last_ident = idents.pop().unwrap();
-        let mut segments: Vec<ast::PathSegment> = Vec::new();
+        let mut segments: Vec<ast::PathSegment> = vec![];
 
         segments.extend(idents.into_iter().map(|ident| {
             ast::PathSegment::from_ident(ident.with_span_pos(span))
         }));
-        let parameters = if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
-            ast::AngleBracketedParameterData { lifetimes, types, bindings, span }.into()
+        let args = if !args.is_empty() || !bindings.is_empty() {
+            ast::AngleBracketedArgs { args, bindings, span }.into()
         } else {
             None
         };
-        segments.push(ast::PathSegment { ident: last_ident.with_span_pos(span), parameters });
+        segments.push(ast::PathSegment { ident: last_ident.with_span_pos(span), args });
         let mut path = ast::Path { span, segments };
         if global {
             if let Some(seg) = path.make_root() {
@@ -349,7 +346,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
              trait_path: ast::Path,
              ident: ast::Ident)
              -> (ast::QSelf, ast::Path) {
-        self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![])
+        self.qpath_all(self_type, trait_path, ident, vec![], vec![])
     }
 
     /// Constructs a qualified path.
@@ -359,17 +356,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                  self_type: P<ast::Ty>,
                  trait_path: ast::Path,
                  ident: ast::Ident,
-                 lifetimes: Vec<ast::Lifetime>,
-                 types: Vec<P<ast::Ty>>,
+                 args: Vec<ast::GenericArg>,
                  bindings: Vec<ast::TypeBinding>)
                  -> (ast::QSelf, ast::Path) {
         let mut path = trait_path;
-        let parameters = if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
-            ast::AngleBracketedParameterData { lifetimes, types, bindings, span: ident.span }.into()
+        let args = if !args.is_empty() || !bindings.is_empty() {
+            ast::AngleBracketedArgs { args, bindings, span: ident.span }.into()
         } else {
             None
         };
-        path.segments.push(ast::PathSegment { ident, parameters });
+        path.segments.push(ast::PathSegment { ident, args });
 
         (ast::QSelf {
             ty: self_type,
@@ -428,8 +424,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             self.path_all(DUMMY_SP,
                           true,
                           self.std_path(&["option", "Option"]),
-                          Vec::new(),
-                          vec![ ty ],
+                          vec![ast::GenericArg::Type(ty)],
                           Vec::new()))
     }
 
@@ -441,14 +436,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                span: Span,
                ident: ast::Ident,
                attrs: Vec<ast::Attribute>,
-               bounds: ast::TyParamBounds,
-               default: Option<P<ast::Ty>>) -> ast::TyParam {
-        ast::TyParam {
+               bounds: ast::GenericBounds,
+               default: Option<P<ast::Ty>>) -> ast::GenericParam {
+        ast::GenericParam {
             ident: ident.with_span_pos(span),
             id: ast::DUMMY_NODE_ID,
             attrs: attrs.into(),
             bounds,
-            default,
+            kind: ast::GenericParamKind::Type {
+                default,
+            }
         }
     }
 
@@ -467,8 +464,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         }
     }
 
-    fn typarambound(&self, path: ast::Path) -> ast::TyParamBound {
-        ast::TraitTyParamBound(self.poly_trait_ref(path.span, path), ast::TraitBoundModifier::None)
+    fn trait_bound(&self, path: ast::Path) -> ast::GenericBound {
+        ast::GenericBound::Trait(self.poly_trait_ref(path.span, path),
+                                 ast::TraitBoundModifier::None)
     }
 
     fn lifetime(&self, span: Span, ident: ast::Ident) -> ast::Lifetime {
@@ -479,12 +477,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                     span: Span,
                     ident: ast::Ident,
                     attrs: Vec<ast::Attribute>,
-                    bounds: Vec<ast::Lifetime>)
-                    -> ast::LifetimeDef {
-        ast::LifetimeDef {
+                    bounds: ast::GenericBounds)
+                    -> ast::GenericParam {
+        let lifetime = self.lifetime(span, ident);
+        ast::GenericParam {
+            ident: lifetime.ident,
+            id: lifetime.id,
             attrs: attrs.into(),
-            lifetime: self.lifetime(span, ident),
             bounds,
+            kind: ast::GenericParamKind::Lifetime,
         }
     }
 
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index a2ea6a21484..be4cf197be4 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1797,7 +1797,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     gate_feature_post!(&self, associated_type_defaults, ti.span,
                                        "associated type defaults are unstable");
                 }
-                if ti.generics.is_parameterized() {
+                if !ti.generics.params.is_empty() {
                     gate_feature_post!(&self, generic_associated_types, ti.span,
                                        "generic associated types are unstable");
                 }
@@ -1824,7 +1824,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
                 }
             }
-            ast::ImplItemKind::Type(_) if ii.generics.is_parameterized() => {
+            ast::ImplItemKind::Type(_) if !ii.generics.params.is_empty() => {
                 gate_feature_post!(&self, generic_associated_types, ii.span,
                                    "generic associated types are unstable");
             }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 8544ef330dc..93248fe3bfa 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -132,10 +132,21 @@ pub trait Folder : Sized {
         noop_fold_exprs(es, self)
     }
 
+    fn fold_generic_arg(&mut self, arg: GenericArg) -> GenericArg {
+        match arg {
+            GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.fold_lifetime(lt)),
+            GenericArg::Type(ty) => GenericArg::Type(self.fold_ty(ty)),
+        }
+    }
+
     fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
         noop_fold_ty(t, self)
     }
 
+    fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime {
+        noop_fold_lifetime(l, self)
+    }
+
     fn fold_ty_binding(&mut self, t: TypeBinding) -> TypeBinding {
         noop_fold_ty_binding(t, self)
     }
@@ -172,18 +183,18 @@ pub trait Folder : Sized {
         noop_fold_qpath(qs, p, self)
     }
 
-    fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters {
-        noop_fold_path_parameters(p, self)
+    fn fold_generic_args(&mut self, p: GenericArgs) -> GenericArgs {
+        noop_fold_generic_args(p, self)
     }
 
-    fn fold_angle_bracketed_parameter_data(&mut self, p: AngleBracketedParameterData)
-                                           -> AngleBracketedParameterData
+    fn fold_angle_bracketed_parameter_data(&mut self, p: AngleBracketedArgs)
+                                           -> AngleBracketedArgs
     {
         noop_fold_angle_bracketed_parameter_data(p, self)
     }
 
-    fn fold_parenthesized_parameter_data(&mut self, p: ParenthesizedParameterData)
-                                         -> ParenthesizedParameterData
+    fn fold_parenthesized_parameter_data(&mut self, p: ParenthesisedArgs)
+                                         -> ParenthesisedArgs
     {
         noop_fold_parenthesized_parameter_data(p, self)
     }
@@ -233,10 +244,6 @@ pub trait Folder : Sized {
         noop_fold_variant_data(vdata, self)
     }
 
-    fn fold_ty_param(&mut self, tp: TyParam) -> TyParam {
-        noop_fold_ty_param(tp, self)
-    }
-
     fn fold_generic_param(&mut self, param: GenericParam) -> GenericParam {
         noop_fold_generic_param(param, self)
     }
@@ -261,18 +268,16 @@ pub trait Folder : Sized {
         noop_fold_interpolated(nt, self)
     }
 
-    fn fold_opt_bounds(&mut self, b: Option<TyParamBounds>)
-                       -> Option<TyParamBounds> {
+    fn fold_opt_bounds(&mut self, b: Option<GenericBounds>) -> Option<GenericBounds> {
         noop_fold_opt_bounds(b, self)
     }
 
-    fn fold_bounds(&mut self, b: TyParamBounds)
-                       -> TyParamBounds {
+    fn fold_bounds(&mut self, b: GenericBounds) -> GenericBounds {
         noop_fold_bounds(b, self)
     }
 
-    fn fold_ty_param_bound(&mut self, tpb: TyParamBound) -> TyParamBound {
-        noop_fold_ty_param_bound(tpb, self)
+    fn fold_param_bound(&mut self, tpb: GenericBound) -> GenericBound {
+        noop_fold_param_bound(tpb, self)
     }
 
     fn fold_mt(&mut self, mt: MutTy) -> MutTy {
@@ -385,10 +390,10 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
                 TyKind::Typeof(fld.fold_anon_const(expr))
             }
             TyKind::TraitObject(bounds, syntax) => {
-                TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)), syntax)
+                TyKind::TraitObject(bounds.move_map(|b| fld.fold_param_bound(b)), syntax)
             }
             TyKind::ImplTrait(bounds) => {
-                TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+                TyKind::ImplTrait(bounds.move_map(|b| fld.fold_param_bound(b)))
             }
             TyKind::Mac(mac) => {
                 TyKind::Mac(fld.fold_mac(mac))
@@ -433,9 +438,9 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
 
 pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
     Path {
-        segments: segments.move_map(|PathSegment {ident, parameters}| PathSegment {
+        segments: segments.move_map(|PathSegment { ident, args }| PathSegment {
             ident: fld.fold_ident(ident),
-            parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))),
+            args: args.map(|args| args.map(|args| fld.fold_generic_args(args))),
         }),
         span: fld.new_span(span)
     }
@@ -454,36 +459,40 @@ pub fn noop_fold_qpath<T: Folder>(qself: Option<QSelf>,
     (qself, fld.fold_path(path))
 }
 
-pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters, fld: &mut T)
-                                            -> PathParameters
+pub fn noop_fold_generic_args<T: Folder>(generic_args: GenericArgs, fld: &mut T) -> GenericArgs
 {
-    match path_parameters {
-        PathParameters::AngleBracketed(data) =>
-            PathParameters::AngleBracketed(fld.fold_angle_bracketed_parameter_data(data)),
-        PathParameters::Parenthesized(data) =>
-            PathParameters::Parenthesized(fld.fold_parenthesized_parameter_data(data)),
+    match generic_args {
+        GenericArgs::AngleBracketed(data) => {
+            GenericArgs::AngleBracketed(fld.fold_angle_bracketed_parameter_data(data))
+        }
+        GenericArgs::Parenthesized(data) => {
+            GenericArgs::Parenthesized(fld.fold_parenthesized_parameter_data(data))
+        }
     }
 }
 
-pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedParameterData,
+pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedArgs,
                                                            fld: &mut T)
-                                                           -> AngleBracketedParameterData
+                                                           -> AngleBracketedArgs
 {
-    let AngleBracketedParameterData { lifetimes, types, bindings, span } = data;
-    AngleBracketedParameterData { lifetimes: lifetimes.move_map(|l| noop_fold_lifetime(l, fld)),
-                                  types: types.move_map(|ty| fld.fold_ty(ty)),
-                                  bindings: bindings.move_map(|b| fld.fold_ty_binding(b)),
-                                  span: fld.new_span(span) }
+    let AngleBracketedArgs { args, bindings, span } = data;
+    AngleBracketedArgs {
+        args: args.move_map(|arg| fld.fold_generic_arg(arg)),
+        bindings: bindings.move_map(|b| fld.fold_ty_binding(b)),
+        span: fld.new_span(span)
+    }
 }
 
-pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData,
+pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesisedArgs,
                                                          fld: &mut T)
-                                                         -> ParenthesizedParameterData
+                                                         -> ParenthesisedArgs
 {
-    let ParenthesizedParameterData { inputs, output, span } = data;
-    ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
-                                 output: output.map(|ty| fld.fold_ty(ty)),
-                                 span: fld.new_span(span) }
+    let ParenthesisedArgs { inputs, output, span } = data;
+    ParenthesisedArgs {
+        inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
+        output: output.map(|ty| fld.fold_ty(ty)),
+        span: fld.new_span(span)
+    }
 }
 
 pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
@@ -667,47 +676,33 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
     })
 }
 
-pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
-                                   -> TyParamBound
-                                   where T: Folder {
-    match tpb {
-        TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier),
-        RegionTyParamBound(lifetime) => RegionTyParamBound(noop_fold_lifetime(lifetime, fld)),
-    }
-}
-
-pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
-    let TyParam {attrs, id, ident, bounds, default} = tp;
-    let attrs: Vec<_> = attrs.into();
-    TyParam {
-        attrs: attrs.into_iter()
-            .flat_map(|x| fld.fold_attribute(x).into_iter())
-            .collect::<Vec<_>>()
-            .into(),
-        id: fld.new_id(id),
-        ident: fld.fold_ident(ident),
-        bounds: fld.fold_bounds(bounds),
-        default: default.map(|x| fld.fold_ty(x)),
+pub fn noop_fold_param_bound<T>(pb: GenericBound, fld: &mut T) -> GenericBound where T: Folder {
+    match pb {
+        GenericBound::Trait(ty, modifier) => {
+            GenericBound::Trait(fld.fold_poly_trait_ref(ty), modifier)
+        }
+        GenericBound::Outlives(lifetime) => {
+            GenericBound::Outlives(noop_fold_lifetime(lifetime, fld))
+        }
     }
 }
 
 pub fn noop_fold_generic_param<T: Folder>(param: GenericParam, fld: &mut T) -> GenericParam {
-    match param {
-        GenericParam::Lifetime(l) => {
-            let attrs: Vec<_> = l.attrs.into();
-            GenericParam::Lifetime(LifetimeDef {
-                attrs: attrs.into_iter()
+    let attrs: Vec<_> = param.attrs.into();
+    GenericParam {
+        ident: fld.fold_ident(param.ident),
+        id: fld.new_id(param.id),
+        attrs: attrs.into_iter()
                     .flat_map(|x| fld.fold_attribute(x).into_iter())
                     .collect::<Vec<_>>()
                     .into(),
-                lifetime: Lifetime {
-                    id: fld.new_id(l.lifetime.id),
-                    ident: fld.fold_ident(l.lifetime.ident),
-                },
-                bounds: l.bounds.move_map(|l| noop_fold_lifetime(l, fld)),
-            })
+        bounds: param.bounds.move_map(|l| noop_fold_param_bound(l, fld)),
+        kind: match param.kind {
+            GenericParamKind::Lifetime => GenericParamKind::Lifetime,
+            GenericParamKind::Type { default } => GenericParamKind::Type {
+                default: default.map(|ty| fld.fold_ty(ty))
+            }
         }
-        GenericParam::Type(t) => GenericParam::Type(fld.fold_ty_param(t)),
     }
 }
 
@@ -765,7 +760,7 @@ pub fn noop_fold_where_predicate<T: Folder>(
             ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
                 bound_generic_params: fld.fold_generic_params(bound_generic_params),
                 bounded_ty: fld.fold_ty(bounded_ty),
-                bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
+                bounds: bounds.move_map(|x| fld.fold_param_bound(x)),
                 span: fld.new_span(span)
             })
         }
@@ -775,7 +770,7 @@ pub fn noop_fold_where_predicate<T: Folder>(
             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
                 span: fld.new_span(span),
                 lifetime: noop_fold_lifetime(lifetime, fld),
-                bounds: bounds.move_map(|bound| noop_fold_lifetime(bound, fld))
+                bounds: bounds.move_map(|bound| noop_fold_param_bound(bound, fld))
             })
         }
         ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
@@ -854,14 +849,14 @@ pub fn noop_fold_mt<T: Folder>(MutTy {ty, mutbl}: MutTy, folder: &mut T) -> MutT
     }
 }
 
-pub fn noop_fold_opt_bounds<T: Folder>(b: Option<TyParamBounds>, folder: &mut T)
-                                       -> Option<TyParamBounds> {
+pub fn noop_fold_opt_bounds<T: Folder>(b: Option<GenericBounds>, folder: &mut T)
+                                       -> Option<GenericBounds> {
     b.map(|bounds| folder.fold_bounds(bounds))
 }
 
-fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T)
-                          -> TyParamBounds {
-    bounds.move_map(|bound| folder.fold_ty_param_bound(bound))
+fn noop_fold_bounds<T: Folder>(bounds: GenericBounds, folder: &mut T)
+                          -> GenericBounds {
+    bounds.move_map(|bound| folder.fold_param_bound(bound))
 }
 
 pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
@@ -1184,8 +1179,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 ExprKind::MethodCall(
                     PathSegment {
                         ident: folder.fold_ident(seg.ident),
-                        parameters: seg.parameters.map(|ps| {
-                            ps.map(|ps| folder.fold_path_parameters(ps))
+                        args: seg.args.map(|args| {
+                            args.map(|args| folder.fold_generic_args(args))
                         }),
                     },
                     folder.fold_exprs(args))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 1735951da2f..6f78ae9ebca 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 use rustc_target::spec::abi::{self, Abi};
-use ast::{AngleBracketedParameterData, ParenthesizedParameterData, AttrStyle, BareFnTy};
-use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
+use ast::{AngleBracketedArgs, ParenthesisedArgs, AttrStyle, BareFnTy};
+use ast::{GenericBound, TraitBoundModifier};
 use ast::Unsafety;
 use ast::{Mod, AnonConst, Arg, Arm, Attribute, BindingMode, TraitItemKind};
 use ast::Block;
@@ -21,9 +21,10 @@ use ast::EnumDef;
 use ast::{Expr, ExprKind, RangeLimits};
 use ast::{Field, FnDecl};
 use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
-use ast::GenericParam;
+use ast::{GenericParam, GenericParamKind};
+use ast::GenericArg;
 use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
-use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind};
+use ast::{Label, Lifetime, Lit, LitKind};
 use ast::Local;
 use ast::MacStmtStyle;
 use ast::{Mac, Mac_, MacDelimiter};
@@ -35,7 +36,7 @@ use ast::{VariantData, StructField};
 use ast::StrStyle;
 use ast::SelfKind;
 use ast::{TraitItem, TraitRef, TraitObjectSyntax};
-use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
+use ast::{Ty, TyKind, TypeBinding, GenericBounds};
 use ast::{Visibility, VisibilityKind, WhereClause, CrateSugar};
 use ast::{UseTree, UseTreeKind};
 use ast::{BinOpKind, UnOp};
@@ -1245,8 +1246,7 @@ impl<'a> Parser<'a> {
     }
 
     /// parse a TyKind::BareFn type:
-    fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>)
-                            -> PResult<'a, TyKind> {
+    fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> {
         /*
 
         [unsafe] [extern "ABI"] fn (S) -> T
@@ -1311,9 +1311,7 @@ impl<'a> Parser<'a> {
         let lo = self.span;
 
         let (name, node, generics) = if self.eat_keyword(keywords::Type) {
-            let (generics, TyParam {ident, bounds, default, ..}) =
-                self.parse_trait_item_assoc_ty(vec![])?;
-            (ident, TraitItemKind::Type(bounds, default), generics)
+            self.parse_trait_item_assoc_ty()?
         } else if self.is_const_item() {
             self.expect_keyword(keywords::Const)?;
             let ident = self.parse_ident()?;
@@ -1446,7 +1444,7 @@ impl<'a> Parser<'a> {
                     TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
                             if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
                         let path = match bounds[0] {
-                            TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
+                            GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(),
                             _ => self.bug("unexpected lifetime bound"),
                         };
                         self.parse_remaining_bounds(Vec::new(), path, lo, true)?
@@ -1511,7 +1509,7 @@ impl<'a> Parser<'a> {
             }
         } else if self.eat_keyword(keywords::Impl) {
             // Always parse bounds greedily for better error recovery.
-            let bounds = self.parse_ty_param_bounds()?;
+            let bounds = self.parse_generic_bounds()?;
             impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
             TyKind::ImplTrait(bounds)
         } else if self.check_keyword(keywords::Dyn) &&
@@ -1519,13 +1517,13 @@ impl<'a> Parser<'a> {
                                          !can_continue_type_after_non_fn_ident(t)) {
             self.bump(); // `dyn`
             // Always parse bounds greedily for better error recovery.
-            let bounds = self.parse_ty_param_bounds()?;
+            let bounds = self.parse_generic_bounds()?;
             impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
             TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
         } else if self.check(&token::Question) ||
                   self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) {
             // Bound list (trait object type)
-            TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?,
+            TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus)?,
                                 TraitObjectSyntax::None)
         } else if self.eat_lt() {
             // Qualified path
@@ -1568,10 +1566,10 @@ impl<'a> Parser<'a> {
     fn parse_remaining_bounds(&mut self, generic_params: Vec<GenericParam>, path: ast::Path,
                               lo: Span, parse_plus: bool) -> PResult<'a, TyKind> {
         let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
-        let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)];
+        let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
         if parse_plus {
             self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
-            bounds.append(&mut self.parse_ty_param_bounds()?);
+            bounds.append(&mut self.parse_generic_bounds()?);
         }
         Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
     }
@@ -1596,7 +1594,7 @@ impl<'a> Parser<'a> {
         }
 
         self.bump(); // `+`
-        let bounds = self.parse_ty_param_bounds()?;
+        let bounds = self.parse_generic_bounds()?;
         let sum_span = ty.span.to(self.prev_span);
 
         let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178,
@@ -1612,7 +1610,7 @@ impl<'a> Parser<'a> {
                     s.print_mutability(mut_ty.mutbl)?;
                     s.popen()?;
                     s.print_type(&mut_ty.ty)?;
-                    s.print_bounds(" +", &bounds)?;
+                    s.print_type_bounds(" +", &bounds)?;
                     s.pclose()
                 });
                 err.span_suggestion_with_applicability(
@@ -1894,7 +1892,7 @@ impl<'a> Parser<'a> {
                              -> PResult<'a, ast::Path> {
         maybe_whole!(self, NtPath, |path| {
             if style == PathStyle::Mod &&
-               path.segments.iter().any(|segment| segment.parameters.is_some()) {
+               path.segments.iter().any(|segment| segment.args.is_some()) {
                 self.diagnostic().span_err(path.span, "unexpected generic arguments in path");
             }
             path
@@ -1969,12 +1967,12 @@ impl<'a> Parser<'a> {
                                  .span_label(self.prev_span, "try removing `::`").emit();
             }
 
-            let parameters = if self.eat_lt() {
+            let args = if self.eat_lt() {
                 // `<'a, T, A = U>`
-                let (lifetimes, types, bindings) = self.parse_generic_args()?;
+                let (args, bindings) = self.parse_generic_args()?;
                 self.expect_gt()?;
                 let span = lo.to(self.prev_span);
-                AngleBracketedParameterData { lifetimes, types, bindings, span }.into()
+                AngleBracketedArgs { args, bindings, span }.into()
             } else {
                 // `(T, U) -> R`
                 self.bump(); // `(`
@@ -1990,10 +1988,10 @@ impl<'a> Parser<'a> {
                     None
                 };
                 let span = lo.to(self.prev_span);
-                ParenthesizedParameterData { inputs, output, span }.into()
+                ParenthesisedArgs { inputs, output, span }.into()
             };
 
-            PathSegment { ident, parameters }
+            PathSegment { ident, args }
         } else {
             // Generic arguments are not found.
             PathSegment::from_ident(ident)
@@ -2543,8 +2541,8 @@ impl<'a> Parser<'a> {
             }
             _ => {
                 // Field access `expr.f`
-                if let Some(parameters) = segment.parameters {
-                    self.span_err(parameters.span(),
+                if let Some(args) = segment.args {
+                    self.span_err(args.span(),
                                   "field expressions may not have generic arguments");
                 }
 
@@ -4737,7 +4735,7 @@ impl<'a> Parser<'a> {
     // LT_BOUND = LIFETIME (e.g. `'a`)
     // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
     // TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
-    fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
+    fn parse_generic_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, GenericBounds> {
         let mut bounds = Vec::new();
         loop {
             // This needs to be syncronized with `Token::can_begin_bound`.
@@ -4754,7 +4752,7 @@ impl<'a> Parser<'a> {
                         self.span_err(question_span,
                                       "`?` may only modify trait bounds, not lifetime bounds");
                     }
-                    bounds.push(RegionTyParamBound(self.expect_lifetime()));
+                    bounds.push(GenericBound::Outlives(self.expect_lifetime()));
                     if has_parens {
                         self.expect(&token::CloseDelim(token::Paren))?;
                         self.span_err(self.prev_span,
@@ -4772,7 +4770,7 @@ impl<'a> Parser<'a> {
                     } else {
                         TraitBoundModifier::None
                     };
-                    bounds.push(TraitTyParamBound(poly_trait, modifier));
+                    bounds.push(GenericBound::Trait(poly_trait, modifier));
                 }
             } else {
                 break
@@ -4786,16 +4784,16 @@ impl<'a> Parser<'a> {
         return Ok(bounds);
     }
 
-    fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> {
-        self.parse_ty_param_bounds_common(true)
+    fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
+        self.parse_generic_bounds_common(true)
     }
 
     // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
     // BOUND = LT_BOUND (e.g. `'a`)
-    fn parse_lt_param_bounds(&mut self) -> Vec<Lifetime> {
+    fn parse_lt_param_bounds(&mut self) -> GenericBounds {
         let mut lifetimes = Vec::new();
         while self.check_lifetime() {
-            lifetimes.push(self.expect_lifetime());
+            lifetimes.push(ast::GenericBound::Outlives(self.expect_lifetime()));
 
             if !self.eat_plus() {
                 break
@@ -4805,12 +4803,14 @@ impl<'a> Parser<'a> {
     }
 
     /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
-    fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, TyParam> {
+    fn parse_ty_param(&mut self,
+                      preceding_attrs: Vec<Attribute>)
+                      -> PResult<'a, GenericParam> {
         let ident = self.parse_ident()?;
 
         // Parse optional colon and param bounds.
         let bounds = if self.eat(&token::Colon) {
-            self.parse_ty_param_bounds()?
+            self.parse_generic_bounds()?
         } else {
             Vec::new()
         };
@@ -4821,25 +4821,27 @@ impl<'a> Parser<'a> {
             None
         };
 
-        Ok(TyParam {
-            attrs: preceding_attrs.into(),
+        Ok(GenericParam {
             ident,
             id: ast::DUMMY_NODE_ID,
+            attrs: preceding_attrs.into(),
             bounds,
-            default,
+            kind: GenericParamKind::Type {
+                default,
+            }
         })
     }
 
     /// Parses the following grammar:
-    ///     TraitItemAssocTy = Ident ["<"...">"] [":" [TyParamBounds]] ["where" ...] ["=" Ty]
-    fn parse_trait_item_assoc_ty(&mut self, preceding_attrs: Vec<Attribute>)
-        -> PResult<'a, (ast::Generics, TyParam)> {
+    ///     TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
+    fn parse_trait_item_assoc_ty(&mut self)
+        -> PResult<'a, (Ident, TraitItemKind, ast::Generics)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
 
         // Parse optional colon and param bounds.
         let bounds = if self.eat(&token::Colon) {
-            self.parse_ty_param_bounds()?
+            self.parse_generic_bounds()?
         } else {
             Vec::new()
         };
@@ -4852,13 +4854,7 @@ impl<'a> Parser<'a> {
         };
         self.expect(&token::Semi)?;
 
-        Ok((generics, TyParam {
-            attrs: preceding_attrs.into(),
-            ident,
-            id: ast::DUMMY_NODE_ID,
-            bounds,
-            default,
-        }))
+        Ok((ident, TraitItemKind::Type(bounds, default), generics))
     }
 
     /// Parses (possibly empty) list of lifetime and type parameters, possibly including
@@ -4876,18 +4872,20 @@ impl<'a> Parser<'a> {
                 } else {
                     Vec::new()
                 };
-                params.push(ast::GenericParam::Lifetime(LifetimeDef {
+                params.push(ast::GenericParam {
+                    ident: lifetime.ident,
+                    id: lifetime.id,
                     attrs: attrs.into(),
-                    lifetime,
                     bounds,
-                }));
+                    kind: ast::GenericParamKind::Lifetime,
+                });
                 if seen_ty_param {
                     self.span_err(self.prev_span,
                         "lifetime parameters must be declared prior to type parameters");
                 }
             } else if self.check_ident() {
                 // Parse type parameter.
-                params.push(ast::GenericParam::Type(self.parse_ty_param(attrs)?));
+                params.push(self.parse_ty_param(attrs)?);
                 seen_ty_param = true;
             } else {
                 // Check for trailing attributes and stop parsing.
@@ -4936,16 +4934,16 @@ impl<'a> Parser<'a> {
 
     /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
     /// possibly including trailing comma.
-    fn parse_generic_args(&mut self) -> PResult<'a, (Vec<Lifetime>, Vec<P<Ty>>, Vec<TypeBinding>)> {
-        let mut lifetimes = Vec::new();
-        let mut types = Vec::new();
+    fn parse_generic_args(&mut self)
+                          -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
+        let mut args = Vec::new();
         let mut bindings = Vec::new();
         let mut seen_type = false;
         let mut seen_binding = false;
         loop {
             if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
                 // Parse lifetime argument.
-                lifetimes.push(self.expect_lifetime());
+                args.push(GenericArg::Lifetime(self.expect_lifetime()));
                 if seen_type || seen_binding {
                     self.span_err(self.prev_span,
                         "lifetime parameters must be declared prior to type parameters");
@@ -4965,11 +4963,12 @@ impl<'a> Parser<'a> {
                 seen_binding = true;
             } else if self.check_type() {
                 // Parse type argument.
-                types.push(self.parse_ty()?);
+                let ty_param = self.parse_ty()?;
                 if seen_binding {
-                    self.span_err(types[types.len() - 1].span,
+                    self.span_err(ty_param.span,
                         "type parameters must be declared prior to associated type bindings");
                 }
+                args.push(GenericArg::Type(ty_param));
                 seen_type = true;
             } else {
                 break
@@ -4979,7 +4978,7 @@ impl<'a> Parser<'a> {
                 break
             }
         }
-        Ok((lifetimes, types, bindings))
+        Ok((args, bindings))
     }
 
     /// Parses an optional `where` clause and places it in `generics`.
@@ -5037,7 +5036,7 @@ impl<'a> Parser<'a> {
                 // or with mandatory equality sign and the second type.
                 let ty = self.parse_ty()?;
                 if self.eat(&token::Colon) {
-                    let bounds = self.parse_ty_param_bounds()?;
+                    let bounds = self.parse_generic_bounds()?;
                     where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
                         ast::WhereBoundPredicate {
                             span: lo.to(self.prev_span),
@@ -5537,14 +5536,14 @@ impl<'a> Parser<'a> {
 
         // Parse optional colon and supertrait bounds.
         let bounds = if self.eat(&token::Colon) {
-            self.parse_ty_param_bounds()?
+            self.parse_generic_bounds()?
         } else {
             Vec::new()
         };
 
         if self.eat(&token::Eq) {
             // it's a trait alias
-            let bounds = self.parse_ty_param_bounds()?;
+            let bounds = self.parse_generic_bounds()?;
             tps.where_clause = self.parse_where_clause()?;
             self.expect(&token::Semi)?;
             if unsafety != Unsafety::Normal {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 87edfd69e2b..7a55919f422 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -12,8 +12,8 @@ pub use self::AnnNode::*;
 
 use rustc_target::spec::abi::{self, Abi};
 use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
-use ast::{Attribute, MacDelimiter};
+use ast::{SelfKind, GenericBound, TraitBoundModifier};
+use ast::{Attribute, MacDelimiter, GenericArg};
 use util::parser::{self, AssocOp, Fixity};
 use attr;
 use codemap::{self, CodeMap};
@@ -292,8 +292,8 @@ pub fn ty_to_string(ty: &ast::Ty) -> String {
     to_string(|s| s.print_type(ty))
 }
 
-pub fn bounds_to_string(bounds: &[ast::TyParamBound]) -> String {
-    to_string(|s| s.print_bounds("", bounds))
+pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
+    to_string(|s| s.print_type_bounds("", bounds))
 }
 
 pub fn pat_to_string(pat: &ast::Pat) -> String {
@@ -308,8 +308,8 @@ pub fn expr_to_string(e: &ast::Expr) -> String {
     to_string(|s| s.print_expr(e))
 }
 
-pub fn lifetime_to_string(e: &ast::Lifetime) -> String {
-    to_string(|s| s.print_lifetime(e))
+pub fn lifetime_to_string(lt: &ast::Lifetime) -> String {
+    to_string(|s| s.print_lifetime(*lt))
 }
 
 pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
@@ -1008,15 +1008,21 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_opt_lifetime(&mut self,
-                              lifetime: &Option<ast::Lifetime>) -> io::Result<()> {
-        if let Some(l) = *lifetime {
-            self.print_lifetime(&l)?;
+    pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) -> io::Result<()> {
+        if let Some(lt) = *lifetime {
+            self.print_lifetime(lt)?;
             self.nbsp()?;
         }
         Ok(())
     }
 
+    pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) -> io::Result<()> {
+        match generic_arg {
+            GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
+            GenericArg::Type(ty) => self.print_type(ty),
+        }
+    }
+
     pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
         self.maybe_print_comment(ty.span.lo())?;
         self.ibox(0)?;
@@ -1071,10 +1077,10 @@ impl<'a> State<'a> {
             }
             ast::TyKind::TraitObject(ref bounds, syntax) => {
                 let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
-                self.print_bounds(prefix, &bounds[..])?;
+                self.print_type_bounds(prefix, &bounds[..])?;
             }
             ast::TyKind::ImplTrait(ref bounds) => {
-                self.print_bounds("impl", &bounds[..])?;
+                self.print_type_bounds("impl", &bounds[..])?;
             }
             ast::TyKind::Array(ref ty, ref length) => {
                 self.s.word("[")?;
@@ -1171,13 +1177,13 @@ impl<'a> State<'a> {
 
     fn print_associated_type(&mut self,
                              ident: ast::Ident,
-                             bounds: Option<&ast::TyParamBounds>,
+                             bounds: Option<&ast::GenericBounds>,
                              ty: Option<&ast::Ty>)
                              -> io::Result<()> {
         self.word_space("type")?;
         self.print_ident(ident)?;
         if let Some(bounds) = bounds {
-            self.print_bounds(":", bounds)?;
+            self.print_type_bounds(":", bounds)?;
         }
         if let Some(ty) = ty {
             self.s.space()?;
@@ -1322,7 +1328,7 @@ impl<'a> State<'a> {
                 self.print_unsafety(unsafety)?;
                 self.word_nbsp("impl")?;
 
-                if generics.is_parameterized() {
+                if !generics.params.is_empty() {
                     self.print_generic_params(&generics.params)?;
                     self.s.space()?;
                 }
@@ -1358,7 +1364,7 @@ impl<'a> State<'a> {
                 self.print_generic_params(&generics.params)?;
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 for b in bounds.iter() {
-                    if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
                         self.s.space()?;
                         self.word_space("for ?")?;
                         self.print_trait_ref(&ptr.trait_ref)?;
@@ -1366,7 +1372,7 @@ impl<'a> State<'a> {
                         real_bounds.push(b.clone());
                     }
                 }
-                self.print_bounds(":", &real_bounds[..])?;
+                self.print_type_bounds(":", &real_bounds[..])?;
                 self.print_where_clause(&generics.where_clause)?;
                 self.s.word(" ")?;
                 self.bopen()?;
@@ -1384,7 +1390,7 @@ impl<'a> State<'a> {
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 // FIXME(durka) this seems to be some quite outdated syntax
                 for b in bounds.iter() {
-                    if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
                         self.s.space()?;
                         self.word_space("for ?")?;
                         self.print_trait_ref(&ptr.trait_ref)?;
@@ -1393,7 +1399,7 @@ impl<'a> State<'a> {
                     }
                 }
                 self.nbsp()?;
-                self.print_bounds("=", &real_bounds[..])?;
+                self.print_type_bounds("=", &real_bounds[..])?;
                 self.print_where_clause(&generics.where_clause)?;
                 self.s.word(";")?;
             }
@@ -1984,8 +1990,8 @@ impl<'a> State<'a> {
         self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX)?;
         self.s.word(".")?;
         self.print_ident(segment.ident)?;
-        if let Some(ref parameters) = segment.parameters {
-            self.print_path_parameters(parameters, true)?;
+        if let Some(ref args) = segment.args {
+            self.print_generic_args(args, true)?;
         }
         self.print_call_post(base_args)
     }
@@ -2428,8 +2434,8 @@ impl<'a> State<'a> {
         if segment.ident.name != keywords::CrateRoot.name() &&
            segment.ident.name != keywords::DollarCrate.name() {
             self.print_ident(segment.ident)?;
-            if let Some(ref parameters) = segment.parameters {
-                self.print_path_parameters(parameters, colons_before_params)?;
+            if let Some(ref args) = segment.args {
+                self.print_generic_args(args, colons_before_params)?;
             }
         } else if segment.ident.name == keywords::DollarCrate.name() {
             self.print_dollar_crate(segment.ident.span.ctxt())?;
@@ -2455,44 +2461,30 @@ impl<'a> State<'a> {
         self.s.word("::")?;
         let item_segment = path.segments.last().unwrap();
         self.print_ident(item_segment.ident)?;
-        match item_segment.parameters {
-            Some(ref parameters) => self.print_path_parameters(parameters, colons_before_params),
+        match item_segment.args {
+            Some(ref args) => self.print_generic_args(args, colons_before_params),
             None => Ok(()),
         }
     }
 
-    fn print_path_parameters(&mut self,
-                             parameters: &ast::PathParameters,
-                             colons_before_params: bool)
-                             -> io::Result<()>
+    fn print_generic_args(&mut self,
+                          args: &ast::GenericArgs,
+                          colons_before_params: bool)
+                          -> io::Result<()>
     {
         if colons_before_params {
             self.s.word("::")?
         }
 
-        match *parameters {
-            ast::PathParameters::AngleBracketed(ref data) => {
+        match *args {
+            ast::GenericArgs::AngleBracketed(ref data) => {
                 self.s.word("<")?;
 
-                let mut comma = false;
-                for lifetime in &data.lifetimes {
-                    if comma {
-                        self.word_space(",")?
-                    }
-                    self.print_lifetime(lifetime)?;
-                    comma = true;
-                }
+                self.commasep(Inconsistent, &data.args, |s, generic_arg| {
+                    s.print_generic_arg(generic_arg)
+                })?;
 
-                if !data.types.is_empty() {
-                    if comma {
-                        self.word_space(",")?
-                    }
-                    self.commasep(
-                        Inconsistent,
-                        &data.types,
-                        |s, ty| s.print_type(ty))?;
-                        comma = true;
-                }
+                let mut comma = data.args.len() != 0;
 
                 for binding in data.bindings.iter() {
                     if comma {
@@ -2508,7 +2500,7 @@ impl<'a> State<'a> {
                 self.s.word(">")?
             }
 
-            ast::PathParameters::Parenthesized(ref data) => {
+            ast::GenericArgs::Parenthesized(ref data) => {
                 self.s.word("(")?;
                 self.commasep(
                     Inconsistent,
@@ -2816,9 +2808,9 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_bounds(&mut self,
+    pub fn print_type_bounds(&mut self,
                         prefix: &str,
-                        bounds: &[ast::TyParamBound])
+                        bounds: &[ast::GenericBound])
                         -> io::Result<()> {
         if !bounds.is_empty() {
             self.s.word(prefix)?;
@@ -2834,32 +2826,25 @@ impl<'a> State<'a> {
                 }
 
                 match bound {
-                    TraitTyParamBound(tref, modifier) => {
+                    GenericBound::Trait(tref, modifier) => {
                         if modifier == &TraitBoundModifier::Maybe {
                             self.s.word("?")?;
                         }
                         self.print_poly_trait_ref(tref)?;
                     }
-                    RegionTyParamBound(lt) => {
-                        self.print_lifetime(lt)?;
-                    }
+                    GenericBound::Outlives(lt) => self.print_lifetime(*lt)?,
                 }
             }
         }
         Ok(())
     }
 
-    pub fn print_lifetime(&mut self,
-                          lifetime: &ast::Lifetime)
-                          -> io::Result<()>
-    {
+    pub fn print_lifetime(&mut self, lifetime: ast::Lifetime) -> io::Result<()> {
         self.print_name(lifetime.ident.name)
     }
 
-    pub fn print_lifetime_bounds(&mut self,
-                                 lifetime: &ast::Lifetime,
-                                 bounds: &[ast::Lifetime])
-                                 -> io::Result<()>
+    pub fn print_lifetime_bounds(&mut self, lifetime: ast::Lifetime, bounds: &ast::GenericBounds)
+        -> io::Result<()>
     {
         self.print_lifetime(lifetime)?;
         if !bounds.is_empty() {
@@ -2868,7 +2853,10 @@ impl<'a> State<'a> {
                 if i != 0 {
                     self.s.word(" + ")?;
                 }
-                self.print_lifetime(bound)?;
+                match bound {
+                    ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt)?,
+                    _ => panic!(),
+                }
             }
         }
         Ok(())
@@ -2885,12 +2873,25 @@ impl<'a> State<'a> {
         self.s.word("<")?;
 
         self.commasep(Inconsistent, &generic_params, |s, param| {
-            match *param {
-                ast::GenericParam::Lifetime(ref lifetime_def) => {
-                    s.print_outer_attributes_inline(&lifetime_def.attrs)?;
-                    s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
+            match param.kind {
+                ast::GenericParamKind::Lifetime => {
+                    s.print_outer_attributes_inline(&param.attrs)?;
+                    let lt = ast::Lifetime { id: param.id, ident: param.ident };
+                    s.print_lifetime_bounds(lt, &param.bounds)
                 },
-                ast::GenericParam::Type(ref ty_param) => s.print_ty_param(ty_param),
+                ast::GenericParamKind::Type { ref default } => {
+                    s.print_outer_attributes_inline(&param.attrs)?;
+                    s.print_ident(param.ident)?;
+                    s.print_type_bounds(":", &param.bounds)?;
+                    match default {
+                        Some(ref default) => {
+                            s.s.space()?;
+                            s.word_space("=")?;
+                            s.print_type(default)
+                        }
+                        _ => Ok(())
+                    }
+                }
             }
         })?;
 
@@ -2898,20 +2899,6 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
-        self.print_outer_attributes_inline(&param.attrs)?;
-        self.print_ident(param.ident)?;
-        self.print_bounds(":", &param.bounds)?;
-        match param.default {
-            Some(ref default) => {
-                self.s.space()?;
-                self.word_space("=")?;
-                self.print_type(default)
-            }
-            _ => Ok(())
-        }
-    }
-
     pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
                               -> io::Result<()> {
         if where_clause.predicates.is_empty() {
@@ -2935,12 +2922,12 @@ impl<'a> State<'a> {
                 }) => {
                     self.print_formal_generic_params(bound_generic_params)?;
                     self.print_type(bounded_ty)?;
-                    self.print_bounds(":", bounds)?;
+                    self.print_type_bounds(":", bounds)?;
                 }
                 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
                                                                                ref bounds,
                                                                                ..}) => {
-                    self.print_lifetime_bounds(lifetime, bounds)?;
+                    self.print_lifetime_bounds(*lifetime, bounds)?;
                 }
                 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref lhs_ty,
                                                                        ref rhs_ty,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index da7deb3c4cf..f896fa351b0 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -353,7 +353,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
 
                 match (has_output, has_should_panic_attr) {
                     (true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
-                    (true, false) => if generics.is_parameterized() {
+                    (true, false) => if !generics.params.is_empty() {
                         No(BadTestSignature::WrongTypeSignature)
                     } else {
                         Yes
diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs
index d4c6b4b158b..ebb3081c1fd 100644
--- a/src/libsyntax/util/node_count.rs
+++ b/src/libsyntax/util/node_count.rs
@@ -95,9 +95,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_trait_ref(self, t)
     }
-    fn visit_ty_param_bound(&mut self, bounds: &TyParamBound) {
+    fn visit_param_bound(&mut self, bounds: &GenericBound) {
         self.count += 1;
-        walk_ty_param_bound(self, bounds)
+        walk_param_bound(self, bounds)
     }
     fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) {
         self.count += 1;
@@ -137,9 +137,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_use_tree(self, use_tree, id)
     }
-    fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &PathParameters) {
+    fn visit_generic_args(&mut self, path_span: Span, generic_args: &GenericArgs) {
         self.count += 1;
-        walk_path_parameters(self, path_span, path_parameters)
+        walk_generic_args(self, path_span, generic_args)
     }
     fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
         self.count += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index adda39c62ed..613f1a4f113 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 GenericParam) { walk_generic_param(self, param) }
+    fn visit_generic_param(&mut self, param: &'ast GenericParam) {
+        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)
@@ -84,8 +86,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_trait_item(&mut self, ti: &'ast TraitItem) { walk_trait_item(self, ti) }
     fn visit_impl_item(&mut self, ii: &'ast ImplItem) { walk_impl_item(self, ii) }
     fn visit_trait_ref(&mut self, t: &'ast TraitRef) { walk_trait_ref(self, t) }
-    fn visit_ty_param_bound(&mut self, bounds: &'ast TyParamBound) {
-        walk_ty_param_bound(self, bounds)
+    fn visit_param_bound(&mut self, bounds: &'ast GenericBound) {
+        walk_param_bound(self, bounds)
     }
     fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
         walk_poly_trait_ref(self, t, m)
@@ -128,8 +130,14 @@ pub trait Visitor<'ast>: Sized {
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
         walk_path_segment(self, path_span, path_segment)
     }
-    fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'ast PathParameters) {
-        walk_path_parameters(self, path_span, path_parameters)
+    fn visit_generic_args(&mut self, path_span: Span, generic_args: &'ast GenericArgs) {
+        walk_generic_args(self, path_span, generic_args)
+    }
+    fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
+        match generic_arg {
+            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
+            GenericArg::Type(ty) => self.visit_ty(ty),
+        }
     }
     fn visit_assoc_type_binding(&mut self, type_binding: &'ast TypeBinding) {
         walk_assoc_type_binding(self, type_binding)
@@ -268,12 +276,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         }
         ItemKind::Trait(.., ref generics, ref bounds, ref methods) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_trait_item, methods);
         }
         ItemKind::TraitAlias(ref generics, ref bounds) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
         }
         ItemKind::Mac(ref mac) => visitor.visit_mac(mac),
         ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
@@ -333,7 +341,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
         }
         TyKind::TraitObject(ref bounds, ..) |
         TyKind::ImplTrait(ref bounds) => {
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
         }
         TyKind::Typeof(ref expression) => {
             visitor.visit_anon_const(expression)
@@ -375,23 +383,22 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V,
                                              path_span: Span,
                                              segment: &'a PathSegment) {
     visitor.visit_ident(segment.ident);
-    if let Some(ref parameters) = segment.parameters {
-        visitor.visit_path_parameters(path_span, parameters);
+    if let Some(ref args) = segment.args {
+        visitor.visit_generic_args(path_span, args);
     }
 }
 
-pub fn walk_path_parameters<'a, V>(visitor: &mut V,
-                                   _path_span: Span,
-                                   path_parameters: &'a PathParameters)
+pub fn walk_generic_args<'a, V>(visitor: &mut V,
+                                _path_span: Span,
+                                generic_args: &'a GenericArgs)
     where V: Visitor<'a>,
 {
-    match *path_parameters {
-        PathParameters::AngleBracketed(ref data) => {
-            walk_list!(visitor, visit_ty, &data.types);
-            walk_list!(visitor, visit_lifetime, &data.lifetimes);
+    match *generic_args {
+        GenericArgs::AngleBracketed(ref data) => {
+            walk_list!(visitor, visit_generic_arg, &data.args);
             walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
         }
-        PathParameters::Parenthesized(ref data) => {
+        GenericArgs::Parenthesized(ref data) => {
             walk_list!(visitor, visit_ty, &data.inputs);
             walk_list!(visitor, visit_ty, &data.output);
         }
@@ -472,30 +479,20 @@ pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) {
     // Empty!
 }
 
-pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyParamBound) {
+pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) {
     match *bound {
-        TraitTyParamBound(ref typ, ref modifier) => {
-            visitor.visit_poly_trait_ref(typ, modifier);
-        }
-        RegionTyParamBound(ref lifetime) => {
-            visitor.visit_lifetime(lifetime);
-        }
+        GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier),
+        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
     }
 }
 
 pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParam) {
-    match *param {
-        GenericParam::Lifetime(ref l) => {
-            visitor.visit_ident(l.lifetime.ident);
-            walk_list!(visitor, visit_lifetime, &l.bounds);
-            walk_list!(visitor, visit_attribute, &*l.attrs);
-        }
-        GenericParam::Type(ref t) => {
-            visitor.visit_ident(t.ident);
-            walk_list!(visitor, visit_ty_param_bound, &t.bounds);
-            walk_list!(visitor, visit_ty, &t.default);
-            walk_list!(visitor, visit_attribute, &*t.attrs);
-        }
+    visitor.visit_ident(param.ident);
+    walk_list!(visitor, visit_attribute, param.attrs.iter());
+    walk_list!(visitor, visit_param_bound, &param.bounds);
+    match param.kind {
+        GenericParamKind::Lifetime => {}
+        GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
     }
 }
 
@@ -511,14 +508,14 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a
                                                            ref bound_generic_params,
                                                            ..}) => {
             visitor.visit_ty(bounded_ty);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_generic_param, bound_generic_params);
         }
         WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
                                                              ref bounds,
                                                              ..}) => {
             visitor.visit_lifetime(lifetime);
-            walk_list!(visitor, visit_lifetime, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
         }
         WherePredicate::EqPredicate(WhereEqPredicate{ref lhs_ty,
                                                      ref rhs_ty,
@@ -579,7 +576,7 @@ pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a Trai
                              &sig.decl, trait_item.span, trait_item.id);
         }
         TraitItemKind::Type(ref bounds, ref default) => {
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
         }
         TraitItemKind::Macro(ref mac) => {
diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs
index dec24d13c9b..9aeac5b1ddb 100644
--- a/src/libsyntax_ext/deriving/clone.rs
+++ b/src/libsyntax_ext/deriving/clone.rs
@@ -13,6 +13,7 @@ use deriving::generic::*;
 use deriving::generic::ty::*;
 
 use syntax::ast::{self, Expr, Generics, ItemKind, MetaItem, VariantData};
+use syntax::ast::GenericArg;
 use syntax::attr;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
@@ -48,7 +49,10 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
                 ItemKind::Struct(_, Generics { ref params, .. }) |
                 ItemKind::Enum(_, Generics { ref params, .. }) => {
                     if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") &&
-                        !params.iter().any(|param| param.is_type_param())
+                        !params.iter().any(|param| match param.kind {
+                            ast::GenericParamKind::Type { .. } => true,
+                            _ => false,
+                        })
                     {
                         bounds = vec![];
                         is_shallow = true;
@@ -123,7 +127,7 @@ fn cs_clone_shallow(name: &str,
         let span = span.with_ctxt(cx.backtrace());
         let assert_path = cx.path_all(span, true,
                                         cx.std_path(&["clone", helper_name]),
-                                        vec![], vec![ty], vec![]);
+                                        vec![GenericArg::Type(ty)], vec![]);
         stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
     }
     fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec<ast::Stmt>, variant: &VariantData) {
diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs
index 237c8654edf..00ab39032ac 100644
--- a/src/libsyntax_ext/deriving/cmp/eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/eq.rs
@@ -12,7 +12,7 @@ use deriving::path_std;
 use deriving::generic::*;
 use deriving::generic::ty::*;
 
-use syntax::ast::{self, Expr, MetaItem};
+use syntax::ast::{self, Expr, MetaItem, GenericArg};
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
 use syntax::ptr::P;
@@ -62,7 +62,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
         let span = span.with_ctxt(cx.backtrace());
         let assert_path = cx.path_all(span, true,
                                         cx.std_path(&["cmp", helper_name]),
-                                        vec![], vec![ty], vec![]);
+                                        vec![GenericArg::Type(ty)], vec![]);
         stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
     }
     fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec<ast::Stmt>, variant: &ast::VariantData) {
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 80f65957c39..672726d1475 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -192,10 +192,8 @@ use std::collections::HashSet;
 use std::vec;
 
 use rustc_target::spec::abi::Abi;
-use syntax::ast::{
-    self, BinOpKind, EnumDef, Expr, GenericParam, Generics, Ident, PatKind, VariantData
-};
-
+use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind};
+use syntax::ast::{VariantData, GenericParamKind, GenericArg};
 use syntax::attr;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
@@ -424,7 +422,10 @@ impl<'a> TraitDef<'a> {
                     ast::ItemKind::Struct(_, ref generics) |
                     ast::ItemKind::Enum(_, ref generics) |
                     ast::ItemKind::Union(_, ref generics) => {
-                        !generics.params.iter().any(|p| p.is_type_param())
+                        !generics.params.iter().any(|param| match param.kind {
+                            ast::GenericParamKind::Type { .. } => true,
+                            _ => false,
+                        })
                     }
                     _ => {
                         // Non-ADT derive is an error, but it should have been
@@ -548,30 +549,27 @@ impl<'a> TraitDef<'a> {
             .to_generics(cx, self.span, type_ident, generics);
 
         // Create the generic parameters
-        params.extend(generics.params.iter().map(|param| {
-            match *param {
-                ref l @ GenericParam::Lifetime(_) => l.clone(),
-                GenericParam::Type(ref ty_param) => {
-                    // I don't think this can be moved out of the loop, since
-                    // a TyParamBound requires an ast id
-                    let mut bounds: Vec<_> =
-                        // extra restrictions on the generics parameters to the
-                        // type being derived upon
-                        self.additional_bounds.iter().map(|p| {
-                            cx.typarambound(p.to_path(cx, self.span,
-                                                        type_ident, generics))
-                        }).collect();
-
-                    // require the current trait
-                    bounds.push(cx.typarambound(trait_path.clone()));
-
-                    // also add in any bounds from the declaration
-                    for declared_bound in ty_param.bounds.iter() {
-                        bounds.push((*declared_bound).clone());
-                    }
-
-                    GenericParam::Type(cx.typaram(self.span, ty_param.ident, vec![], bounds, None))
+        params.extend(generics.params.iter().map(|param| match param.kind {
+            GenericParamKind::Lifetime { .. } => param.clone(),
+            GenericParamKind::Type { .. } => {
+                // I don't think this can be moved out of the loop, since
+                // a GenericBound requires an ast id
+                let mut bounds: Vec<_> =
+                    // extra restrictions on the generics parameters to the
+                    // type being derived upon
+                    self.additional_bounds.iter().map(|p| {
+                        cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
+                    }).collect();
+
+                // require the current trait
+                bounds.push(cx.trait_bound(trait_path.clone()));
+
+                // also add in any bounds from the declaration
+                for declared_bound in &param.bounds {
+                    bounds.push((*declared_bound).clone());
                 }
+
+                cx.typaram(self.span, param.ident, vec![], bounds, None)
             }
         }));
 
@@ -608,8 +606,8 @@ impl<'a> TraitDef<'a> {
             // Extra scope required here so ty_params goes out of scope before params is moved
 
             let mut ty_params = params.iter()
-                .filter_map(|param| match *param {
-                    ast::GenericParam::Type(ref t) => Some(t),
+                .filter_map(|param| match param.kind {
+                    ast::GenericParamKind::Type { .. } => Some(param),
                     _ => None,
                 })
                 .peekable();
@@ -636,12 +634,12 @@ impl<'a> TraitDef<'a> {
                         let mut bounds: Vec<_> = self.additional_bounds
                             .iter()
                             .map(|p| {
-                                cx.typarambound(p.to_path(cx, self.span, type_ident, generics))
+                                cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
                             })
                             .collect();
 
                         // require the current trait
-                        bounds.push(cx.typarambound(trait_path.clone()));
+                        bounds.push(cx.trait_bound(trait_path.clone()));
 
                         let predicate = ast::WhereBoundPredicate {
                             span: self.span,
@@ -666,31 +664,18 @@ impl<'a> TraitDef<'a> {
         // Create the reference to the trait.
         let trait_ref = cx.trait_ref(trait_path);
 
-        // Create the type parameters on the `self` path.
-        let self_ty_params = generics.params
-            .iter()
-            .filter_map(|param| match *param {
-                GenericParam::Type(ref ty_param)
-                    => Some(cx.ty_ident(self.span, ty_param.ident)),
-                _ => None,
-            })
-            .collect();
-
-        let self_lifetimes: Vec<ast::Lifetime> = generics.params
-            .iter()
-            .filter_map(|param| match *param {
-                GenericParam::Lifetime(ref ld) => Some(ld.lifetime),
-                _ => None,
-            })
-            .collect();
+        let self_params: Vec<_> = generics.params.iter().map(|param| match param.kind {
+            GenericParamKind::Lifetime { .. } => {
+                GenericArg::Lifetime(cx.lifetime(self.span, param.ident))
+            }
+            GenericParamKind::Type { .. } => {
+                GenericArg::Type(cx.ty_ident(self.span, param.ident))
+            }
+        }).collect();
 
         // Create the type of `self`.
-        let self_type = cx.ty_path(cx.path_all(self.span,
-                                               false,
-                                               vec![type_ident],
-                                               self_lifetimes,
-                                               self_ty_params,
-                                               Vec::new()));
+        let path = cx.path_all(self.span, false, vec![type_ident], self_params, vec![]);
+        let self_type = cx.ty_path(path);
 
         let attr = cx.attribute(self.span,
                                 cx.meta_word(self.span,
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index 25a29694488..0b809ab585c 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -15,7 +15,7 @@ pub use self::PtrTy::*;
 pub use self::Ty::*;
 
 use syntax::ast;
-use syntax::ast::{Expr, GenericParam, Generics, Ident, SelfKind};
+use syntax::ast::{Expr, GenericParamKind, Generics, Ident, SelfKind, GenericArg};
 use syntax::ext::base::ExtCtxt;
 use syntax::ext::build::AstBuilder;
 use syntax::codemap::{respan, DUMMY_SP};
@@ -86,15 +86,20 @@ impl<'a> Path<'a> {
                    -> ast::Path {
         let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
         let lt = mk_lifetimes(cx, span, &self.lifetime);
-        let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
+        let tys: Vec<P<ast::Ty>> =
+            self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
+        let params = lt.into_iter()
+                       .map(|lt| GenericArg::Lifetime(lt))
+                       .chain(tys.into_iter().map(|ty| GenericArg::Type(ty)))
+                       .collect();
 
         match self.kind {
-            PathKind::Global => cx.path_all(span, true, idents, lt, tys, Vec::new()),
-            PathKind::Local => cx.path_all(span, false, idents, lt, tys, Vec::new()),
+            PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()),
+            PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()),
             PathKind::Std => {
                 let def_site = DUMMY_SP.apply_mark(cx.current_expansion.mark);
                 idents.insert(0, Ident::new(keywords::DollarCrate.name(), def_site));
-                cx.path_all(span, false, idents, lt, tys, Vec::new())
+                cx.path_all(span, false, idents, params, Vec::new())
             }
         }
 
@@ -180,34 +185,22 @@ impl<'a> Ty<'a> {
                    cx: &ExtCtxt,
                    span: Span,
                    self_ty: Ident,
-                   self_generics: &Generics)
+                   generics: &Generics)
                    -> ast::Path {
         match *self {
             Self_ => {
-                let self_params = self_generics.params
-                    .iter()
-                    .filter_map(|param| match *param {
-                        GenericParam::Type(ref ty_param) => Some(cx.ty_ident(span, ty_param.ident)),
-                        _ => None,
-                    })
-                    .collect();
-
-                let lifetimes: Vec<ast::Lifetime> = self_generics.params
-                    .iter()
-                    .filter_map(|param| match *param {
-                        GenericParam::Lifetime(ref ld) => Some(ld.lifetime),
-                        _ => None,
-                    })
-                    .collect();
+                let params: Vec<_> = generics.params.iter().map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
+                    }
+                    GenericParamKind::Type { .. } => {
+                        GenericArg::Type(cx.ty_ident(span, param.ident))
+                    }
+                }).collect();
 
-                cx.path_all(span,
-                            false,
-                            vec![self_ty],
-                            lifetimes,
-                            self_params,
-                            Vec::new())
+                cx.path_all(span, false, vec![self_ty], params, vec![])
             }
-            Literal(ref p) => p.to_path(cx, span, self_ty, self_generics),
+            Literal(ref p) => p.to_path(cx, span, self_ty, generics),
             Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
             Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
         }
@@ -222,17 +215,17 @@ fn mk_ty_param(cx: &ExtCtxt,
                bounds: &[Path],
                self_ident: Ident,
                self_generics: &Generics)
-               -> ast::TyParam {
+               -> ast::GenericParam {
     let bounds = bounds.iter()
         .map(|b| {
             let path = b.to_path(cx, span, self_ident, self_generics);
-            cx.typarambound(path)
+            cx.trait_bound(path)
         })
         .collect();
     cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
 }
 
-fn mk_generics(params: Vec<GenericParam>, span: Span) -> Generics {
+fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
     Generics {
         params,
         where_clause: ast::WhereClause {
@@ -268,17 +261,14 @@ impl<'a> LifetimeBounds<'a> {
             .iter()
             .map(|&(lt, ref bounds)| {
                 let bounds = bounds.iter()
-                    .map(|b| cx.lifetime(span, Ident::from_str(b)))
-                    .collect();
-                GenericParam::Lifetime(cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds))
+                    .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b))));
+                cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect())
             })
             .chain(self.bounds
                 .iter()
                 .map(|t| {
                     let (name, ref bounds) = *t;
-                    GenericParam::Type(mk_ty_param(
-                        cx, span, name, &[], &bounds, self_ty, self_generics
-                    ))
+                    mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
                 })
             )
             .collect();
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index a5b348a661a..6ff385b18e8 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -134,9 +134,12 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
         match item.node {
             ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
             ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
-                for param in params.iter() {
-                    if let ast::GenericParam::Type(ref ty) = *param{
-                        typaram.push_str(&ty.ident.as_str());
+                for param in params {
+                    match param.kind {
+                        ast::GenericParamKind::Type { .. } => {
+                            typaram.push_str(&param.ident.as_str());
+                        }
+                        _ => {}
                     }
                 }
             }
diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs
index 4e1af108ab4..bbc5b03d688 100644
--- a/src/libsyntax_ext/env.rs
+++ b/src/libsyntax_ext/env.rs
@@ -13,7 +13,7 @@
 // interface.
 //
 
-use syntax::ast::{self, Ident};
+use syntax::ast::{self, Ident, GenericArg};
 use syntax::ext::base::*;
 use syntax::ext::base;
 use syntax::ext::build::AstBuilder;
@@ -39,12 +39,11 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt,
             cx.expr_path(cx.path_all(sp,
                                      true,
                                      cx.std_path(&["option", "Option", "None"]),
-                                     Vec::new(),
-                                     vec![cx.ty_rptr(sp,
+                                     vec![GenericArg::Type(cx.ty_rptr(sp,
                                                      cx.ty_ident(sp, Ident::from_str("str")),
                                                      Some(lt),
-                                                     ast::Mutability::Immutable)],
-                                     Vec::new()))
+                                                     ast::Mutability::Immutable))],
+                                     vec![]))
         }
         Ok(s) => {
             cx.expr_call_global(sp,
diff --git a/src/test/compile-fail/issue-1900.rs b/src/test/compile-fail/issue-1900.rs
index c7564a9355b..ccdd9db25c4 100644
--- a/src/test/compile-fail/issue-1900.rs
+++ b/src/test/compile-fail/issue-1900.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: `main` function is not allowed to have type parameters
+// error-pattern: `main` function is not allowed to have generic parameters
 fn main<T>() { }
diff --git a/src/test/run-pass/issue-22777.rs b/src/test/run-pass/issue-22777.rs
index 2dc4d775a9c..4df46c0e2e1 100644
--- a/src/test/run-pass/issue-22777.rs
+++ b/src/test/run-pass/issue-22777.rs
@@ -32,8 +32,8 @@ struct S04_TyParamBound(S05_PolyTraitRef);
 struct S05_PolyTraitRef(S06_TraitRef);
 struct S06_TraitRef(S07_Path);
 struct S07_Path(Vec<S08_PathSegment>);
-struct S08_PathSegment(S09_PathParameters);
-struct S09_PathParameters(P<S10_ParenthesizedParameterData>);
+struct S08_PathSegment(S09_GenericArgs);
+struct S09_GenericArgs(P<S10_ParenthesizedParameterData>);
 struct S10_ParenthesizedParameterData(Option<P<S11_Ty>>);
 struct S11_Ty(P<S12_Expr>);
 struct S12_Expr(P<S13_Block>);
diff --git a/src/test/ui/error-codes/E0110.stderr b/src/test/ui/error-codes/E0110.stderr
index 10e06ee6d02..7f5b78684fb 100644
--- a/src/test/ui/error-codes/E0110.stderr
+++ b/src/test/ui/error-codes/E0110.stderr
@@ -2,7 +2,7 @@ error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/E0110.rs:11:14
    |
 LL | type X = u32<'static>; //~ ERROR E0110
-   |              ^^^^^^^ lifetime parameter not allowed on this type
+   |              ^^^^^^^ lifetime parameter not allowed
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0131.stderr b/src/test/ui/error-codes/E0131.stderr
index ba9355763f6..46bc872746c 100644
--- a/src/test/ui/error-codes/E0131.stderr
+++ b/src/test/ui/error-codes/E0131.stderr
@@ -1,8 +1,8 @@
-error[E0131]: `main` function is not allowed to have type parameters
+error[E0131]: `main` function is not allowed to have generic parameters
   --> $DIR/E0131.rs:11:8
    |
 LL | fn main<T>() {
-   |        ^^^ `main` cannot have type parameters
+   |        ^^^ `main` cannot have generic parameters
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issue-51022.rs b/src/test/ui/issue-51022.rs
index f9486fa57b1..831c3e5fda0 100644
--- a/src/test/ui/issue-51022.rs
+++ b/src/test/ui/issue-51022.rs
@@ -9,4 +9,4 @@
 // except according to those terms.
 
 fn main<'a>() { }
-    //~^ ERROR `main` function is not allowed to have lifetime parameters [E0131]
+    //~^ ERROR `main` function is not allowed to have generic parameters [E0131]
diff --git a/src/test/ui/issue-51022.stderr b/src/test/ui/issue-51022.stderr
index 3b691bbb033..1daa8dfbba6 100644
--- a/src/test/ui/issue-51022.stderr
+++ b/src/test/ui/issue-51022.stderr
@@ -1,8 +1,8 @@
-error[E0131]: `main` function is not allowed to have lifetime parameters
+error[E0131]: `main` function is not allowed to have generic parameters
   --> $DIR/issue-51022.rs:11:8
    |
 LL | fn main<'a>() { }
-   |        ^^^^ `main` cannot have lifetime parameters
+   |        ^^^^ `main` cannot have generic parameters
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc1598-generic-associated-types/collections.stderr b/src/test/ui/rfc1598-generic-associated-types/collections.stderr
index ed96570583f..8c31ab2ca88 100644
--- a/src/test/ui/rfc1598-generic-associated-types/collections.stderr
+++ b/src/test/ui/rfc1598-generic-associated-types/collections.stderr
@@ -20,13 +20,13 @@ error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/collections.rs:33:50
    |
 LL |     fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
-   |                                                  ^^^^^ lifetime parameter not allowed on this type
+   |                                                  ^^^^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/collections.rs:59:50
    |
 LL |     fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
-   |                                                  ^^^^^ lifetime parameter not allowed on this type
+   |                                                  ^^^^^ lifetime parameter not allowed
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr
index 764a0db2478..1746122eb49 100644
--- a/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr
+++ b/src/test/ui/rfc1598-generic-associated-types/construct_with_other_type.stderr
@@ -2,19 +2,19 @@ error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/construct_with_other_type.rs:26:46
    |
 LL |     type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
-   |                                              ^^ lifetime parameter not allowed on this type
+   |                                              ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/construct_with_other_type.rs:26:63
    |
 LL |     type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
-   |                                                               ^^ lifetime parameter not allowed on this type
+   |                                                               ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/construct_with_other_type.rs:34:40
    |
 LL |     type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static>;
-   |                                        ^^ lifetime parameter not allowed on this type
+   |                                        ^^ lifetime parameter not allowed
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
index 64e82c0d109..d48c21477b3 100644
--- a/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
+++ b/src/test/ui/rfc1598-generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
@@ -14,19 +14,19 @@ error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/generic_associated_type_undeclared_lifetimes.rs:20:47
    |
 LL |     type Iter<'a>: Iterator<Item = Self::Item<'a>>
-   |                                               ^^ lifetime parameter not allowed on this type
+   |                                               ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/generic_associated_type_undeclared_lifetimes.rs:22:37
    |
 LL |         + Deref<Target = Self::Item<'b>>;
-   |                                     ^^ lifetime parameter not allowed on this type
+   |                                     ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/generic_associated_type_undeclared_lifetimes.rs:26:41
    |
 LL |     fn iter<'a>(&'a self) -> Self::Iter<'undeclared>;
-   |                                         ^^^^^^^^^^^ lifetime parameter not allowed on this type
+   |                                         ^^^^^^^^^^^ lifetime parameter not allowed
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr
index 0e251300e45..737a29ec2c8 100644
--- a/src/test/ui/rfc1598-generic-associated-types/iterable.stderr
+++ b/src/test/ui/rfc1598-generic-associated-types/iterable.stderr
@@ -2,37 +2,37 @@ error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/iterable.rs:20:47
    |
 LL |     type Iter<'a>: Iterator<Item = Self::Item<'a>>;
-   |                                               ^^ lifetime parameter not allowed on this type
+   |                                               ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/iterable.rs:49:53
    |
 LL | fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
-   |                                                     ^^ lifetime parameter not allowed on this type
+   |                                                     ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/iterable.rs:54:60
    |
 LL | fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
-   |                                                            ^^ lifetime parameter not allowed on this type
+   |                                                            ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/iterable.rs:23:41
    |
 LL |     fn iter<'a>(&'a self) -> Self::Iter<'a>;
-   |                                         ^^ lifetime parameter not allowed on this type
+   |                                         ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/iterable.rs:32:41
    |
 LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-   |                                         ^^ lifetime parameter not allowed on this type
+   |                                         ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/iterable.rs:43:41
    |
 LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-   |                                         ^^ lifetime parameter not allowed on this type
+   |                                         ^^ lifetime parameter not allowed
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr
index df83fdaad5b..c8d37a51fa9 100644
--- a/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr
+++ b/src/test/ui/rfc1598-generic-associated-types/parameter_number_and_kind.stderr
@@ -1,3 +1,9 @@
+error[E0110]: lifetime parameters are not allowed on this type
+  --> $DIR/parameter_number_and_kind.rs:26:27
+   |
+LL |     type FOk<T> = Self::E<'static, T>;
+   |                           ^^^^^^^ lifetime parameter not allowed
+
 error[E0109]: type parameters are not allowed on this type
   --> $DIR/parameter_number_and_kind.rs:26:36
    |
@@ -5,16 +11,16 @@ LL |     type FOk<T> = Self::E<'static, T>;
    |                                    ^ type parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
-  --> $DIR/parameter_number_and_kind.rs:26:27
+  --> $DIR/parameter_number_and_kind.rs:29:26
    |
-LL |     type FOk<T> = Self::E<'static, T>;
-   |                           ^^^^^^^ lifetime parameter not allowed on this type
+LL |     type FErr1 = Self::E<'static, 'static>; // Error
+   |                          ^^^^^^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
-  --> $DIR/parameter_number_and_kind.rs:29:26
+  --> $DIR/parameter_number_and_kind.rs:31:29
    |
-LL |     type FErr1 = Self::E<'static, 'static>; // Error
-   |                          ^^^^^^^ lifetime parameter not allowed on this type
+LL |     type FErr2<T> = Self::E<'static, T, u32>; // Error
+   |                             ^^^^^^^ lifetime parameter not allowed
 
 error[E0109]: type parameters are not allowed on this type
   --> $DIR/parameter_number_and_kind.rs:31:38
@@ -22,12 +28,6 @@ error[E0109]: type parameters are not allowed on this type
 LL |     type FErr2<T> = Self::E<'static, T, u32>; // Error
    |                                      ^ type parameter not allowed
 
-error[E0110]: lifetime parameters are not allowed on this type
-  --> $DIR/parameter_number_and_kind.rs:31:29
-   |
-LL |     type FErr2<T> = Self::E<'static, T, u32>; // Error
-   |                             ^^^^^^^ lifetime parameter not allowed on this type
-
 error: aborting due to 5 previous errors
 
 Some errors occurred: E0109, E0110.
diff --git a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr
index 607a4b8d579..12e206cbd47 100644
--- a/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr
+++ b/src/test/ui/rfc1598-generic-associated-types/streaming_iterator.stderr
@@ -2,31 +2,31 @@ error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/streaming_iterator.rs:27:41
    |
 LL |     bar: <T as StreamingIterator>::Item<'static>,
-   |                                         ^^^^^^^ lifetime parameter not allowed on this type
+   |                                         ^^^^^^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/streaming_iterator.rs:35:64
    |
 LL | fn foo<T>(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ }
-   |                                                                ^^ lifetime parameter not allowed on this type
+   |                                                                ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/streaming_iterator.rs:21:48
    |
 LL |     fn next<'a>(&'a self) -> Option<Self::Item<'a>>;
-   |                                                ^^ lifetime parameter not allowed on this type
+   |                                                ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/streaming_iterator.rs:47:37
    |
 LL |     type Item<'a> = (usize, I::Item<'a>);
-   |                                     ^^ lifetime parameter not allowed on this type
+   |                                     ^^ lifetime parameter not allowed
 
 error[E0110]: lifetime parameters are not allowed on this type
   --> $DIR/streaming_iterator.rs:49:48
    |
 LL |     fn next<'a>(&'a self) -> Option<Self::Item<'a>> {
-   |                                                ^^ lifetime parameter not allowed on this type
+   |                                                ^^ lifetime parameter not allowed
 
 error: aborting due to 5 previous errors