Rollup merge of #33639 - petrochenkov:dotdot, r=nmatsakis

cc https://github.com/rust-lang/rust/issues/33627
r? @nikomatsakis

plugin-[breaking-change] cc https://github.com/rust-lang/rust/issues/31645 @Manishearth
This commit is contained in:
Manish Goregaokar 2016-05-27 09:57:00 +05:30
commit 35785712cd
50 changed files with 873 additions and 297 deletions

View file

@ -954,25 +954,6 @@ impl<'a> Parser<'a> {
Ok(result)
}
/// Parse a sequence parameter of enum variant. For consistency purposes,
/// these should not be empty.
pub fn parse_enum_variant_seq<T, F>(&mut self,
bra: &token::Token,
ket: &token::Token,
sep: SeqSep,
f: F)
-> PResult<'a, Vec<T>> where
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
{
let result = self.parse_unspanned_seq(bra, ket, sep, f)?;
if result.is_empty() {
let last_span = self.last_span;
self.span_err(last_span,
"nullary enum variants are written with no trailing `( )`");
}
Ok(result)
}
// NB: Do not use this function unless you actually plan to place the
// spanned list in the AST.
pub fn parse_seq<T, F>(&mut self,
@ -3434,21 +3415,33 @@ impl<'a> Parser<'a> {
};
}
fn parse_pat_tuple_elements(&mut self) -> PResult<'a, Vec<P<Pat>>> {
fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool)
-> PResult<'a, (Vec<P<Pat>>, Option<usize>)> {
let mut fields = vec![];
if !self.check(&token::CloseDelim(token::Paren)) {
fields.push(self.parse_pat()?);
if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) {
while self.eat(&token::Comma) &&
!self.check(&token::CloseDelim(token::Paren)) {
let mut ddpos = None;
while !self.check(&token::CloseDelim(token::Paren)) {
if ddpos.is_none() && self.eat(&token::DotDot) {
ddpos = Some(fields.len());
if self.eat(&token::Comma) {
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
fields.push(self.parse_pat()?);
}
} else if ddpos.is_some() && self.eat(&token::DotDot) {
// Emit a friendly error, ignore `..` and continue parsing
self.span_err(self.last_span, "`..` can only be used once per \
tuple or tuple struct pattern");
} else {
fields.push(self.parse_pat()?);
}
if fields.len() == 1 {
if !self.check(&token::CloseDelim(token::Paren)) ||
(unary_needs_comma && fields.len() == 1 && ddpos.is_none()) {
self.expect(&token::Comma)?;
}
}
Ok(fields)
Ok((fields, ddpos))
}
fn parse_pat_vec_elements(
@ -3627,9 +3620,9 @@ impl<'a> Parser<'a> {
token::OpenDelim(token::Paren) => {
// Parse (pat,pat,pat,...) as tuple pattern
self.bump();
let fields = self.parse_pat_tuple_elements()?;
let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
self.expect(&token::CloseDelim(token::Paren))?;
pat = PatKind::Tup(fields);
pat = PatKind::Tuple(fields, ddpos);
}
token::OpenDelim(token::Bracket) => {
// Parse [pat,pat,...] as slice pattern
@ -3714,20 +3707,10 @@ impl<'a> Parser<'a> {
return Err(self.fatal("unexpected `(` after qualified path"));
}
// Parse tuple struct or enum pattern
if self.look_ahead(1, |t| *t == token::DotDot) {
// This is a "top constructor only" pat
self.bump();
self.bump();
self.expect(&token::CloseDelim(token::Paren))?;
pat = PatKind::TupleStruct(path, None);
} else {
let args = self.parse_enum_variant_seq(
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
|p| p.parse_pat())?;
pat = PatKind::TupleStruct(path, Some(args));
}
self.bump();
let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
self.expect(&token::CloseDelim(token::Paren))?;
pat = PatKind::TupleStruct(path, fields, ddpos)
}
_ => {
pat = match qself {