Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7d1e5d0

Browse files
committedMar 16, 2025·
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.
1 parent 99c71d9 commit 7d1e5d0

File tree

26 files changed

+395
-235
lines changed

26 files changed

+395
-235
lines changed
 

‎compiler/rustc_ast/src/ast.rs

+70-1
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,75 @@ impl BinOpKind {
989989

990990
pub type BinOp = Spanned<BinOpKind>;
991991

992+
// Sometimes `BinOpKind` and `AssignOpKind` need the same treatment. The
993+
// operations covered by `AssignOpKind` are a subset of those covered by
994+
// `BinOpKind`, so it makes sense to convert `AssignOpKind` to `BinOpKind`.
995+
impl From<AssignOpKind> for BinOpKind {
996+
fn from(op: AssignOpKind) -> BinOpKind {
997+
match op {
998+
AssignOpKind::AddAssign => BinOpKind::Add,
999+
AssignOpKind::SubAssign => BinOpKind::Sub,
1000+
AssignOpKind::MulAssign => BinOpKind::Mul,
1001+
AssignOpKind::DivAssign => BinOpKind::Div,
1002+
AssignOpKind::RemAssign => BinOpKind::Rem,
1003+
AssignOpKind::BitXorAssign => BinOpKind::BitXor,
1004+
AssignOpKind::BitAndAssign => BinOpKind::BitAnd,
1005+
AssignOpKind::BitOrAssign => BinOpKind::BitOr,
1006+
AssignOpKind::ShlAssign => BinOpKind::Shl,
1007+
AssignOpKind::ShrAssign => BinOpKind::Shr,
1008+
}
1009+
}
1010+
}
1011+
1012+
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1013+
pub enum AssignOpKind {
1014+
/// The `+=` operator (addition)
1015+
AddAssign,
1016+
/// The `-=` operator (subtraction)
1017+
SubAssign,
1018+
/// The `*=` operator (multiplication)
1019+
MulAssign,
1020+
/// The `/=` operator (division)
1021+
DivAssign,
1022+
/// The `%=` operator (modulus)
1023+
RemAssign,
1024+
/// The `^=` operator (bitwise xor)
1025+
BitXorAssign,
1026+
/// The `&=` operator (bitwise and)
1027+
BitAndAssign,
1028+
/// The `|=` operator (bitwise or)
1029+
BitOrAssign,
1030+
/// The `<<=` operator (shift left)
1031+
ShlAssign,
1032+
/// The `>>=` operator (shift right)
1033+
ShrAssign,
1034+
}
1035+
1036+
impl AssignOpKind {
1037+
pub fn as_str(&self) -> &'static str {
1038+
use AssignOpKind::*;
1039+
match self {
1040+
AddAssign => "+=",
1041+
SubAssign => "-=",
1042+
MulAssign => "*=",
1043+
DivAssign => "/=",
1044+
RemAssign => "%=",
1045+
BitXorAssign => "^=",
1046+
BitAndAssign => "&=",
1047+
BitOrAssign => "|=",
1048+
ShlAssign => "<<=",
1049+
ShrAssign => ">>=",
1050+
}
1051+
}
1052+
1053+
/// AssignOps are always by value.
1054+
pub fn is_by_value(self) -> bool {
1055+
true
1056+
}
1057+
}
1058+
1059+
pub type AssignOp = Spanned<AssignOpKind>;
1060+
9921061
/// Unary operator.
9931062
///
9941063
/// Note that `&data` is not an operator, it's an `AddrOf` expression.
@@ -1601,7 +1670,7 @@ pub enum ExprKind {
16011670
/// An assignment with an operator.
16021671
///
16031672
/// E.g., `a += 1`.
1604-
AssignOp(BinOp, P<Expr>, P<Expr>),
1673+
AssignOp(AssignOp, P<Expr>, P<Expr>),
16051674
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
16061675
Field(P<Expr>, Ident),
16071676
/// An indexing operation (e.g., `foo[2]`).

‎compiler/rustc_ast/src/util/parser.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_span::kw;
22

3-
use crate::ast::{self, BinOpKind, RangeLimits};
3+
use crate::ast::{self, AssignOpKind, BinOpKind, RangeLimits};
44
use crate::token::{self, Token};
55

66
/// Associative operator.
@@ -9,7 +9,7 @@ pub enum AssocOp {
99
/// A binary op.
1010
Binary(BinOpKind),
1111
/// `?=` where ? is one of the assignable BinOps
12-
AssignOp(BinOpKind),
12+
AssignOp(AssignOpKind),
1313
/// `=`
1414
Assign,
1515
/// `as`
@@ -44,16 +44,16 @@ impl AssocOp {
4444
token::Or => Some(Binary(BinOpKind::BitOr)),
4545
token::Shl => Some(Binary(BinOpKind::Shl)),
4646
token::Shr => Some(Binary(BinOpKind::Shr)),
47-
token::PlusEq => Some(AssignOp(BinOpKind::Add)),
48-
token::MinusEq => Some(AssignOp(BinOpKind::Sub)),
49-
token::StarEq => Some(AssignOp(BinOpKind::Mul)),
50-
token::SlashEq => Some(AssignOp(BinOpKind::Div)),
51-
token::PercentEq => Some(AssignOp(BinOpKind::Rem)),
52-
token::CaretEq => Some(AssignOp(BinOpKind::BitXor)),
53-
token::AndEq => Some(AssignOp(BinOpKind::BitAnd)),
54-
token::OrEq => Some(AssignOp(BinOpKind::BitOr)),
55-
token::ShlEq => Some(AssignOp(BinOpKind::Shl)),
56-
token::ShrEq => Some(AssignOp(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)),
5757
token::Lt => Some(Binary(BinOpKind::Lt)),
5858
token::Le => Some(Binary(BinOpKind::Le)),
5959
token::Ge => Some(Binary(BinOpKind::Ge)),

‎compiler/rustc_ast_lowering/src/expr.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
274274
}
275275
ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),
276276
ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(
277-
self.lower_binop(*op),
277+
self.lower_assign_op(*op),
278278
self.lower_expr(el),
279279
self.lower_expr(er),
280280
),
@@ -443,6 +443,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
443443
Spanned { node: b.node, span: self.lower_span(b.span) }
444444
}
445445

446+
fn lower_assign_op(&mut self, a: AssignOp) -> AssignOp {
447+
Spanned { node: a.node, span: self.lower_span(a.span) }
448+
}
449+
446450
fn lower_legacy_const_generics(
447451
&mut self,
448452
mut f: Expr,

‎compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,7 @@ impl<'a> State<'a> {
605605
fixup.leftmost_subexpression(),
606606
);
607607
self.space();
608-
self.word(op.node.as_str());
609-
self.word_space("=");
608+
self.word_space(op.node.as_str());
610609
self.print_expr_cond_paren(
611610
rhs,
612611
rhs.precedence() < ExprPrecedence::Assign,

‎compiler/rustc_hir/src/hir.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use rustc_ast::{
1010
LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind,
1111
};
1212
pub use rustc_ast::{
13-
AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity,
14-
ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, MetaItemInner, MetaItemLit, Movability,
15-
Mutability, UnOp,
13+
AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind,
14+
BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto,
15+
MetaItemInner, MetaItemLit, Movability, Mutability, UnOp,
1616
};
1717
use rustc_attr_data_structures::AttributeKind;
1818
use rustc_data_structures::fingerprint::Fingerprint;
@@ -2609,7 +2609,7 @@ pub enum ExprKind<'hir> {
26092609
/// An assignment with an operator.
26102610
///
26112611
/// E.g., `a += 1`.
2612-
AssignOp(BinOp, &'hir Expr<'hir>, &'hir Expr<'hir>),
2612+
AssignOp(AssignOp, &'hir Expr<'hir>, &'hir Expr<'hir>),
26132613
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct or tuple field.
26142614
Field(&'hir Expr<'hir>, Ident),
26152615
/// An indexing operation (`foo[2]`).

‎compiler/rustc_hir_pretty/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1584,8 +1584,7 @@ impl<'a> State<'a> {
15841584
hir::ExprKind::AssignOp(op, lhs, rhs) => {
15851585
self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign);
15861586
self.space();
1587-
self.word(op.node.as_str());
1588-
self.word_space("=");
1587+
self.word_space(op.node.as_str());
15891588
self.print_expr_cond_paren(rhs, rhs.precedence() < ExprPrecedence::Assign);
15901589
}
15911590
hir::ExprKind::Field(expr, ident) => {

‎compiler/rustc_hir_typeck/src/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
512512
self.check_expr_assign(expr, expected, lhs, rhs, span)
513513
}
514514
ExprKind::AssignOp(op, lhs, rhs) => {
515-
self.check_expr_binop_assign(expr, op, lhs, rhs, expected)
515+
self.check_expr_assign_op(expr, op, lhs, rhs, expected)
516516
}
517517
ExprKind::Unary(unop, oprnd) => self.check_expr_unop(unop, oprnd, expected, expr),
518518
ExprKind::AddrOf(kind, mutbl, oprnd) => {

‎compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+16-22
Original file line numberDiff line numberDiff line change
@@ -3478,30 +3478,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
34783478
lhs_ty: Ty<'tcx>,
34793479
rhs_expr: &'tcx hir::Expr<'tcx>,
34803480
lhs_expr: &'tcx hir::Expr<'tcx>,
3481-
op: hir::BinOpKind,
34823481
) {
3483-
match op {
3484-
hir::BinOpKind::Eq => {
3485-
if let Some(partial_eq_def_id) = self.infcx.tcx.lang_items().eq_trait()
3486-
&& self
3487-
.infcx
3488-
.type_implements_trait(partial_eq_def_id, [rhs_ty, lhs_ty], self.param_env)
3489-
.must_apply_modulo_regions()
3490-
{
3491-
let sm = self.tcx.sess.source_map();
3492-
if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_expr.span)
3493-
&& let Ok(lhs_snippet) = sm.span_to_snippet(lhs_expr.span)
3494-
{
3495-
err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`"));
3496-
err.multipart_suggestion(
3497-
"consider swapping the equality",
3498-
vec![(lhs_expr.span, rhs_snippet), (rhs_expr.span, lhs_snippet)],
3499-
Applicability::MaybeIncorrect,
3500-
);
3501-
}
3502-
}
3482+
if let Some(partial_eq_def_id) = self.infcx.tcx.lang_items().eq_trait()
3483+
&& self
3484+
.infcx
3485+
.type_implements_trait(partial_eq_def_id, [rhs_ty, lhs_ty], self.param_env)
3486+
.must_apply_modulo_regions()
3487+
{
3488+
let sm = self.tcx.sess.source_map();
3489+
if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_expr.span)
3490+
&& let Ok(lhs_snippet) = sm.span_to_snippet(lhs_expr.span)
3491+
{
3492+
err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`"));
3493+
err.multipart_suggestion(
3494+
"consider swapping the equality",
3495+
vec![(lhs_expr.span, rhs_snippet), (rhs_expr.span, lhs_snippet)],
3496+
Applicability::MaybeIncorrect,
3497+
);
35033498
}
3504-
_ => {}
35053499
}
35063500
}
35073501
}

‎compiler/rustc_hir_typeck/src/op.rs

+147-139
Large diffs are not rendered by default.

‎compiler/rustc_hir_typeck/src/writeback.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -160,33 +160,35 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
160160
self.typeck_results.node_args_mut().remove(e.hir_id);
161161
}
162162
}
163-
hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => {
163+
hir::ExprKind::Binary(ref op, lhs, rhs) => {
164164
let lhs_ty = self.typeck_results.node_type(lhs.hir_id);
165165
let rhs_ty = self.typeck_results.node_type(rhs.hir_id);
166166

167167
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
168168
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
169169
self.typeck_results.node_args_mut().remove(e.hir_id);
170170

171-
match e.kind {
172-
hir::ExprKind::Binary(..) => {
173-
if !op.node.is_by_value() {
174-
let mut adjustments = self.typeck_results.adjustments_mut();
175-
if let Some(a) = adjustments.get_mut(lhs.hir_id) {
176-
a.pop();
177-
}
178-
if let Some(a) = adjustments.get_mut(rhs.hir_id) {
179-
a.pop();
180-
}
181-
}
171+
if !op.node.is_by_value() {
172+
let mut adjustments = self.typeck_results.adjustments_mut();
173+
if let Some(a) = adjustments.get_mut(lhs.hir_id) {
174+
a.pop();
182175
}
183-
hir::ExprKind::AssignOp(..)
184-
if let Some(a) =
185-
self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
186-
{
176+
if let Some(a) = adjustments.get_mut(rhs.hir_id) {
187177
a.pop();
188178
}
189-
_ => {}
179+
}
180+
}
181+
}
182+
hir::ExprKind::AssignOp(_, lhs, rhs) => {
183+
let lhs_ty = self.typeck_results.node_type(lhs.hir_id);
184+
let rhs_ty = self.typeck_results.node_type(rhs.hir_id);
185+
186+
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
187+
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
188+
self.typeck_results.node_args_mut().remove(e.hir_id);
189+
190+
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) {
191+
a.pop();
190192
}
191193
}
192194
}

‎compiler/rustc_middle/src/mir/syntax.rs

+36
Original file line numberDiff line numberDiff line change
@@ -1612,6 +1612,42 @@ pub enum BinOp {
16121612
Offset,
16131613
}
16141614

1615+
// Assignment operators, e.g. `+=`. See comments on the corresponding variants
1616+
// in `BinOp` for details.
1617+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
1618+
pub enum AssignOp {
1619+
AddAssign,
1620+
SubAssign,
1621+
MulAssign,
1622+
DivAssign,
1623+
RemAssign,
1624+
BitXorAssign,
1625+
BitAndAssign,
1626+
BitOrAssign,
1627+
ShlAssign,
1628+
ShrAssign,
1629+
}
1630+
1631+
// Sometimes `BinOp` and `AssignOp` need the same treatment. The operations
1632+
// covered by `AssignOp` are a subset of those covered by `BinOp`, so it makes
1633+
// sense to convert `AssignOp` to `BinOp`.
1634+
impl From<AssignOp> for BinOp {
1635+
fn from(op: AssignOp) -> BinOp {
1636+
match op {
1637+
AssignOp::AddAssign => BinOp::Add,
1638+
AssignOp::SubAssign => BinOp::Sub,
1639+
AssignOp::MulAssign => BinOp::Mul,
1640+
AssignOp::DivAssign => BinOp::Div,
1641+
AssignOp::RemAssign => BinOp::Rem,
1642+
AssignOp::BitXorAssign => BinOp::BitXor,
1643+
AssignOp::BitAndAssign => BinOp::BitAnd,
1644+
AssignOp::BitOrAssign => BinOp::BitOr,
1645+
AssignOp::ShlAssign => BinOp::Shl,
1646+
AssignOp::ShrAssign => BinOp::Shr,
1647+
}
1648+
}
1649+
}
1650+
16151651
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
16161652
#[cfg(target_pointer_width = "64")]
16171653
mod size_asserts {

‎compiler/rustc_middle/src/thir.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use tracing::instrument;
2727

2828
use crate::middle::region;
2929
use crate::mir::interpret::AllocId;
30-
use crate::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp};
30+
use crate::mir::{self, AssignOp, BinOp, BorrowKind, FakeReadCause, UnOp};
3131
use crate::ty::adjustment::PointerCoercion;
3232
use crate::ty::layout::IntegerExt;
3333
use crate::ty::{
@@ -402,7 +402,7 @@ pub enum ExprKind<'tcx> {
402402
},
403403
/// A *non-overloaded* operation assignment, e.g. `lhs += rhs`.
404404
AssignOp {
405-
op: BinOp,
405+
op: AssignOp,
406406
lhs: ExprId,
407407
rhs: ExprId,
408408
},

‎compiler/rustc_mir_build/src/builder/expr/stmt.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7878
// because AssignOp is only legal for Copy types
7979
// (overloaded ops should be desugared into a call).
8080
let result = unpack!(
81-
block =
82-
this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs)
81+
block = this.build_binary_op(
82+
block,
83+
op.into(),
84+
expr_span,
85+
lhs_ty,
86+
Operand::Copy(lhs),
87+
rhs
88+
)
8389
);
8490
this.cfg.push_assign(block, source_info, lhs, result);
8591

‎compiler/rustc_mir_build/src/thir/cx/expr.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_middle::hir::place::{
99
Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
1010
};
1111
use rustc_middle::middle::region;
12-
use rustc_middle::mir::{self, BinOp, BorrowKind, UnOp};
12+
use rustc_middle::mir::{self, AssignOp, BinOp, BorrowKind, UnOp};
1313
use rustc_middle::thir::*;
1414
use rustc_middle::ty::adjustment::{
1515
Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCoercion,
@@ -489,7 +489,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
489489
self.overloaded_operator(expr, Box::new([lhs, rhs]))
490490
} else {
491491
ExprKind::AssignOp {
492-
op: bin_op(op.node),
492+
op: assign_op(op.node),
493493
lhs: self.mirror_expr(lhs),
494494
rhs: self.mirror_expr(rhs),
495495
}
@@ -1347,3 +1347,18 @@ fn bin_op(op: hir::BinOpKind) -> BinOp {
13471347
_ => bug!("no equivalent for ast binop {:?}", op),
13481348
}
13491349
}
1350+
1351+
fn assign_op(op: hir::AssignOpKind) -> AssignOp {
1352+
match op {
1353+
hir::AssignOpKind::AddAssign => AssignOp::AddAssign,
1354+
hir::AssignOpKind::SubAssign => AssignOp::SubAssign,
1355+
hir::AssignOpKind::MulAssign => AssignOp::MulAssign,
1356+
hir::AssignOpKind::DivAssign => AssignOp::DivAssign,
1357+
hir::AssignOpKind::RemAssign => AssignOp::RemAssign,
1358+
hir::AssignOpKind::BitXorAssign => AssignOp::BitXorAssign,
1359+
hir::AssignOpKind::BitAndAssign => AssignOp::BitAndAssign,
1360+
hir::AssignOpKind::BitOrAssign => AssignOp::BitOrAssign,
1361+
hir::AssignOpKind::ShlAssign => AssignOp::ShlAssign,
1362+
hir::AssignOpKind::ShrAssign => AssignOp::ShrAssign,
1363+
}
1364+
}

‎compiler/rustc_parse/src/parser/expr.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ use rustc_ast::util::classify;
1414
use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
1515
use rustc_ast::visit::{Visitor, walk_expr};
1616
use rustc_ast::{
17-
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
18-
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
19-
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
17+
self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
18+
BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
19+
FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind,
20+
UnOp, UnsafeBinderCastKind,
2021
};
2122
use rustc_ast_pretty::pprust;
2223
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -359,7 +360,7 @@ impl<'a> Parser<'a> {
359360
(
360361
Some(
361362
AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
362-
| AssocOp::AssignOp(BinOpKind::Shr),
363+
| AssocOp::AssignOp(AssignOpKind::ShrAssign),
363364
),
364365
_,
365366
) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
@@ -3795,8 +3796,8 @@ impl<'a> Parser<'a> {
37953796
self.dcx().emit_err(errors::LeftArrowOperator { span });
37963797
}
37973798

3798-
fn mk_assign_op(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
3799-
ExprKind::AssignOp(binop, lhs, rhs)
3799+
fn mk_assign_op(&self, assign_op: AssignOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
3800+
ExprKind::AssignOp(assign_op, lhs, rhs)
38003801
}
38013802

38023803
fn mk_range(

‎src/tools/clippy/clippy_lints/src/format_push_string.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::higher;
33
use clippy_utils::ty::is_type_lang_item;
4-
use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
4+
use rustc_hir::{AssignOpKind, Expr, ExprKind, LangItem, MatchSource};
55
use rustc_lint::{LateContext, LateLintPass};
66
use rustc_session::declare_lint_pass;
77
use rustc_span::sym;
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
7777
return;
7878
}
7979
},
80-
ExprKind::AssignOp(op, left, arg) if op.node == BinOpKind::Add && is_string(cx, left) => arg,
80+
ExprKind::AssignOp(op, left, arg) if op.node == AssignOpKind::AddAssign && is_string(cx, left) => arg,
8181
_ => return,
8282
};
8383
if is_format(cx, arg) {

‎src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use clippy_utils::source::snippet_with_context;
55
use rustc_ast::ast::{LitIntType, LitKind};
66
use rustc_data_structures::packed::Pu128;
77
use rustc_errors::Applicability;
8-
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
8+
use rustc_hir::{AssignOpKind, BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::ty::{IntTy, Ty, UintTy};
1111
use rustc_session::declare_lint_pass;
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
6868
&& ex.span.ctxt() == ctxt
6969
&& expr1.span.ctxt() == ctxt
7070
&& clippy_utils::SpanlessEq::new(cx).eq_expr(l, target)
71-
&& BinOpKind::Add == op1.node
71+
&& AssignOpKind::AddAssign == op1.node
7272
&& let ExprKind::Lit(lit) = value.kind
7373
&& let LitKind::Int(Pu128(1), LitIntType::Unsuffixed) = lit.node
7474
&& block.expr.is_none()

‎src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use clippy_utils::{
88
use rustc_ast::ast::LitKind;
99
use rustc_data_structures::packed::Pu128;
1010
use rustc_errors::Applicability;
11-
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, HirId, QPath};
11+
use rustc_hir::{AssignOpKind, BinOp, BinOpKind, Expr, ExprKind, HirId, QPath};
1212
use rustc_lint::{LateContext, LateLintPass};
1313
use rustc_session::impl_lint_pass;
1414
use rustc_span::Span;
@@ -379,7 +379,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp
379379
match peel_blocks_with_stmt(expr).kind {
380380
ExprKind::AssignOp(ref op1, target, value) => {
381381
// Check if literal being subtracted is one
382-
(BinOpKind::Sub == op1.node && is_integer_literal(value, 1)).then_some(target)
382+
(AssignOpKind::SubAssign == op1.node && is_integer_literal(value, 1)).then_some(target)
383383
},
384384
ExprKind::Assign(target, value, _) => {
385385
if let ExprKind::Binary(ref op1, left1, right1) = value.kind

‎src/tools/clippy/clippy_lints/src/loops/utils.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_loc
33
use rustc_ast::ast::{LitIntType, LitKind};
44
use rustc_errors::Applicability;
55
use rustc_hir::intravisit::{Visitor, walk_expr, walk_local};
6-
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind};
6+
use rustc_hir::{
7+
AssignOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind
8+
};
79
use rustc_lint::LateContext;
810
use rustc_middle::hir::nested_filter;
911
use rustc_middle::ty::{self, Ty};
@@ -58,7 +60,7 @@ impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
5860
match parent.kind {
5961
ExprKind::AssignOp(op, lhs, rhs) => {
6062
if lhs.hir_id == expr.hir_id {
61-
*state = if op.node == BinOpKind::Add
63+
*state = if op.node == AssignOpKind::AddAssign
6264
&& is_integer_const(self.cx, rhs, 1)
6365
&& *state == IncrementVisitorVarState::Initial
6466
&& self.depth == 0

‎src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,11 @@ fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> St
261261
| ExprKind::Assign(..)
262262
| ExprKind::Index(..)
263263
| ExprKind::Repeat(_, _)
264-
| ExprKind::Struct(_, _, _) => {
264+
| ExprKind::Struct(_, _, _)
265+
| ExprKind::AssignOp(_, _, _) => {
265266
walk_expr(vis, expr);
266267
},
267-
ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
268+
ExprKind::Binary(op, _, _) => {
268269
if op.node == BinOpKind::And || op.node == BinOpKind::Or {
269270
// x && y and x || y always evaluate x first, so these are
270271
// strictly sequenced.

‎src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,12 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
335335
return;
336336
}
337337
match &expr.kind {
338-
hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => {
338+
hir::ExprKind::Binary(op, lhs, rhs) => {
339339
self.manage_bin_ops(cx, expr, op.node, lhs, rhs);
340340
},
341+
hir::ExprKind::AssignOp(op, lhs, rhs) => {
342+
self.manage_bin_ops(cx, expr, op.node.into(), lhs, rhs);
343+
},
341344
hir::ExprKind::MethodCall(ps, receiver, args, _) => {
342345
self.manage_method_call(args, cx, expr, ps, receiver);
343346
},

‎src/tools/clippy/clippy_lints/src/operators/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -945,9 +945,10 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
945945
);
946946
},
947947
ExprKind::AssignOp(op, lhs, rhs) => {
948-
self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
949-
misrefactored_assign_op::check(cx, e, op.node, lhs, rhs);
950-
modulo_arithmetic::check(cx, e, op.node, lhs, rhs, false);
948+
let bin_op = op.node.into();
949+
self.arithmetic_context.check_binary(cx, e, bin_op, lhs, rhs);
950+
misrefactored_assign_op::check(cx, e, bin_op, lhs, rhs);
951+
modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false);
951952
},
952953
ExprKind::Assign(lhs, rhs, _) => {
953954
assign_op_pattern::check(cx, e, lhs, rhs);

‎src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use core::ops::ControlFlow;
55
use rustc_hir as hir;
66
use rustc_lint::{LateContext, LateLintPass};
77
use rustc_session::declare_lint_pass;
8+
use rustc_span::Span;
89

910
declare_clippy_lint! {
1011
/// ### What it does
@@ -56,8 +57,27 @@ declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_
5657

5758
impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
5859
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
59-
if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind
60-
&& let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node)
60+
match expr.kind {
61+
hir::ExprKind::Binary(op, _, _) => {
62+
self.check_expr_inner(cx, expr, op.node, op.span);
63+
}
64+
hir::ExprKind::AssignOp(op, _, _) => {
65+
self.check_expr_inner(cx, expr, op.node.into(), op.span);
66+
}
67+
_ => {}
68+
}
69+
}
70+
}
71+
72+
impl<'tcx> SuspiciousImpl {
73+
fn check_expr_inner(
74+
&mut self,
75+
cx: &LateContext<'tcx>,
76+
expr: &'tcx hir::Expr<'_>,
77+
binop: hir::BinOpKind,
78+
span: Span,
79+
) {
80+
if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop)
6181
&& let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang)
6282
&& let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang)
6383

@@ -82,10 +102,10 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
82102
span_lint(
83103
cx,
84104
lint,
85-
binop.span,
105+
span,
86106
format!(
87107
"suspicious use of `{}` in `{}` impl",
88-
binop.node.as_str(),
108+
binop.as_str(),
89109
cx.tcx.item_name(trait_id)
90110
),
91111
);

‎src/tools/clippy/clippy_lints/src/swap.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxIndexSet;
1010
use rustc_hir::intravisit::{Visitor, walk_expr};
1111

1212
use rustc_errors::Applicability;
13-
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind};
13+
use rustc_hir::{AssignOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind};
1414
use rustc_lint::{LateContext, LateLintPass, LintContext};
1515
use rustc_middle::ty;
1616
use rustc_session::declare_lint_pass;
@@ -307,7 +307,7 @@ fn extract_sides_of_xor_assign<'a, 'hir>(
307307
if let StmtKind::Semi(expr) = stmt.kind
308308
&& let ExprKind::AssignOp(
309309
Spanned {
310-
node: BinOpKind::BitXor,
310+
node: AssignOpKind::BitXorAssign,
311311
..
312312
},
313313
lhs,

‎src/tools/clippy/clippy_utils/src/sugg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
357357
match op {
358358
AssocOp::Binary(op) => format!("{lhs} {} {rhs}", op.as_str()),
359359
AssocOp::Assign => format!("{lhs} = {rhs}"),
360-
AssocOp::AssignOp(op) => format!("{lhs} {}= {rhs}", op.as_str()),
360+
AssocOp::AssignOp(op) => format!("{lhs} {} {rhs}", op.as_str()),
361361
AssocOp::Cast => format!("{lhs} as {rhs}"),
362362
AssocOp::Range(limits) => format!("{lhs}{}{rhs}", limits.as_str()),
363363
}

‎src/tools/rustfmt/src/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2057,7 +2057,7 @@ fn rewrite_assignment(
20572057
context: &RewriteContext<'_>,
20582058
lhs: &ast::Expr,
20592059
rhs: &ast::Expr,
2060-
op: Option<&ast::BinOp>,
2060+
op: Option<&ast::AssignOp>,
20612061
shape: Shape,
20622062
) -> RewriteResult {
20632063
let operator_str = match op {

0 commit comments

Comments
 (0)
Please sign in to comment.