@@ -156,6 +156,52 @@ impl AttemptLocalParseRecovery {
156156 }
157157}
158158
159+ #[ derive( Debug , Copy , Clone ) ]
160+ struct IncDecRecovery {
161+ standalone : bool ,
162+ op : IncOrDec ,
163+ fixity : UnaryFixity ,
164+ }
165+
166+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
167+ enum IncOrDec {
168+ Inc ,
169+ // FIXME: `i--` recovery isn't implemented yet
170+ #[ allow( dead_code) ]
171+ Dec ,
172+ }
173+
174+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
175+ enum UnaryFixity {
176+ Pre ,
177+ Post ,
178+ }
179+
180+ impl IncOrDec {
181+ fn chr ( & self ) -> char {
182+ match self {
183+ Self :: Inc => '+' ,
184+ Self :: Dec => '-' ,
185+ }
186+ }
187+
188+ fn name ( & self ) -> & ' static str {
189+ match self {
190+ Self :: Inc => "increment" ,
191+ Self :: Dec => "decrement" ,
192+ }
193+ }
194+ }
195+
196+ impl std:: fmt:: Display for UnaryFixity {
197+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
198+ match self {
199+ Self :: Pre => write ! ( f, "prefix" ) ,
200+ Self :: Post => write ! ( f, "postfix" ) ,
201+ }
202+ }
203+ }
204+
159205// SnapshotParser is used to create a snapshot of the parser
160206// without causing duplicate errors being emitted when the `Parser`
161207// is dropped.
@@ -1167,6 +1213,145 @@ impl<'a> Parser<'a> {
11671213 Ok ( ( ) )
11681214 }
11691215
1216+ pub ( super ) fn maybe_recover_from_prefix_increment (
1217+ & mut self ,
1218+ operand_expr : P < Expr > ,
1219+ op_span : Span ,
1220+ prev_is_semi : bool ,
1221+ ) -> PResult < ' a , P < Expr > > {
1222+ let kind = IncDecRecovery {
1223+ standalone : prev_is_semi,
1224+ op : IncOrDec :: Inc ,
1225+ fixity : UnaryFixity :: Pre ,
1226+ } ;
1227+
1228+ self . recover_from_inc_dec ( operand_expr, kind, op_span)
1229+ }
1230+
1231+ pub ( super ) fn maybe_recover_from_postfix_increment (
1232+ & mut self ,
1233+ operand_expr : P < Expr > ,
1234+ op_span : Span ,
1235+ prev_is_semi : bool ,
1236+ ) -> PResult < ' a , P < Expr > > {
1237+ let kind = IncDecRecovery {
1238+ standalone : prev_is_semi,
1239+ op : IncOrDec :: Inc ,
1240+ fixity : UnaryFixity :: Post ,
1241+ } ;
1242+
1243+ self . recover_from_inc_dec ( operand_expr, kind, op_span)
1244+ }
1245+
1246+ fn recover_from_inc_dec (
1247+ & mut self ,
1248+ base : P < Expr > ,
1249+ kind : IncDecRecovery ,
1250+ op_span : Span ,
1251+ ) -> PResult < ' a , P < Expr > > {
1252+ let mut err = self . struct_span_err (
1253+ op_span,
1254+ & format ! ( "Rust has no {} {} operator" , kind. fixity, kind. op. name( ) ) ,
1255+ ) ;
1256+ err. span_label ( op_span, & format ! ( "not a valid {} operator" , kind. fixity) ) ;
1257+
1258+ if let ExprKind :: Path ( _, path) = & base. kind {
1259+ if let [ segment] = path. segments . as_slice ( ) {
1260+ let ident = segment. ident ;
1261+ // (pre, post)
1262+ let spans = match kind. fixity {
1263+ UnaryFixity :: Pre => ( op_span, ident. span . shrink_to_hi ( ) ) ,
1264+ UnaryFixity :: Post => ( ident. span . shrink_to_lo ( ) , op_span) ,
1265+ } ;
1266+
1267+ if !ident. is_reserved ( ) {
1268+ if kind. standalone {
1269+ return self . inc_dec_standalone_recovery ( base, err, kind, ident, spans) ;
1270+ } else {
1271+ match kind. fixity {
1272+ UnaryFixity :: Pre => {
1273+ return self . prefix_inc_dec_suggest_and_recover (
1274+ base, err, kind, ident, spans,
1275+ ) ;
1276+ }
1277+ UnaryFixity :: Post => {
1278+ return self . postfix_inc_dec_suggest_and_recover (
1279+ base, err, kind, ident, spans,
1280+ ) ;
1281+ }
1282+ }
1283+ }
1284+ }
1285+ }
1286+ }
1287+
1288+ // base case
1289+ err. help ( & format ! ( "use `{}= 1` instead" , kind. op. chr( ) ) ) ;
1290+ err. emit ( ) ;
1291+
1292+ Ok ( base)
1293+ }
1294+
1295+ fn prefix_inc_dec_suggest_and_recover (
1296+ & mut self ,
1297+ base : P < Expr > ,
1298+ mut err : DiagnosticBuilder < ' _ > ,
1299+ kind : IncDecRecovery ,
1300+ ident : Ident ,
1301+ ( pre_span, post_span) : ( Span , Span ) ,
1302+ ) -> PResult < ' a , P < Expr > > {
1303+ err. multipart_suggestion (
1304+ & format ! ( "use `{}= 1` instead" , kind. op. chr( ) ) ,
1305+ vec ! [
1306+ ( pre_span, "{ " . to_string( ) ) ,
1307+ ( post_span, format!( " {}= 1; {} }}" , kind. op. chr( ) , ident) ) ,
1308+ ] ,
1309+ Applicability :: MachineApplicable ,
1310+ ) ;
1311+ err. emit ( ) ;
1312+ // TODO: recover
1313+ Ok ( base)
1314+ }
1315+
1316+ fn postfix_inc_dec_suggest_and_recover (
1317+ & mut self ,
1318+ base : P < Expr > ,
1319+ mut err : DiagnosticBuilder < ' _ > ,
1320+ kind : IncDecRecovery ,
1321+ ident : Ident ,
1322+ ( pre_span, post_span) : ( Span , Span ) ,
1323+ ) -> PResult < ' a , P < Expr > > {
1324+ err. multipart_suggestion (
1325+ & format ! ( "use `{}= 1` instead" , kind. op. chr( ) ) ,
1326+ vec ! [
1327+ ( pre_span, "{ let tmp = " . to_string( ) ) ,
1328+ ( post_span, format!( "; {} {}= 1; tmp }}" , ident, kind. op. chr( ) ) ) ,
1329+ ] ,
1330+ Applicability :: MachineApplicable ,
1331+ ) ;
1332+ err. emit ( ) ;
1333+ // TODO: recover
1334+ Ok ( base)
1335+ }
1336+
1337+ fn inc_dec_standalone_recovery (
1338+ & mut self ,
1339+ base : P < Expr > ,
1340+ mut err : DiagnosticBuilder < ' _ > ,
1341+ kind : IncDecRecovery ,
1342+ _ident : Ident ,
1343+ ( pre_span, post_span) : ( Span , Span ) ,
1344+ ) -> PResult < ' a , P < Expr > > {
1345+ err. multipart_suggestion (
1346+ & format ! ( "use `{}= 1` instead" , kind. op. chr( ) ) ,
1347+ vec ! [ ( pre_span, String :: new( ) ) , ( post_span, format!( " {}= 1" , kind. op. chr( ) ) ) ] ,
1348+ Applicability :: MachineApplicable ,
1349+ ) ;
1350+ err. emit ( ) ;
1351+ // TODO: recover
1352+ Ok ( base)
1353+ }
1354+
11701355 /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`.
11711356 /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem`
11721357 /// tail, and combines them into a `<Ty>::AssocItem` expression/pattern/type.
@@ -1882,49 +2067,6 @@ impl<'a> Parser<'a> {
18822067 self . sess . expr_parentheses_needed ( & mut err, * sp) ;
18832068 }
18842069 err. span_label ( span, "expected expression" ) ;
1885- if self . prev_token . kind == TokenKind :: BinOp ( token:: Plus )
1886- && self . token . kind == TokenKind :: BinOp ( token:: Plus )
1887- && self . look_ahead ( 1 , |t| !t. is_lit ( ) )
1888- {
1889- let span = self . prev_token . span . to ( self . token . span ) ;
1890- err. note ( "Rust has no dedicated increment operator" ) ;
1891- err. span_suggestion_verbose (
1892- span,
1893- "try using `+= 1` instead" ,
1894- " += 1" . into ( ) ,
1895- Applicability :: Unspecified ,
1896- ) ;
1897- } else if self . token . kind == TokenKind :: BinOp ( token:: Plus )
1898- && self . look_ahead ( 1 , |t| t. kind == TokenKind :: BinOp ( token:: Plus ) )
1899- && self . look_ahead ( 2 , |t| !t. is_lit ( ) )
1900- {
1901- let target_span = self . look_ahead ( 2 , |t| t. span ) ;
1902- let left_brace_span = target_span. shrink_to_lo ( ) ;
1903- let pre_span = self . token . span . to ( self . look_ahead ( 1 , |t| t. span ) ) ;
1904- let post_span = target_span. shrink_to_hi ( ) ;
1905-
1906- err. note ( "Rust has no dedicated increment operator" ) ;
1907-
1908- if self . prev_token . kind == TokenKind :: Semi {
1909- err. multipart_suggestion (
1910- "try using `+= 1` instead" ,
1911- vec ! [ ( pre_span, String :: new( ) ) , ( post_span, " += 1" . into( ) ) ] ,
1912- Applicability :: MachineApplicable ,
1913- ) ;
1914- } else if let Ok ( target_snippet) = self . span_to_snippet ( target_span) {
1915- err. multipart_suggestion (
1916- "try using `+= 1` instead" ,
1917- vec ! [
1918- ( left_brace_span, "{ " . to_string( ) ) ,
1919- ( pre_span, String :: new( ) ) ,
1920- ( post_span, format!( " += 1; {} }}" , target_snippet) ) ,
1921- ] ,
1922- Applicability :: MachineApplicable ,
1923- ) ;
1924- } else {
1925- err. span_help ( pre_span. to ( target_span) , "try using `+= 1` instead" ) ;
1926- }
1927- }
19282070 err
19292071 }
19302072
0 commit comments