1+ use super :: pat:: Expected ;
12use 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+ } ;
47
58use rustc_ast as ast;
69use rustc_ast:: ptr:: P ;
@@ -19,6 +22,8 @@ use rustc_span::source_map::Spanned;
1922use rustc_span:: symbol:: { kw, Ident } ;
2023use rustc_span:: { MultiSpan , Span , SpanSnippetError , DUMMY_SP } ;
2124
25+ use std:: mem:: take;
26+
2227use tracing:: { debug, trace} ;
2328
2429const TURBOFISH_SUGGESTION_STR : & str =
@@ -2075,4 +2080,177 @@ impl<'a> Parser<'a> {
20752080 ) ;
20762081 err
20772082 }
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+ }
20782256}
0 commit comments