@@ -933,15 +933,20 @@ impl<'a> Parser<'a> {
933933 has_parens : bool ,
934934 modifiers : BoundModifiers ,
935935 ) -> PResult < ' a , GenericBound > {
936- let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
937- let path = if self . token . is_keyword ( kw:: Fn )
936+ let mut lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
937+ let mut path = if self . token . is_keyword ( kw:: Fn )
938938 && self . look_ahead ( 1 , |tok| tok. kind == TokenKind :: OpenDelim ( Delimiter :: Parenthesis ) )
939939 && let Some ( path) = self . recover_path_from_fn ( )
940940 {
941941 path
942942 } else {
943943 self . parse_path ( PathStyle :: Type ) ?
944944 } ;
945+
946+ if self . may_recover ( ) && self . token == TokenKind :: OpenDelim ( Delimiter :: Parenthesis ) {
947+ self . recover_fn_trait_with_lifetime_params ( & mut path, & mut lifetime_defs) ?;
948+ }
949+
945950 if has_parens {
946951 if self . token . is_like_plus ( ) {
947952 // Someone has written something like `&dyn (Trait + Other)`. The correct code
@@ -1016,6 +1021,92 @@ impl<'a> Parser<'a> {
10161021 }
10171022 }
10181023
1024+ /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments
1025+ /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already
1026+ /// been eaten.
1027+ fn recover_fn_trait_with_lifetime_params (
1028+ & mut self ,
1029+ fn_path : & mut ast:: Path ,
1030+ lifetime_defs : & mut Vec < GenericParam > ,
1031+ ) -> PResult < ' a , ( ) > {
1032+ let fn_path_segment = fn_path. segments . last_mut ( ) . unwrap ( ) ;
1033+ let generic_args = if let Some ( p_args) = & fn_path_segment. args {
1034+ p_args. clone ( ) . into_inner ( )
1035+ } else {
1036+ // Normally it wouldn't come here because the upstream should have parsed
1037+ // generic parameters (otherwise it's impossible to call this function).
1038+ return Ok ( ( ) ) ;
1039+ } ;
1040+ let lifetimes =
1041+ if let ast:: GenericArgs :: AngleBracketed ( ast:: AngleBracketedArgs { span : _, args } ) =
1042+ & generic_args
1043+ {
1044+ args. into_iter ( )
1045+ . filter_map ( |arg| {
1046+ if let ast:: AngleBracketedArg :: Arg ( generic_arg) = arg
1047+ && let ast:: GenericArg :: Lifetime ( lifetime) = generic_arg {
1048+ Some ( lifetime)
1049+ } else {
1050+ None
1051+ }
1052+ } )
1053+ . collect ( )
1054+ } else {
1055+ Vec :: new ( )
1056+ } ;
1057+ // Only try to recover if the trait has lifetime params.
1058+ if lifetimes. is_empty ( ) {
1059+ return Ok ( ( ) ) ;
1060+ }
1061+
1062+ // Parse `(T, U) -> R`.
1063+ let inputs_lo = self . token . span ;
1064+ let inputs: Vec < _ > =
1065+ self . parse_fn_params ( |_| false ) ?. into_iter ( ) . map ( |input| input. ty ) . collect ( ) ;
1066+ let inputs_span = inputs_lo. to ( self . prev_token . span ) ;
1067+ let output = self . parse_ret_ty ( AllowPlus :: No , RecoverQPath :: No , RecoverReturnSign :: No ) ?;
1068+ let args = ast:: ParenthesizedArgs {
1069+ span : fn_path_segment. span ( ) . to ( self . prev_token . span ) ,
1070+ inputs,
1071+ inputs_span,
1072+ output,
1073+ }
1074+ . into ( ) ;
1075+ * fn_path_segment =
1076+ ast:: PathSegment { ident : fn_path_segment. ident , args, id : ast:: DUMMY_NODE_ID } ;
1077+
1078+ // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`.
1079+ let mut generic_params = lifetimes
1080+ . iter ( )
1081+ . map ( |lt| GenericParam {
1082+ id : lt. id ,
1083+ ident : lt. ident ,
1084+ attrs : ast:: AttrVec :: new ( ) ,
1085+ bounds : Vec :: new ( ) ,
1086+ is_placeholder : false ,
1087+ kind : ast:: GenericParamKind :: Lifetime ,
1088+ colon_span : None ,
1089+ } )
1090+ . collect :: < Vec < GenericParam > > ( ) ;
1091+ lifetime_defs. append ( & mut generic_params) ;
1092+
1093+ let generic_args_span = generic_args. span ( ) ;
1094+ let mut err =
1095+ self . struct_span_err ( generic_args_span, "`Fn` traits cannot take lifetime parameters" ) ;
1096+ let snippet = format ! (
1097+ "for<{}> " ,
1098+ lifetimes. iter( ) . map( |lt| lt. ident. as_str( ) ) . intersperse( ", " ) . collect:: <String >( ) ,
1099+ ) ;
1100+ let before_fn_path = fn_path. span . shrink_to_lo ( ) ;
1101+ err. multipart_suggestion (
1102+ "consider using a higher-ranked trait bound instead" ,
1103+ vec ! [ ( generic_args_span, "" . to_owned( ) ) , ( before_fn_path, snippet) ] ,
1104+ Applicability :: MaybeIncorrect ,
1105+ )
1106+ . emit ( ) ;
1107+ Ok ( ( ) )
1108+ }
1109+
10191110 pub ( super ) fn check_lifetime ( & mut self ) -> bool {
10201111 self . expected_tokens . push ( TokenType :: Lifetime ) ;
10211112 self . token . is_lifetime ( )
0 commit comments