Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
use AssocOp::*;
1use rustc_span::kw;23use crate::ast::{self, AssignOpKind, BinOpKind, RangeLimits};4use crate::token::{self, Token};56/// Associative operator.7#[derive(Copy, Clone, PartialEq, Debug)]8pub enum AssocOp {9 /// A binary op.10 Binary(BinOpKind),11 /// `?=` where ? is one of the assignable BinOps12 AssignOp(AssignOpKind),13 /// `=`14 Assign,15 /// `as`16 Cast,17 /// `..` or `..=` range18 Range(RangeLimits),19}2021#[derive(PartialEq, Debug)]22pub enum Fixity {23 /// The operator is left-associative24 Left,25 /// The operator is right-associative26 Right,27 /// The operator is not associative28 None,29}3031impl AssocOp {32 /// Creates a new AssocOp from a token.33 pub fn from_token(t: &Token) -> Option<AssocOp> {34 use AssocOp::*;35 match t.kind {36 token::Eq => Some(Assign),37 token::Plus => Some(Binary(BinOpKind::Add)),38 token::Minus => Some(Binary(BinOpKind::Sub)),39 token::Star => Some(Binary(BinOpKind::Mul)),40 token::Slash => Some(Binary(BinOpKind::Div)),41 token::Percent => Some(Binary(BinOpKind::Rem)),42 token::Caret => Some(Binary(BinOpKind::BitXor)),43 token::And => Some(Binary(BinOpKind::BitAnd)),44 token::Or => Some(Binary(BinOpKind::BitOr)),45 token::Shl => Some(Binary(BinOpKind::Shl)),46 token::Shr => Some(Binary(BinOpKind::Shr)),47 token::PlusEq => Some(AssignOp(AssignOpKind::AddAssign)),48 token::MinusEq => Some(AssignOp(AssignOpKind::SubAssign)),49 token::StarEq => Some(AssignOp(AssignOpKind::MulAssign)),50 token::SlashEq => Some(AssignOp(AssignOpKind::DivAssign)),51 token::PercentEq => Some(AssignOp(AssignOpKind::RemAssign)),52 token::CaretEq => Some(AssignOp(AssignOpKind::BitXorAssign)),53 token::AndEq => Some(AssignOp(AssignOpKind::BitAndAssign)),54 token::OrEq => Some(AssignOp(AssignOpKind::BitOrAssign)),55 token::ShlEq => Some(AssignOp(AssignOpKind::ShlAssign)),56 token::ShrEq => Some(AssignOp(AssignOpKind::ShrAssign)),57 token::Lt => Some(Binary(BinOpKind::Lt)),58 token::Le => Some(Binary(BinOpKind::Le)),59 token::Ge => Some(Binary(BinOpKind::Ge)),60 token::Gt => Some(Binary(BinOpKind::Gt)),61 token::EqEq => Some(Binary(BinOpKind::Eq)),62 token::Ne => Some(Binary(BinOpKind::Ne)),63 token::AndAnd => Some(Binary(BinOpKind::And)),64 token::OrOr => Some(Binary(BinOpKind::Or)),65 token::DotDot => Some(Range(RangeLimits::HalfOpen)),66 // DotDotDot is no longer supported, but we need some way to display the error67 token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)),68 // `<-` should probably be `< -`69 token::LArrow => Some(Binary(BinOpKind::Lt)),70 _ if t.is_keyword(kw::As) => Some(Cast),71 _ => None,72 }73 }7475 /// Gets the precedence of this operator76 pub fn precedence(&self) -> ExprPrecedence {77 use AssocOp::*;78 match *self {79 Cast => ExprPrecedence::Cast,80 Binary(bin_op) => bin_op.precedence(),81 Range(_) => ExprPrecedence::Range,82 Assign | AssignOp(_) => ExprPrecedence::Assign,83 }84 }8586 /// Gets the fixity of this operator87 pub fn fixity(&self) -> Fixity {88 use AssocOp::*;89 // NOTE: it is a bug to have an operators that has same precedence but different fixities!90 match *self {91 Assign | AssignOp(_) => Fixity::Right,92 Binary(binop) => binop.fixity(),93 Cast => Fixity::Left,94 Range(_) => Fixity::None,95 }96 }9798 pub fn is_comparison(&self) -> bool {99 use AssocOp::*;100 match *self {101 Binary(binop) => binop.is_comparison(),102 Assign | AssignOp(_) | Cast | Range(_) => false,103 }104 }105106 pub fn is_assign_like(&self) -> bool {107 use AssocOp::*;108 match *self {109 Assign | AssignOp(_) => true,110 Cast | Binary(_) | Range(_) => false,111 }112 }113114 /// This operator could be used to follow a block unambiguously.115 ///116 /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with117 /// parentheses while having a high degree of confidence on the correctness of the suggestion.118 pub fn can_continue_expr_unambiguously(&self) -> bool {119 use AssocOp::*;120 use BinOpKind::*;121 matches!(122 self,123 Assign | // `{ 42 } = { 42 }`124 Binary(125 BitXor | // `{ 42 } ^ 3`126 Div | // `{ 42 } / 42`127 Rem | // `{ 42 } % 2`128 Shr | // `{ 42 } >> 2`129 Le | // `{ 42 } <= 3`130 Gt | // `{ 42 } > 3`131 Ge // `{ 42 } >= 3`132 ) |133 AssignOp(_) | // `{ 42 } +=`134 // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect135 // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.136 Cast // `{ 42 } as usize`137 )138 }139}140141#[derive(Clone, Copy, PartialEq, PartialOrd)]142pub enum ExprPrecedence {143 // return, break, yield, closures144 Jump,145 // = += -= *= /= %= &= |= ^= <<= >>=146 Assign,147 // .. ..=148 Range,149 // ||150 LOr,151 // &&152 LAnd,153 // == != < > <= >=154 Compare,155 // |156 BitOr,157 // ^158 BitXor,159 // &160 BitAnd,161 // << >>162 Shift,163 // + -164 Sum,165 // * / %166 Product,167 // as168 Cast,169 // unary - * ! & &mut170 Prefix,171 // paths, loops, function calls, array indexing, field expressions, method calls172 Unambiguous,173}174175/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.176pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {177 ExprPrecedence::LAnd178}179180/// Suppose we have `let _ = e` and the `order` of `e`.181/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?182///183/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.184/// Can we print this as `let _ = a OP b`?185pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {186 order <= prec_let_scrutinee_needs_par()187}188189/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any190/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and191/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.192pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {193 match &value.kind {194 ast::ExprKind::Struct(..) => true,195196 ast::ExprKind::Assign(lhs, rhs, _)197 | ast::ExprKind::AssignOp(_, lhs, rhs)198 | ast::ExprKind::Binary(_, lhs, rhs) => {199 // X { y: 1 } + X { y: 2 }200 contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)201 }202 ast::ExprKind::Await(x, _)203 | ast::ExprKind::Unary(_, x)204 | ast::ExprKind::Cast(x, _)205 | ast::ExprKind::Type(x, _)206 | ast::ExprKind::Field(x, _)207 | ast::ExprKind::Index(x, _, _)208 | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {209 // &X { y: 1 }, X { y: 1 }.y210 contains_exterior_struct_lit(x)211 }212213 ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {214 // X { y: 1 }.bar(...)215 contains_exterior_struct_lit(receiver)216 }217218 _ => false,219 }220}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.