@@ -53,7 +53,7 @@ use parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership};
53
53
use util:: parser:: { AssocOp , Fixity } ;
54
54
use print:: pprust;
55
55
use ptr:: P ;
56
- use parse:: PResult ;
56
+ use parse:: { PResult , PartialPResult } ;
57
57
use tokenstream:: { self , Delimited , ThinTokenStream , TokenTree , TokenStream } ;
58
58
use symbol:: { Symbol , keywords} ;
59
59
use util:: ThinVec ;
@@ -3485,7 +3485,7 @@ impl<'a> Parser<'a> {
3485
3485
}
3486
3486
3487
3487
fn parse_pat_tuple_elements ( & mut self , unary_needs_comma : bool )
3488
- -> PResult < ' a , ( Vec < P < Pat > > , Option < usize > ) > {
3488
+ -> PartialPResult < ' a , ( Vec < P < Pat > > , Option < usize > ) > {
3489
3489
let mut fields = vec ! [ ] ;
3490
3490
let mut ddpos = None ;
3491
3491
@@ -3494,19 +3494,24 @@ impl<'a> Parser<'a> {
3494
3494
ddpos = Some ( fields. len ( ) ) ;
3495
3495
if self . eat ( & token:: Comma ) {
3496
3496
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
3497
- fields. push ( self . parse_pat ( ) ?) ;
3497
+ let field = self . parse_pat ( )
3498
+ . map_err ( |err| ( ( fields. clone ( ) , ddpos) , err) ) ?;
3499
+ fields. push ( field) ;
3498
3500
}
3499
3501
} else if ddpos. is_some ( ) && self . eat ( & token:: DotDot ) {
3500
3502
// Emit a friendly error, ignore `..` and continue parsing
3501
3503
self . span_err ( self . prev_span , "`..` can only be used once per \
3502
3504
tuple or tuple struct pattern") ;
3503
3505
} else {
3504
- fields. push ( self . parse_pat ( ) ?) ;
3506
+ let field = self . parse_pat ( )
3507
+ . map_err ( |err| ( ( fields. clone ( ) , ddpos) , err) ) ?;
3508
+ fields. push ( field) ;
3505
3509
}
3506
3510
3507
3511
if !self . check ( & token:: CloseDelim ( token:: Paren ) ) ||
3508
3512
( unary_needs_comma && fields. len ( ) == 1 && ddpos. is_none ( ) ) {
3509
- self . expect ( & token:: Comma ) ?;
3513
+ self . expect ( & token:: Comma )
3514
+ . map_err ( |err| ( ( fields. clone ( ) , ddpos) , err) ) ?;
3510
3515
}
3511
3516
}
3512
3517
@@ -3690,11 +3695,11 @@ impl<'a> Parser<'a> {
3690
3695
} ) )
3691
3696
}
3692
3697
3693
- /// A wrapper around `parse_pat` with some special error handling for the
3694
- /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contast
3695
- /// to subpatterns within such).
3698
+ /// A wrapper around `parse_pat` with some special error handling and
3699
+ /// recovery for the "top-level" patterns in a match arm, `for` loop,
3700
+ /// `let`, &c. (in contast to subpatterns within such).
3696
3701
pub fn parse_top_level_pat ( & mut self ) -> PResult < ' a , P < Pat > > {
3697
- let pat = self . parse_pat ( ) ?;
3702
+ let mut pat = self . parse_pat ( ) ?;
3698
3703
if self . token == token:: Comma {
3699
3704
// An unexpected comma after a top-level pattern is a clue that the
3700
3705
// user (perhaps more accustomed to some other language) forgot the
@@ -3703,12 +3708,21 @@ impl<'a> Parser<'a> {
3703
3708
// later.
3704
3709
let comma_span = self . span ;
3705
3710
self . bump ( ) ;
3706
- if let Err ( mut err) = self . parse_pat_tuple_elements ( false ) {
3707
- // We didn't expect this to work anyway; we just wanted
3708
- // to advance to the end of the comma-sequence so we know
3709
- // the span to suggest parenthesizing
3710
- err. cancel ( ) ;
3711
- }
3711
+ let mut fields = vec ! [ pat. clone( ) ] ;
3712
+ let ( rest_fields, ddpos) = match self . parse_pat_tuple_elements ( false ) {
3713
+ Ok ( fields_ddpos) => fields_ddpos,
3714
+ Err ( ( fields_ddpos, mut err) ) => {
3715
+ // We didn't really expect this to work anyway; we want the
3716
+ // partial result (so that post-recovery code knows about
3717
+ // any bindings) and to advance to the end of the
3718
+ // comma-sequence (so we know the span to suggest
3719
+ // parenthesizing), but we'll emit our own error in just a
3720
+ // moment
3721
+ err. cancel ( ) ;
3722
+ fields_ddpos
3723
+ }
3724
+ } ;
3725
+ fields. extend ( rest_fields) ;
3712
3726
let seq_span = pat. span . to ( self . prev_span ) ;
3713
3727
let mut err = self . struct_span_err ( comma_span,
3714
3728
"unexpected `,` in pattern" ) ;
@@ -3717,6 +3731,11 @@ impl<'a> Parser<'a> {
3717
3731
format ! ( "({})" , seq_snippet) ) ;
3718
3732
}
3719
3733
err. emit ( ) ;
3734
+ // Now that we've emitted our own error, the rest of the parser
3735
+ // can pretend this was actually a tuple
3736
+ pat = P ( Pat { node : PatKind :: Tuple ( fields, ddpos) ,
3737
+ span : seq_span,
3738
+ id : ast:: DUMMY_NODE_ID } ) ;
3720
3739
}
3721
3740
Ok ( pat)
3722
3741
}
@@ -3746,7 +3765,8 @@ impl<'a> Parser<'a> {
3746
3765
token:: OpenDelim ( token:: Paren ) => {
3747
3766
// Parse (pat,pat,pat,...) as tuple pattern
3748
3767
self . bump ( ) ;
3749
- let ( fields, ddpos) = self . parse_pat_tuple_elements ( true ) ?;
3768
+ let ( fields, ddpos) = self . parse_pat_tuple_elements ( true )
3769
+ . map_err ( |( _partial, err) | err) ?;
3750
3770
self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?;
3751
3771
pat = PatKind :: Tuple ( fields, ddpos) ;
3752
3772
}
@@ -3839,7 +3859,8 @@ impl<'a> Parser<'a> {
3839
3859
}
3840
3860
// Parse tuple struct or enum pattern
3841
3861
self . bump ( ) ;
3842
- let ( fields, ddpos) = self . parse_pat_tuple_elements ( false ) ?;
3862
+ let ( fields, ddpos) = self . parse_pat_tuple_elements ( false )
3863
+ . map_err ( |( _partial, err) | err) ?;
3843
3864
self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?;
3844
3865
pat = PatKind :: TupleStruct ( path, fields, ddpos)
3845
3866
}
0 commit comments