1
1
use super :: { Parser , PathStyle , TokenType } ;
2
2
3
+ use crate :: errors:: { FnPtrWithGenerics , FnPtrWithGenericsSugg } ;
3
4
use crate :: { maybe_recover_from_interpolated_ty_qpath, maybe_whole} ;
4
5
5
6
use rustc_ast:: ptr:: P ;
@@ -270,14 +271,19 @@ impl<'a> Parser<'a> {
270
271
TyKind :: Infer
271
272
} else if self . check_fn_front_matter ( false , Case :: Sensitive ) {
272
273
// Function pointer type
273
- self . parse_ty_bare_fn ( lo, Vec :: new ( ) , recover_return_sign) ?
274
+ self . parse_ty_bare_fn ( lo, Vec :: new ( ) , None , recover_return_sign) ?
274
275
} else if self . check_keyword ( kw:: For ) {
275
276
// Function pointer type or bound list (trait object type) starting with a poly-trait.
276
277
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
277
278
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
278
279
let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
279
280
if self . check_fn_front_matter ( false , Case :: Sensitive ) {
280
- self . parse_ty_bare_fn ( lo, lifetime_defs, recover_return_sign) ?
281
+ self . parse_ty_bare_fn (
282
+ lo,
283
+ lifetime_defs,
284
+ Some ( self . prev_token . span . shrink_to_lo ( ) ) ,
285
+ recover_return_sign,
286
+ ) ?
281
287
} else {
282
288
let path = self . parse_path ( PathStyle :: Type ) ?;
283
289
let parse_plus = allow_plus == AllowPlus :: Yes && self . check_plus ( ) ;
@@ -519,7 +525,8 @@ impl<'a> Parser<'a> {
519
525
fn parse_ty_bare_fn (
520
526
& mut self ,
521
527
lo : Span ,
522
- params : Vec < GenericParam > ,
528
+ mut params : Vec < GenericParam > ,
529
+ param_insertion_point : Option < Span > ,
523
530
recover_return_sign : RecoverReturnSign ,
524
531
) -> PResult < ' a , TyKind > {
525
532
let inherited_vis = rustc_ast:: Visibility {
@@ -530,6 +537,9 @@ impl<'a> Parser<'a> {
530
537
let span_start = self . token . span ;
531
538
let ast:: FnHeader { ext, unsafety, constness, asyncness } =
532
539
self . parse_fn_front_matter ( & inherited_vis) ?;
540
+ if self . may_recover ( ) && self . token . kind == TokenKind :: Lt {
541
+ self . recover_fn_ptr_with_generics ( lo, & mut params, param_insertion_point) ?;
542
+ }
533
543
let decl = self . parse_fn_decl ( |_| false , AllowPlus :: No , recover_return_sign) ?;
534
544
let whole_span = lo. to ( self . prev_token . span ) ;
535
545
if let ast:: Const :: Yes ( span) = constness {
@@ -545,6 +555,48 @@ impl<'a> Parser<'a> {
545
555
Ok ( TyKind :: BareFn ( P ( BareFnTy { ext, unsafety, generic_params : params, decl, decl_span } ) ) )
546
556
}
547
557
558
+ /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`).
559
+ fn recover_fn_ptr_with_generics (
560
+ & mut self ,
561
+ lo : Span ,
562
+ params : & mut Vec < GenericParam > ,
563
+ param_insertion_point : Option < Span > ,
564
+ ) -> PResult < ' a , ( ) > {
565
+ let generics = self . parse_generics ( ) ?;
566
+ let arity = generics. params . len ( ) ;
567
+
568
+ let mut lifetimes: Vec < _ > = generics
569
+ . params
570
+ . into_iter ( )
571
+ . filter ( |param| matches ! ( param. kind, ast:: GenericParamKind :: Lifetime ) )
572
+ . collect ( ) ;
573
+
574
+ let sugg = if !lifetimes. is_empty ( ) {
575
+ let snippet =
576
+ lifetimes. iter ( ) . map ( |param| param. ident . as_str ( ) ) . intersperse ( ", " ) . collect ( ) ;
577
+
578
+ let ( left, snippet) = if let Some ( span) = param_insertion_point {
579
+ ( span, if params. is_empty ( ) { snippet } else { format ! ( ", {snippet}" ) } )
580
+ } else {
581
+ ( lo. shrink_to_lo ( ) , format ! ( "for<{snippet}> " ) )
582
+ } ;
583
+
584
+ Some ( FnPtrWithGenericsSugg {
585
+ left,
586
+ snippet,
587
+ right : generics. span ,
588
+ arity,
589
+ for_param_list_exists : param_insertion_point. is_some ( ) ,
590
+ } )
591
+ } else {
592
+ None
593
+ } ;
594
+
595
+ self . sess . emit_err ( FnPtrWithGenerics { span : generics. span , sugg } ) ;
596
+ params. append ( & mut lifetimes) ;
597
+ Ok ( ( ) )
598
+ }
599
+
548
600
/// Emit an error for the given bad function pointer qualifier.
549
601
fn error_fn_ptr_bad_qualifier ( & self , span : Span , qual_span : Span , qual : & str ) {
550
602
self . struct_span_err ( span, & format ! ( "an `fn` pointer type cannot be `{}`" , qual) )
0 commit comments