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: &ExprBinary) => match Precedence::of_binop(&e.op) {
483 Precedence::Assign => fixup.previous_operator <= Precedence::Assign,
484 binop_prec: Precedence => fixup.previous_operator < binop_prec,
485 },
486 Expr::Cast(_) => fixup.previous_operator < Precedence::Cast,
487 Expr::Range(e: &ExprRange) => 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}
771