xref: /linux/rust/syn/fixup.rs (revision 69942c0a8965f311ed7ddf842f160c9cfdcda73a)
1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 use crate::classify;
4 use crate::expr::Expr;
5 #[cfg(feature = "full")]
6 use crate::expr::{
7     ExprBreak, ExprRange, ExprRawAddr, ExprReference, ExprReturn, ExprUnary, ExprYield,
8 };
9 use crate::precedence::Precedence;
10 #[cfg(feature = "full")]
11 use crate::ty::ReturnType;
12 
13 pub(crate) struct FixupContext {
14     #[cfg(feature = "full")]
15     previous_operator: Precedence,
16     #[cfg(feature = "full")]
17     next_operator: Precedence,
18 
19     // Print expression such that it can be parsed back as a statement
20     // consisting of the original expression.
21     //
22     // The effect of this is for binary operators in statement position to set
23     // `leftmost_subexpression_in_stmt` when printing their left-hand operand.
24     //
25     //     (match x {}) - 1;  // match needs parens when LHS of binary operator
26     //
27     //     match x {};  // not when its own statement
28     //
29     #[cfg(feature = "full")]
30     stmt: bool,
31 
32     // This is the difference between:
33     //
34     //     (match x {}) - 1;  // subexpression needs parens
35     //
36     //     let _ = match x {} - 1;  // no parens
37     //
38     // There are 3 distinguishable contexts in which `print_expr` might be
39     // called with the expression `$match` as its argument, where `$match`
40     // represents an expression of kind `ExprKind::Match`:
41     //
42     //   - stmt=false leftmost_subexpression_in_stmt=false
43     //
44     //     Example: `let _ = $match - 1;`
45     //
46     //     No parentheses required.
47     //
48     //   - stmt=false leftmost_subexpression_in_stmt=true
49     //
50     //     Example: `$match - 1;`
51     //
52     //     Must parenthesize `($match)`, otherwise parsing back the output as a
53     //     statement would terminate the statement after the closing brace of
54     //     the match, parsing `-1;` as a separate statement.
55     //
56     //   - stmt=true leftmost_subexpression_in_stmt=false
57     //
58     //     Example: `$match;`
59     //
60     //     No parentheses required.
61     #[cfg(feature = "full")]
62     leftmost_subexpression_in_stmt: bool,
63 
64     // Print expression such that it can be parsed as a match arm.
65     //
66     // This is almost equivalent to `stmt`, but the grammar diverges a tiny bit
67     // between statements and match arms when it comes to braced macro calls.
68     // Macro calls with brace delimiter terminate a statement without a
69     // semicolon, but do not terminate a match-arm without comma.
70     //
71     //     m! {} - 1;  // two statements: a macro call followed by -1 literal
72     //
73     //     match () {
74     //         _ => m! {} - 1,  // binary subtraction operator
75     //     }
76     //
77     #[cfg(feature = "full")]
78     match_arm: bool,
79 
80     // This is almost equivalent to `leftmost_subexpression_in_stmt`, other than
81     // for braced macro calls.
82     //
83     // If we have `m! {} - 1` as an expression, the leftmost subexpression
84     // `m! {}` will need to be parenthesized in the statement case but not the
85     // match-arm case.
86     //
87     //     (m! {}) - 1;  // subexpression needs parens
88     //
89     //     match () {
90     //         _ => m! {} - 1,  // no parens
91     //     }
92     //
93     #[cfg(feature = "full")]
94     leftmost_subexpression_in_match_arm: bool,
95 
96     // This is the difference between:
97     //
98     //     if let _ = (Struct {}) {}  // needs parens
99     //
100     //     match () {
101     //         () if let _ = Struct {} => {}  // no parens
102     //     }
103     //
104     #[cfg(feature = "full")]
105     condition: bool,
106 
107     // This is the difference between:
108     //
109     //     if break Struct {} == (break) {}  // needs parens
110     //
111     //     if break break == Struct {} {}  // no parens
112     //
113     #[cfg(feature = "full")]
114     rightmost_subexpression_in_condition: bool,
115 
116     // This is the difference between:
117     //
118     //     if break ({ x }).field + 1 {}  needs parens
119     //
120     //     if break 1 + { x }.field {}  // no parens
121     //
122     #[cfg(feature = "full")]
123     leftmost_subexpression_in_optional_operand: bool,
124 
125     // This is the difference between:
126     //
127     //     let _ = (return) - 1;  // without paren, this would return -1
128     //
129     //     let _ = return + 1;  // no paren because '+' cannot begin expr
130     //
131     #[cfg(feature = "full")]
132     next_operator_can_begin_expr: bool,
133 
134     // This is the difference between:
135     //
136     //     let _ = 1 + return 1;  // no parens if rightmost subexpression
137     //
138     //     let _ = 1 + (return 1) + 1;  // needs parens
139     //
140     #[cfg(feature = "full")]
141     next_operator_can_continue_expr: bool,
142 
143     // This is the difference between:
144     //
145     //     let _ = x as u8 + T;
146     //
147     //     let _ = (x as u8) < T;
148     //
149     // Without parens, the latter would want to parse `u8<T...` as a type.
150     next_operator_can_begin_generics: bool,
151 }
152 
153 impl FixupContext {
154     /// The default amount of fixing is minimal fixing. Fixups should be turned
155     /// on in a targeted fashion where needed.
156     pub const NONE: Self = FixupContext {
157         #[cfg(feature = "full")]
158         previous_operator: Precedence::MIN,
159         #[cfg(feature = "full")]
160         next_operator: Precedence::MIN,
161         #[cfg(feature = "full")]
162         stmt: false,
163         #[cfg(feature = "full")]
164         leftmost_subexpression_in_stmt: false,
165         #[cfg(feature = "full")]
166         match_arm: false,
167         #[cfg(feature = "full")]
168         leftmost_subexpression_in_match_arm: false,
169         #[cfg(feature = "full")]
170         condition: false,
171         #[cfg(feature = "full")]
172         rightmost_subexpression_in_condition: false,
173         #[cfg(feature = "full")]
174         leftmost_subexpression_in_optional_operand: false,
175         #[cfg(feature = "full")]
176         next_operator_can_begin_expr: false,
177         #[cfg(feature = "full")]
178         next_operator_can_continue_expr: false,
179         next_operator_can_begin_generics: false,
180     };
181 
182     /// Create the initial fixup for printing an expression in statement
183     /// position.
184     #[cfg(feature = "full")]
185     pub fn new_stmt() -> Self {
186         FixupContext {
187             stmt: true,
188             ..FixupContext::NONE
189         }
190     }
191 
192     /// Create the initial fixup for printing an expression as the right-hand
193     /// side of a match arm.
194     #[cfg(feature = "full")]
195     pub fn new_match_arm() -> Self {
196         FixupContext {
197             match_arm: true,
198             ..FixupContext::NONE
199         }
200     }
201 
202     /// Create the initial fixup for printing an expression as the "condition"
203     /// of an `if` or `while`. There are a few other positions which are
204     /// grammatically equivalent and also use this, such as the iterator
205     /// expression in `for` and the scrutinee in `match`.
206     #[cfg(feature = "full")]
207     pub fn new_condition() -> Self {
208         FixupContext {
209             condition: true,
210             rightmost_subexpression_in_condition: true,
211             ..FixupContext::NONE
212         }
213     }
214 
215     /// Transform this fixup into the one that should apply when printing the
216     /// leftmost subexpression of the current expression.
217     ///
218     /// The leftmost subexpression is any subexpression that has the same first
219     /// token as the current expression, but has a different last token.
220     ///
221     /// For example in `$a + $b` and `$a.method()`, the subexpression `$a` is a
222     /// leftmost subexpression.
223     ///
224     /// Not every expression has a leftmost subexpression. For example neither
225     /// `-$a` nor `[$a]` have one.
226     pub fn leftmost_subexpression_with_operator(
227         self,
228         expr: &Expr,
229         #[cfg(feature = "full")] next_operator_can_begin_expr: bool,
230         next_operator_can_begin_generics: bool,
231         #[cfg(feature = "full")] precedence: Precedence,
232     ) -> (Precedence, Self) {
233         let fixup = FixupContext {
234             #[cfg(feature = "full")]
235             next_operator: precedence,
236             #[cfg(feature = "full")]
237             stmt: false,
238             #[cfg(feature = "full")]
239             leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt,
240             #[cfg(feature = "full")]
241             match_arm: false,
242             #[cfg(feature = "full")]
243             leftmost_subexpression_in_match_arm: self.match_arm
244                 || self.leftmost_subexpression_in_match_arm,
245             #[cfg(feature = "full")]
246             rightmost_subexpression_in_condition: false,
247             #[cfg(feature = "full")]
248             next_operator_can_begin_expr,
249             #[cfg(feature = "full")]
250             next_operator_can_continue_expr: true,
251             next_operator_can_begin_generics,
252             ..self
253         };
254 
255         (fixup.leftmost_subexpression_precedence(expr), fixup)
256     }
257 
258     /// Transform this fixup into the one that should apply when printing a
259     /// leftmost subexpression followed by a `.` or `?` token, which confer
260     /// different statement boundary rules compared to other leftmost
261     /// subexpressions.
262     pub fn leftmost_subexpression_with_dot(self, expr: &Expr) -> (Precedence, Self) {
263         let fixup = FixupContext {
264             #[cfg(feature = "full")]
265             next_operator: Precedence::Unambiguous,
266             #[cfg(feature = "full")]
267             stmt: self.stmt || self.leftmost_subexpression_in_stmt,
268             #[cfg(feature = "full")]
269             leftmost_subexpression_in_stmt: false,
270             #[cfg(feature = "full")]
271             match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
272             #[cfg(feature = "full")]
273             leftmost_subexpression_in_match_arm: false,
274             #[cfg(feature = "full")]
275             rightmost_subexpression_in_condition: false,
276             #[cfg(feature = "full")]
277             next_operator_can_begin_expr: false,
278             #[cfg(feature = "full")]
279             next_operator_can_continue_expr: true,
280             next_operator_can_begin_generics: false,
281             ..self
282         };
283 
284         (fixup.leftmost_subexpression_precedence(expr), fixup)
285     }
286 
287     fn leftmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
288         #[cfg(feature = "full")]
289         if !self.next_operator_can_begin_expr || self.next_operator == Precedence::Range {
290             if let Scan::Bailout = scan_right(expr, self, Precedence::MIN, 0, 0) {
291                 if scan_left(expr, self) {
292                     return Precedence::Unambiguous;
293                 }
294             }
295         }
296 
297         self.precedence(expr)
298     }
299 
300     /// Transform this fixup into the one that should apply when printing the
301     /// rightmost subexpression of the current expression.
302     ///
303     /// The rightmost subexpression is any subexpression that has a different
304     /// first token than the current expression, but has the same last token.
305     ///
306     /// For example in `$a + $b` and `-$b`, the subexpression `$b` is a
307     /// rightmost subexpression.
308     ///
309     /// Not every expression has a rightmost subexpression. For example neither
310     /// `[$b]` nor `$a.f($b)` have one.
311     pub fn rightmost_subexpression(
312         self,
313         expr: &Expr,
314         #[cfg(feature = "full")] precedence: Precedence,
315     ) -> (Precedence, Self) {
316         let fixup = self.rightmost_subexpression_fixup(
317             #[cfg(feature = "full")]
318             false,
319             #[cfg(feature = "full")]
320             false,
321             #[cfg(feature = "full")]
322             precedence,
323         );
324         (fixup.rightmost_subexpression_precedence(expr), fixup)
325     }
326 
327     pub fn rightmost_subexpression_fixup(
328         self,
329         #[cfg(feature = "full")] reset_allow_struct: bool,
330         #[cfg(feature = "full")] optional_operand: bool,
331         #[cfg(feature = "full")] precedence: Precedence,
332     ) -> Self {
333         FixupContext {
334             #[cfg(feature = "full")]
335             previous_operator: precedence,
336             #[cfg(feature = "full")]
337             stmt: false,
338             #[cfg(feature = "full")]
339             leftmost_subexpression_in_stmt: false,
340             #[cfg(feature = "full")]
341             match_arm: false,
342             #[cfg(feature = "full")]
343             leftmost_subexpression_in_match_arm: false,
344             #[cfg(feature = "full")]
345             condition: self.condition && !reset_allow_struct,
346             #[cfg(feature = "full")]
347             leftmost_subexpression_in_optional_operand: self.condition && optional_operand,
348             ..self
349         }
350     }
351 
352     pub fn rightmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
353         let default_prec = self.precedence(expr);
354 
355         #[cfg(feature = "full")]
356         if match self.previous_operator {
357             Precedence::Assign | Precedence::Let | Precedence::Prefix => {
358                 default_prec < self.previous_operator
359             }
360             _ => default_prec <= self.previous_operator,
361         } && match self.next_operator {
362             Precedence::Range | Precedence::Or | Precedence::And => true,
363             _ => !self.next_operator_can_begin_expr,
364         } {
365             if let Scan::Bailout | Scan::Fail = scan_right(expr, self, self.previous_operator, 1, 0)
366             {
367                 if scan_left(expr, self) {
368                     return Precedence::Prefix;
369                 }
370             }
371         }
372 
373         default_prec
374     }
375 
376     /// Determine whether parentheses are needed around the given expression to
377     /// head off the early termination of a statement or condition.
378     #[cfg(feature = "full")]
379     pub fn parenthesize(self, expr: &Expr) -> bool {
380         (self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr))
381             || ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_)))
382             || (self.leftmost_subexpression_in_match_arm
383                 && !classify::requires_comma_to_be_match_arm(expr))
384             || (self.condition && matches!(expr, Expr::Struct(_)))
385             || (self.rightmost_subexpression_in_condition
386                 && matches!(
387                     expr,
388                     Expr::Return(ExprReturn { expr: None, .. })
389                         | Expr::Yield(ExprYield { expr: None, .. })
390                 ))
391             || (self.rightmost_subexpression_in_condition
392                 && !self.condition
393                 && matches!(
394                     expr,
395                     Expr::Break(ExprBreak { expr: None, .. })
396                         | Expr::Path(_)
397                         | Expr::Range(ExprRange { end: None, .. })
398                 ))
399             || (self.leftmost_subexpression_in_optional_operand
400                 && matches!(expr, Expr::Block(expr) if expr.attrs.is_empty() && expr.label.is_none()))
401     }
402 
403     /// Determines the effective precedence of a subexpression. Some expressions
404     /// have higher or lower precedence when adjacent to particular operators.
405     fn precedence(self, expr: &Expr) -> Precedence {
406         #[cfg(feature = "full")]
407         if self.next_operator_can_begin_expr {
408             // Decrease precedence of value-less jumps when followed by an
409             // operator that would otherwise get interpreted as beginning a
410             // value for the jump.
411             if let Expr::Break(ExprBreak { expr: None, .. })
412             | Expr::Return(ExprReturn { expr: None, .. })
413             | Expr::Yield(ExprYield { expr: None, .. }) = expr
414             {
415                 return Precedence::Jump;
416             }
417         }
418 
419         #[cfg(feature = "full")]
420         if !self.next_operator_can_continue_expr {
421             match expr {
422                 // Increase precedence of expressions that extend to the end of
423                 // current statement or group.
424                 Expr::Break(_)
425                 | Expr::Closure(_)
426                 | Expr::Let(_)
427                 | Expr::Return(_)
428                 | Expr::Yield(_) => {
429                     return Precedence::Prefix;
430                 }
431                 Expr::Range(e) if e.start.is_none() => return Precedence::Prefix,
432                 _ => {}
433             }
434         }
435 
436         if self.next_operator_can_begin_generics {
437             if let Expr::Cast(cast) = expr {
438                 if classify::trailing_unparameterized_path(&cast.ty) {
439                     return Precedence::MIN;
440                 }
441             }
442         }
443 
444         Precedence::of(expr)
445     }
446 }
447 
448 impl Copy for FixupContext {}
449 
450 impl Clone for FixupContext {
451     fn clone(&self) -> Self {
452         *self
453     }
454 }
455 
456 #[cfg(feature = "full")]
457 enum Scan {
458     Fail,
459     Bailout,
460     Consume,
461 }
462 
463 #[cfg(feature = "full")]
464 impl Copy for Scan {}
465 
466 #[cfg(feature = "full")]
467 impl Clone for Scan {
468     fn clone(&self) -> Self {
469         *self
470     }
471 }
472 
473 #[cfg(feature = "full")]
474 impl PartialEq for Scan {
475     fn eq(&self, other: &Self) -> bool {
476         *self as u8 == *other as u8
477     }
478 }
479 
480 #[cfg(feature = "full")]
481 fn scan_left(expr: &Expr, fixup: FixupContext) -> bool {
482     match expr {
483         Expr::Assign(_) => fixup.previous_operator <= Precedence::Assign,
484         Expr::Binary(e) => match Precedence::of_binop(&e.op) {
485             Precedence::Assign => fixup.previous_operator <= Precedence::Assign,
486             binop_prec => fixup.previous_operator < binop_prec,
487         },
488         Expr::Cast(_) => fixup.previous_operator < Precedence::Cast,
489         Expr::Range(e) => e.start.is_none() || fixup.previous_operator < Precedence::Assign,
490         _ => true,
491     }
492 }
493 
494 #[cfg(feature = "full")]
495 fn scan_right(
496     expr: &Expr,
497     fixup: FixupContext,
498     precedence: Precedence,
499     fail_offset: u8,
500     bailout_offset: u8,
501 ) -> Scan {
502     let consume_by_precedence = if match precedence {
503         Precedence::Assign | Precedence::Compare => precedence <= fixup.next_operator,
504         _ => precedence < fixup.next_operator,
505     } || fixup.next_operator == Precedence::MIN
506     {
507         Scan::Consume
508     } else {
509         Scan::Bailout
510     };
511     if fixup.parenthesize(expr) {
512         return consume_by_precedence;
513     }
514     match expr {
515         Expr::Assign(e) if e.attrs.is_empty() => {
516             if match fixup.next_operator {
517                 Precedence::Unambiguous => fail_offset >= 2,
518                 _ => bailout_offset >= 1,
519             } {
520                 return Scan::Consume;
521             }
522             let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign);
523             let scan = scan_right(
524                 &e.right,
525                 right_fixup,
526                 Precedence::Assign,
527                 match fixup.next_operator {
528                     Precedence::Unambiguous => fail_offset,
529                     _ => 1,
530                 },
531                 1,
532             );
533             if let Scan::Bailout | Scan::Consume = scan {
534                 Scan::Consume
535             } else if let Precedence::Unambiguous = fixup.next_operator {
536                 Scan::Fail
537             } else {
538                 Scan::Bailout
539             }
540         }
541         Expr::Binary(e) if e.attrs.is_empty() => {
542             if match fixup.next_operator {
543                 Precedence::Unambiguous => {
544                     fail_offset >= 2
545                         && (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
546                 }
547                 _ => bailout_offset >= 1,
548             } {
549                 return Scan::Consume;
550             }
551             let binop_prec = Precedence::of_binop(&e.op);
552             if binop_prec == Precedence::Compare && fixup.next_operator == Precedence::Compare {
553                 return Scan::Consume;
554             }
555             let right_fixup = fixup.rightmost_subexpression_fixup(false, false, binop_prec);
556             let scan = scan_right(
557                 &e.right,
558                 right_fixup,
559                 binop_prec,
560                 match fixup.next_operator {
561                     Precedence::Unambiguous => fail_offset,
562                     _ => 1,
563                 },
564                 consume_by_precedence as u8 - Scan::Bailout as u8,
565             );
566             match scan {
567                 Scan::Fail => {}
568                 Scan::Bailout => return consume_by_precedence,
569                 Scan::Consume => return Scan::Consume,
570             }
571             let right_needs_group = binop_prec != Precedence::Assign
572                 && right_fixup.rightmost_subexpression_precedence(&e.right) <= binop_prec;
573             if right_needs_group {
574                 consume_by_precedence
575             } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
576                 Scan::Fail
577             } else {
578                 Scan::Bailout
579             }
580         }
581         Expr::RawAddr(ExprRawAddr { expr, .. })
582         | Expr::Reference(ExprReference { expr, .. })
583         | Expr::Unary(ExprUnary { expr, .. }) => {
584             if match fixup.next_operator {
585                 Precedence::Unambiguous => {
586                     fail_offset >= 2
587                         && (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
588                 }
589                 _ => bailout_offset >= 1,
590             } {
591                 return Scan::Consume;
592             }
593             let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Prefix);
594             let scan = scan_right(
595                 expr,
596                 right_fixup,
597                 precedence,
598                 match fixup.next_operator {
599                     Precedence::Unambiguous => fail_offset,
600                     _ => 1,
601                 },
602                 consume_by_precedence as u8 - Scan::Bailout as u8,
603             );
604             match scan {
605                 Scan::Fail => {}
606                 Scan::Bailout => return consume_by_precedence,
607                 Scan::Consume => return Scan::Consume,
608             }
609             if right_fixup.rightmost_subexpression_precedence(expr) < Precedence::Prefix {
610                 consume_by_precedence
611             } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
612                 Scan::Fail
613             } else {
614                 Scan::Bailout
615             }
616         }
617         Expr::Range(e) if e.attrs.is_empty() => match &e.end {
618             Some(end) => {
619                 if fail_offset >= 2 {
620                     return Scan::Consume;
621                 }
622                 let right_fixup =
623                     fixup.rightmost_subexpression_fixup(false, true, Precedence::Range);
624                 let scan = scan_right(
625                     end,
626                     right_fixup,
627                     Precedence::Range,
628                     fail_offset,
629                     match fixup.next_operator {
630                         Precedence::Assign | Precedence::Range => 0,
631                         _ => 1,
632                     },
633                 );
634                 if match (scan, fixup.next_operator) {
635                     (Scan::Fail, _) => false,
636                     (Scan::Bailout, Precedence::Assign | Precedence::Range) => false,
637                     (Scan::Bailout | Scan::Consume, _) => true,
638                 } {
639                     return Scan::Consume;
640                 }
641                 if right_fixup.rightmost_subexpression_precedence(end) <= Precedence::Range {
642                     Scan::Consume
643                 } else {
644                     Scan::Fail
645                 }
646             }
647             None => {
648                 if fixup.next_operator_can_begin_expr {
649                     Scan::Consume
650                 } else {
651                     Scan::Fail
652                 }
653             }
654         },
655         Expr::Break(e) => match &e.expr {
656             Some(value) => {
657                 if bailout_offset >= 1 || e.label.is_none() && classify::expr_leading_label(value) {
658                     return Scan::Consume;
659                 }
660                 let right_fixup = fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump);
661                 match scan_right(value, right_fixup, Precedence::Jump, 1, 1) {
662                     Scan::Fail => Scan::Bailout,
663                     Scan::Bailout | Scan::Consume => Scan::Consume,
664                 }
665             }
666             None => match fixup.next_operator {
667                 Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
668                 _ => Scan::Consume,
669             },
670         },
671         Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr {
672             Some(e) => {
673                 if bailout_offset >= 1 {
674                     return Scan::Consume;
675                 }
676                 let right_fixup =
677                     fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump);
678                 match scan_right(e, right_fixup, Precedence::Jump, 1, 1) {
679                     Scan::Fail => Scan::Bailout,
680                     Scan::Bailout | Scan::Consume => Scan::Consume,
681                 }
682             }
683             None => match fixup.next_operator {
684                 Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
685                 _ => Scan::Consume,
686             },
687         },
688         Expr::Closure(e) => {
689             if matches!(e.output, ReturnType::Default)
690                 || matches!(&*e.body, Expr::Block(body) if body.attrs.is_empty() && body.label.is_none())
691             {
692                 if bailout_offset >= 1 {
693                     return Scan::Consume;
694                 }
695                 let right_fixup =
696                     fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump);
697                 match scan_right(&e.body, right_fixup, Precedence::Jump, 1, 1) {
698                     Scan::Fail => Scan::Bailout,
699                     Scan::Bailout | Scan::Consume => Scan::Consume,
700                 }
701             } else {
702                 Scan::Consume
703             }
704         }
705         Expr::Let(e) => {
706             if bailout_offset >= 1 {
707                 return Scan::Consume;
708             }
709             let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Let);
710             let scan = scan_right(
711                 &e.expr,
712                 right_fixup,
713                 Precedence::Let,
714                 1,
715                 if fixup.next_operator < Precedence::Let {
716                     0
717                 } else {
718                     1
719                 },
720             );
721             match scan {
722                 Scan::Fail | Scan::Bailout if fixup.next_operator < Precedence::Let => {
723                     return Scan::Bailout;
724                 }
725                 Scan::Consume => return Scan::Consume,
726                 _ => {}
727             }
728             if right_fixup.rightmost_subexpression_precedence(&e.expr) < Precedence::Let {
729                 Scan::Consume
730             } else if let Scan::Fail = scan {
731                 Scan::Bailout
732             } else {
733                 Scan::Consume
734             }
735         }
736         Expr::Array(_)
737         | Expr::Assign(_)
738         | Expr::Async(_)
739         | Expr::Await(_)
740         | Expr::Binary(_)
741         | Expr::Block(_)
742         | Expr::Call(_)
743         | Expr::Cast(_)
744         | Expr::Const(_)
745         | Expr::Continue(_)
746         | Expr::Field(_)
747         | Expr::ForLoop(_)
748         | Expr::Group(_)
749         | Expr::If(_)
750         | Expr::Index(_)
751         | Expr::Infer(_)
752         | Expr::Lit(_)
753         | Expr::Loop(_)
754         | Expr::Macro(_)
755         | Expr::Match(_)
756         | Expr::MethodCall(_)
757         | Expr::Paren(_)
758         | Expr::Path(_)
759         | Expr::Range(_)
760         | Expr::Repeat(_)
761         | Expr::Struct(_)
762         | Expr::Try(_)
763         | Expr::TryBlock(_)
764         | Expr::Tuple(_)
765         | Expr::Unsafe(_)
766         | Expr::Verbatim(_)
767         | Expr::While(_) => match fixup.next_operator {
768             Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail,
769             _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => {
770                 Scan::Fail
771             }
772             _ => consume_by_precedence,
773         },
774     }
775 }
776