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