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