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