@@ -19,14 +19,14 @@ const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"
1919
2020/// Whether or not an or-pattern should be gated when occurring in the current context. 
2121#[ derive( PartialEq ,  Clone ,  Copy ) ]  
22- pub ( super )  enum  GateOr  { 
22+ pub  enum  GateOr  { 
2323    Yes , 
2424    No , 
2525} 
2626
2727/// Whether or not to recover a `,` when parsing or-patterns. 
2828#[ derive( PartialEq ,  Copy ,  Clone ) ]  
29- pub ( super )  enum  RecoverComma  { 
29+ pub  enum  RecoverComma  { 
3030    Yes , 
3131    No , 
3232} 
@@ -37,80 +37,57 @@ impl<'a> Parser<'a> {
3737     /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns 
3838     /// at the top level. Used when parsing the parameters of lambda expressions, 
3939     /// functions, function pointers, and `pat` macro fragments. 
40-      pub  fn  parse_pat ( & mut  self ,  expected :  Expected )  -> PResult < ' a ,  P < Pat > >  { 
40+      pub  fn  parse_pat_no_top_alt ( & mut  self ,  expected :  Expected )  -> PResult < ' a ,  P < Pat > >  { 
4141        self . parse_pat_with_range_pat ( true ,  expected) 
4242    } 
4343
44-     /// Entry point to the main pattern parser. 
44+     /// Parses a pattern. 
45+      /// 
4546     /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. 
46-      pub ( super )  fn  parse_top_pat ( 
47+      /// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used. 
48+      /// 
49+      /// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>, 
50+      /// a leading vert is allowed in nested or-patterns, too. This allows us to 
51+      /// simplify the grammar somewhat. 
52+      pub  fn  parse_pat_allow_top_alt ( 
4753        & mut  self , 
54+         expected :  Expected , 
4855        gate_or :  GateOr , 
4956        rc :  RecoverComma , 
5057    )  -> PResult < ' a ,  P < Pat > >  { 
5158        // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). 
52-         let  gated_leading_vert = self . eat_or_separator ( None )  && gate_or == GateOr :: Yes ; 
53-         let  leading_vert_span = self . prev_token . span ; 
54- 
55-         // Parse the possibly-or-pattern. 
56-         let  pat = self . parse_pat_with_or ( None ,  gate_or,  rc) ?; 
57- 
58-         // If we parsed a leading `|` which should be gated, 
59-         // and no other gated or-pattern has been parsed thus far, 
60-         // then we should really gate the leading `|`. 
61-         // This complicated procedure is done purely for diagnostics UX. 
62-         if  gated_leading_vert && self . sess . gated_spans . is_ungated ( sym:: or_patterns)  { 
63-             self . sess . gated_spans . gate ( sym:: or_patterns,  leading_vert_span) ; 
64-         } 
65- 
66-         Ok ( pat) 
67-     } 
68- 
69-     /// Parse the pattern for a function or function pointer parameter. 
70-      /// Special recovery is provided for or-patterns and leading `|`. 
71-      pub ( super )  fn  parse_fn_param_pat ( & mut  self )  -> PResult < ' a ,  P < Pat > >  { 
72-         self . recover_leading_vert ( None ,  "not allowed in a parameter pattern" ) ; 
73-         let  pat = self . parse_pat_with_or ( PARAM_EXPECTED ,  GateOr :: No ,  RecoverComma :: No ) ?; 
74- 
75-         if  let  PatKind :: Or ( ..)  = & pat. kind  { 
76-             self . ban_illegal_fn_param_or_pat ( & pat) ; 
77-         } 
78- 
79-         Ok ( pat) 
80-     } 
59+         let  leading_vert_span =
60+             if  self . eat_or_separator ( None )  {  Some ( self . prev_token . span )  }  else  {  None  } ; 
8161
82-     /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. 
83-      fn  ban_illegal_fn_param_or_pat ( & self ,  pat :  & Pat )  { 
84-         let  msg = "wrap the pattern in parenthesis" ; 
85-         let  fix = format ! ( "({})" ,  pprust:: pat_to_string( pat) ) ; 
86-         self . struct_span_err ( pat. span ,  "an or-pattern parameter must be wrapped in parenthesis" ) 
87-             . span_suggestion ( pat. span ,  msg,  fix,  Applicability :: MachineApplicable ) 
88-             . emit ( ) ; 
89-     } 
90- 
91-     /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). 
92-      /// Corresponds to `pat<allow_top_alt>` in RFC 2535. 
93-      fn  parse_pat_with_or ( 
94-         & mut  self , 
95-         expected :  Expected , 
96-         gate_or :  GateOr , 
97-         rc :  RecoverComma , 
98-     )  -> PResult < ' a ,  P < Pat > >  { 
9962        // Parse the first pattern (`p_0`). 
100-         let  first_pat = self . parse_pat ( expected) ?; 
63+         let  first_pat = self . parse_pat_no_top_alt ( expected) ?; 
10164        self . maybe_recover_unexpected_comma ( first_pat. span ,  rc,  gate_or) ?; 
10265
10366        // If the next token is not a `|`, 
10467        // this is not an or-pattern and we should exit here. 
10568        if  !self . check ( & token:: BinOp ( token:: Or ) )  && self . token  != token:: OrOr  { 
69+             // If we parsed a leading `|` which should be gated, 
70+             // then we should really gate the leading `|`. 
71+             // This complicated procedure is done purely for diagnostics UX. 
72+             if  let  Some ( leading_vert_span)  = leading_vert_span { 
73+                 if  gate_or == GateOr :: Yes  && self . sess . gated_spans . is_ungated ( sym:: or_patterns)  { 
74+                     self . sess . gated_spans . gate ( sym:: or_patterns,  leading_vert_span) ; 
75+                 } 
76+ 
77+                 // If there was a leading vert, treat this as an or-pattern. This improves 
78+                 // diagnostics. 
79+                 let  span = leading_vert_span. to ( self . prev_token . span ) ; 
80+                 return  Ok ( self . mk_pat ( span,  PatKind :: Or ( vec ! [ first_pat] ) ) ) ; 
81+             } 
82+ 
10683            return  Ok ( first_pat) ; 
10784        } 
10885
10986        // Parse the patterns `p_1 | ... | p_n` where `n > 0`. 
110-         let  lo = first_pat. span ; 
87+         let  lo = leading_vert_span . unwrap_or ( first_pat. span ) ; 
11188        let  mut  pats = vec ! [ first_pat] ; 
11289        while  self . eat_or_separator ( Some ( lo) )  { 
113-             let  pat = self . parse_pat ( expected) . map_err ( |mut  err| { 
90+             let  pat = self . parse_pat_no_top_alt ( expected) . map_err ( |mut  err| { 
11491                err. span_label ( lo,  WHILE_PARSING_OR_MSG ) ; 
11592                err
11693            } ) ?; 
@@ -127,6 +104,62 @@ impl<'a> Parser<'a> {
127104        Ok ( self . mk_pat ( or_pattern_span,  PatKind :: Or ( pats) ) ) 
128105    } 
129106
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+         // 
113+         // In order to get good UX, we first recover in the case of a leading vert for an illegal 
114+         // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case, 
115+         // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that 
116+         // separately. 
117+         if  let  token:: OrOr  = self . token . kind  { 
118+             let  span = self . token . span ; 
119+             let  mut  err = self . struct_span_err ( span,  "unexpected `||` before function parameter" ) ; 
120+             err. span_suggestion ( 
121+                 span, 
122+                 "remove the `||`" , 
123+                 String :: new ( ) , 
124+                 Applicability :: MachineApplicable , 
125+             ) ; 
126+             err. note ( "alternatives in or-patterns are separated with `|`, not `||`" ) ; 
127+             err. emit ( ) ; 
128+             self . bump ( ) ; 
129+         } 
130+ 
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 ( ) ; 
161+     } 
162+ 
130163    /// Eat the or-pattern `|` separator. 
131164     /// If instead a `||` token is encountered, recover and pretend we parsed `|`. 
132165     fn  eat_or_separator ( & mut  self ,  lo :  Option < Span > )  -> bool  { 
@@ -179,7 +212,7 @@ impl<'a> Parser<'a> {
179212
180213    /// We have parsed `||` instead of `|`. Error and suggest `|` instead. 
181214     fn  ban_unexpected_or_or ( & mut  self ,  lo :  Option < Span > )  { 
182-         let  mut  err = self . struct_span_err ( self . token . span ,  "unexpected token `||` after  pattern" ) ; 
215+         let  mut  err = self . struct_span_err ( self . token . span ,  "unexpected token `||` in  pattern" ) ; 
183216        err. span_suggestion ( 
184217            self . token . span , 
185218            "use a single `|` to separate multiple alternative patterns" , 
@@ -244,30 +277,14 @@ impl<'a> Parser<'a> {
244277     /// sequence of patterns until `)` is reached. 
245278     fn  skip_pat_list ( & mut  self )  -> PResult < ' a ,  ( ) >  { 
246279        while  !self . check ( & token:: CloseDelim ( token:: Paren ) )  { 
247-             self . parse_pat ( None ) ?; 
280+             self . parse_pat_no_top_alt ( None ) ?; 
248281            if  !self . eat ( & token:: Comma )  { 
249282                return  Ok ( ( ) ) ; 
250283            } 
251284        } 
252285        Ok ( ( ) ) 
253286    } 
254287
255-     /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. 
256-      /// See `parse_pat_with_or` for details on parsing or-patterns. 
257-      fn  parse_pat_with_or_inner ( & mut  self )  -> PResult < ' a ,  P < Pat > >  { 
258-         self . recover_leading_vert ( None ,  "only allowed in a top-level pattern" ) ; 
259-         self . parse_pat_with_or ( None ,  GateOr :: Yes ,  RecoverComma :: No ) 
260-     } 
261- 
262-     /// Recover if `|` or `||` is here. 
263-      /// The user is thinking that a leading `|` is allowed in this position. 
264-      fn  recover_leading_vert ( & mut  self ,  lo :  Option < Span > ,  ctx :  & str )  { 
265-         if  let  token:: BinOp ( token:: Or )  | token:: OrOr  = self . token . kind  { 
266-             self . ban_illegal_vert ( lo,  "leading" ,  ctx) ; 
267-             self . bump ( ) ; 
268-         } 
269-     } 
270- 
271288    /// A `|` or possibly `||` token shouldn't be here. Ban it. 
272289     fn  ban_illegal_vert ( & mut  self ,  lo :  Option < Span > ,  pos :  & str ,  ctx :  & str )  { 
273290        let  span = self . token . span ; 
@@ -305,8 +322,9 @@ impl<'a> Parser<'a> {
305322            self . parse_pat_tuple_or_parens ( ) ?
306323        }  else  if  self . check ( & token:: OpenDelim ( token:: Bracket ) )  { 
307324            // Parse `[pat, pat,...]` as a slice pattern. 
308-             let  ( pats,  _)  =
309-                 self . parse_delim_comma_seq ( token:: Bracket ,  |p| p. parse_pat_with_or_inner ( ) ) ?; 
325+             let  ( pats,  _)  = self . parse_delim_comma_seq ( token:: Bracket ,  |p| { 
326+                 p. parse_pat_allow_top_alt ( None ,  GateOr :: Yes ,  RecoverComma :: No ) 
327+             } ) ?; 
310328            PatKind :: Slice ( pats) 
311329        }  else  if  self . check ( & token:: DotDot )  && !self . is_pat_range_end_start ( 1 )  { 
312330            // A rest pattern `..`. 
@@ -429,7 +447,7 @@ impl<'a> Parser<'a> {
429447
430448        // At this point we attempt to parse `@ $pat_rhs` and emit an error. 
431449        self . bump ( ) ;  // `@` 
432-         let  mut  rhs = self . parse_pat ( None ) ?; 
450+         let  mut  rhs = self . parse_pat_no_top_alt ( None ) ?; 
433451        let  sp = lhs. span . to ( rhs. span ) ; 
434452
435453        if  let  PatKind :: Ident ( _,  _,  ref  mut  sub @ None )  = rhs. kind  { 
@@ -518,8 +536,9 @@ impl<'a> Parser<'a> {
518536
519537    /// Parse a tuple or parenthesis pattern. 
520538     fn  parse_pat_tuple_or_parens ( & mut  self )  -> PResult < ' a ,  PatKind >  { 
521-         let  ( fields,  trailing_comma)  =
522-             self . parse_paren_comma_seq ( |p| p. parse_pat_with_or_inner ( ) ) ?; 
539+         let  ( fields,  trailing_comma)  = self . parse_paren_comma_seq ( |p| { 
540+             p. parse_pat_allow_top_alt ( None ,  GateOr :: Yes ,  RecoverComma :: No ) 
541+         } ) ?; 
523542
524543        // Here, `(pat,)` is a tuple pattern. 
525544        // For backward compatibility, `(..)` is a tuple pattern as well. 
@@ -548,7 +567,7 @@ impl<'a> Parser<'a> {
548567        } 
549568
550569        // Parse the pattern we hope to be an identifier. 
551-         let  mut  pat = self . parse_pat ( Some ( "identifier" ) ) ?; 
570+         let  mut  pat = self . parse_pat_no_top_alt ( Some ( "identifier" ) ) ?; 
552571
553572        // If we don't have `mut $ident (@ pat)?`, error. 
554573        if  let  PatKind :: Ident ( BindingMode :: ByValue ( m @ Mutability :: Not ) ,  ..)  = & mut  pat. kind  { 
@@ -793,7 +812,7 @@ impl<'a> Parser<'a> {
793812     fn  parse_pat_ident ( & mut  self ,  binding_mode :  BindingMode )  -> PResult < ' a ,  PatKind >  { 
794813        let  ident = self . parse_ident ( ) ?; 
795814        let  sub = if  self . eat ( & token:: At )  { 
796-             Some ( self . parse_pat ( Some ( "binding pattern" ) ) ?) 
815+             Some ( self . parse_pat_no_top_alt ( Some ( "binding pattern" ) ) ?) 
797816        }  else  { 
798817            None 
799818        } ; 
@@ -832,7 +851,9 @@ impl<'a> Parser<'a> {
832851        if  qself. is_some ( )  { 
833852            return  self . error_qpath_before_pat ( & path,  "(" ) ; 
834853        } 
835-         let  ( fields,  _)  = self . parse_paren_comma_seq ( |p| p. parse_pat_with_or_inner ( ) ) ?; 
854+         let  ( fields,  _)  = self . parse_paren_comma_seq ( |p| { 
855+             p. parse_pat_allow_top_alt ( None ,  GateOr :: Yes ,  RecoverComma :: No ) 
856+         } ) ?; 
836857        Ok ( PatKind :: TupleStruct ( path,  fields) ) 
837858    } 
838859
@@ -998,7 +1019,7 @@ impl<'a> Parser<'a> {
9981019            // Parsing a pattern of the form `fieldname: pat`. 
9991020            let  fieldname = self . parse_field_name ( ) ?; 
10001021            self . bump ( ) ; 
1001-             let  pat = self . parse_pat_with_or_inner ( ) ?; 
1022+             let  pat = self . parse_pat_allow_top_alt ( None ,   GateOr :: Yes ,   RecoverComma :: No ) ?; 
10021023            hi = pat. span ; 
10031024            ( pat,  fieldname,  false ) 
10041025        }  else  { 
0 commit comments