diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9e2829e638050..bd995d44fead5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -86,6 +86,7 @@ use std::collections::HashSet; use std::mem::replace; use std::rc::Rc; use std::gc::{Gc, GC}; +use std::iter; #[allow(non_camel_case_types)] #[deriving(PartialEq)] @@ -762,20 +763,26 @@ impl<'a> Parser<'a> { sep: Option, f: |&mut Parser| -> T) -> OwnedSlice { - let mut first = true; let mut v = Vec::new(); - while self.token != token::GT - && self.token != token::BINOP(token::SHR) - && self.token != token::GE - && self.token != token::BINOPEQ(token::SHR) { - match sep { - Some(ref t) => { - if first { first = false; } - else { self.expect(t); } - } - _ => () + // This loop works by alternating back and forth between parsing types + // and commas. For example, given a string `A, B,>`, the parser would + // first parse `A`, then a comma, then `B`, then a comma. After that it + // would encounter a `>` and stop. This lets the parser handle trailing + // commas in generic parameters, because it can stop either after + // parsing a type or after parsing a comma. + for i in iter::count(0u, 1) { + if self.token == token::GT + || self.token == token::BINOP(token::SHR) + || self.token == token::GE + || self.token == token::BINOPEQ(token::SHR) { + break; + } + + if i % 2 == 0 { + v.push(f(self)); + } else { + sep.as_ref().map(|t| self.expect(t)); } - v.push(f(self)); } return OwnedSlice::from_vec(v); } @@ -2266,7 +2273,7 @@ impl<'a> Parser<'a> { let mut es = self.parse_unspanned_seq( &token::LPAREN, &token::RPAREN, - seq_sep_trailing_disallowed(token::COMMA), + seq_sep_trailing_allowed(token::COMMA), |p| p.parse_expr() ); hi = self.last_span.hi; @@ -3196,7 +3203,7 @@ impl<'a> Parser<'a> { args = self.parse_enum_variant_seq( &token::LPAREN, &token::RPAREN, - seq_sep_trailing_disallowed(token::COMMA), + seq_sep_trailing_allowed(token::COMMA), |p| p.parse_pat() ); pat = PatEnum(enum_path, Some(args)); @@ -4068,7 +4075,7 @@ impl<'a> Parser<'a> { match self.token { token::COMMA => { self.bump(); - let sep = seq_sep_trailing_disallowed(token::COMMA); + let sep = seq_sep_trailing_allowed(token::COMMA); let mut fn_inputs = self.parse_seq_to_before_end( &token::RPAREN, sep, @@ -4091,7 +4098,7 @@ impl<'a> Parser<'a> { let fn_inputs = match explicit_self { SelfStatic => { - let sep = seq_sep_trailing_disallowed(token::COMMA); + let sep = seq_sep_trailing_allowed(token::COMMA); self.parse_seq_to_before_end(&token::RPAREN, sep, parse_arg_fn) } SelfValue(id) => parse_remaining_arguments!(id), @@ -4128,7 +4135,7 @@ impl<'a> Parser<'a> { self.parse_optional_unboxed_closure_kind(); let args = self.parse_seq_to_before_end( &token::BINOP(token::OR), - seq_sep_trailing_disallowed(token::COMMA), + seq_sep_trailing_allowed(token::COMMA), |p| p.parse_fn_block_arg() ); self.bump(); @@ -4950,7 +4957,7 @@ impl<'a> Parser<'a> { let arg_tys = self.parse_enum_variant_seq( &token::LPAREN, &token::RPAREN, - seq_sep_trailing_disallowed(token::COMMA), + seq_sep_trailing_allowed(token::COMMA), |p| p.parse_ty(true) ); for ty in arg_tys.move_iter() { diff --git a/src/test/run-pass/trailing-comma.rs b/src/test/run-pass/trailing-comma.rs index 8d580729da980..394ff831d9bd6 100644 --- a/src/test/run-pass/trailing-comma.rs +++ b/src/test/run-pass/trailing-comma.rs @@ -8,9 +8,31 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f(_: int,) {} +fn f(_: T,) {} + +struct Foo; + +struct Bar; + +impl Bar { + fn f(_: int,) {} + fn g(self, _: int,) {} + fn h(self,) {} +} + +enum Baz { + Qux(int,), +} pub fn main() { - f(0i,); + f::(0i,); let (_, _,) = (1i, 1i,); + + let x: Foo = Foo::; + + Bar::f(0i,); + Bar.g(0i,); + Bar.h(); + + let x = Qux(1,); }