Skip to content

Commit 6bfba39

Browse files
committed
Adjust parsing of Slice, Tuple, TupleStruct patterns.
1 parent 77d8752 commit 6bfba39

File tree

1 file changed

+26
-127
lines changed

1 file changed

+26
-127
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 26 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3534,122 +3534,6 @@ impl<'a> Parser<'a> {
35343534
};
35353535
}
35363536

3537-
// Parses a parenthesized list of patterns like
3538-
// `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
3539-
// - a vector of the patterns that were parsed
3540-
// - an option indicating the index of the `..` element
3541-
// - a boolean indicating whether a trailing comma was present.
3542-
// Trailing commas are significant because (p) and (p,) are different patterns.
3543-
fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
3544-
self.expect(&token::OpenDelim(token::Paren))?;
3545-
let result = match self.parse_pat_list() {
3546-
Ok(result) => result,
3547-
Err(mut err) => { // recover from parse error in tuple pattern list
3548-
err.emit();
3549-
self.consume_block(token::Paren);
3550-
return Ok((vec![], Some(0), false));
3551-
}
3552-
};
3553-
self.expect(&token::CloseDelim(token::Paren))?;
3554-
Ok(result)
3555-
}
3556-
3557-
fn parse_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
3558-
let mut fields = Vec::new();
3559-
let mut ddpos = None;
3560-
let mut prev_dd_sp = None;
3561-
let mut trailing_comma = false;
3562-
loop {
3563-
if self.eat(&token::DotDot) {
3564-
if ddpos.is_none() {
3565-
ddpos = Some(fields.len());
3566-
prev_dd_sp = Some(self.prev_span);
3567-
} else {
3568-
// Emit a friendly error, ignore `..` and continue parsing
3569-
let mut err = self.struct_span_err(
3570-
self.prev_span,
3571-
"`..` can only be used once per tuple or tuple struct pattern",
3572-
);
3573-
err.span_label(self.prev_span, "can only be used once per pattern");
3574-
if let Some(sp) = prev_dd_sp {
3575-
err.span_label(sp, "previously present here");
3576-
}
3577-
err.emit();
3578-
}
3579-
} else if !self.check(&token::CloseDelim(token::Paren)) {
3580-
fields.push(self.parse_pat(None)?);
3581-
} else {
3582-
break
3583-
}
3584-
3585-
trailing_comma = self.eat(&token::Comma);
3586-
if !trailing_comma {
3587-
break
3588-
}
3589-
}
3590-
3591-
if ddpos == Some(fields.len()) && trailing_comma {
3592-
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
3593-
let msg = "trailing comma is not permitted after `..`";
3594-
self.struct_span_err(self.prev_span, msg)
3595-
.span_label(self.prev_span, msg)
3596-
.emit();
3597-
}
3598-
3599-
Ok((fields, ddpos, trailing_comma))
3600-
}
3601-
3602-
fn parse_pat_vec_elements(
3603-
&mut self,
3604-
) -> PResult<'a, (Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>)> {
3605-
let mut before = Vec::new();
3606-
let mut slice = None;
3607-
let mut after = Vec::new();
3608-
let mut first = true;
3609-
let mut before_slice = true;
3610-
3611-
while self.token != token::CloseDelim(token::Bracket) {
3612-
if first {
3613-
first = false;
3614-
} else {
3615-
self.expect(&token::Comma)?;
3616-
3617-
if self.token == token::CloseDelim(token::Bracket)
3618-
&& (before_slice || !after.is_empty()) {
3619-
break
3620-
}
3621-
}
3622-
3623-
if before_slice {
3624-
if self.eat(&token::DotDot) {
3625-
3626-
if self.check(&token::Comma) ||
3627-
self.check(&token::CloseDelim(token::Bracket)) {
3628-
slice = Some(P(Pat {
3629-
id: ast::DUMMY_NODE_ID,
3630-
node: PatKind::Wild,
3631-
span: self.prev_span,
3632-
}));
3633-
before_slice = false;
3634-
}
3635-
continue
3636-
}
3637-
}
3638-
3639-
let subpat = self.parse_pat(None)?;
3640-
if before_slice && self.eat(&token::DotDot) {
3641-
slice = Some(subpat);
3642-
before_slice = false;
3643-
} else if before_slice {
3644-
before.push(subpat);
3645-
} else {
3646-
after.push(subpat);
3647-
}
3648-
}
3649-
3650-
Ok((before, slice, after))
3651-
}
3652-
36533537
fn parse_pat_field(
36543538
&mut self,
36553539
lo: Span,
@@ -3861,6 +3745,17 @@ impl<'a> Parser<'a> {
38613745
}))
38623746
}
38633747

3748+
/// Parse a parentesized comma separated sequence of patterns until `delim` is reached.
3749+
fn parse_recover_pat_list(&mut self) -> PResult<'a, ()> {
3750+
while !self.check(&token::CloseDelim(token::Paren)) {
3751+
self.parse_pat(None)?;
3752+
if !self.eat(&token::Comma) {
3753+
return Ok(())
3754+
}
3755+
}
3756+
Ok(())
3757+
}
3758+
38643759
/// A wrapper around `parse_pat` with some special error handling for the
38653760
/// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast
38663761
/// to subpatterns within such).
@@ -3874,7 +3769,7 @@ impl<'a> Parser<'a> {
38743769
// later.
38753770
let comma_span = self.token.span;
38763771
self.bump();
3877-
if let Err(mut err) = self.parse_pat_list() {
3772+
if let Err(mut err) = self.parse_recover_pat_list() {
38783773
// We didn't expect this to work anyway; we just wanted
38793774
// to advance to the end of the comma-sequence so we know
38803775
// the span to suggest parenthesizing
@@ -3932,20 +3827,24 @@ impl<'a> Parser<'a> {
39323827
pat = PatKind::Ref(subpat, mutbl);
39333828
}
39343829
token::OpenDelim(token::Paren) => {
3935-
// Parse (pat,pat,pat,...) as tuple pattern
3936-
let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?;
3937-
pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
3830+
// Parse `(pat, pat, pat, ...)` as tuple pattern.
3831+
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
3832+
3833+
pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
39383834
PatKind::Paren(fields.into_iter().nth(0).unwrap())
39393835
} else {
3940-
PatKind::Tuple(fields, ddpos)
3836+
PatKind::Tuple(fields)
39413837
};
39423838
}
39433839
token::OpenDelim(token::Bracket) => {
3944-
// Parse [pat,pat,...] as slice pattern
3840+
// Parse `[pat, pat,...]` as a slice pattern.
3841+
let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?;
3842+
pat = PatKind::Slice(slice);
3843+
}
3844+
token::DotDot => {
3845+
// Parse `..`.
39453846
self.bump();
3946-
let (before, slice, after) = self.parse_pat_vec_elements()?;
3947-
self.expect(&token::CloseDelim(token::Bracket))?;
3948-
pat = PatKind::Slice(before, slice, after);
3847+
pat = PatKind::Rest;
39493848
}
39503849
// At this point, token != &, &&, (, [
39513850
_ => if self.eat_keyword(kw::Underscore) {
@@ -4043,8 +3942,8 @@ impl<'a> Parser<'a> {
40433942
return Err(err);
40443943
}
40453944
// Parse tuple struct or enum pattern
4046-
let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
4047-
pat = PatKind::TupleStruct(path, fields, ddpos)
3945+
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
3946+
pat = PatKind::TupleStruct(path, fields)
40483947
}
40493948
_ => pat = PatKind::Path(qself, path),
40503949
}

0 commit comments

Comments
 (0)