@@ -2834,7 +2834,7 @@ impl<'a> Parser<'a> {
2834
2834
) ?;
2835
2835
let guard = if this. eat_keyword ( kw:: If ) {
2836
2836
let if_span = this. prev_token . span ;
2837
- let mut cond = this. parse_expr_res ( Restrictions :: ALLOW_LET , None ) ?;
2837
+ let mut cond = this. parse_match_guard_condition ( ) ?;
2838
2838
2839
2839
CondChecker { parser : this, forbid_let_reason : None } . visit_expr ( & mut cond) ;
2840
2840
@@ -2860,9 +2860,9 @@ impl<'a> Parser<'a> {
2860
2860
{
2861
2861
err. span_suggestion (
2862
2862
this. token . span ,
2863
- "try using a fat arrow here " ,
2863
+ "use a fat arrow to start a match arm " ,
2864
2864
"=>" ,
2865
- Applicability :: MaybeIncorrect ,
2865
+ Applicability :: MachineApplicable ,
2866
2866
) ;
2867
2867
err. emit ( ) ;
2868
2868
this. bump ( ) ;
@@ -2979,6 +2979,34 @@ impl<'a> Parser<'a> {
2979
2979
} )
2980
2980
}
2981
2981
2982
+ fn parse_match_guard_condition ( & mut self ) -> PResult < ' a , P < Expr > > {
2983
+ self . parse_expr_res ( Restrictions :: ALLOW_LET | Restrictions :: IN_IF_GUARD , None ) . map_err (
2984
+ |mut err| {
2985
+ if self . prev_token == token:: OpenDelim ( Delimiter :: Brace ) {
2986
+ let sugg_sp = self . prev_token . span . shrink_to_lo ( ) ;
2987
+ // Consume everything within the braces, let's avoid further parse
2988
+ // errors.
2989
+ self . recover_stmt_ ( SemiColonMode :: Ignore , BlockMode :: Ignore ) ;
2990
+ let msg = "you might have meant to start a match arm after the match guard" ;
2991
+ if self . eat ( & token:: CloseDelim ( Delimiter :: Brace ) ) {
2992
+ let applicability = if self . token . kind != token:: FatArrow {
2993
+ // We have high confidence that we indeed didn't have a struct
2994
+ // literal in the match guard, but rather we had some operation
2995
+ // that ended in a path, immediately followed by a block that was
2996
+ // meant to be the match arm.
2997
+ Applicability :: MachineApplicable
2998
+ } else {
2999
+ Applicability :: MaybeIncorrect
3000
+ } ;
3001
+ // self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3002
+ err. span_suggestion_verbose ( sugg_sp, msg, "=> " . to_string ( ) , applicability) ;
3003
+ }
3004
+ }
3005
+ err
3006
+ } ,
3007
+ )
3008
+ }
3009
+
2982
3010
pub ( crate ) fn is_builtin ( & self ) -> bool {
2983
3011
self . token . is_keyword ( kw:: Builtin ) && self . look_ahead ( 1 , |t| * t == token:: Pound )
2984
3012
}
@@ -3049,9 +3077,10 @@ impl<'a> Parser<'a> {
3049
3077
|| self . look_ahead ( 2 , |t| t == & token:: Colon )
3050
3078
&& (
3051
3079
// `{ ident: token, ` cannot start a block.
3052
- self . look_ahead ( 4 , |t| t == & token:: Comma ) ||
3053
- // `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`.
3054
- self . look_ahead ( 3 , |t| !t. can_begin_type ( ) )
3080
+ self . look_ahead ( 4 , |t| t == & token:: Comma )
3081
+ // `{ ident: ` cannot start a block unless it's a type ascription
3082
+ // `ident: Type`.
3083
+ || self . look_ahead ( 3 , |t| !t. can_begin_type ( ) )
3055
3084
)
3056
3085
)
3057
3086
}
@@ -3091,6 +3120,7 @@ impl<'a> Parser<'a> {
3091
3120
let mut fields = ThinVec :: new ( ) ;
3092
3121
let mut base = ast:: StructRest :: None ;
3093
3122
let mut recover_async = false ;
3123
+ let in_if_guard = self . restrictions . contains ( Restrictions :: IN_IF_GUARD ) ;
3094
3124
3095
3125
let mut async_block_err = |e : & mut Diagnostic , span : Span | {
3096
3126
recover_async = true ;
@@ -3128,6 +3158,26 @@ impl<'a> Parser<'a> {
3128
3158
e. span_label ( pth. span , "while parsing this struct" ) ;
3129
3159
}
3130
3160
3161
+ if let Some ( ( ident, _) ) = self . token . ident ( )
3162
+ && !self . token . is_reserved_ident ( )
3163
+ && self . look_ahead ( 1 , |t| {
3164
+ AssocOp :: from_token ( & t) . is_some ( )
3165
+ || matches ! ( t. kind, token:: OpenDelim ( _) )
3166
+ || t. kind == token:: Dot
3167
+ } )
3168
+ {
3169
+ // Looks like they tried to write a shorthand, complex expression.
3170
+ e. span_suggestion_verbose (
3171
+ self . token . span . shrink_to_lo ( ) ,
3172
+ "try naming a field" ,
3173
+ & format ! ( "{ident}: " , ) ,
3174
+ Applicability :: HasPlaceholders ,
3175
+ ) ;
3176
+ }
3177
+ if in_if_guard && close_delim == Delimiter :: Brace {
3178
+ return Err ( e) ;
3179
+ }
3180
+
3131
3181
if !recover {
3132
3182
return Err ( e) ;
3133
3183
}
@@ -3173,19 +3223,6 @@ impl<'a> Parser<'a> {
3173
3223
"," ,
3174
3224
Applicability :: MachineApplicable ,
3175
3225
) ;
3176
- } else if is_shorthand
3177
- && ( AssocOp :: from_token ( & self . token ) . is_some ( )
3178
- || matches ! ( & self . token. kind, token:: OpenDelim ( _) )
3179
- || self . token . kind == token:: Dot )
3180
- {
3181
- // Looks like they tried to write a shorthand, complex expression.
3182
- let ident = parsed_field. expect ( "is_shorthand implies Some" ) . ident ;
3183
- e. span_suggestion (
3184
- ident. span . shrink_to_lo ( ) ,
3185
- "try naming a field" ,
3186
- & format ! ( "{ident}: " ) ,
3187
- Applicability :: HasPlaceholders ,
3188
- ) ;
3189
3226
}
3190
3227
}
3191
3228
if !recover {
@@ -3288,6 +3325,24 @@ impl<'a> Parser<'a> {
3288
3325
3289
3326
// Check if a colon exists one ahead. This means we're parsing a fieldname.
3290
3327
let is_shorthand = !this. look_ahead ( 1 , |t| t == & token:: Colon || t == & token:: Eq ) ;
3328
+ // Proactively check whether parsing the field will be correct.
3329
+ let is_wrong = this. token . is_ident ( )
3330
+ && !this. token . is_reserved_ident ( )
3331
+ && !this. look_ahead ( 1 , |t| {
3332
+ t == & token:: Colon
3333
+ || t == & token:: Eq
3334
+ || t == & token:: Comma
3335
+ || t == & token:: CloseDelim ( Delimiter :: Brace )
3336
+ || t == & token:: CloseDelim ( Delimiter :: Parenthesis )
3337
+ } ) ;
3338
+ if is_wrong {
3339
+ return Err ( errors:: ExpectedStructField {
3340
+ span : this. look_ahead ( 1 , |t| t. span ) ,
3341
+ ident_span : this. token . span ,
3342
+ token : this. look_ahead ( 1 , |t| t. clone ( ) ) ,
3343
+ }
3344
+ . into_diagnostic ( & self . sess . span_diagnostic ) ) ;
3345
+ }
3291
3346
let ( ident, expr) = if is_shorthand {
3292
3347
// Mimic `x: x` for the `x` field shorthand.
3293
3348
let ident = this. parse_ident_common ( false ) ?;
0 commit comments