Tighten up assignment operator representations.
In the AST, currently we use `BinOpKind` within `ExprKind::AssignOp` and `AssocOp::AssignOp`, even though this allows some nonsensical combinations. E.g. there is no `&&=` operator. Likewise for HIR and THIR. This commit introduces `AssignOpKind` which only includes the ten assignable operators, and uses it in `ExprKind::AssignOp` and `AssocOp::AssignOp`. (And does similar things for `hir::ExprKind` and `thir::ExprKind`.) This avoids the possibility of nonsensical combinations, as seen by the removal of the `bug!` case in `lang_item_for_binop`. The commit is mostly plumbing, including: - Adds an `impl From<AssignOpKind> for BinOpKind` (AST) and `impl From<AssignOp> for BinOp` (MIR/THIR). - `BinOpCategory` can now be created from both `BinOpKind` and `AssignOpKind`. - Replaces the `IsAssign` type with `Op`, which has more information and a few methods. - `suggest_swapping_lhs_and_rhs`: moves the condition to the call site, it's easier that way. - `check_expr_inner`: had to factor out some code into a separate method. I'm on the fence about whether avoiding the nonsensical combinations is worth the extra code.
This commit is contained in:
parent
ac8ccf09b4
commit
ddcb370bc6
26 changed files with 391 additions and 239 deletions
|
@ -981,6 +981,75 @@ impl BinOpKind {
|
|||
|
||||
pub type BinOp = Spanned<BinOpKind>;
|
||||
|
||||
// Sometimes `BinOpKind` and `AssignOpKind` need the same treatment. The
|
||||
// operations covered by `AssignOpKind` are a subset of those covered by
|
||||
// `BinOpKind`, so it makes sense to convert `AssignOpKind` to `BinOpKind`.
|
||||
impl From<AssignOpKind> for BinOpKind {
|
||||
fn from(op: AssignOpKind) -> BinOpKind {
|
||||
match op {
|
||||
AssignOpKind::AddAssign => BinOpKind::Add,
|
||||
AssignOpKind::SubAssign => BinOpKind::Sub,
|
||||
AssignOpKind::MulAssign => BinOpKind::Mul,
|
||||
AssignOpKind::DivAssign => BinOpKind::Div,
|
||||
AssignOpKind::RemAssign => BinOpKind::Rem,
|
||||
AssignOpKind::BitXorAssign => BinOpKind::BitXor,
|
||||
AssignOpKind::BitAndAssign => BinOpKind::BitAnd,
|
||||
AssignOpKind::BitOrAssign => BinOpKind::BitOr,
|
||||
AssignOpKind::ShlAssign => BinOpKind::Shl,
|
||||
AssignOpKind::ShrAssign => BinOpKind::Shr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum AssignOpKind {
|
||||
/// The `+=` operator (addition)
|
||||
AddAssign,
|
||||
/// The `-=` operator (subtraction)
|
||||
SubAssign,
|
||||
/// The `*=` operator (multiplication)
|
||||
MulAssign,
|
||||
/// The `/=` operator (division)
|
||||
DivAssign,
|
||||
/// The `%=` operator (modulus)
|
||||
RemAssign,
|
||||
/// The `^=` operator (bitwise xor)
|
||||
BitXorAssign,
|
||||
/// The `&=` operator (bitwise and)
|
||||
BitAndAssign,
|
||||
/// The `|=` operator (bitwise or)
|
||||
BitOrAssign,
|
||||
/// The `<<=` operator (shift left)
|
||||
ShlAssign,
|
||||
/// The `>>=` operator (shift right)
|
||||
ShrAssign,
|
||||
}
|
||||
|
||||
impl AssignOpKind {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
use AssignOpKind::*;
|
||||
match self {
|
||||
AddAssign => "+=",
|
||||
SubAssign => "-=",
|
||||
MulAssign => "*=",
|
||||
DivAssign => "/=",
|
||||
RemAssign => "%=",
|
||||
BitXorAssign => "^=",
|
||||
BitAndAssign => "&=",
|
||||
BitOrAssign => "|=",
|
||||
ShlAssign => "<<=",
|
||||
ShrAssign => ">>=",
|
||||
}
|
||||
}
|
||||
|
||||
/// AssignOps are always by value.
|
||||
pub fn is_by_value(self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub type AssignOp = Spanned<AssignOpKind>;
|
||||
|
||||
/// Unary operator.
|
||||
///
|
||||
/// Note that `&data` is not an operator, it's an `AddrOf` expression.
|
||||
|
@ -1593,7 +1662,7 @@ pub enum ExprKind {
|
|||
/// An assignment with an operator.
|
||||
///
|
||||
/// E.g., `a += 1`.
|
||||
AssignOp(BinOp, P<Expr>, P<Expr>),
|
||||
AssignOp(AssignOp, P<Expr>, P<Expr>),
|
||||
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
|
||||
Field(P<Expr>, Ident),
|
||||
/// An indexing operation (e.g., `foo[2]`).
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_span::kw;
|
||||
|
||||
use crate::ast::{self, BinOpKind, RangeLimits};
|
||||
use crate::ast::{self, AssignOpKind, BinOpKind, RangeLimits};
|
||||
use crate::token::{self, Token};
|
||||
|
||||
/// Associative operator.
|
||||
|
@ -9,7 +9,7 @@ pub enum AssocOp {
|
|||
/// A binary op.
|
||||
Binary(BinOpKind),
|
||||
/// `?=` where ? is one of the assignable BinOps
|
||||
AssignOp(BinOpKind),
|
||||
AssignOp(AssignOpKind),
|
||||
/// `=`
|
||||
Assign,
|
||||
/// `as`
|
||||
|
@ -44,16 +44,16 @@ impl AssocOp {
|
|||
token::Or => Some(Binary(BinOpKind::BitOr)),
|
||||
token::Shl => Some(Binary(BinOpKind::Shl)),
|
||||
token::Shr => Some(Binary(BinOpKind::Shr)),
|
||||
token::PlusEq => Some(AssignOp(BinOpKind::Add)),
|
||||
token::MinusEq => Some(AssignOp(BinOpKind::Sub)),
|
||||
token::StarEq => Some(AssignOp(BinOpKind::Mul)),
|
||||
token::SlashEq => Some(AssignOp(BinOpKind::Div)),
|
||||
token::PercentEq => Some(AssignOp(BinOpKind::Rem)),
|
||||
token::CaretEq => Some(AssignOp(BinOpKind::BitXor)),
|
||||
token::AndEq => Some(AssignOp(BinOpKind::BitAnd)),
|
||||
token::OrEq => Some(AssignOp(BinOpKind::BitOr)),
|
||||
token::ShlEq => Some(AssignOp(BinOpKind::Shl)),
|
||||
token::ShrEq => Some(AssignOp(BinOpKind::Shr)),
|
||||
token::PlusEq => Some(AssignOp(AssignOpKind::AddAssign)),
|
||||
token::MinusEq => Some(AssignOp(AssignOpKind::SubAssign)),
|
||||
token::StarEq => Some(AssignOp(AssignOpKind::MulAssign)),
|
||||
token::SlashEq => Some(AssignOp(AssignOpKind::DivAssign)),
|
||||
token::PercentEq => Some(AssignOp(AssignOpKind::RemAssign)),
|
||||
token::CaretEq => Some(AssignOp(AssignOpKind::BitXorAssign)),
|
||||
token::AndEq => Some(AssignOp(AssignOpKind::BitAndAssign)),
|
||||
token::OrEq => Some(AssignOp(AssignOpKind::BitOrAssign)),
|
||||
token::ShlEq => Some(AssignOp(AssignOpKind::ShlAssign)),
|
||||
token::ShrEq => Some(AssignOp(AssignOpKind::ShrAssign)),
|
||||
token::Lt => Some(Binary(BinOpKind::Lt)),
|
||||
token::Le => Some(Binary(BinOpKind::Le)),
|
||||
token::Ge => Some(Binary(BinOpKind::Ge)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue