syn/
fixup.rs

1use crate::classify;
2use crate::expr::Expr;
3#[cfg(feature = "full")]
4use crate::expr::{
5    ExprBreak, ExprRange, ExprRawAddr, ExprReference, ExprReturn, ExprUnary, ExprYield,
6};
7use crate::precedence::Precedence;
8#[cfg(feature = "full")]
9use crate::ty::ReturnType;
10
11pub(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
151impl 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
446impl Copy for FixupContext {}
447
448impl Clone for FixupContext {
449    fn clone(&self) -> Self {
450        *self
451    }
452}
453
454#[cfg(feature = "full")]
455enum Scan {
456    Fail,
457    Bailout,
458    Consume,
459}
460
461#[cfg(feature = "full")]
462impl Copy for Scan {}
463
464#[cfg(feature = "full")]
465impl Clone for Scan {
466    fn clone(&self) -> Self {
467        *self
468    }
469}
470
471#[cfg(feature = "full")]
472impl PartialEq for Scan {
473    fn eq(&self, other: &Self) -> bool {
474        *self as u8 == *other as u8
475    }
476}
477
478#[cfg(feature = "full")]
479fn 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")]
493fn 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) => {
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) => {
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) => 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::Async(_)
736        | Expr::Await(_)
737        | Expr::Block(_)
738        | Expr::Call(_)
739        | Expr::Cast(_)
740        | Expr::Const(_)
741        | Expr::Continue(_)
742        | Expr::Field(_)
743        | Expr::ForLoop(_)
744        | Expr::Group(_)
745        | Expr::If(_)
746        | Expr::Index(_)
747        | Expr::Infer(_)
748        | Expr::Lit(_)
749        | Expr::Loop(_)
750        | Expr::Macro(_)
751        | Expr::Match(_)
752        | Expr::MethodCall(_)
753        | Expr::Paren(_)
754        | Expr::Path(_)
755        | Expr::Repeat(_)
756        | Expr::Struct(_)
757        | Expr::Try(_)
758        | Expr::TryBlock(_)
759        | Expr::Tuple(_)
760        | Expr::Unsafe(_)
761        | Expr::Verbatim(_)
762        | Expr::While(_) => match fixup.next_operator {
763            Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail,
764            _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => {
765                Scan::Fail
766            }
767            _ => consume_by_precedence,
768        },
769    }
770}