1
+ use super :: pat:: Expected ;
1
2
use super :: ty:: AllowPlus ;
2
- use super :: TokenType ;
3
- use super :: { BlockMode , Parser , PathStyle , Restrictions , SemiColonMode , SeqSep , TokenExpectType } ;
3
+ use super :: {
4
+ BlockMode , Parser , PathStyle , RecoverColon , RecoverComma , Restrictions , SemiColonMode , SeqSep ,
5
+ TokenExpectType , TokenType ,
6
+ } ;
4
7
5
8
use rustc_ast as ast;
6
9
use rustc_ast:: ptr:: P ;
@@ -19,6 +22,8 @@ use rustc_span::source_map::Spanned;
19
22
use rustc_span:: symbol:: { kw, Ident } ;
20
23
use rustc_span:: { MultiSpan , Span , SpanSnippetError , DUMMY_SP } ;
21
24
25
+ use std:: mem:: take;
26
+
22
27
use tracing:: { debug, trace} ;
23
28
24
29
const TURBOFISH_SUGGESTION_STR : & str =
@@ -2075,4 +2080,177 @@ impl<'a> Parser<'a> {
2075
2080
) ;
2076
2081
err
2077
2082
}
2083
+
2084
+ /// Some special error handling for the "top-level" patterns in a match arm,
2085
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
2086
+ crate fn maybe_recover_colon_colon_in_pat_typo (
2087
+ & mut self ,
2088
+ mut first_pat : P < Pat > ,
2089
+ ra : RecoverColon ,
2090
+ expected : Expected ,
2091
+ ) -> P < Pat > {
2092
+ if RecoverColon :: Yes != ra || token:: Colon != self . token . kind {
2093
+ return first_pat;
2094
+ }
2095
+ if !matches ! ( first_pat. kind, PatKind :: Ident ( _, _, None ) | PatKind :: Path ( ..) )
2096
+ || !self . look_ahead ( 1 , |token| token. is_ident ( ) && !token. is_reserved_ident ( ) )
2097
+ {
2098
+ return first_pat;
2099
+ }
2100
+ // The pattern looks like it might be a path with a `::` -> `:` typo:
2101
+ // `match foo { bar:baz => {} }`
2102
+ let span = self . token . span ;
2103
+ // We only emit "unexpected `:`" error here if we can successfully parse the
2104
+ // whole pattern correctly in that case.
2105
+ let snapshot = self . clone ( ) ;
2106
+
2107
+ // Create error for "unexpected `:`".
2108
+ match self . expected_one_of_not_found ( & [ ] , & [ ] ) {
2109
+ Err ( mut err) => {
2110
+ self . bump ( ) ; // Skip the `:`.
2111
+ match self . parse_pat_no_top_alt ( expected) {
2112
+ Err ( mut inner_err) => {
2113
+ // Carry on as if we had not done anything, callers will emit a
2114
+ // reasonable error.
2115
+ inner_err. cancel ( ) ;
2116
+ err. cancel ( ) ;
2117
+ * self = snapshot;
2118
+ }
2119
+ Ok ( mut pat) => {
2120
+ // We've parsed the rest of the pattern.
2121
+ let new_span = first_pat. span . to ( pat. span ) ;
2122
+ let mut show_sugg = false ;
2123
+ // Try to construct a recovered pattern.
2124
+ match & mut pat. kind {
2125
+ PatKind :: Struct ( qself @ None , path, ..)
2126
+ | PatKind :: TupleStruct ( qself @ None , path, _)
2127
+ | PatKind :: Path ( qself @ None , path) => match & first_pat. kind {
2128
+ PatKind :: Ident ( _, ident, _) => {
2129
+ path. segments . insert ( 0 , PathSegment :: from_ident ( ident. clone ( ) ) ) ;
2130
+ path. span = new_span;
2131
+ show_sugg = true ;
2132
+ first_pat = pat;
2133
+ }
2134
+ PatKind :: Path ( old_qself, old_path) => {
2135
+ path. segments = old_path
2136
+ . segments
2137
+ . iter ( )
2138
+ . cloned ( )
2139
+ . chain ( take ( & mut path. segments ) )
2140
+ . collect ( ) ;
2141
+ path. span = new_span;
2142
+ * qself = old_qself. clone ( ) ;
2143
+ first_pat = pat;
2144
+ show_sugg = true ;
2145
+ }
2146
+ _ => { }
2147
+ } ,
2148
+ PatKind :: Ident ( BindingMode :: ByValue ( Mutability :: Not ) , ident, None ) => {
2149
+ match & first_pat. kind {
2150
+ PatKind :: Ident ( _, old_ident, _) => {
2151
+ let path = PatKind :: Path (
2152
+ None ,
2153
+ Path {
2154
+ span : new_span,
2155
+ segments : vec ! [
2156
+ PathSegment :: from_ident( old_ident. clone( ) ) ,
2157
+ PathSegment :: from_ident( ident. clone( ) ) ,
2158
+ ] ,
2159
+ tokens : None ,
2160
+ } ,
2161
+ ) ;
2162
+ first_pat = self . mk_pat ( new_span, path) ;
2163
+ show_sugg = true ;
2164
+ }
2165
+ PatKind :: Path ( old_qself, old_path) => {
2166
+ let mut segments = old_path. segments . clone ( ) ;
2167
+ segments. push ( PathSegment :: from_ident ( ident. clone ( ) ) ) ;
2168
+ let path = PatKind :: Path (
2169
+ old_qself. clone ( ) ,
2170
+ Path { span : new_span, segments, tokens : None } ,
2171
+ ) ;
2172
+ first_pat = self . mk_pat ( new_span, path) ;
2173
+ show_sugg = true ;
2174
+ }
2175
+ _ => { }
2176
+ }
2177
+ }
2178
+ _ => { }
2179
+ }
2180
+ if show_sugg {
2181
+ err. span_suggestion (
2182
+ span,
2183
+ "maybe write a path separator here" ,
2184
+ "::" . to_string ( ) ,
2185
+ Applicability :: MaybeIncorrect ,
2186
+ ) ;
2187
+ } else {
2188
+ first_pat = self . mk_pat ( new_span, PatKind :: Wild ) ;
2189
+ }
2190
+ err. emit ( ) ;
2191
+ }
2192
+ }
2193
+ }
2194
+ _ => {
2195
+ // Carry on as if we had not done anything. This should be unreachable.
2196
+ * self = snapshot;
2197
+ }
2198
+ } ;
2199
+ first_pat
2200
+ }
2201
+
2202
+ /// Some special error handling for the "top-level" patterns in a match arm,
2203
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
2204
+ crate fn maybe_recover_unexpected_comma (
2205
+ & mut self ,
2206
+ lo : Span ,
2207
+ rc : RecoverComma ,
2208
+ ) -> PResult < ' a , ( ) > {
2209
+ if rc == RecoverComma :: No || self . token != token:: Comma {
2210
+ return Ok ( ( ) ) ;
2211
+ }
2212
+
2213
+ // An unexpected comma after a top-level pattern is a clue that the
2214
+ // user (perhaps more accustomed to some other language) forgot the
2215
+ // parentheses in what should have been a tuple pattern; return a
2216
+ // suggestion-enhanced error here rather than choking on the comma later.
2217
+ let comma_span = self . token . span ;
2218
+ self . bump ( ) ;
2219
+ if let Err ( mut err) = self . skip_pat_list ( ) {
2220
+ // We didn't expect this to work anyway; we just wanted to advance to the
2221
+ // end of the comma-sequence so we know the span to suggest parenthesizing.
2222
+ err. cancel ( ) ;
2223
+ }
2224
+ let seq_span = lo. to ( self . prev_token . span ) ;
2225
+ let mut err = self . struct_span_err ( comma_span, "unexpected `,` in pattern" ) ;
2226
+ if let Ok ( seq_snippet) = self . span_to_snippet ( seq_span) {
2227
+ const MSG : & str = "try adding parentheses to match on a tuple..." ;
2228
+
2229
+ err. span_suggestion (
2230
+ seq_span,
2231
+ MSG ,
2232
+ format ! ( "({})" , seq_snippet) ,
2233
+ Applicability :: MachineApplicable ,
2234
+ ) ;
2235
+ err. span_suggestion (
2236
+ seq_span,
2237
+ "...or a vertical bar to match on multiple alternatives" ,
2238
+ seq_snippet. replace ( "," , " |" ) ,
2239
+ Applicability :: MachineApplicable ,
2240
+ ) ;
2241
+ }
2242
+ Err ( err)
2243
+ }
2244
+
2245
+ /// Parse and throw away a parenthesized comma separated
2246
+ /// sequence of patterns until `)` is reached.
2247
+ fn skip_pat_list ( & mut self ) -> PResult < ' a , ( ) > {
2248
+ while !self . check ( & token:: CloseDelim ( token:: Paren ) ) {
2249
+ self . parse_pat_no_top_alt ( None ) ?;
2250
+ if !self . eat ( & token:: Comma ) {
2251
+ return Ok ( ( ) ) ;
2252
+ }
2253
+ }
2254
+ Ok ( ( ) )
2255
+ }
2078
2256
}
0 commit comments