@@ -24,6 +24,13 @@ pub enum RecoverComma {
24
24
No ,
25
25
}
26
26
27
+ /// Whether or not to recover a `:` when parsing patterns that were meant to be paths.
28
+ #[ derive( PartialEq , Copy , Clone ) ]
29
+ pub enum RecoverColon {
30
+ Yes ,
31
+ No ,
32
+ }
33
+
27
34
/// The result of `eat_or_separator`. We want to distinguish which case we are in to avoid
28
35
/// emitting duplicate diagnostics.
29
36
#[ derive( Debug , Clone , Copy ) ]
@@ -58,8 +65,9 @@ impl<'a> Parser<'a> {
58
65
& mut self ,
59
66
expected : Expected ,
60
67
rc : RecoverComma ,
68
+ ra : RecoverColon ,
61
69
) -> PResult < ' a , P < Pat > > {
62
- self . parse_pat_allow_top_alt_inner ( expected, rc) . map ( |( pat, _) | pat)
70
+ self . parse_pat_allow_top_alt_inner ( expected, rc, ra ) . map ( |( pat, _) | pat)
63
71
}
64
72
65
73
/// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
@@ -68,6 +76,7 @@ impl<'a> Parser<'a> {
68
76
& mut self ,
69
77
expected : Expected ,
70
78
rc : RecoverComma ,
79
+ ra : RecoverColon ,
71
80
) -> PResult < ' a , ( P < Pat > , bool ) > {
72
81
// Keep track of whether we recovered from a trailing vert so that we can avoid duplicated
73
82
// suggestions (which bothers rustfix).
@@ -89,6 +98,56 @@ impl<'a> Parser<'a> {
89
98
// If we parsed a leading `|` which should be gated,
90
99
// then we should really gate the leading `|`.
91
100
// This complicated procedure is done purely for diagnostics UX.
101
+ let mut first_pat = first_pat;
102
+
103
+ if let ( RecoverColon :: Yes , token:: Colon ) = ( ra, & self . token . kind ) {
104
+ if matches ! (
105
+ first_pat. kind,
106
+ PatKind :: Ident ( BindingMode :: ByValue ( Mutability :: Not ) , _, None )
107
+ | PatKind :: Path ( ..)
108
+ ) && self . look_ahead ( 1 , |token| token. is_ident ( ) && !token. is_reserved_ident ( ) )
109
+ {
110
+ // The pattern looks like it might be a path with a `::` -> `:` typo:
111
+ // `match foo { bar:baz => {} }`
112
+ let span = self . token . span ;
113
+ // We only emit "unexpected `:`" error here if we can successfully parse the
114
+ // whole pattern correctly in that case.
115
+ let snapshot = self . clone ( ) ;
116
+
117
+ // Create error for "unexpected `:`".
118
+ match self . expected_one_of_not_found ( & [ ] , & [ ] ) {
119
+ Err ( mut err) => {
120
+ self . bump ( ) ; // Skip the `:`.
121
+ match self . parse_pat_no_top_alt ( expected) {
122
+ Err ( mut inner_err) => {
123
+ // Carry on as if we had not done anything, callers will emit a
124
+ // reasonable error.
125
+ inner_err. cancel ( ) ;
126
+ err. cancel ( ) ;
127
+ * self = snapshot;
128
+ }
129
+ Ok ( pat) => {
130
+ // We've parsed the rest of the pattern.
131
+ err. span_suggestion (
132
+ span,
133
+ "maybe write a path separator here" ,
134
+ "::" . to_string ( ) ,
135
+ Applicability :: MachineApplicable ,
136
+ ) ;
137
+ err. emit ( ) ;
138
+ first_pat =
139
+ self . mk_pat ( first_pat. span . to ( pat. span ) , PatKind :: Wild ) ;
140
+ }
141
+ }
142
+ }
143
+ _ => {
144
+ // Carry on as if we had not done anything. This should be unreachable.
145
+ * self = snapshot;
146
+ }
147
+ } ;
148
+ }
149
+ }
150
+
92
151
if let Some ( leading_vert_span) = leading_vert_span {
93
152
// If there was a leading vert, treat this as an or-pattern. This improves
94
153
// diagnostics.
@@ -140,7 +199,8 @@ impl<'a> Parser<'a> {
140
199
// We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
141
200
// or-patterns so that we can detect when a user tries to use it. This allows us to print a
142
201
// better error message.
143
- let ( pat, trailing_vert) = self . parse_pat_allow_top_alt_inner ( expected, rc) ?;
202
+ let ( pat, trailing_vert) =
203
+ self . parse_pat_allow_top_alt_inner ( expected, rc, RecoverColon :: No ) ?;
144
204
let colon = self . eat ( & token:: Colon ) ;
145
205
146
206
if let PatKind :: Or ( pats) = & pat. kind {
@@ -350,7 +410,7 @@ impl<'a> Parser<'a> {
350
410
} else if self . check ( & token:: OpenDelim ( token:: Bracket ) ) {
351
411
// Parse `[pat, pat,...]` as a slice pattern.
352
412
let ( pats, _) = self . parse_delim_comma_seq ( token:: Bracket , |p| {
353
- p. parse_pat_allow_top_alt ( None , RecoverComma :: No )
413
+ p. parse_pat_allow_top_alt ( None , RecoverComma :: No , RecoverColon :: No )
354
414
} ) ?;
355
415
PatKind :: Slice ( pats)
356
416
} else if self . check ( & token:: DotDot ) && !self . is_pat_range_end_start ( 1 ) {
@@ -563,8 +623,9 @@ impl<'a> Parser<'a> {
563
623
564
624
/// Parse a tuple or parenthesis pattern.
565
625
fn parse_pat_tuple_or_parens ( & mut self ) -> PResult < ' a , PatKind > {
566
- let ( fields, trailing_comma) =
567
- self . parse_paren_comma_seq ( |p| p. parse_pat_allow_top_alt ( None , RecoverComma :: No ) ) ?;
626
+ let ( fields, trailing_comma) = self . parse_paren_comma_seq ( |p| {
627
+ p. parse_pat_allow_top_alt ( None , RecoverComma :: No , RecoverColon :: No )
628
+ } ) ?;
568
629
569
630
// Here, `(pat,)` is a tuple pattern.
570
631
// For backward compatibility, `(..)` is a tuple pattern as well.
@@ -873,8 +934,9 @@ impl<'a> Parser<'a> {
873
934
874
935
/// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
875
936
fn parse_pat_tuple_struct ( & mut self , qself : Option < QSelf > , path : Path ) -> PResult < ' a , PatKind > {
876
- let ( fields, _) =
877
- self . parse_paren_comma_seq ( |p| p. parse_pat_allow_top_alt ( None , RecoverComma :: No ) ) ?;
937
+ let ( fields, _) = self . parse_paren_comma_seq ( |p| {
938
+ p. parse_pat_allow_top_alt ( None , RecoverComma :: No , RecoverColon :: No )
939
+ } ) ?;
878
940
if qself. is_some ( ) {
879
941
self . sess . gated_spans . gate ( sym:: more_qualified_paths, path. span ) ;
880
942
}
@@ -1033,7 +1095,7 @@ impl<'a> Parser<'a> {
1033
1095
// Parsing a pattern of the form `fieldname: pat`.
1034
1096
let fieldname = self . parse_field_name ( ) ?;
1035
1097
self . bump ( ) ;
1036
- let pat = self . parse_pat_allow_top_alt ( None , RecoverComma :: No ) ?;
1098
+ let pat = self . parse_pat_allow_top_alt ( None , RecoverComma :: No , RecoverColon :: No ) ?;
1037
1099
hi = pat. span ;
1038
1100
( pat, fieldname, false )
1039
1101
} else {
0 commit comments