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")] 185 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")] 195 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")] 207 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. 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. 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 287 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. 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 327 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 352 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")] 379 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. 405 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 { 451 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 { 468 fn clone(&self) -> Self { 469 *self 470 } 471 } 472 473 #[cfg(feature = "full")] 474 impl PartialEq for Scan { 475 fn eq(&self, other: &Self) -> bool { 476 *self as u8 == *other as u8 477 } 478 } 479 480 #[cfg(feature = "full")] 481 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")] 495 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