@@ -31,6 +31,18 @@ pub enum RecoverComma {
3131    No , 
3232} 
3333
34+ /// The result of `eat_or_separator`. We want to distinguish which case we are in to avoid 
35+ /// emitting duplicate diagnostics. 
36+ #[ derive( Debug ,  Clone ,  Copy ) ]  
37+ enum  EatOrResult  { 
38+     /// We recovered from a trailing vert. 
39+      TrailingVert , 
40+     /// We ate an `|` (or `||` and recovered). 
41+      AteOr , 
42+     /// We did not eat anything (i.e. the current token is not `|` or `||`). 
43+      None , 
44+ } 
45+ 
3446impl < ' a >  Parser < ' a >  { 
3547    /// Parses a pattern. 
3648     /// 
@@ -55,9 +67,26 @@ impl<'a> Parser<'a> {
5567        gate_or :  GateOr , 
5668        rc :  RecoverComma , 
5769    )  -> PResult < ' a ,  P < Pat > >  { 
70+         self . parse_pat_allow_top_alt_inner ( expected,  gate_or,  rc) . map ( |( pat,  _) | pat) 
71+     } 
72+ 
73+     /// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true = 
74+      /// recovered). 
75+      fn  parse_pat_allow_top_alt_inner ( 
76+         & mut  self , 
77+         expected :  Expected , 
78+         gate_or :  GateOr , 
79+         rc :  RecoverComma , 
80+     )  -> PResult < ' a ,  ( P < Pat > ,  bool ) >  { 
81+         // Keep track of whether we recovered from a trailing vert so that we can avoid duplicated 
82+         // suggestions (which bothers rustfix). 
83+         // 
5884        // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). 
59-         let  leading_vert_span =
60-             if  self . eat_or_separator ( None )  {  Some ( self . prev_token . span )  }  else  {  None  } ; 
85+         let  ( leading_vert_span,  mut  trailing_vert)  = match  self . eat_or_separator ( None )  { 
86+             EatOrResult :: AteOr  => ( Some ( self . prev_token . span ) ,  false ) , 
87+             EatOrResult :: TrailingVert  => ( None ,  true ) , 
88+             EatOrResult :: None  => ( None ,  false ) , 
89+         } ; 
6190
6291        // Parse the first pattern (`p_0`). 
6392        let  first_pat = self . parse_pat_no_top_alt ( expected) ?; 
@@ -77,16 +106,24 @@ impl<'a> Parser<'a> {
77106                // If there was a leading vert, treat this as an or-pattern. This improves 
78107                // diagnostics. 
79108                let  span = leading_vert_span. to ( self . prev_token . span ) ; 
80-                 return  Ok ( self . mk_pat ( span,  PatKind :: Or ( vec ! [ first_pat] ) ) ) ; 
109+                 return  Ok ( ( self . mk_pat ( span,  PatKind :: Or ( vec ! [ first_pat] ) ) ,  trailing_vert ) ) ; 
81110            } 
82111
83-             return  Ok ( first_pat) ; 
112+             return  Ok ( ( first_pat,  trailing_vert ) ) ; 
84113        } 
85114
86115        // Parse the patterns `p_1 | ... | p_n` where `n > 0`. 
87116        let  lo = leading_vert_span. unwrap_or ( first_pat. span ) ; 
88117        let  mut  pats = vec ! [ first_pat] ; 
89-         while  self . eat_or_separator ( Some ( lo) )  { 
118+         loop  { 
119+             match  self . eat_or_separator ( Some ( lo) )  { 
120+                 EatOrResult :: AteOr  => { } 
121+                 EatOrResult :: None  => break , 
122+                 EatOrResult :: TrailingVert  => { 
123+                     trailing_vert = true ; 
124+                     break ; 
125+                 } 
126+             } 
90127            let  pat = self . parse_pat_no_top_alt ( expected) . map_err ( |mut  err| { 
91128                err. span_label ( lo,  WHILE_PARSING_OR_MSG ) ; 
92129                err
@@ -101,15 +138,63 @@ impl<'a> Parser<'a> {
101138            self . sess . gated_spans . gate ( sym:: or_patterns,  or_pattern_span) ; 
102139        } 
103140
104-         Ok ( self . mk_pat ( or_pattern_span,  PatKind :: Or ( pats) ) ) 
141+         Ok ( ( self . mk_pat ( or_pattern_span,  PatKind :: Or ( pats) ) ,  trailing_vert ) ) 
105142    } 
106143
107-     /// Parse the pattern for a function or function pointer parameter. 
108-      pub ( super )  fn  parse_fn_param_pat ( & mut  self )  -> PResult < ' a ,  P < Pat > >  { 
109-         // We actually do _not_ allow top-level or-patterns in function params, but we use 
110-         // `parse_pat_allow_top_alt` anyway so that we can detect when a user tries to use it. This 
111-         // allows us to print a better error message. 
112-         // 
144+     /// Parse a pattern and (maybe) a `Colon` in positions where a pattern may be followed by a 
145+      /// type annotation (e.g. for `let` bindings or `fn` params). 
146+      /// 
147+      /// Generally, this corresponds to `pat_no_top_alt` followed by an optional `Colon`. It will 
148+      /// eat the `Colon` token if one is present. 
149+      /// 
150+      /// The return value represents the parsed pattern and `true` if a `Colon` was parsed (`false` 
151+      /// otherwise). 
152+      pub ( super )  fn  parse_pat_before_ty ( 
153+         & mut  self , 
154+         expected :  Expected , 
155+         gate_or :  GateOr , 
156+         rc :  RecoverComma , 
157+         syntax_loc :  & str , 
158+     )  -> PResult < ' a ,  ( P < Pat > ,  bool ) >  { 
159+         // We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level 
160+         // or-patterns so that we can detect when a user tries to use it. This allows us to print a 
161+         // better error message. 
162+         let  ( pat,  trailing_vert)  = self . parse_pat_allow_top_alt_inner ( expected,  gate_or,  rc) ?; 
163+         let  colon = self . eat ( & token:: Colon ) ; 
164+ 
165+         if  let  PatKind :: Or ( pats)  = & pat. kind  { 
166+             let  msg = format ! ( "top-level or-patterns are not allowed in {}" ,  syntax_loc) ; 
167+             let  ( help,  fix)  = if  pats. len ( )  == 1  { 
168+                 // If all we have is a leading vert, then print a special message. This is the case 
169+                 // if `parse_pat_allow_top_alt` returns an or-pattern with one variant. 
170+                 let  msg = "remove the `|`" ; 
171+                 let  fix = pprust:: pat_to_string ( & pat) ; 
172+                 ( msg,  fix) 
173+             }  else  { 
174+                 let  msg = "wrap the pattern in parentheses" ; 
175+                 let  fix = format ! ( "({})" ,  pprust:: pat_to_string( & pat) ) ; 
176+                 ( msg,  fix) 
177+             } ; 
178+ 
179+             if  trailing_vert { 
180+                 // We already emitted an error and suggestion to remove the trailing vert. Don't 
181+                 // emit again. 
182+                 self . sess . span_diagnostic . delay_span_bug ( pat. span ,  & msg) ; 
183+             }  else  { 
184+                 self . struct_span_err ( pat. span ,  & msg) 
185+                     . span_suggestion ( pat. span ,  help,  fix,  Applicability :: MachineApplicable ) 
186+                     . emit ( ) ; 
187+             } 
188+         } 
189+ 
190+         Ok ( ( pat,  colon) ) 
191+     } 
192+ 
193+     /// Parse the pattern for a function or function pointer parameter, followed by a colon. 
194+      /// 
195+      /// The return value represents the parsed pattern and `true` if a `Colon` was parsed (`false` 
196+      /// otherwise). 
197+      pub ( super )  fn  parse_fn_param_pat_colon ( & mut  self )  -> PResult < ' a ,  ( P < Pat > ,  bool ) >  { 
113198        // In order to get good UX, we first recover in the case of a leading vert for an illegal 
114199        // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case, 
115200        // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that 
@@ -128,53 +213,28 @@ impl<'a> Parser<'a> {
128213            self . bump ( ) ; 
129214        } 
130215
131-         let  pat = self . parse_pat_allow_top_alt ( PARAM_EXPECTED ,  GateOr :: No ,  RecoverComma :: No ) ?; 
132- 
133-         if  let  PatKind :: Or ( ..)  = & pat. kind  { 
134-             self . ban_illegal_fn_param_or_pat ( & pat) ; 
135-         } 
136- 
137-         Ok ( pat) 
138-     } 
139- 
140-     /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. 
141-      fn  ban_illegal_fn_param_or_pat ( & self ,  pat :  & Pat )  { 
142-         // If all we have a leading vert, then print a special message. This is the case if 
143-         // `parse_pat_allow_top_alt` returns an or-pattern with one variant. 
144-         let  ( msg,  fix)  = match  & pat. kind  { 
145-             PatKind :: Or ( pats)  if  pats. len ( )  == 1  => { 
146-                 let  msg = "remove the leading `|`" ; 
147-                 let  fix = pprust:: pat_to_string ( pat) ; 
148-                 ( msg,  fix) 
149-             } 
150- 
151-             _ => { 
152-                 let  msg = "wrap the pattern in parentheses" ; 
153-                 let  fix = format ! ( "({})" ,  pprust:: pat_to_string( pat) ) ; 
154-                 ( msg,  fix) 
155-             } 
156-         } ; 
157- 
158-         self . struct_span_err ( pat. span ,  "an or-pattern parameter must be wrapped in parentheses" ) 
159-             . span_suggestion ( pat. span ,  msg,  fix,  Applicability :: MachineApplicable ) 
160-             . emit ( ) ; 
216+         self . parse_pat_before_ty ( 
217+             PARAM_EXPECTED , 
218+             GateOr :: No , 
219+             RecoverComma :: No , 
220+             "function parameters" , 
221+         ) 
161222    } 
162223
163224    /// Eat the or-pattern `|` separator. 
164225     /// If instead a `||` token is encountered, recover and pretend we parsed `|`. 
165-      fn  eat_or_separator ( & mut  self ,  lo :  Option < Span > )  -> bool  { 
226+      fn  eat_or_separator ( & mut  self ,  lo :  Option < Span > )  -> EatOrResult  { 
166227        if  self . recover_trailing_vert ( lo)  { 
167-             return  false ; 
168-         } 
169- 
170-         match  self . token . kind  { 
171-             token:: OrOr  => { 
172-                 // Found `||`; Recover and pretend we parsed `|`. 
173-                 self . ban_unexpected_or_or ( lo) ; 
174-                 self . bump ( ) ; 
175-                 true 
176-             } 
177-             _ => self . eat ( & token:: BinOp ( token:: Or ) ) , 
228+             EatOrResult :: TrailingVert 
229+         }  else  if  matches ! ( self . token. kind,  token:: OrOr )  { 
230+             // Found `||`; Recover and pretend we parsed `|`. 
231+             self . ban_unexpected_or_or ( lo) ; 
232+             self . bump ( ) ; 
233+             EatOrResult :: AteOr 
234+         }  else  if  self . eat ( & token:: BinOp ( token:: Or ) )  { 
235+             EatOrResult :: AteOr 
236+         }  else  { 
237+             EatOrResult :: None 
178238        } 
179239    } 
180240
@@ -190,14 +250,14 @@ impl<'a> Parser<'a> {
190250            matches ! ( 
191251                & token. uninterpolate( ) . kind, 
192252                token:: FatArrow  // e.g. `a | => 0,`. 
193-             | token:: Ident ( kw:: If ,  false )  // e.g. `a | if expr`. 
194-             | token:: Eq  // e.g. `let a | = 0`. 
195-             | token:: Semi  // e.g. `let a |;`. 
196-             | token:: Colon  // e.g. `let a | :`. 
197-             | token:: Comma  // e.g. `let (a |,)`. 
198-             | token:: CloseDelim ( token:: Bracket )  // e.g. `let [a | ]`. 
199-             | token:: CloseDelim ( token:: Paren )  // e.g. `let (a | )`. 
200-             | token:: CloseDelim ( token:: Brace )  // e.g. `let A { f: a | }`. 
253+                  | token:: Ident ( kw:: If ,  false )  // e.g. `a | if expr`. 
254+                  | token:: Eq  // e.g. `let a | = 0`. 
255+                  | token:: Semi  // e.g. `let a |;`. 
256+                  | token:: Colon  // e.g. `let a | :`. 
257+                  | token:: Comma  // e.g. `let (a |,)`. 
258+                  | token:: CloseDelim ( token:: Bracket )  // e.g. `let [a | ]`. 
259+                  | token:: CloseDelim ( token:: Paren )  // e.g. `let (a | )`. 
260+                  | token:: CloseDelim ( token:: Brace )  // e.g. `let A { f: a | }`. 
201261            ) 
202262        } ) ; 
203263        match  ( is_end_ahead,  & self . token . kind )  { 
0 commit comments