1
Fork 0

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:
Nicholas Nethercote 2024-12-20 10:15:05 +11:00
parent ac8ccf09b4
commit ddcb370bc6
26 changed files with 391 additions and 239 deletions

View file

@ -78,8 +78,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// because AssignOp is only legal for Copy types
// (overloaded ops should be desugared into a call).
let result = unpack!(
block =
this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs)
block = this.build_binary_op(
block,
op.into(),
expr_span,
lhs_ty,
Operand::Copy(lhs),
rhs
)
);
this.cfg.push_assign(block, source_info, lhs, result);

View file

@ -9,7 +9,7 @@ use rustc_middle::hir::place::{
Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
};
use rustc_middle::middle::region;
use rustc_middle::mir::{self, BinOp, BorrowKind, UnOp};
use rustc_middle::mir::{self, AssignOp, BinOp, BorrowKind, UnOp};
use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCoercion,
@ -489,7 +489,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
self.overloaded_operator(expr, Box::new([lhs, rhs]))
} else {
ExprKind::AssignOp {
op: bin_op(op.node),
op: assign_op(op.node),
lhs: self.mirror_expr(lhs),
rhs: self.mirror_expr(rhs),
}
@ -1347,3 +1347,18 @@ fn bin_op(op: hir::BinOpKind) -> BinOp {
_ => bug!("no equivalent for ast binop {:?}", op),
}
}
fn assign_op(op: hir::AssignOpKind) -> AssignOp {
match op {
hir::AssignOpKind::AddAssign => AssignOp::AddAssign,
hir::AssignOpKind::SubAssign => AssignOp::SubAssign,
hir::AssignOpKind::MulAssign => AssignOp::MulAssign,
hir::AssignOpKind::DivAssign => AssignOp::DivAssign,
hir::AssignOpKind::RemAssign => AssignOp::RemAssign,
hir::AssignOpKind::BitXorAssign => AssignOp::BitXorAssign,
hir::AssignOpKind::BitAndAssign => AssignOp::BitAndAssign,
hir::AssignOpKind::BitOrAssign => AssignOp::BitOrAssign,
hir::AssignOpKind::ShlAssign => AssignOp::ShlAssign,
hir::AssignOpKind::ShrAssign => AssignOp::ShrAssign,
}
}