@@ -269,13 +269,18 @@ impl<'a> Parser<'a> {
269
269
}
270
270
271
271
/// Emits an error with suggestions if an identifier was expected but not found.
272
- pub ( super ) fn expected_ident_found ( & mut self ) -> DiagnosticBuilder < ' a , ErrorGuaranteed > {
272
+ ///
273
+ /// Returns a possibly recovered identifier.
274
+ pub ( super ) fn expected_ident_found (
275
+ & mut self ,
276
+ recover : bool ,
277
+ ) -> PResult < ' a , ( Ident , /* is_raw */ bool ) > {
273
278
if let TokenKind :: DocComment ( ..) = self . prev_token . kind {
274
- return DocCommentDoesNotDocumentAnything {
279
+ return Err ( DocCommentDoesNotDocumentAnything {
275
280
span : self . prev_token . span ,
276
281
missing_comma : None ,
277
282
}
278
- . into_diagnostic ( & self . sess . span_diagnostic ) ;
283
+ . into_diagnostic ( & self . sess . span_diagnostic ) ) ;
279
284
}
280
285
281
286
let valid_follow = & [
@@ -290,34 +295,51 @@ impl<'a> Parser<'a> {
290
295
TokenKind :: CloseDelim ( Delimiter :: Parenthesis ) ,
291
296
] ;
292
297
293
- let suggest_raw = match self . token . ident ( ) {
294
- Some ( ( ident, false ) )
295
- if ident. is_raw_guess ( )
296
- && self . look_ahead ( 1 , |t| valid_follow. contains ( & t. kind ) ) =>
297
- {
298
- Some ( SuggEscapeIdentifier {
299
- span : ident. span . shrink_to_lo ( ) ,
300
- // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
301
- // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
302
- ident_name : ident. name . to_string ( ) ,
303
- } )
304
- }
305
- _ => None ,
306
- } ;
298
+ let mut recovered_ident = None ;
299
+ // we take this here so that the correct original token is retained in
300
+ // the diagnostic, regardless of eager recovery.
301
+ let bad_token = self . token . clone ( ) ;
302
+
303
+ // suggest prepending a keyword in identifier position with `r#`
304
+ let suggest_raw = if let Some ( ( ident, false ) ) = self . token . ident ( )
305
+ && ident. is_raw_guess ( )
306
+ && self . look_ahead ( 1 , |t| valid_follow. contains ( & t. kind ) )
307
+ {
308
+ recovered_ident = Some ( ( ident, true ) ) ;
309
+
310
+ // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
311
+ // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
312
+ let ident_name = ident. name . to_string ( ) ;
313
+
314
+ Some ( SuggEscapeIdentifier {
315
+ span : ident. span . shrink_to_lo ( ) ,
316
+ ident_name
317
+ } )
318
+ } else { None } ;
319
+
320
+ let suggest_remove_comma =
321
+ if self . token == token:: Comma && self . look_ahead ( 1 , |t| t. is_ident ( ) ) {
322
+ if recover {
323
+ self . bump ( ) ;
324
+ recovered_ident = self . ident_or_err ( false ) . ok ( ) ;
325
+ } ;
326
+
327
+ Some ( SuggRemoveComma { span : bad_token. span } )
328
+ } else {
329
+ None
330
+ } ;
307
331
308
- let suggest_remove_comma = ( self . token == token:: Comma
309
- && self . look_ahead ( 1 , |t| t. is_ident ( ) ) )
310
- . then_some ( SuggRemoveComma { span : self . token . span } ) ;
332
+ let help_cannot_start_number = self . is_lit_bad_ident ( ) . map ( |( len, valid_portion) | {
333
+ let ( invalid, valid) = self . token . span . split_at ( len as u32 ) ;
311
334
312
- let help_cannot_start_number = self . is_lit_bad_ident ( ) . map ( |( len, _valid_portion) | {
313
- let ( invalid, _valid) = self . token . span . split_at ( len as u32 ) ;
335
+ recovered_ident = Some ( ( Ident :: new ( valid_portion, valid) , false ) ) ;
314
336
315
337
HelpIdentifierStartsWithNumber { num_span : invalid }
316
338
} ) ;
317
339
318
340
let err = ExpectedIdentifier {
319
- span : self . token . span ,
320
- token : self . token . clone ( ) ,
341
+ span : bad_token . span ,
342
+ token : bad_token ,
321
343
suggest_raw,
322
344
suggest_remove_comma,
323
345
help_cannot_start_number,
@@ -326,6 +348,7 @@ impl<'a> Parser<'a> {
326
348
327
349
// if the token we have is a `<`
328
350
// it *might* be a misplaced generic
351
+ // FIXME: could we recover with this?
329
352
if self . token == token:: Lt {
330
353
// all keywords that could have generic applied
331
354
let valid_prev_keywords =
@@ -376,7 +399,16 @@ impl<'a> Parser<'a> {
376
399
}
377
400
}
378
401
379
- err
402
+ if let Some ( recovered_ident) = recovered_ident && recover {
403
+ err. emit ( ) ;
404
+ Ok ( recovered_ident)
405
+ } else {
406
+ Err ( err)
407
+ }
408
+ }
409
+
410
+ pub ( super ) fn expected_ident_found_err ( & mut self ) -> DiagnosticBuilder < ' a , ErrorGuaranteed > {
411
+ self . expected_ident_found ( false ) . unwrap_err ( )
380
412
}
381
413
382
414
/// Checks if the current token is a integer or float literal and looks like
@@ -392,7 +424,7 @@ impl<'a> Parser<'a> {
392
424
kind : token:: LitKind :: Integer | token:: LitKind :: Float ,
393
425
symbol,
394
426
suffix,
395
- } ) = self . token . uninterpolate ( ) . kind
427
+ } ) = self . token . kind
396
428
&& rustc_ast:: MetaItemLit :: from_token ( & self . token ) . is_none ( )
397
429
{
398
430
Some ( ( symbol. as_str ( ) . len ( ) , suffix. unwrap ( ) ) )
0 commit comments