about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-01-27 01:27:12 +0000
committerbors <bors@rust-lang.org>2017-01-27 01:27:12 +0000
commit23a94697c2fa67ec750a8fc09b2e86213b5e0af1 (patch)
tree453b69936662fd4b908e63a5366d005aa6cb730c /src/libsyntax/parse
parent8430042a49bbd49bbb4fbc54f457feb5fb614f56 (diff)
parentbd4d5ec758cac866af2ca8fc09b27ce0d0112786 (diff)
downloadrust-23a94697c2fa67ec750a8fc09b2e86213b5e0af1.tar.gz
rust-23a94697c2fa67ec750a8fc09b2e86213b5e0af1.zip
Auto merge of #39158 - petrochenkov:bounds, r=nikomatsakis
Bounds parsing refactoring 2

See https://github.com/rust-lang/rust/pull/37511 for previous discussion.
cc @matklad

Relaxed parsing rules:
 - zero bounds after `:` are allowed in all contexts.
 - zero predicates are allowed after `where`.
- trailing separator `,` is allowed after predicates in `where` clauses not followed by `{`.

Other parsing rules:
 - trailing separator `+` is still allowed in all bound lists.

Code is also cleaned up and tests added.

I haven't touched parsing of trait object types yet, I'll do it later.
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs710
-rw-r--r--src/libsyntax/parse/token.rs23
2 files changed, 300 insertions, 433 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b564cc337e4..3480db8ec3b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -22,7 +22,7 @@ use ast::{Expr, ExprKind, RangeLimits};
 use ast::{Field, FnDecl};
 use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
 use ast::{Ident, ImplItem, Item, ItemKind};
-use ast::{Lit, LitKind, UintTy};
+use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy};
 use ast::Local;
 use ast::MacStmtStyle;
 use ast::Mac_;
@@ -193,14 +193,22 @@ pub enum TokenType {
     Token(token::Token),
     Keyword(keywords::Keyword),
     Operator,
+    Lifetime,
+    Ident,
+    Path,
+    Type,
 }
 
 impl TokenType {
     fn to_string(&self) -> String {
         match *self {
             TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)),
-            TokenType::Operator => "an operator".to_string(),
             TokenType::Keyword(kw) => format!("`{}`", kw.name()),
+            TokenType::Operator => "an operator".to_string(),
+            TokenType::Lifetime => "lifetime".to_string(),
+            TokenType::Ident => "identifier".to_string(),
+            TokenType::Path => "path".to_string(),
+            TokenType::Type => "type".to_string(),
         }
     }
 }
@@ -553,6 +561,33 @@ impl<'a> Parser<'a> {
         }
     }
 
+    fn check_ident(&mut self) -> bool {
+        if self.token.is_ident() {
+            true
+        } else {
+            self.expected_tokens.push(TokenType::Ident);
+            false
+        }
+    }
+
+    fn check_path(&mut self) -> bool {
+        if self.token.is_path_start() {
+            true
+        } else {
+            self.expected_tokens.push(TokenType::Path);
+            false
+        }
+    }
+
+    fn check_type(&mut self) -> bool {
+        if self.token.can_begin_type() {
+            true
+        } else {
+            self.expected_tokens.push(TokenType::Type);
+            false
+        }
+    }
+
     /// Expect and consume an `&`. If `&&` is seen, replace it with a single
     /// `&` and continue. If an `&` is not seen, signal an error.
     fn expect_and(&mut self) -> PResult<'a, ()> {
@@ -639,13 +674,7 @@ impl<'a> Parser<'a> {
                 let lo = span.lo + BytePos(1);
                 Ok(self.bump_with(token::Eq, lo, span.hi))
             }
-            _ => {
-                let gt_str = Parser::token_to_string(&token::Gt);
-                let this_token_str = self.this_token_to_string();
-                Err(self.fatal(&format!("expected `{}`, found `{}`",
-                                        gt_str,
-                                        this_token_str)))
-            }
+            _ => self.unexpected()
         }
     }
 
@@ -972,20 +1001,11 @@ impl<'a> Parser<'a> {
         Parses whatever can come after a `for` keyword in a type.
         The `for` hasn't been consumed.
 
-        Deprecated:
-
-        - for <'lt> |S| -> T
-
-        Eventually:
-
         - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T
-        - for <'lt> path::foo(a, b)
-
+        - for <'lt> path::foo(a, b) + Trait + 'a
         */
 
-        // parse <'lt>
         let lo = self.span.lo;
-
         let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
 
         // examine next token to decide to do
@@ -994,9 +1014,9 @@ impl<'a> Parser<'a> {
         } else {
             let hi = self.span.hi;
             let trait_ref = self.parse_trait_ref()?;
-            let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs,
-                                                     trait_ref: trait_ref,
-                                                     span: mk_sp(lo, hi)};
+            let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs,
+                                                trait_ref: trait_ref,
+                                                span: mk_sp(lo, hi)};
             let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
                 self.parse_ty_param_bounds()?
             } else {
@@ -1011,18 +1031,9 @@ impl<'a> Parser<'a> {
     }
 
     pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> {
-        /*
-        Parses whatever can come after a `impl` keyword in a type.
-        The `impl` has already been consumed.
-        */
-
-        let bounds = self.parse_ty_param_bounds()?;
-
-        if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
-            self.span_err(self.prev_span, "at least one trait must be specified");
-        }
-
-        Ok(ast::TyKind::ImplTrait(bounds))
+        // Parses whatever can come after a `impl` keyword in a type.
+        // The `impl` has already been consumed.
+        Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?))
     }
 
     pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> {
@@ -1030,7 +1041,7 @@ impl<'a> Parser<'a> {
     }
 
     /// parse a TyKind::BareFn type:
-    pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<ast::LifetimeDef>)
+    pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<LifetimeDef>)
                             -> PResult<'a, TyKind> {
         /*
 
@@ -1202,13 +1213,6 @@ impl<'a> Parser<'a> {
             })
     }
 
-    /// Parse a possibly mutable type
-    pub fn parse_mt(&mut self) -> PResult<'a, MutTy> {
-        let mutbl = self.parse_mutability()?;
-        let t = self.parse_ty_no_plus()?;
-        Ok(MutTy { ty: t, mutbl: mutbl })
-    }
-
     /// Parse optional return type [ -> TY ] in function decl
     pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
         if self.eat(&token::RArrow) {
@@ -1260,8 +1264,8 @@ impl<'a> Parser<'a> {
                                             pprust::ty_to_string(&lhs));
             err.span_label(lhs.span, &format!("expected a path"));
             let hi = bounds.iter().map(|x| match *x {
-                ast::TraitTyParamBound(ref tr, _) => tr.span.hi,
-                ast::RegionTyParamBound(ref r) => r.span.hi,
+                TraitTyParamBound(ref tr, _) => tr.span.hi,
+                RegionTyParamBound(ref r) => r.span.hi,
             }).max_by_key(|x| x.to_usize());
             let full_span = hi.map(|hi| Span {
                 lo: lhs.span.lo,
@@ -1309,9 +1313,7 @@ impl<'a> Parser<'a> {
 
         let lo = self.span.lo;
 
-        let t = if self.check(&token::OpenDelim(token::Paren)) {
-            self.bump();
-
+        let t = if self.eat(&token::OpenDelim(token::Paren)) {
             // (t) is a parenthesized ty
             // (t,) is the type of a tuple with only one field,
             // of type t
@@ -1319,9 +1321,8 @@ impl<'a> Parser<'a> {
             let mut last_comma = false;
             while self.token != token::CloseDelim(token::Paren) {
                 ts.push(self.parse_ty()?);
-                if self.check(&token::Comma) {
+                if self.eat(&token::Comma) {
                     last_comma = true;
-                    self.bump();
                 } else {
                     last_comma = false;
                     break;
@@ -1336,13 +1337,11 @@ impl<'a> Parser<'a> {
             }
         } else if self.eat(&token::Not) {
             TyKind::Never
-        } else if self.check(&token::BinOp(token::Star)) {
+        } else if self.eat(&token::BinOp(token::Star)) {
             // STAR POINTER (bare pointer?)
-            self.bump();
             TyKind::Ptr(self.parse_ptr()?)
-        } else if self.check(&token::OpenDelim(token::Bracket)) {
+        } else if self.eat(&token::OpenDelim(token::Bracket)) {
             // VECTOR
-            self.expect(&token::OpenDelim(token::Bracket))?;
             let t = self.parse_ty()?;
 
             // Parse the `; e` in `[ i32; e ]`
@@ -1354,13 +1353,15 @@ impl<'a> Parser<'a> {
             self.expect(&token::CloseDelim(token::Bracket))?;
             t
         } else if self.check(&token::BinOp(token::And)) ||
-                  self.token == token::AndAnd {
+                  self.check(&token::AndAnd) {
             // BORROWED POINTER
             self.expect_and()?;
             self.parse_borrowed_pointee()?
         } else if self.check_keyword(keywords::For) {
+            // FIXME `+` has incorrect priority in trait object types starting with `for` (#39317).
             self.parse_for_in_type()?
         } else if self.eat_keyword(keywords::Impl) {
+            // FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
             self.parse_impl_trait_type()?
         } else if self.token_is_bare_fn_keyword() {
             // BARE FUNCTION
@@ -1373,10 +1374,7 @@ impl<'a> Parser<'a> {
             self.expect(&token::CloseDelim(token::Paren))?;
             TyKind::Typeof(e)
         } else if self.eat_lt() {
-
-            let (qself, path) =
-                 self.parse_qualified_path(PathStyle::Type)?;
-
+            let (qself, path) = self.parse_qualified_path(PathStyle::Type)?;
             TyKind::Path(Some(qself), path)
         } else if self.token.is_path_start() {
             let path = self.parse_path(PathStyle::Type)?;
@@ -1406,10 +1404,10 @@ impl<'a> Parser<'a> {
 
     pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
         // look for `&'lt` or `&'foo ` and interpret `foo` as the region name:
-        let opt_lifetime = self.parse_opt_lifetime()?;
-
-        let mt = self.parse_mt()?;
-        return Ok(TyKind::Rptr(opt_lifetime, mt));
+        let opt_lifetime = self.eat_lifetime();
+        let mutbl = self.parse_mutability()?;
+        let ty = self.parse_ty_no_plus()?;
+        return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl }));
     }
 
     pub fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
@@ -1505,8 +1503,7 @@ impl<'a> Parser<'a> {
     }
 
     pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option<P<ast::Expr>>> {
-        if self.check(&token::Semi) {
-            self.bump();
+        if self.eat(&token::Semi) {
             Ok(Some(self.parse_expr()?))
         } else {
             Ok(None)
@@ -1728,7 +1725,8 @@ impl<'a> Parser<'a> {
 
             // Parse types, optionally.
             let parameters = if self.eat_lt() {
-                let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?;
+                let (lifetimes, types, bindings) = self.parse_generic_args()?;
+                self.expect_gt()?;
                 ast::AngleBracketedParameterData {
                     lifetimes: lifetimes,
                     types: types,
@@ -1786,7 +1784,8 @@ impl<'a> Parser<'a> {
             // Check for a type segment.
             if self.eat_lt() {
                 // Consumed `a::b::<`, go look for types
-                let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?;
+                let (lifetimes, types, bindings) = self.parse_generic_args()?;
+                self.expect_gt()?;
                 segments.push(ast::PathSegment {
                     identifier: identifier,
                     parameters: ast::AngleBracketedParameterData {
@@ -1828,121 +1827,21 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// parses 0 or 1 lifetime
-    pub fn parse_opt_lifetime(&mut self) -> PResult<'a, Option<ast::Lifetime>> {
-        match self.token {
-            token::Lifetime(..) => {
-                Ok(Some(self.parse_lifetime()?))
-            }
-            _ => {
-                Ok(None)
-            }
-        }
-    }
-
-    /// Parses a single lifetime
-    /// Matches lifetime = LIFETIME
-    pub fn parse_lifetime(&mut self) -> PResult<'a, ast::Lifetime> {
+    /// Parse single lifetime 'a or nothing.
+    pub fn eat_lifetime(&mut self) -> Option<Lifetime> {
         match self.token {
-            token::Lifetime(i) => {
-                let span = self.span;
+            token::Lifetime(ident) => {
                 self.bump();
-                return Ok(ast::Lifetime {
+                Some(Lifetime {
                     id: ast::DUMMY_NODE_ID,
-                    span: span,
-                    name: i.name
-                });
+                    span: self.prev_span,
+                    name: ident.name
+                })
             }
             _ => {
-                return Err(self.fatal("expected a lifetime name"));
-            }
-        }
-    }
-
-    /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def  =
-    /// lifetime [':' lifetimes]`
-    ///
-    /// If `followed_by_ty_params` is None, then we are in a context
-    /// where only lifetime parameters are allowed, and thus we should
-    /// error if we encounter attributes after the bound lifetimes.
-    ///
-    /// If `followed_by_ty_params` is Some(r), then there may be type
-    /// parameter bindings after the lifetimes, so we should pass
-    /// along the parsed attributes to be attached to the first such
-    /// type parmeter.
-    pub fn parse_lifetime_defs(&mut self,
-                               followed_by_ty_params: Option<&mut Vec<ast::Attribute>>)
-                               -> PResult<'a, Vec<ast::LifetimeDef>>
-    {
-        let mut res = Vec::new();
-        loop {
-            let attrs = self.parse_outer_attributes()?;
-            match self.token {
-                token::Lifetime(_) => {
-                    let lifetime = self.parse_lifetime()?;
-                    let bounds =
-                        if self.eat(&token::Colon) {
-                            self.parse_lifetimes(token::BinOp(token::Plus))?
-                        } else {
-                            Vec::new()
-                        };
-                    res.push(ast::LifetimeDef { attrs: attrs.into(),
-                                                lifetime: lifetime,
-                                                bounds: bounds });
-                }
-
-                _ => {
-                    if let Some(recv) = followed_by_ty_params {
-                        assert!(recv.is_empty());
-                        *recv = attrs;
-                        debug!("parse_lifetime_defs ret {:?}", res);
-                        return Ok(res);
-                    } else if !attrs.is_empty() {
-                        let msg = "trailing attribute after lifetime parameters";
-                        return Err(self.fatal(msg));
-                    }
-                }
-            }
-
-            match self.token {
-                token::Comma => { self.bump();}
-                token::Gt => { return Ok(res); }
-                token::BinOp(token::Shr) => { return Ok(res); }
-                _ => {
-                    let this_token_str = self.this_token_to_string();
-                    let msg = format!("expected `,` or `>` after lifetime \
-                                      name, found `{}`",
-                                      this_token_str);
-                    return Err(self.fatal(&msg[..]));
-                }
-            }
-        }
-    }
-
-    /// matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) actually, it matches the empty
-    /// one too, but putting that in there messes up the grammar....
-    ///
-    /// Parses zero or more comma separated lifetimes. Expects each lifetime to be followed by
-    /// either a comma or `>`.  Used when parsing type parameter lists, where we expect something
-    /// like `<'a, 'b, T>`.
-    pub fn parse_lifetimes(&mut self, sep: token::Token) -> PResult<'a, Vec<ast::Lifetime>> {
-
-        let mut res = Vec::new();
-        loop {
-            match self.token {
-                token::Lifetime(_) => {
-                    res.push(self.parse_lifetime()?);
-                }
-                _ => {
-                    return Ok(res);
-                }
-            }
-
-            if self.token != sep {
-                return Ok(res);
+                self.expected_tokens.push(TokenType::Lifetime);
+                None
             }
-
-            self.bump();
         }
     }
 
@@ -2459,7 +2358,9 @@ impl<'a> Parser<'a> {
                         -> PResult<'a, P<Expr>> {
         let (_, tys, bindings) = if self.eat(&token::ModSep) {
             self.expect_lt()?;
-            self.parse_generic_values_after_lt()?
+            let args = self.parse_generic_args()?;
+            self.expect_gt()?;
+            args
         } else {
             (Vec::new(), Vec::new(), Vec::new())
         };
@@ -4094,69 +3995,68 @@ impl<'a> Parser<'a> {
         }).emit();
     }
 
-    // Parses a sequence of bounds if a `:` is found,
-    // otherwise returns empty list.
-    fn parse_colon_then_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds>
-    {
-        if !self.eat(&token::Colon) {
-            Ok(Vec::new())
-        } else {
-            self.parse_ty_param_bounds()
-        }
-    }
-
-    // matches bounds    = ( boundseq )?
-    // where   boundseq  = ( polybound + boundseq ) | polybound
-    // and     polybound = ( 'for' '<' 'region '>' )? bound
-    // and     bound     = 'region | trait_ref
+    // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`.
+    // BOUND = TY_BOUND | LT_BOUND
+    // LT_BOUND = LIFETIME (e.g. `'a`)
+    // TY_BOUND = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
     fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds>
     {
-        let mut result = vec![];
+        let mut bounds = Vec::new();
         loop {
-            let question_span = self.span;
-            let ate_question = self.eat(&token::Question);
-            match self.token {
-                token::Lifetime(lifetime) => {
-                    if ate_question {
-                        self.span_err(question_span,
-                                      "`?` may only modify trait bounds, not lifetime bounds");
-                    }
-                    result.push(RegionTyParamBound(ast::Lifetime {
-                        id: ast::DUMMY_NODE_ID,
-                        span: self.span,
-                        name: lifetime.name
-                    }));
-                    self.bump();
+            let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
+            if let Some(lifetime) = self.eat_lifetime() {
+                if let Some(question_span) = question {
+                    self.span_err(question_span,
+                                  "`?` may only modify trait bounds, not lifetime bounds");
                 }
-                _ if self.token.is_path_start() || self.token.is_keyword(keywords::For) => {
-                    let poly_trait_ref = self.parse_poly_trait_ref()?;
-                    let modifier = if ate_question {
-                        TraitBoundModifier::Maybe
-                    } else {
-                        TraitBoundModifier::None
-                    };
-                    result.push(TraitTyParamBound(poly_trait_ref, modifier))
-                }
-                _ => break,
-            }
+                bounds.push(RegionTyParamBound(lifetime));
+            } else {if self.check_keyword(keywords::For) || self.check_path() {
+                let poly_trait_ref = self.parse_poly_trait_ref()?;
+                let modifier = if question.is_some() {
+                    TraitBoundModifier::Maybe
+                } else {
+                    TraitBoundModifier::None
+                };
+                bounds.push(TraitTyParamBound(poly_trait_ref, modifier));
+            } else {
+                break
+            }}
 
             if !self.eat(&token::BinOp(token::Plus)) {
-                break;
+                break
             }
         }
 
-        return Ok(result);
+        return Ok(bounds);
+    }
+
+    // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`.
+    // BOUND = LT_BOUND (e.g. `'a`)
+    fn parse_lt_param_bounds(&mut self) -> Vec<Lifetime> {
+        let mut lifetimes = Vec::new();
+        while let Some(lifetime) = self.eat_lifetime() {
+            lifetimes.push(lifetime);
+
+            if !self.eat(&token::BinOp(token::Plus)) {
+                break
+            }
+        }
+        lifetimes
     }
 
     /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
-    fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'a, TyParam> {
+    fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, TyParam> {
         let span = self.span;
         let ident = self.parse_ident()?;
 
-        let bounds = self.parse_colon_then_ty_param_bounds()?;
+        // Parse optional colon and param bounds.
+        let bounds = if self.eat(&token::Colon) {
+            self.parse_ty_param_bounds()?
+        } else {
+            Vec::new()
+        };
 
-        let default = if self.check(&token::Eq) {
-            self.bump();
+        let default = if self.eat(&token::Eq) {
             Some(self.parse_ty()?)
         } else {
             None
@@ -4172,6 +4072,51 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Parses (possibly empty) list of lifetime and type parameters, possibly including
+    /// trailing comma and erroneous trailing attributes.
+    pub fn parse_generic_params(&mut self) -> PResult<'a, (Vec<LifetimeDef>, Vec<TyParam>)> {
+        let mut lifetime_defs = Vec::new();
+        let mut ty_params = Vec::new();
+        let mut seen_ty_param = false;
+        loop {
+            let attrs = self.parse_outer_attributes()?;
+            if let Some(lifetime) = self.eat_lifetime() {
+                // Parse lifetime parameter.
+                let bounds = if self.eat(&token::Colon) {
+                    self.parse_lt_param_bounds()
+                } else {
+                    Vec::new()
+                };
+                lifetime_defs.push(LifetimeDef {
+                    attrs: attrs.into(),
+                    lifetime: lifetime,
+                    bounds: bounds,
+                });
+                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.
+                ty_params.push(self.parse_ty_param(attrs)?);
+                seen_ty_param = true;
+            } else {
+                // Check for trailing attributes and stop parsing.
+                if !attrs.is_empty() {
+                    let param_kind = if seen_ty_param { "type" } else { "lifetime" };
+                    self.span_err(attrs[0].span,
+                        &format!("trailing attribute after {} parameters", param_kind));
+                }
+                break
+            }}
+
+            if !self.eat(&token::Comma) {
+                break
+            }
+        }
+        Ok((lifetime_defs, ty_params))
+    }
+
     /// Parse a set of optional generic type parameter declarations. Where
     /// clauses are not parsed here, and must be added later via
     /// `parse_where_clause()`.
@@ -4181,45 +4126,11 @@ impl<'a> Parser<'a> {
     /// where   typaramseq = ( typaram ) | ( typaram , typaramseq )
     pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
         maybe_whole!(self, NtGenerics, |x| x);
-        let span_lo = self.span.lo;
 
-        if self.eat(&token::Lt) {
-            // Upon encountering attribute in generics list, we do not
-            // know if it is attached to lifetime or to type param.
-            //
-            // Solution: 1. eagerly parse attributes in tandem with
-            // lifetime defs, 2. store last set of parsed (and unused)
-            // attributes in `attrs`, and 3. pass in those attributes
-            // when parsing formal type param after lifetime defs.
-            let mut attrs = vec![];
-            let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
-            let mut seen_default = false;
-            let mut post_lifetime_attrs = Some(attrs);
-            let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
-                p.forbid_lifetime()?;
-                // Move out of `post_lifetime_attrs` if present. O/w
-                // not first type param: parse attributes anew.
-                let attrs = match post_lifetime_attrs.as_mut() {
-                    None => p.parse_outer_attributes()?,
-                    Some(attrs) => mem::replace(attrs, vec![]),
-                };
-                post_lifetime_attrs = None;
-                let ty_param = p.parse_ty_param(attrs)?;
-                if ty_param.default.is_some() {
-                    seen_default = true;
-                } else if seen_default {
-                    let prev_span = p.prev_span;
-                    p.span_err(prev_span,
-                               "type parameters with a default must be trailing");
-                }
-                Ok(ty_param)
-            })?;
-            if let Some(attrs) = post_lifetime_attrs {
-                if !attrs.is_empty() {
-                    self.span_err(attrs[0].span,
-                                  "trailing attribute after lifetime parameters");
-                }
-            }
+        let span_lo = self.span.lo;
+        if self.eat_lt() {
+            let (lifetime_defs, ty_params) = self.parse_generic_params()?;
+            self.expect_gt()?;
             Ok(ast::Generics {
                 lifetimes: lifetime_defs,
                 ty_params: ty_params,
@@ -4234,85 +4145,52 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_generic_values_after_lt(&mut self) -> PResult<'a, (Vec<ast::Lifetime>,
-                                                            Vec<P<Ty>>,
-                                                            Vec<TypeBinding>)> {
-        let span_lo = self.span.lo;
-        let lifetimes = self.parse_lifetimes(token::Comma)?;
-
-        let missing_comma = !lifetimes.is_empty() &&
-                            !self.token.is_like_gt() &&
-                            self.prev_token_kind != PrevTokenKind::Comma;
-
-        if missing_comma {
-
-            let msg = format!("expected `,` or `>` after lifetime \
-                              name, found `{}`",
-                              self.this_token_to_string());
-            let mut err = self.diagnostic().struct_span_err(self.span, &msg);
-
-            let span_hi = self.span.hi;
-            let span_hi = match self.parse_ty_no_plus() {
-                Ok(..) => self.span.hi,
-                Err(ref mut err) => {
-                    self.cancel(err);
-                    span_hi
-                }
-            };
-
-            let msg = format!("did you mean a single argument type &'a Type, \
-                              or did you mean the comma-separated arguments \
-                              'a, Type?");
-            err.span_note(mk_sp(span_lo, span_hi), &msg);
-            return Err(err);
-        }
-
-        // First parse types.
-        let (types, returned) = self.parse_seq_to_gt_or_return(
-            Some(token::Comma),
-            |p| {
-                p.forbid_lifetime()?;
-                if p.look_ahead(1, |t| t == &token::Eq) {
-                    Ok(None)
-                } else {
-                    Ok(Some(p.parse_ty()?))
+    /// 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();
+        let mut bindings = Vec::new();
+        let mut seen_type = false;
+        let mut seen_binding = false;
+        loop {
+            if let Some(lifetime) = self.eat_lifetime() {
+                // Parse lifetime argument.
+                lifetimes.push(lifetime);
+                if seen_type || seen_binding {
+                    self.span_err(self.prev_span,
+                        "lifetime parameters must be declared prior to type parameters");
                 }
-            }
-        )?;
-
-        // If we found the `>`, don't continue.
-        if !returned {
-            return Ok((lifetimes, types, Vec::new()));
-        }
-
-        // Then parse type bindings.
-        let bindings = self.parse_seq_to_gt(
-            Some(token::Comma),
-            |p| {
-                p.forbid_lifetime()?;
-                let lo = p.span.lo;
-                let ident = p.parse_ident()?;
-                p.expect(&token::Eq)?;
-                let ty = p.parse_ty_no_plus()?;
-                let hi = ty.span.hi;
-                let span = mk_sp(lo, hi);
-                return Ok(TypeBinding{id: ast::DUMMY_NODE_ID,
+            } else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
+                // Parse associated type binding.
+                let lo = self.span.lo;
+                let ident = self.parse_ident()?;
+                self.bump();
+                let ty = self.parse_ty()?;
+                bindings.push(TypeBinding {
+                    id: ast::DUMMY_NODE_ID,
                     ident: ident,
                     ty: ty,
-                    span: span,
+                    span: mk_sp(lo, self.prev_span.hi),
                 });
-            }
-        )?;
-        Ok((lifetimes, types, bindings))
-    }
+                seen_binding = true;
+            } else if self.check_type() {
+                // Parse type argument.
+                types.push(self.parse_ty()?);
+                if seen_binding {
+                    self.span_err(types[types.len() - 1].span,
+                        "type parameters must be declared prior to associated type bindings");
+                }
+                seen_type = true;
+            } else {
+                break
+            }}
 
-    fn forbid_lifetime(&mut self) -> PResult<'a, ()> {
-        if self.token.is_lifetime() {
-            let span = self.span;
-            return Err(self.diagnostic().struct_span_err(span, "lifetime parameters must be \
-                                                                declared prior to type parameters"))
+            if !self.eat(&token::Comma) {
+                break
+            }
         }
-        Ok(())
+        Ok((lifetimes, types, bindings))
     }
 
     /// Parses an optional `where` clause and places it in `generics`.
@@ -4320,7 +4198,7 @@ impl<'a> Parser<'a> {
     /// ```ignore
     /// where T : Trait<U, V> + 'b, 'a : 'b
     /// ```
-    pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> {
+    pub fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
         maybe_whole!(self, NtWhereClause, |x| x);
 
         let mut where_clause = WhereClause {
@@ -4332,7 +4210,7 @@ impl<'a> Parser<'a> {
             return Ok(where_clause);
         }
 
-        // This is a temporary hack.
+        // This is a temporary future proofing.
         //
         // We are considering adding generics to the `where` keyword as an alternative higher-rank
         // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
@@ -4349,106 +4227,64 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let mut parsed_something = false;
         loop {
             let lo = self.span.lo;
-            match self.token {
-                token::OpenDelim(token::Brace) => {
-                    break
-                }
-
-                token::Lifetime(..) => {
-                    let bounded_lifetime =
-                        self.parse_lifetime()?;
-
-                    self.expect(&token::Colon)?;
-
-                    let bounds =
-                        self.parse_lifetimes(token::BinOp(token::Plus))?;
-
-                    let hi = self.prev_span.hi;
-                    let span = mk_sp(lo, hi);
-
-                    where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
-                        ast::WhereRegionPredicate {
-                            span: span,
-                            lifetime: bounded_lifetime,
-                            bounds: bounds
+            if let Some(lifetime) = self.eat_lifetime() {
+                // Bounds starting with a colon are mandatory, but possibly empty.
+                self.expect(&token::Colon)?;
+                let bounds = self.parse_lt_param_bounds();
+                where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
+                    ast::WhereRegionPredicate {
+                        span: mk_sp(lo, self.prev_span.hi),
+                        lifetime: lifetime,
+                        bounds: bounds,
+                    }
+                ));
+            } else {if self.check_type() {
+                // Parse optional `for<'a, 'b>`.
+                // This `for` is parsed greedily and applies to the whole predicate,
+                // the bounded type can have its own `for` applying only to it.
+                // Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/>
+                // Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/>
+                // Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/>
+                let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+
+                // Parse type with mandatory colon and (possibly empty) bounds,
+                // 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()?;
+                    where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
+                        ast::WhereBoundPredicate {
+                            span: mk_sp(lo, self.prev_span.hi),
+                            bound_lifetimes: lifetime_defs,
+                            bounded_ty: ty,
+                            bounds: bounds,
                         }
                     ));
-
-                    parsed_something = true;
-                }
-
-                _ => {
-                    let bound_lifetimes = if self.eat_keyword(keywords::For) {
-                        // Higher ranked constraint.
-                        self.expect(&token::Lt)?;
-                        let lifetime_defs = self.parse_lifetime_defs(None)?;
-                        self.expect_gt()?;
-                        lifetime_defs
-                    } else {
-                        vec![]
-                    };
-
-                    let bounded_ty = self.parse_ty_no_plus()?;
-
-                    if self.eat(&token::Colon) {
-                        let bounds = self.parse_ty_param_bounds()?;
-                        let hi = self.prev_span.hi;
-                        let span = mk_sp(lo, hi);
-
-                        if bounds.is_empty() {
-                            self.span_err(span,
-                                          "each predicate in a `where` clause must have \
-                                           at least one bound in it");
+                // FIXME: Decide what should be used here, `=` or `==`.
+                } else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
+                    let rhs_ty = self.parse_ty()?;
+                    where_clause.predicates.push(ast::WherePredicate::EqPredicate(
+                        ast::WhereEqPredicate {
+                            span: mk_sp(lo, self.prev_span.hi),
+                            lhs_ty: ty,
+                            rhs_ty: rhs_ty,
+                            id: ast::DUMMY_NODE_ID,
                         }
-
-                        where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
-                                ast::WhereBoundPredicate {
-                                    span: span,
-                                    bound_lifetimes: bound_lifetimes,
-                                    bounded_ty: bounded_ty,
-                                    bounds: bounds,
-                        }));
-
-                        parsed_something = true;
-                    } else if self.eat(&token::Eq) {
-                        // let ty = try!(self.parse_ty_no_plus());
-                        let hi = self.prev_span.hi;
-                        let span = mk_sp(lo, hi);
-                        // where_clause.predicates.push(
-                        //     ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
-                        //         id: ast::DUMMY_NODE_ID,
-                        //         span: span,
-                        //         path: panic!("NYI"), //bounded_ty,
-                        //         ty: ty,
-                        // }));
-                        // parsed_something = true;
-                        // // FIXME(#18433)
-                        self.span_err(span,
-                                     "equality constraints are not yet supported \
-                                     in where clauses (#20041)");
-                    } else {
-                        let prev_span = self.prev_span;
-                        self.span_err(prev_span,
-                              "unexpected token in `where` clause");
-                    }
+                    ));
+                } else {
+                    return self.unexpected();
                 }
-            };
+            } else {
+                break
+            }}
 
             if !self.eat(&token::Comma) {
                 break
             }
         }
 
-        if !parsed_something {
-            let prev_span = self.prev_span;
-            self.span_err(prev_span,
-                          "a `where` clause must have at least one predicate \
-                           in it");
-        }
-
         Ok(where_clause)
     }
 
@@ -4547,13 +4383,13 @@ impl<'a> Parser<'a> {
                 } else if self.look_ahead(1, |t| t.is_lifetime()) &&
                           isolated_self(self, 2) {
                     self.bump();
-                    let lt = self.parse_lifetime()?;
+                    let lt = self.eat_lifetime().expect("not a lifetime");
                     (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
                 } else if self.look_ahead(1, |t| t.is_lifetime()) &&
                           self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
                           isolated_self(self, 3) {
                     self.bump();
-                    let lt = self.parse_lifetime()?;
+                    let lt = self.eat_lifetime().expect("not a lifetime");
                     self.bump();
                     (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self))
                 } else {
@@ -4855,8 +4691,12 @@ impl<'a> Parser<'a> {
         let ident = self.parse_ident()?;
         let mut tps = self.parse_generics()?;
 
-        // Parse supertrait bounds.
-        let bounds = self.parse_colon_then_ty_param_bounds()?;
+        // Parse optional colon and supertrait bounds.
+        let bounds = if self.eat(&token::Colon) {
+            self.parse_ty_param_bounds()?
+        } else {
+            Vec::new()
+        };
 
         tps.where_clause = self.parse_where_clause()?;
 
@@ -4947,17 +4787,21 @@ impl<'a> Parser<'a> {
 
     /// Parse a::B<String,i32>
     fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> {
-        Ok(ast::TraitRef {
+        Ok(TraitRef {
             path: self.parse_path(PathStyle::Type)?,
             ref_id: ast::DUMMY_NODE_ID,
         })
     }
 
-    fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
+    fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<LifetimeDef>> {
         if self.eat_keyword(keywords::For) {
-            self.expect(&token::Lt)?;
-            let lifetime_defs = self.parse_lifetime_defs(None)?;
+            self.expect_lt()?;
+            let (lifetime_defs, ty_params) = self.parse_generic_params()?;
             self.expect_gt()?;
+            if !ty_params.is_empty() {
+                self.span_err(ty_params[0].span,
+                              "only lifetime parameters can be used in this context");
+            }
             Ok(lifetime_defs)
         } else {
             Ok(Vec::new())
@@ -4969,7 +4813,7 @@ impl<'a> Parser<'a> {
         let lo = self.span.lo;
         let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
 
-        Ok(ast::PolyTraitRef {
+        Ok(PolyTraitRef {
             bound_lifetimes: lifetime_defs,
             trait_ref: self.parse_trait_ref()?,
             span: mk_sp(lo, self.prev_span.hi),
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index bf790b96e37..d9e47a6b56e 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -187,6 +187,29 @@ impl Token {
         }
     }
 
+    /// Returns `true` if the token can appear at the start of a type.
+    pub fn can_begin_type(&self) -> bool {
+        match *self {
+            OpenDelim(Paren)            => true, // tuple
+            OpenDelim(Bracket)          => true, // array
+            Ident(..)                   => true, // type name or keyword
+            Underscore                  => true, // placeholder
+            Not                         => true, // never
+            BinOp(Star)                 => true, // raw pointer
+            BinOp(And)                  => true, // reference
+            AndAnd                      => true, // double reference
+            Lt | BinOp(Shl)             => true, // associated path
+            ModSep                      => true, // global path
+            Interpolated(ref nt) => match **nt {
+                NtTy(..) => true,
+                NtIdent(..) => true,
+                NtPath(..) => true,
+                _ => false,
+            },
+            _ => false,
+        }
+    }
+
     /// Returns `true` if the token is any literal
     pub fn is_lit(&self) -> bool {
         match *self {