@@ -907,6 +907,12 @@ impl<'a> Parser<'a> {
907
907
}
908
908
}
909
909
910
+ fn look_ahead_type_ascription_as_field ( & mut self ) -> bool {
911
+ self . look_ahead ( 1 , |t| t. is_ident ( ) )
912
+ && self . look_ahead ( 2 , |t| t == & token:: Colon )
913
+ && self . look_ahead ( 3 , |t| t. can_begin_expr ( ) )
914
+ }
915
+
910
916
fn parse_dot_suffix_expr ( & mut self , lo : Span , base : P < Expr > ) -> PResult < ' a , P < Expr > > {
911
917
match self . token . uninterpolate ( ) . kind {
912
918
token:: Ident ( ..) => self . parse_dot_suffix ( base, lo) ,
@@ -1056,12 +1062,76 @@ impl<'a> Parser<'a> {
1056
1062
1057
1063
/// Parse a function call expression, `expr(...)`.
1058
1064
fn parse_fn_call_expr ( & mut self , lo : Span , fun : P < Expr > ) -> P < Expr > {
1059
- let seq = self . parse_paren_expr_seq ( ) . map ( |args| {
1065
+ let snapshot = if self . token . kind == token:: OpenDelim ( token:: Paren )
1066
+ && self . look_ahead_type_ascription_as_field ( )
1067
+ {
1068
+ Some ( ( self . clone ( ) , fun. kind . clone ( ) ) )
1069
+ } else {
1070
+ None
1071
+ } ;
1072
+ let open_paren = self . token . span ;
1073
+
1074
+ let mut seq = self . parse_paren_expr_seq ( ) . map ( |args| {
1060
1075
self . mk_expr ( lo. to ( self . prev_token . span ) , self . mk_call ( fun, args) , AttrVec :: new ( ) )
1061
1076
} ) ;
1077
+ if let Some ( expr) =
1078
+ self . maybe_recover_struct_lit_bad_delims ( lo, open_paren, & mut seq, snapshot)
1079
+ {
1080
+ return expr;
1081
+ }
1062
1082
self . recover_seq_parse_error ( token:: Paren , lo, seq)
1063
1083
}
1064
1084
1085
+ /// If we encounter a parser state that looks like the user has written a `struct` literal with
1086
+ /// parentheses instead of braces, recover the parser state and provide suggestions.
1087
+ fn maybe_recover_struct_lit_bad_delims (
1088
+ & mut self ,
1089
+ lo : Span ,
1090
+ open_paren : Span ,
1091
+ seq : & mut PResult < ' a , P < Expr > > ,
1092
+ snapshot : Option < ( Self , ExprKind ) > ,
1093
+ ) -> Option < P < Expr > > {
1094
+ match ( seq. as_mut ( ) , snapshot) {
1095
+ ( Err ( ref mut err) , Some ( ( mut snapshot, ExprKind :: Path ( None , path) ) ) ) => {
1096
+ let name = pprust:: path_to_string ( & path) ;
1097
+ snapshot. bump ( ) ; // `(`
1098
+ match snapshot. parse_struct_fields ( path. clone ( ) , false , token:: Paren ) {
1099
+ Ok ( ( fields, ..) ) if snapshot. eat ( & token:: CloseDelim ( token:: Paren ) ) => {
1100
+ // We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
1101
+ // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
1102
+ * self = snapshot;
1103
+ let close_paren = self . prev_token . span ;
1104
+ let span = lo. to ( self . prev_token . span ) ;
1105
+ err. cancel ( ) ;
1106
+ self . struct_span_err (
1107
+ span,
1108
+ "invalid `struct` delimiters or `fn` call arguments" ,
1109
+ )
1110
+ . multipart_suggestion (
1111
+ & format ! ( "if `{}` is a struct, use braces as delimiters" , name) ,
1112
+ vec ! [ ( open_paren, " { " . to_string( ) ) , ( close_paren, " }" . to_string( ) ) ] ,
1113
+ Applicability :: MaybeIncorrect ,
1114
+ )
1115
+ . multipart_suggestion (
1116
+ & format ! ( "if `{}` is a function, use the arguments directly" , name) ,
1117
+ fields
1118
+ . into_iter ( )
1119
+ . map ( |field| ( field. span . until ( field. expr . span ) , String :: new ( ) ) )
1120
+ . collect ( ) ,
1121
+ Applicability :: MaybeIncorrect ,
1122
+ )
1123
+ . emit ( ) ;
1124
+ return Some ( self . mk_expr_err ( span) ) ;
1125
+ }
1126
+ Ok ( _) => { }
1127
+ Err ( mut err) => err. emit ( ) ,
1128
+ }
1129
+ }
1130
+ _ => { }
1131
+ }
1132
+ None
1133
+ }
1134
+
1065
1135
/// Parse an indexing expression `expr[...]`.
1066
1136
fn parse_index_expr ( & mut self , lo : Span , base : P < Expr > ) -> PResult < ' a , P < Expr > > {
1067
1137
self . bump ( ) ; // `[`
@@ -2374,14 +2444,12 @@ impl<'a> Parser<'a> {
2374
2444
. emit ( ) ;
2375
2445
}
2376
2446
2377
- /// Precondition: already parsed the '{'.
2378
- pub ( super ) fn parse_struct_expr (
2447
+ pub ( super ) fn parse_struct_fields (
2379
2448
& mut self ,
2380
- qself : Option < ast:: QSelf > ,
2381
2449
pth : ast:: Path ,
2382
- attrs : AttrVec ,
2383
2450
recover : bool ,
2384
- ) -> PResult < ' a , P < Expr > > {
2451
+ close_delim : token:: DelimToken ,
2452
+ ) -> PResult < ' a , ( Vec < ExprField > , ast:: StructRest , bool ) > {
2385
2453
let mut fields = Vec :: new ( ) ;
2386
2454
let mut base = ast:: StructRest :: None ;
2387
2455
let mut recover_async = false ;
@@ -2393,11 +2461,11 @@ impl<'a> Parser<'a> {
2393
2461
e. note ( "for more on editions, read https://doc.rust-lang.org/edition-guide" ) ;
2394
2462
} ;
2395
2463
2396
- while self . token != token:: CloseDelim ( token :: Brace ) {
2464
+ while self . token != token:: CloseDelim ( close_delim ) {
2397
2465
if self . eat ( & token:: DotDot ) {
2398
2466
let exp_span = self . prev_token . span ;
2399
2467
// We permit `.. }` on the left-hand side of a destructuring assignment.
2400
- if self . check ( & token:: CloseDelim ( token :: Brace ) ) {
2468
+ if self . check ( & token:: CloseDelim ( close_delim ) ) {
2401
2469
self . sess . gated_spans . gate ( sym:: destructuring_assignment, self . prev_token . span ) ;
2402
2470
base = ast:: StructRest :: Rest ( self . prev_token . span . shrink_to_hi ( ) ) ;
2403
2471
break ;
@@ -2438,7 +2506,7 @@ impl<'a> Parser<'a> {
2438
2506
}
2439
2507
} ;
2440
2508
2441
- match self . expect_one_of ( & [ token:: Comma ] , & [ token:: CloseDelim ( token :: Brace ) ] ) {
2509
+ match self . expect_one_of ( & [ token:: Comma ] , & [ token:: CloseDelim ( close_delim ) ] ) {
2442
2510
Ok ( _) => {
2443
2511
if let Some ( f) = parsed_field. or ( recovery_field) {
2444
2512
// Only include the field if there's no parse error for the field name.
@@ -2469,8 +2537,21 @@ impl<'a> Parser<'a> {
2469
2537
}
2470
2538
}
2471
2539
}
2540
+ Ok ( ( fields, base, recover_async) )
2541
+ }
2472
2542
2473
- let span = pth. span . to ( self . token . span ) ;
2543
+ /// Precondition: already parsed the '{'.
2544
+ pub ( super ) fn parse_struct_expr (
2545
+ & mut self ,
2546
+ qself : Option < ast:: QSelf > ,
2547
+ pth : ast:: Path ,
2548
+ attrs : AttrVec ,
2549
+ recover : bool ,
2550
+ ) -> PResult < ' a , P < Expr > > {
2551
+ let lo = pth. span ;
2552
+ let ( fields, base, recover_async) =
2553
+ self . parse_struct_fields ( pth. clone ( ) , recover, token:: Brace ) ?;
2554
+ let span = lo. to ( self . token . span ) ;
2474
2555
self . expect ( & token:: CloseDelim ( token:: Brace ) ) ?;
2475
2556
let expr = if recover_async {
2476
2557
ExprKind :: Err
0 commit comments