@@ -269,13 +269,18 @@ impl<'a> Parser<'a> {
269269 }
270270
271271 /// 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 ) > {
273278 if let TokenKind :: DocComment ( ..) = self . prev_token . kind {
274- return DocCommentDoesNotDocumentAnything {
279+ return Err ( DocCommentDoesNotDocumentAnything {
275280 span : self . prev_token . span ,
276281 missing_comma : None ,
277282 }
278- . into_diagnostic ( & self . sess . span_diagnostic ) ;
283+ . into_diagnostic ( & self . sess . span_diagnostic ) ) ;
279284 }
280285
281286 let valid_follow = & [
@@ -290,34 +295,51 @@ impl<'a> Parser<'a> {
290295 TokenKind :: CloseDelim ( Delimiter :: Parenthesis ) ,
291296 ] ;
292297
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+ } ;
307331
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 ) ;
311334
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 ) ) ;
314336
315337 HelpIdentifierStartsWithNumber { num_span : invalid }
316338 } ) ;
317339
318340 let err = ExpectedIdentifier {
319- span : self . token . span ,
320- token : self . token . clone ( ) ,
341+ span : bad_token . span ,
342+ token : bad_token ,
321343 suggest_raw,
322344 suggest_remove_comma,
323345 help_cannot_start_number,
@@ -326,6 +348,7 @@ impl<'a> Parser<'a> {
326348
327349 // if the token we have is a `<`
328350 // it *might* be a misplaced generic
351+ // FIXME: could we recover with this?
329352 if self . token == token:: Lt {
330353 // all keywords that could have generic applied
331354 let valid_prev_keywords =
@@ -376,7 +399,16 @@ impl<'a> Parser<'a> {
376399 }
377400 }
378401
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 ( )
380412 }
381413
382414 /// Checks if the current token is a integer or float literal and looks like
@@ -392,7 +424,7 @@ impl<'a> Parser<'a> {
392424 kind : token:: LitKind :: Integer | token:: LitKind :: Float ,
393425 symbol,
394426 suffix,
395- } ) = self . token . uninterpolate ( ) . kind
427+ } ) = self . token . kind
396428 && rustc_ast:: MetaItemLit :: from_token ( & self . token ) . is_none ( )
397429 {
398430 Some ( ( symbol. as_str ( ) . len ( ) , suffix. unwrap ( ) ) )
0 commit comments