Skip to content

Commit 62b29a1

Browse files
committed
Adjust parsing of Slice, Tuple, TupleStruct patterns.
1 parent 7e1b671 commit 62b29a1

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
@@ -3535,122 +3535,6 @@ impl<'a> Parser<'a> {
35353535
};
35363536
}
35373537

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

3749+
/// Parse a parentesized comma separated sequence of patterns until `delim` is reached.
3750+
fn parse_recover_pat_list(&mut self) -> PResult<'a, ()> {
3751+
while !self.check(&token::CloseDelim(token::Paren)) {
3752+
self.parse_pat(None)?;
3753+
if !self.eat(&token::Comma) {
3754+
return Ok(())
3755+
}
3756+
}
3757+
Ok(())
3758+
}
3759+
38653760
/// A wrapper around `parse_pat` with some special error handling for the
38663761
/// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast
38673762
/// to subpatterns within such).
@@ -3875,7 +3770,7 @@ impl<'a> Parser<'a> {
38753770
// later.
38763771
let comma_span = self.token.span;
38773772
self.bump();
3878-
if let Err(mut err) = self.parse_pat_list() {
3773+
if let Err(mut err) = self.parse_recover_pat_list() {
38793774
// We didn't expect this to work anyway; we just wanted
38803775
// to advance to the end of the comma-sequence so we know
38813776
// the span to suggest parenthesizing
@@ -3933,20 +3828,24 @@ impl<'a> Parser<'a> {
39333828
pat = PatKind::Ref(subpat, mutbl);
39343829
}
39353830
token::OpenDelim(token::Paren) => {
3936-
// Parse (pat,pat,pat,...) as tuple pattern
3937-
let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?;
3938-
pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
3831+
// Parse `(pat, pat, pat, ...)` as tuple pattern.
3832+
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
3833+
3834+
pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
39393835
PatKind::Paren(fields.into_iter().nth(0).unwrap())
39403836
} else {
3941-
PatKind::Tuple(fields, ddpos)
3837+
PatKind::Tuple(fields)
39423838
};
39433839
}
39443840
token::OpenDelim(token::Bracket) => {
3945-
// Parse [pat,pat,...] as slice pattern
3841+
// Parse `[pat, pat,...]` as a slice pattern.
3842+
let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?;
3843+
pat = PatKind::Slice(slice);
3844+
}
3845+
token::DotDot => {
3846+
// Parse `..`.
39463847
self.bump();
3947-
let (before, slice, after) = self.parse_pat_vec_elements()?;
3948-
self.expect(&token::CloseDelim(token::Bracket))?;
3949-
pat = PatKind::Slice(before, slice, after);
3848+
pat = PatKind::Rest;
39503849
}
39513850
// At this point, token != &, &&, (, [
39523851
_ => if self.eat_keyword(kw::Underscore) {
@@ -4044,8 +3943,8 @@ impl<'a> Parser<'a> {
40443943
return Err(err);
40453944
}
40463945
// Parse tuple struct or enum pattern
4047-
let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
4048-
pat = PatKind::TupleStruct(path, fields, ddpos)
3946+
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
3947+
pat = PatKind::TupleStruct(path, fields)
40493948
}
40503949
_ => pat = PatKind::Path(qself, path),
40513950
}

0 commit comments

Comments
 (0)