]> git.lizzy.rs Git - rust.git/commitdiff
Refactor parsing of generic arguments/parameters and where clauses
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Tue, 17 Jan 2017 18:18:29 +0000 (21:18 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Tue, 24 Jan 2017 19:56:02 +0000 (22:56 +0300)
23 files changed:
src/librustc_passes/ast_validation.rs
src/librustc_typeck/collect.rs
src/librustdoc/clean/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs
src/test/compile-fail/generic-non-trailing-defaults.rs [new file with mode: 0644]
src/test/compile-fail/issue-20616-1.rs
src/test/compile-fail/issue-20616-2.rs
src/test/compile-fail/issue-20616-3.rs
src/test/compile-fail/issue-20616-4.rs
src/test/compile-fail/issue-20616-5.rs
src/test/compile-fail/issue-20616-6.rs
src/test/compile-fail/issue-20616-7.rs
src/test/compile-fail/issue-20616-8.rs
src/test/compile-fail/issue-20616-9.rs
src/test/parse-fail/generic-non-trailing-defaults.rs [deleted file]
src/test/parse-fail/issue-14303-path.rs
src/test/parse-fail/issue-17904-2.rs [new file with mode: 0644]
src/test/parse-fail/issue-17904.rs
src/test/parse-fail/issue-32214.rs
src/test/parse-fail/lifetime-semicolon.rs
src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs

index b7b027102b2afbd3c999d85f74d9982725fb0277..9720bb8426475b6a476d450ecc8f2374e54acf01 100644 (file)
@@ -146,6 +146,12 @@ fn visit_ty(&mut self, ty: &'a Ty) {
             TyKind::TraitObject(ref bounds) => {
                 self.no_questions_in_bounds(bounds, "trait object types", false);
             }
+            TyKind::ImplTrait(ref bounds) => {
+                if !bounds.iter()
+                          .any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
+                    self.err_handler().span_err(ty.span, "at least one trait must be specified");
+                }
+            }
             _ => {}
         }
 
@@ -284,6 +290,26 @@ fn visit_vis(&mut self, vis: &'a Visibility) {
 
         visit::walk_vis(self, vis)
     }
+
+    fn visit_generics(&mut self, g: &'a Generics) {
+        let mut seen_default = None;
+        for ty_param in &g.ty_params {
+            if ty_param.default.is_some() {
+                seen_default = Some(ty_param.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 {
+            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)
+    }
 }
 
 pub fn check_crate(session: &Session, krate: &Crate) {
index d403ac43435319b9e47ffe3a0e3afb68dd66fa67..b9ee1c2b84cb0be352f5fb666f3847853011e54d 100644 (file)
@@ -1833,11 +1833,8 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                 }
             }
 
-            &hir::WherePredicate::EqPredicate(ref eq_pred) => {
+            &hir::WherePredicate::EqPredicate(..) => {
                 // FIXME(#20041)
-                span_bug!(eq_pred.span,
-                         "Equality constraints are not yet \
-                          implemented (#20041)")
             }
         }
     }
index a77485477b1591330dec2162217592e8ccadb12e..77f0482e11318c1b4bd6c659d0ef5479bbffce89 100644 (file)
@@ -842,8 +842,11 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
                 }
             }
 
-            hir::WherePredicate::EqPredicate(_) => {
-                unimplemented!() // FIXME(#20041)
+            hir::WherePredicate::EqPredicate(ref wrp) => {
+                WherePredicate::EqPredicate {
+                    lhs: wrp.lhs_ty.clean(cx),
+                    rhs: wrp.rhs_ty.clean(cx)
+                }
             }
         }
     }
index 2a0a73859987b5f26014e553e77c93f448ce530b..c589f1a7aaaa00481c8955a6d00a27b45c4ea96d 100644 (file)
@@ -22,7 +22,7 @@
 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_;
@@ -638,13 +638,7 @@ pub fn expect_gt(&mut self) -> PResult<'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()
         }
     }
 
@@ -971,20 +965,11 @@ pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> {
         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
@@ -993,9 +978,9 @@ pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> {
         } 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 {
@@ -1010,18 +995,9 @@ pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> {
     }
 
     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> {
@@ -1029,7 +1005,7 @@ pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> {
     }
 
     /// 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> {
         /*
 
@@ -1201,13 +1177,6 @@ pub fn parse_trait_items(&mut self) -> PResult<'a,  Vec<TraitItem>> {
             })
     }
 
-    /// 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) {
@@ -1259,8 +1228,8 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
                                             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,
@@ -1308,9 +1277,7 @@ pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
 
         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
@@ -1318,9 +1285,8 @@ pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             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;
@@ -1335,13 +1301,11 @@ pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             }
         } 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 ]`
@@ -1353,13 +1317,15 @@ pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             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 plus priority
             self.parse_for_in_type()?
         } else if self.eat_keyword(keywords::Impl) {
+            // FIXME plus priority
             self.parse_impl_trait_type()?
         } else if self.token_is_bare_fn_keyword() {
             // BARE FUNCTION
@@ -1372,10 +1338,7 @@ pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             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)?;
@@ -1405,10 +1368,10 @@ pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
 
     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> {
@@ -1504,8 +1467,7 @@ pub fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
     }
 
     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)
@@ -1727,7 +1689,8 @@ pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec<ast::Pat
 
             // 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,
@@ -1785,7 +1748,8 @@ pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec<ast::PathSe
             // 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 {
@@ -1827,121 +1791,18 @@ pub fn parse_path_segments_without_types(&mut self)
         }
     }
 
-    /// 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
-                });
-            }
-            _ => {
-                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);
+                    span: self.prev_span,
+                    name: ident.name
+                })
             }
-
-            self.bump();
+            _ => None
         }
     }
 
@@ -2458,7 +2319,9 @@ fn parse_dot_suffix(&mut self,
                         -> 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())
         };
@@ -4075,69 +3938,76 @@ fn warn_missing_semicolon(&self) {
         }).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.token.is_keyword(keywords::For) || self.token.is_path_start() {
+                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;
+            // Trailing plus is not allowed for now and we have to detect it.
+            let is_bound_start = |token: &token::Token| {
+                token == &token::Question || token.is_lifetime() ||
+                token.is_keyword(keywords::For) || token.is_path_start()
+            };
+            if self.check(&token::BinOp(token::Plus)) && self.look_ahead(1, is_bound_start) {
+                self.bump();
+            } else {
+                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.check(&token::BinOp(token::Plus)) && self.look_ahead(1, |t| t.is_lifetime()) {
+                self.bump();
+            } else {
+                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
@@ -4153,6 +4023,51 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'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.token.is_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()`.
@@ -4162,45 +4077,11 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'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,
@@ -4215,85 +4096,53 @@ pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
         }
     }
 
-    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 {
+            let eq_is_next = self.look_ahead(1, |t| t == &token::Eq); // borrowck workaround
+            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.token.is_ident() && eq_is_next {
+                // 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),
                 });
+                seen_binding = true;
+            } else if self.token.can_begin_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
             }
-        )?;
-        Ok((lifetimes, types, bindings))
-    }
 
-    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`.
@@ -4301,7 +4150,7 @@ fn forbid_lifetime(&mut self) -> PResult<'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 {
@@ -4313,7 +4162,7 @@ pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> {
             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
@@ -4330,106 +4179,64 @@ pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> {
             }
         }
 
-        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.token.can_begin_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)
     }
 
@@ -4528,13 +4335,13 @@ fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> {
                 } 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 {
@@ -4836,8 +4643,12 @@ fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
         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()?;
 
@@ -4928,17 +4739,21 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo>
 
     /// 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())
@@ -4950,7 +4765,7 @@ fn parse_poly_trait_ref(&mut self) -> PResult<'a, PolyTraitRef> {
         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),
index bf790b96e37f6c09270284840e549b9d379afc03..d9e47a6b56e8f1cd5c0f12f18f0d58d6f79e72e3 100644 (file)
@@ -187,6 +187,29 @@ pub fn can_begin_expr(&self) -> bool {
         }
     }
 
+    /// 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 {
index a38a7bfb9378526d090f42bdcd6f4a01a20ea162..5e09473ab77da9ee2987123bc7c740a158247908 100644 (file)
 
 struct RefAny<'a, T>(&'a T);
 
-impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {
-    //~^ ERROR expected identifier, found `>`
-}
+impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {}
+//~^ ERROR trailing attribute after type parameters
 
-fn main() {
-
-}
+fn main() {}
diff --git a/src/test/compile-fail/generic-non-trailing-defaults.rs b/src/test/compile-fail/generic-non-trailing-defaults.rs
new file mode 100644 (file)
index 0000000..77e5520
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Heap;
+
+struct Vec<A = Heap, T>;
+//~^ ERROR type parameters with a default must be trailing
+
+struct Foo<A, B = Vec<C>, C>;
+//~^ ERROR type parameters with a default must be trailing
+//~| ERROR type parameters with a default cannot use forward declared identifiers
+
+fn main() {}
index 5b4f9942d28b606fd41e60e9f562b6059c3a89e0..a1949df661a34a699e9708864f1ad069d16c3867 100644 (file)
@@ -16,7 +16,7 @@
 type Type_1_<'a, T> = &'a T;
 
 
-type Type_1<'a T> = &'a T; //~ error: expected `,` or `>` after lifetime name, found `T`
+type Type_1<'a T> = &'a T; //~ error: expected one of `,`, `:`, or `>`, found `T`
 
 
 //type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
index 65305ff3ac82f2490af1e89841018ce241943b86..87b836d68727480b74e09e10d68b37a26056daba 100644 (file)
@@ -19,7 +19,7 @@
 //type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
 
 
-type Type_2 = Type_1_<'static ()>; //~ error: expected `,` or `>` after lifetime name, found `(`
+type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(`
 
 
 //type Type_3<T> = Box<T,,>; // error: expected type, found `,`
index 101f81019d97cd4e3de9e3aa3e729f81de80ff98..9a5972a7a1641ae0b85e416d02ba6c727e802fd6 100644 (file)
@@ -22,7 +22,7 @@
 //type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
 
 
-type Type_3<T> = Box<T,,>; //~ error: expected type, found `,`
+type Type_3<T> = Box<T,,>; //~ error: expected `>`, found `,`
 
 
 //type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
index 6450e9ed68cb710fba8db89e817f112d0a4f3cdb..1567698e476ba0b90af6307247abc98543b8e271 100644 (file)
@@ -25,7 +25,7 @@
 //type Type_3<T> = Box<T,,>; // error: expected type, found `,`
 
 
-type Type_4<T> = Type_1_<'static,, T>; //~ error: expected type, found `,`
+type Type_4<T> = Type_1_<'static,, T>; //~ error: expected `>`, found `,`
 
 
 type Type_5_<'a> = Type_1_<'a, ()>;
index d1840427ad8b24319c1517f883cfd3f1ce7ccb68..c5a0624574d0e2b79b529a2d0c9bc1242a210ee3 100644 (file)
@@ -31,7 +31,7 @@
 type Type_5_<'a> = Type_1_<'a, ()>;
 
 
-type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected type, found `,`
+type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected `>`, found `,`
 
 
 //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
index b0b5bc653f6d0bdfc55976cff3296f0b56869d68..56578409546ff758ee98d6789e4a645fc1fbcbda 100644 (file)
@@ -34,7 +34,7 @@
 //type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
 
 
-type Type_6 = Type_5_<'a,,>; //~ error: expected type, found `,`
+type Type_6 = Type_5_<'a,,>; //~ error: expected `>`, found `,`
 
 
 //type Type_7 = Box<(),,>; // error: expected type, found `,`
index 0958f8b4ed22c4a538a9db4ec48a7d0d54ad7e47..ecd0a467cf6b069bdaf6596086adc1a47354d4db 100644 (file)
@@ -37,7 +37,7 @@
 //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
 
 
-type Type_7 = Box<(),,>; //~ error: expected type, found `,`
+type Type_7 = Box<(),,>; //~ error: expected `>`, found `,`
 
 
 //type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
index d6cf9acae9b0b9351329685bb01f793697caa6c2..535672c65e46e457eabd39e170ac73968878323e 100644 (file)
@@ -40,7 +40,7 @@
 //type Type_7 = Box<(),,>; // error: expected type, found `,`
 
 
-type Type_8<'a,,> = &'a (); //~ error: expected identifier, found `,`
+type Type_8<'a,,> = &'a (); //~ error: expected `>`, found `,`
 
 
 //type Type_9<T,,> = Box<T>; // error: expected identifier, found `,`
index d64cec446ef3dafce7ca825b3425a20c547b2954..b666a8b67aa3f09a7334ffcbcc96fdf272bd2401 100644 (file)
@@ -43,4 +43,4 @@
 //type Type_8<'a,,> = &'a (); // error: expected identifier, found `,`
 
 
-type Type_9<T,,> = Box<T>; //~ error: expected identifier, found `,`
+type Type_9<T,,> = Box<T>; //~ error: expected `>`, found `,`
diff --git a/src/test/parse-fail/generic-non-trailing-defaults.rs b/src/test/parse-fail/generic-non-trailing-defaults.rs
deleted file mode 100644 (file)
index 2bb5932..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only -Z continue-parse-after-error
-
-struct Heap;
-
-struct Vec<A = Heap, T>; //~ ERROR type parameters with a default must be trailing
-
-struct Foo<A, B = Vec<C>, C>; //~ ERROR type parameters with a default must be trailing
-
-fn main() {}
index 431a917c2d9f4cd9f76633c4a4e48f73e4d9d55f..f0d1feffec80bbe57568f53000e64adde3120d2f 100644 (file)
@@ -12,4 +12,3 @@
 
 fn bar<'a, T>(x: mymodule::X<'a, T, 'b, 'c>) {}
 //~^ ERROR lifetime parameters must be declared prior to type parameters
-//~^^ ERROR expected pattern, found `'c`
diff --git a/src/test/parse-fail/issue-17904-2.rs b/src/test/parse-fail/issue-17904-2.rs
new file mode 100644 (file)
index 0000000..3f41c0e
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
+struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found `where`
+
+fn main() {}
index de5aeb02ab788d91612f76a97de202d86e91d76d..ae28ac76acb9827621a2453983861190cb164d81 100644 (file)
@@ -13,7 +13,6 @@
 struct Baz<U> where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax.
 struct Baz<U> where U: Eq(U) -> R; // Notice this parses as well.
 struct Baz<U>(U) where U: Eq; // This rightfully signals no error as well.
-struct Foo<T> where T: Copy, (T); //~ ERROR unexpected token in `where` clause
-struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found `where`
+struct Foo<T> where T: Copy, (T); //~ ERROR expected one of `+`, `:`, `==`, or `=`, found `;`
 
 fn main() {}
index 3ba59c8ee946bfc792442a2a94a9f79aa43ab160..9e200094093683d3ba9e9b38f83902c53e191bd1 100644 (file)
@@ -10,8 +10,7 @@
 
 // compile-flags: -Z parse-only -Z continue-parse-after-error
 
-pub fn test<W, I: Iterator<Item=(), W> >() {
-    //~^ ERROR expected `=`, found `>`
-}
+pub fn test<W, I: Iterator<Item=(), W> >() {}
+//~^ ERROR type parameters must be declared prior to associated type bindings
 
 fn main() { }
index 7010d0e7debf24ced3eb27b9c756fc61c5b035e3..e1975952fca3ea268bb7bfe1c861d663535bd860 100644 (file)
@@ -15,5 +15,4 @@ struct Foo<'a, 'b> {
 }
 
 fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
-//~^ ERROR expected `,` or `>` after lifetime name, found `;`
-//~^^ NOTE did you mean a single argument type &'a Type, or did you mean the comma-separated
+//~^ ERROR expected one of `,` or `>`, found `;`
index 78d9745408735fb8d660fc4f6c91f3501b839de4..cf67b518fff9180eba63d68eddf72feff8f330ad 100644 (file)
 
 // compile-flags: -Z parse-only -Z continue-parse-after-error
 
+// Empty predicate list is OK
 fn equal1<T>(_: &T, _: &T) -> bool where {
-//~^ ERROR a `where` clause must have at least one predicate in it
     true
 }
 
+// Empty bound list is OK
 fn equal2<T>(_: &T, _: &T) -> bool where T: {
-//~^ ERROR each predicate in a `where` clause must have at least one bound
     true
 }