@@ -2332,10 +2332,20 @@ impl<'a> Parser<'a> {
2332
2332
}
2333
2333
}
2334
2334
} ;
2335
+
2336
+ // Store the end of function parameters to give better diagnostics
2337
+ // inside `parse_fn_body()`.
2338
+ let fn_params_end = self . prev_token . span . shrink_to_hi ( ) ;
2339
+
2335
2340
generics. where_clause = self . parse_where_clause ( ) ?; // `where T: Ord`
2336
2341
2342
+ // `fn_params_end` is needed only when it's followed by a where clause.
2343
+ let fn_params_end =
2344
+ if generics. where_clause . has_where_token { Some ( fn_params_end) } else { None } ;
2345
+
2337
2346
let mut sig_hi = self . prev_token . span ;
2338
- let body = self . parse_fn_body ( attrs, & ident, & mut sig_hi, fn_parse_mode. req_body ) ?; // `;` or `{ ... }`.
2347
+ let body =
2348
+ self . parse_fn_body ( attrs, & ident, & mut sig_hi, fn_parse_mode. req_body , fn_params_end) ?; // `;` or `{ ... }`.
2339
2349
let fn_sig_span = sig_lo. to ( sig_hi) ;
2340
2350
Ok ( ( ident, FnSig { header, decl, span : fn_sig_span } , generics, body) )
2341
2351
}
@@ -2349,6 +2359,7 @@ impl<'a> Parser<'a> {
2349
2359
ident : & Ident ,
2350
2360
sig_hi : & mut Span ,
2351
2361
req_body : bool ,
2362
+ fn_params_end : Option < Span > ,
2352
2363
) -> PResult < ' a , Option < P < Block > > > {
2353
2364
let has_semi = if req_body {
2354
2365
self . token . kind == TokenKind :: Semi
@@ -2388,20 +2399,58 @@ impl<'a> Parser<'a> {
2388
2399
// the AST for typechecking.
2389
2400
err. span_label ( ident. span , "while parsing this `fn`" ) ;
2390
2401
err. emit ( ) ;
2391
- } else {
2392
- // check for typo'd Fn* trait bounds such as
2393
- // fn foo<F>() where F: FnOnce -> () {}
2394
- if self . token . kind == token:: RArrow {
2395
- let machine_applicable = [ sym:: FnOnce , sym:: FnMut , sym:: Fn ]
2396
- . into_iter ( )
2397
- . any ( |s| self . prev_token . is_ident_named ( s) ) ;
2398
-
2399
- err. subdiagnostic ( errors:: FnTraitMissingParen {
2400
- span : self . prev_token . span ,
2401
- machine_applicable,
2402
+ } else if self . token . kind == token:: RArrow
2403
+ && let Some ( fn_params_end) = fn_params_end
2404
+ {
2405
+ // Instead of a function body, the parser has encountered a right arrow
2406
+ // preceded by a where clause.
2407
+
2408
+ // Find whether token behind the right arrow is a function trait and
2409
+ // store its span.
2410
+ let prev_token_is_fn_trait = [ sym:: FnOnce , sym:: FnMut , sym:: Fn ]
2411
+ . into_iter ( )
2412
+ . any ( |s| self . prev_token . is_ident_named ( s) ) ;
2413
+ let fn_trait_span = self . prev_token . span ;
2414
+
2415
+ // Parse the return type (along with the right arrow) and store its span.
2416
+ // If there's a parse error, cancel it and return the existing error
2417
+ // as we are primarily concerned with the
2418
+ // expected-function-body-but-found-something-else error here.
2419
+ let arrow_span = self . token . span ;
2420
+ let ty_span = match self . parse_ret_ty (
2421
+ AllowPlus :: Yes ,
2422
+ RecoverQPath :: Yes ,
2423
+ RecoverReturnSign :: Yes ,
2424
+ ) {
2425
+ Ok ( ty_span) => ty_span. span ( ) . shrink_to_hi ( ) ,
2426
+ Err ( parse_error) => {
2427
+ parse_error. cancel ( ) ;
2428
+ return Err ( err) ;
2429
+ }
2430
+ } ;
2431
+ let ret_ty_span = arrow_span. to ( ty_span) ;
2432
+
2433
+ if prev_token_is_fn_trait {
2434
+ // Typo'd Fn* trait bounds such as
2435
+ // fn foo<F>() where F: FnOnce -> () {}
2436
+ err. subdiagnostic ( errors:: FnTraitMissingParen { span : fn_trait_span } ) ;
2437
+ } else if let Ok ( snippet) = self . psess . source_map ( ) . span_to_snippet ( ret_ty_span)
2438
+ {
2439
+ // If token behind right arrow is not a Fn* trait, the programmer
2440
+ // probably misplaced the return type after the where clause like
2441
+ // `fn foo<T>() where T: Default -> u8 {}`
2442
+ err. primary_message (
2443
+ "return type should be specified after the function parameters" ,
2444
+ ) ;
2445
+ err. subdiagnostic ( errors:: MisplacedReturnType {
2446
+ fn_params_end,
2447
+ snippet,
2448
+ ret_ty_span,
2402
2449
} ) ;
2403
2450
}
2404
2451
return Err ( err) ;
2452
+ } else {
2453
+ return Err ( err) ;
2405
2454
}
2406
2455
}
2407
2456
( AttrVec :: new ( ) , None )
0 commit comments