@@ -4,6 +4,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
4
4
use crate :: ptr:: P ;
5
5
use crate :: ast:: { self , Attribute , Pat , PatKind , FieldPat , RangeEnd , RangeSyntax , Mac } ;
6
6
use crate :: ast:: { BindingMode , Ident , Mutability , Path , QSelf , Expr , ExprKind } ;
7
+ use crate :: mut_visit:: { noop_visit_pat, MutVisitor } ;
7
8
use crate :: parse:: token:: { self } ;
8
9
use crate :: print:: pprust;
9
10
use crate :: source_map:: { respan, Span , Spanned } ;
@@ -273,21 +274,20 @@ impl<'a> Parser<'a> {
273
274
// Parse _
274
275
PatKind :: Wild
275
276
} else if self . eat_keyword ( kw:: Mut ) {
276
- self . recover_pat_ident_mut_first ( ) ?
277
+ self . parse_pat_ident_mut ( ) ?
277
278
} else if self . eat_keyword ( kw:: Ref ) {
278
279
// Parse ref ident @ pat / ref mut ident @ pat
279
280
let mutbl = self . parse_mutability ( ) ;
280
281
self . parse_pat_ident ( BindingMode :: ByRef ( mutbl) ) ?
281
282
} else if self . eat_keyword ( kw:: Box ) {
282
283
// Parse `box pat`
283
284
PatKind :: Box ( self . parse_pat_with_range_pat ( false , None ) ?)
284
- } else if self . token . is_ident ( ) && !self . token . is_reserved_ident ( ) &&
285
- self . parse_as_ident ( ) {
285
+ } else if self . can_be_ident_pat ( ) {
286
286
// Parse `ident @ pat`
287
287
// This can give false positives and parse nullary enums,
288
288
// they are dealt with later in resolve.
289
289
self . parse_pat_ident ( BindingMode :: ByValue ( Mutability :: Immutable ) ) ?
290
- } else if self . token . is_path_start ( ) {
290
+ } else if self . is_start_of_pat_with_path ( ) {
291
291
// Parse pattern starting with a path
292
292
let ( qself, path) = if self . eat_lt ( ) {
293
293
// Parse a qualified path
@@ -384,24 +384,85 @@ impl<'a> Parser<'a> {
384
384
} )
385
385
}
386
386
387
+ fn parse_pat_ident_mut ( & mut self ) -> PResult < ' a , PatKind > {
388
+ let mut_span = self . prev_span ;
389
+
390
+ if self . eat_keyword ( kw:: Ref ) {
391
+ return self . recover_mut_ref_ident ( mut_span)
392
+ }
393
+
394
+ self . recover_additional_muts ( ) ;
395
+
396
+ let mut pat = self . parse_pat ( Some ( "identifier" ) ) ?;
397
+
398
+ // Add `mut` to any binding in the parsed pattern.
399
+ struct AddMut ;
400
+ impl MutVisitor for AddMut {
401
+ fn visit_pat ( & mut self , pat : & mut P < Pat > ) {
402
+ if let PatKind :: Ident ( BindingMode :: ByValue ( ref mut m) , ..) = pat. node {
403
+ * m = Mutability :: Mutable ;
404
+ }
405
+ noop_visit_pat ( pat, self ) ;
406
+ }
407
+ }
408
+ AddMut . visit_pat ( & mut pat) ;
409
+
410
+ // Unwrap; If we don't have `mut $ident`, error.
411
+ let pat = pat. into_inner ( ) ;
412
+ match & pat. node {
413
+ PatKind :: Ident ( ..) => { }
414
+ _ => self . ban_mut_general_pat ( mut_span, & pat) ,
415
+ }
416
+
417
+ Ok ( pat. node )
418
+ }
419
+
387
420
/// Recover on `mut ref? ident @ pat` and suggest
388
421
/// that the order of `mut` and `ref` is incorrect.
389
- fn recover_pat_ident_mut_first ( & mut self ) -> PResult < ' a , PatKind > {
390
- let mutref_span = self . prev_span . to ( self . token . span ) ;
391
- let binding_mode = if self . eat_keyword ( kw:: Ref ) {
392
- self . struct_span_err ( mutref_span, "the order of `mut` and `ref` is incorrect" )
393
- . span_suggestion (
394
- mutref_span,
395
- "try switching the order" ,
396
- "ref mut" . into ( ) ,
397
- Applicability :: MachineApplicable
398
- )
399
- . emit ( ) ;
400
- BindingMode :: ByRef ( Mutability :: Mutable )
401
- } else {
402
- BindingMode :: ByValue ( Mutability :: Mutable )
403
- } ;
404
- self . parse_pat_ident ( binding_mode)
422
+ fn recover_mut_ref_ident ( & mut self , lo : Span ) -> PResult < ' a , PatKind > {
423
+ let mutref_span = lo. to ( self . prev_span ) ;
424
+ self . struct_span_err ( mutref_span, "the order of `mut` and `ref` is incorrect" )
425
+ . span_suggestion (
426
+ mutref_span,
427
+ "try switching the order" ,
428
+ "ref mut" . into ( ) ,
429
+ Applicability :: MachineApplicable
430
+ )
431
+ . emit ( ) ;
432
+
433
+ self . parse_pat_ident ( BindingMode :: ByRef ( Mutability :: Mutable ) )
434
+ }
435
+
436
+ /// Error on `mut $pat` where `$pat` is not an ident.
437
+ fn ban_mut_general_pat ( & self , lo : Span , pat : & Pat ) {
438
+ let span = lo. to ( pat. span ) ;
439
+ self . struct_span_err ( span, "`mut` must be attached to each individual binding" )
440
+ . span_suggestion (
441
+ span,
442
+ "add `mut` to each binding" ,
443
+ pprust:: pat_to_string ( & pat) ,
444
+ Applicability :: MachineApplicable ,
445
+ )
446
+ . emit ( ) ;
447
+ }
448
+
449
+ /// Eat any extraneous `mut`s and error + recover if we ate any.
450
+ fn recover_additional_muts ( & mut self ) {
451
+ let lo = self . token . span ;
452
+ while self . eat_keyword ( kw:: Mut ) { }
453
+ if lo == self . token . span {
454
+ return ;
455
+ }
456
+
457
+ let span = lo. to ( self . prev_span ) ;
458
+ self . struct_span_err ( span, "`mut` on a binding may not be repeated" )
459
+ . span_suggestion (
460
+ span,
461
+ "remove the additional `mut`s" ,
462
+ String :: new ( ) ,
463
+ Applicability :: MachineApplicable ,
464
+ )
465
+ . emit ( ) ;
405
466
}
406
467
407
468
/// Parse macro invocation
@@ -479,17 +540,6 @@ impl<'a> Parser<'a> {
479
540
Err ( err)
480
541
}
481
542
482
- // Helper function to decide whether to parse as ident binding
483
- // or to try to do something more complex like range patterns.
484
- fn parse_as_ident ( & mut self ) -> bool {
485
- self . look_ahead ( 1 , |t| match t. kind {
486
- token:: OpenDelim ( token:: Paren ) | token:: OpenDelim ( token:: Brace ) |
487
- token:: DotDotDot | token:: DotDotEq | token:: DotDot |
488
- token:: ModSep | token:: Not => false ,
489
- _ => true ,
490
- } )
491
- }
492
-
493
543
/// Is the current token suitable as the start of a range patterns end?
494
544
fn is_pat_range_end_start ( & self ) -> bool {
495
545
self . token . is_path_start ( ) // e.g. `MY_CONST`;
@@ -563,6 +613,30 @@ impl<'a> Parser<'a> {
563
613
}
564
614
}
565
615
616
+ /// Is this the start of a pattern beginning with a path?
617
+ fn is_start_of_pat_with_path ( & mut self ) -> bool {
618
+ self . check_path ( )
619
+ // Just for recovery (see `can_be_ident`).
620
+ || self . token . is_ident ( ) && !self . token . is_bool_lit ( ) && !self . token . is_keyword ( kw:: In )
621
+ }
622
+
623
+ /// Would `parse_pat_ident` be appropriate here?
624
+ fn can_be_ident_pat ( & mut self ) -> bool {
625
+ self . check_ident ( )
626
+ && !self . token . is_bool_lit ( ) // Avoid `true` or `false` as a binding as it is a literal.
627
+ && !self . token . is_path_segment_keyword ( ) // Avoid e.g. `Self` as it is a path.
628
+ // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`.
629
+ && !self . token . is_keyword ( kw:: In )
630
+ && self . look_ahead ( 1 , |t| match t. kind { // Try to do something more complex?
631
+ token:: OpenDelim ( token:: Paren ) // A tuple struct pattern.
632
+ | token:: OpenDelim ( token:: Brace ) // A struct pattern.
633
+ | token:: DotDotDot | token:: DotDotEq | token:: DotDot // A range pattern.
634
+ | token:: ModSep // A tuple / struct variant pattern.
635
+ | token:: Not => false , // A macro expanding to a pattern.
636
+ _ => true ,
637
+ } )
638
+ }
639
+
566
640
/// Parses `ident` or `ident @ pat`.
567
641
/// Used by the copy foo and ref foo patterns to give a good
568
642
/// error message when parsing mistakes like `ref foo(a, b)`.
0 commit comments