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")]
new_stmt() -> Self185 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")]
new_match_arm() -> Self195 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")]
new_condition() -> Self207 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.
leftmost_subexpression_with_operator( self, expr: &Expr, #[cfg(feature = "full")] next_operator_can_begin_expr: bool, next_operator_can_begin_generics: bool, #[cfg(feature = "full")] precedence: Precedence, ) -> (Precedence, Self)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.
leftmost_subexpression_with_dot(self, expr: &Expr) -> (Precedence, Self)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
leftmost_subexpression_precedence(self, expr: &Expr) -> Precedence287 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.
rightmost_subexpression( self, expr: &Expr, #[cfg(feature = "full")] precedence: Precedence, ) -> (Precedence, Self)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
rightmost_subexpression_fixup( self, #[cfg(feature = "full")] reset_allow_struct: bool, #[cfg(feature = "full")] optional_operand: bool, #[cfg(feature = "full")] precedence: Precedence, ) -> Self327 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
rightmost_subexpression_precedence(self, expr: &Expr) -> Precedence352 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")]
parenthesize(self, expr: &Expr) -> bool379 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.
precedence(self, expr: &Expr) -> Precedence405 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 {
clone(&self) -> Self451 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 {
clone(&self) -> Self468 fn clone(&self) -> Self {
469 *self
470 }
471 }
472
473 #[cfg(feature = "full")]
474 impl PartialEq for Scan {
eq(&self, other: &Self) -> bool475 fn eq(&self, other: &Self) -> bool {
476 *self as u8 == *other as u8
477 }
478 }
479
480 #[cfg(feature = "full")]
scan_left(expr: &Expr, fixup: FixupContext) -> bool481 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")]
scan_right( expr: &Expr, fixup: FixupContext, precedence: Precedence, fail_offset: u8, bailout_offset: u8, ) -> Scan495 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