@@ -933,15 +933,20 @@ impl<'a> Parser<'a> {
933
933
has_parens : bool ,
934
934
modifiers : BoundModifiers ,
935
935
) -> 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 )
938
938
&& self . look_ahead ( 1 , |tok| tok. kind == TokenKind :: OpenDelim ( Delimiter :: Parenthesis ) )
939
939
&& let Some ( path) = self . recover_path_from_fn ( )
940
940
{
941
941
path
942
942
} else {
943
943
self . parse_path ( PathStyle :: Type ) ?
944
944
} ;
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
+
945
950
if has_parens {
946
951
if self . token . is_like_plus ( ) {
947
952
// Someone has written something like `&dyn (Trait + Other)`. The correct code
@@ -1016,6 +1021,92 @@ impl<'a> Parser<'a> {
1016
1021
}
1017
1022
}
1018
1023
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
+
1019
1110
pub ( super ) fn check_lifetime ( & mut self ) -> bool {
1020
1111
self . expected_tokens . push ( TokenType :: Lifetime ) ;
1021
1112
self . token . is_lifetime ( )
0 commit comments