@@ -155,53 +155,13 @@ impl<'a> Parser<'a> {
155
155
} ;
156
156
let last_type_ascription_set = self . last_type_ascription . is_some ( ) ;
157
157
158
- match ( self . expr_is_complete ( & lhs) , AssocOp :: from_token ( & self . token ) ) {
159
- ( true , None ) => {
160
- self . last_type_ascription = None ;
161
- // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
162
- return Ok ( lhs) ;
163
- }
164
- ( false , _) => { } // continue parsing the expression
165
- // An exhaustive check is done in the following block, but these are checked first
166
- // because they *are* ambiguous but also reasonable looking incorrect syntax, so we
167
- // want to keep their span info to improve diagnostics in these cases in a later stage.
168
- ( true , Some ( AssocOp :: Multiply ) ) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
169
- ( true , Some ( AssocOp :: Subtract ) ) | // `{ 42 } -5`
170
- ( true , Some ( AssocOp :: LAnd ) ) | // `{ 42 } &&x` (#61475)
171
- ( true , Some ( AssocOp :: Add ) ) // `{ 42 } + 42
172
- // If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
173
- // `if x { a } else { b } && if y { c } else { d }`
174
- if !self . look_ahead ( 1 , |t| t. is_reserved_ident ( ) ) => {
175
- self . last_type_ascription = None ;
176
- // These cases are ambiguous and can't be identified in the parser alone
177
- let sp = self . sess . source_map ( ) . start_point ( self . token . span ) ;
178
- self . sess . ambiguous_block_expr_parse . borrow_mut ( ) . insert ( sp, lhs. span ) ;
179
- return Ok ( lhs) ;
180
- }
181
- ( true , Some ( ref op) ) if !op. can_continue_expr_unambiguously ( ) => {
182
- self . last_type_ascription = None ;
183
- return Ok ( lhs) ;
184
- }
185
- ( true , Some ( _) ) => {
186
- // We've found an expression that would be parsed as a statement, but the next
187
- // token implies this should be parsed as an expression.
188
- // For example: `if let Some(x) = x { x } else { 0 } / 2`
189
- let mut err = self . struct_span_err ( self . token . span , & format ! (
190
- "expected expression, found `{}`" ,
191
- pprust:: token_to_string( & self . token) ,
192
- ) ) ;
193
- err. span_label ( self . token . span , "expected expression" ) ;
194
- self . sess . expr_parentheses_needed (
195
- & mut err,
196
- lhs. span ,
197
- Some ( pprust:: expr_to_string ( & lhs) ,
198
- ) ) ;
199
- err. emit ( ) ;
200
- }
158
+ if !self . should_continue_as_assoc_expr ( & lhs) {
159
+ self . last_type_ascription = None ;
160
+ return Ok ( lhs) ;
201
161
}
202
- self . expected_tokens . push ( TokenType :: Operator ) ;
203
- while let Some ( op) = AssocOp :: from_token ( & self . token ) {
204
162
163
+ self . expected_tokens . push ( TokenType :: Operator ) ;
164
+ while let Some ( op) = self . check_assoc_op ( ) {
205
165
// Adjust the span for interpolated LHS to point to the `$lhs` token and not to what
206
166
// it refers to. Interpolated identifiers are unwrapped early and never show up here
207
167
// as `PrevTokenKind::Interpolated` so if LHS is a single identifier we always process
@@ -338,6 +298,56 @@ impl<'a> Parser<'a> {
338
298
Ok ( lhs)
339
299
}
340
300
301
+ fn should_continue_as_assoc_expr ( & mut self , lhs : & Expr ) -> bool {
302
+ match ( self . expr_is_complete ( lhs) , self . check_assoc_op ( ) ) {
303
+ // Semi-statement forms are odd:
304
+ // See https://github.com/rust-lang/rust/issues/29071
305
+ ( true , None ) => false ,
306
+ ( false , _) => true , // Continue parsing the expression.
307
+ // An exhaustive check is done in the following block, but these are checked first
308
+ // because they *are* ambiguous but also reasonable looking incorrect syntax, so we
309
+ // want to keep their span info to improve diagnostics in these cases in a later stage.
310
+ ( true , Some ( AssocOp :: Multiply ) ) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
311
+ ( true , Some ( AssocOp :: Subtract ) ) | // `{ 42 } -5`
312
+ ( true , Some ( AssocOp :: LAnd ) ) | // `{ 42 } &&x` (#61475)
313
+ ( true , Some ( AssocOp :: Add ) ) // `{ 42 } + 42
314
+ // If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
315
+ // `if x { a } else { b } && if y { c } else { d }`
316
+ if !self . look_ahead ( 1 , |t| t. is_reserved_ident ( ) ) => {
317
+ // These cases are ambiguous and can't be identified in the parser alone.
318
+ let sp = self . sess . source_map ( ) . start_point ( self . token . span ) ;
319
+ self . sess . ambiguous_block_expr_parse . borrow_mut ( ) . insert ( sp, lhs. span ) ;
320
+ false
321
+ }
322
+ ( true , Some ( ref op) ) if !op. can_continue_expr_unambiguously ( ) => false ,
323
+ ( true , Some ( _) ) => {
324
+ self . error_found_expr_would_be_stmt ( lhs) ;
325
+ true
326
+ }
327
+ }
328
+ }
329
+
330
+ /// We've found an expression that would be parsed as a statement,
331
+ /// but the next token implies this should be parsed as an expression.
332
+ /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
333
+ fn error_found_expr_would_be_stmt ( & self , lhs : & Expr ) {
334
+ let mut err = self . struct_span_err ( self . token . span , & format ! (
335
+ "expected expression, found `{}`" ,
336
+ pprust:: token_to_string( & self . token) ,
337
+ ) ) ;
338
+ err. span_label ( self . token . span , "expected expression" ) ;
339
+ self . sess . expr_parentheses_needed ( & mut err, lhs. span , Some ( pprust:: expr_to_string ( & lhs) ) ) ;
340
+ err. emit ( ) ;
341
+ }
342
+
343
+ /// Possibly translate the current token to an associative operator.
344
+ /// The method does not advance the current token.
345
+ ///
346
+ /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
347
+ fn check_assoc_op ( & self ) -> Option < AssocOp > {
348
+ AssocOp :: from_token ( & self . token )
349
+ }
350
+
341
351
/// Checks if this expression is a successfully parsed statement.
342
352
fn expr_is_complete ( & self , e : & Expr ) -> bool {
343
353
self . restrictions . contains ( Restrictions :: STMT_EXPR ) &&
0 commit comments