Use BinOpKind instead of BinOp for function args where possible.

Because it's nice to avoid passing in unnecessary data.
This commit is contained in:
Nicholas Nethercote 2024-12-20 08:33:43 +11:00
parent 076cccd412
commit ac8ccf09b4
7 changed files with 77 additions and 78 deletions

View file

@ -274,22 +274,22 @@ impl<'a> State<'a> {
fn print_expr_binary(
&mut self,
op: ast::BinOp,
op: ast::BinOpKind,
lhs: &ast::Expr,
rhs: &ast::Expr,
fixup: FixupContext,
) {
let binop_prec = op.node.precedence();
let binop_prec = op.precedence();
let left_prec = lhs.precedence();
let right_prec = rhs.precedence();
let (mut left_needs_paren, right_needs_paren) = match op.node.fixity() {
let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
};
match (&lhs.kind, op.node) {
match (&lhs.kind, op) {
// These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
// the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
@ -312,7 +312,7 @@ impl<'a> State<'a> {
self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
self.space();
self.word_space(op.node.as_str());
self.word_space(op.as_str());
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
}
@ -410,7 +410,7 @@ impl<'a> State<'a> {
self.print_expr_method_call(seg, receiver, args, fixup);
}
ast::ExprKind::Binary(op, lhs, rhs) => {
self.print_expr_binary(*op, lhs, rhs, fixup);
self.print_expr_binary(op.node, lhs, rhs, fixup);
}
ast::ExprKind::Unary(op, expr) => {
self.print_expr_unary(*op, expr, fixup);

View file

@ -1271,18 +1271,18 @@ impl<'a> State<'a> {
self.print_call_post(base_args)
}
fn print_expr_binary(&mut self, op: hir::BinOp, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) {
let binop_prec = op.node.precedence();
fn print_expr_binary(&mut self, op: hir::BinOpKind, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) {
let binop_prec = op.precedence();
let left_prec = lhs.precedence();
let right_prec = rhs.precedence();
let (mut left_needs_paren, right_needs_paren) = match op.node.fixity() {
let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
};
match (&lhs.kind, op.node) {
match (&lhs.kind, op) {
// These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
// the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
@ -1297,7 +1297,7 @@ impl<'a> State<'a> {
self.print_expr_cond_paren(lhs, left_needs_paren);
self.space();
self.word_space(op.node.as_str());
self.word_space(op.as_str());
self.print_expr_cond_paren(rhs, right_needs_paren);
}
@ -1451,7 +1451,7 @@ impl<'a> State<'a> {
self.word(".use");
}
hir::ExprKind::Binary(op, lhs, rhs) => {
self.print_expr_binary(op, lhs, rhs);
self.print_expr_binary(op.node, lhs, rhs);
}
hir::ExprKind::Unary(op, expr) => {
self.print_expr_unary(op, expr);

View file

@ -3477,9 +3477,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lhs_ty: Ty<'tcx>,
rhs_expr: &'tcx hir::Expr<'tcx>,
lhs_expr: &'tcx hir::Expr<'tcx>,
op: hir::BinOp,
op: hir::BinOpKind,
) {
match op.node {
match op {
hir::BinOpKind::Eq => {
if let Some(partial_eq_def_id) = self.infcx.tcx.lang_items().eq_trait()
&& self

View file

@ -35,13 +35,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (lhs_ty, rhs_ty, return_ty) =
self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes, expected);
let ty =
if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
self.enforce_builtin_binop_types(lhs.span, lhs_ty, rhs.span, rhs_ty, op);
self.tcx.types.unit
} else {
return_ty
};
let ty = if !lhs_ty.is_ty_var()
&& !rhs_ty.is_ty_var()
&& is_builtin_binop(lhs_ty, rhs_ty, op.node)
{
self.enforce_builtin_binop_types(lhs.span, lhs_ty, rhs.span, rhs_ty, op.node);
self.tcx.types.unit
} else {
return_ty
};
self.check_lhs_assignable(lhs, E0067, op.span, |err| {
if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
@ -49,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.lookup_op_method(
(lhs, lhs_deref_ty),
Some((rhs, rhs_ty)),
lang_item_for_binop(self.tcx, op, IsAssign::Yes),
lang_item_for_binop(self.tcx, op.node, IsAssign::Yes),
op.span,
expected,
)
@ -61,7 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.lookup_op_method(
(lhs, lhs_ty),
Some((rhs, rhs_ty)),
lang_item_for_binop(self.tcx, op, IsAssign::Yes),
lang_item_for_binop(self.tcx, op.node, IsAssign::Yes),
op.span,
expected,
)
@ -100,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr.hir_id, expr, op, lhs_expr, rhs_expr
);
match BinOpCategory::from(op) {
match BinOpCategory::from(op.node) {
BinOpCategory::Shortcircuit => {
// && and || are a simple case.
self.check_expr_coercible_to_type(lhs_expr, tcx.types.bool, None);
@ -139,14 +141,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// can't pin this down to a specific impl.
if !lhs_ty.is_ty_var()
&& !rhs_ty.is_ty_var()
&& is_builtin_binop(lhs_ty, rhs_ty, op)
&& is_builtin_binop(lhs_ty, rhs_ty, op.node)
{
let builtin_return_ty = self.enforce_builtin_binop_types(
lhs_expr.span,
lhs_ty,
rhs_expr.span,
rhs_ty,
op,
op.node,
);
self.demand_eqtype(expr.span, builtin_return_ty, return_ty);
builtin_return_ty
@ -163,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lhs_ty: Ty<'tcx>,
rhs_span: Span,
rhs_ty: Ty<'tcx>,
op: hir::BinOp,
op: hir::BinOpKind,
) -> Ty<'tcx> {
debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op));
@ -244,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let result = self.lookup_op_method(
(lhs_expr, lhs_ty),
Some((rhs_expr, rhs_ty_var)),
lang_item_for_binop(self.tcx, op, is_assign),
lang_item_for_binop(self.tcx, op.node, is_assign),
op.span,
expected,
);
@ -255,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rhs_ty_var,
Some(lhs_expr),
|err, ty| {
self.suggest_swapping_lhs_and_rhs(err, ty, lhs_ty, rhs_expr, lhs_expr, op);
self.suggest_swapping_lhs_and_rhs(err, ty, lhs_ty, rhs_expr, lhs_expr, op.node);
},
);
let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
@ -304,7 +306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ty::new_misc_error(self.tcx)
}
Err(errors) => {
let (_, trait_def_id) = lang_item_for_binop(self.tcx, op, is_assign);
let (_, trait_def_id) = lang_item_for_binop(self.tcx, op.node, is_assign);
let missing_trait = trait_def_id
.map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id)));
let mut path = None;
@ -411,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.lookup_op_method(
(lhs_expr, lhs_deref_ty),
Some((rhs_expr, rhs_ty)),
lang_item_for_binop(self.tcx, op, is_assign),
lang_item_for_binop(self.tcx, op.node, is_assign),
op.span,
expected,
)
@ -445,7 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.lookup_op_method(
(lhs_expr, lhs_adjusted_ty),
Some((rhs_expr, rhs_adjusted_ty)),
lang_item_for_binop(self.tcx, op, is_assign),
lang_item_for_binop(self.tcx, op.node, is_assign),
op.span,
expected,
)
@ -503,7 +505,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.lookup_op_method(
(lhs_expr, lhs_ty),
Some((rhs_expr, rhs_ty)),
lang_item_for_binop(self.tcx, op, is_assign),
lang_item_for_binop(self.tcx, op.node, is_assign),
op.span,
expected,
)
@ -597,7 +599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.lookup_op_method(
(lhs_expr, lhs_ty),
Some((rhs_expr, rhs_ty)),
lang_item_for_binop(self.tcx, op, is_assign),
lang_item_for_binop(self.tcx, op.node, is_assign),
op.span,
expected,
)
@ -991,12 +993,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn lang_item_for_binop(
tcx: TyCtxt<'_>,
op: hir::BinOp,
op: hir::BinOpKind,
is_assign: IsAssign,
) -> (Symbol, Option<hir::def_id::DefId>) {
let lang = tcx.lang_items();
if is_assign == IsAssign::Yes {
match op.node {
match op {
hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()),
hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()),
hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()),
@ -1015,11 +1017,11 @@ fn lang_item_for_binop(
| hir::BinOpKind::Ne
| hir::BinOpKind::And
| hir::BinOpKind::Or => {
bug!("impossible assignment operation: {}=", op.node.as_str())
bug!("impossible assignment operation: {}=", op.as_str())
}
}
} else {
match op.node {
match op {
hir::BinOpKind::Add => (sym::add, lang.add_trait()),
hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()),
hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()),
@ -1076,8 +1078,8 @@ enum BinOpCategory {
}
impl BinOpCategory {
fn from(op: hir::BinOp) -> BinOpCategory {
match op.node {
fn from(op: hir::BinOpKind) -> BinOpCategory {
match op {
hir::BinOpKind::Shl | hir::BinOpKind::Shr => BinOpCategory::Shift,
hir::BinOpKind::Add
@ -1133,7 +1135,7 @@ fn deref_ty_if_possible(ty: Ty<'_>) -> Ty<'_> {
/// Reason #2 is the killer. I tried for a while to always use
/// overloaded logic and just check the types in constants/codegen after
/// the fact, and it worked fine, except for SIMD types. -nmatsakis
fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool {
fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOpKind) -> bool {
// Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work.
// (See https://github.com/rust-lang/rust/issues/57447.)
let (lhs, rhs) = (deref_ty_if_possible(lhs), deref_ty_if_possible(rhs));

View file

@ -14,7 +14,7 @@ use rustc_middle::ty::{
};
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
use rustc_span::def_id::LocalDefId;
use rustc_span::{Span, Symbol, source_map, sym};
use rustc_span::{Span, Symbol, sym};
use tracing::debug;
use {rustc_ast as ast, rustc_hir as hir};
@ -223,7 +223,7 @@ impl TypeLimits {
fn lint_nan<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx hir::Expr<'tcx>,
binop: hir::BinOp,
binop: hir::BinOpKind,
l: &'tcx hir::Expr<'tcx>,
r: &'tcx hir::Expr<'tcx>,
) {
@ -262,19 +262,19 @@ fn lint_nan<'tcx>(
InvalidNanComparisons::EqNe { suggestion }
}
let lint = match binop.node {
let lint = match binop {
hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => {
eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
nan_plus_binop: l_span.until(r_span),
float: r_span.shrink_to_hi(),
neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()),
neg: (binop == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()),
})
}
hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => {
eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
nan_plus_binop: l_span.shrink_to_hi().to(r_span),
float: l_span.shrink_to_hi(),
neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()),
neg: (binop == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()),
})
}
hir::BinOpKind::Lt | hir::BinOpKind::Le | hir::BinOpKind::Gt | hir::BinOpKind::Ge
@ -560,11 +560,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
}
}
hir::ExprKind::Binary(binop, ref l, ref r) => {
if is_comparison(binop) {
if !check_limits(cx, binop, l, r) {
if is_comparison(binop.node) {
if !check_limits(cx, binop.node, l, r) {
cx.emit_span_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
} else {
lint_nan(cx, e, binop, l, r);
lint_nan(cx, e, binop.node, l, r);
let cmpop = ComparisonOp::BinOp(binop.node);
lint_wide_pointer(cx, e, cmpop, l, r);
lint_fn_pointer(cx, e, cmpop, l, r);
@ -591,8 +591,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
_ => {}
};
fn is_valid<T: PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
match binop.node {
fn is_valid<T: PartialOrd>(binop: hir::BinOpKind, v: T, min: T, max: T) -> bool {
match binop {
hir::BinOpKind::Lt => v > min && v <= max,
hir::BinOpKind::Le => v >= min && v < max,
hir::BinOpKind::Gt => v >= min && v < max,
@ -602,22 +602,19 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
}
}
fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
source_map::respan(
binop.span,
match binop.node {
hir::BinOpKind::Lt => hir::BinOpKind::Gt,
hir::BinOpKind::Le => hir::BinOpKind::Ge,
hir::BinOpKind::Gt => hir::BinOpKind::Lt,
hir::BinOpKind::Ge => hir::BinOpKind::Le,
_ => return binop,
},
)
fn rev_binop(binop: hir::BinOpKind) -> hir::BinOpKind {
match binop {
hir::BinOpKind::Lt => hir::BinOpKind::Gt,
hir::BinOpKind::Le => hir::BinOpKind::Ge,
hir::BinOpKind::Gt => hir::BinOpKind::Lt,
hir::BinOpKind::Ge => hir::BinOpKind::Le,
_ => binop,
}
}
fn check_limits(
cx: &LateContext<'_>,
binop: hir::BinOp,
binop: hir::BinOpKind,
l: &hir::Expr<'_>,
r: &hir::Expr<'_>,
) -> bool {
@ -659,9 +656,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
}
}
fn is_comparison(binop: hir::BinOp) -> bool {
fn is_comparison(binop: hir::BinOpKind) -> bool {
matches!(
binop.node,
binop,
hir::BinOpKind::Eq
| hir::BinOpKind::Lt
| hir::BinOpKind::Le

View file

@ -10,7 +10,7 @@ use rustc_ast::{LitKind, RangeLimits};
use rustc_data_structures::packed::Pu128;
use rustc_data_structures::unhash::UnindexMap;
use rustc_errors::{Applicability, Diag};
use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp};
use rustc_hir::{BinOpKind, Block, Body, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
@ -97,7 +97,7 @@ enum LengthComparison {
///
/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, v.len()))`
fn len_comparison<'hir>(
bin_op: BinOp,
bin_op: BinOpKind,
left: &'hir Expr<'hir>,
right: &'hir Expr<'hir>,
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
@ -112,7 +112,7 @@ fn len_comparison<'hir>(
// normalize comparison, `v.len() > 4` becomes `4 < v.len()`
// this simplifies the logic a bit
let (op, left, right) = normalize_comparison(bin_op.node, left, right)?;
let (op, left, right) = normalize_comparison(bin_op, left, right)?;
match (op, left.kind, right.kind) {
(Rel::Lt, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanLength, left as usize, right)),
(Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, right as usize, left)),
@ -138,7 +138,7 @@ fn assert_len_expr<'hir>(
&& let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
&& let ExprKind::Binary(bin_op, left, right) = &condition.kind
&& let Some((cmp, asserted_len, slice_len)) = len_comparison(*bin_op, left, right)
&& let Some((cmp, asserted_len, slice_len)) = len_comparison(bin_op.node, left, right)
&& let ExprKind::MethodCall(method, recv, [], _) = &slice_len.kind
&& cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
&& method.ident.name == sym::len

View file

@ -15,7 +15,7 @@ use rustc_apfloat::ieee::{Half, Quad};
use rustc_ast::ast::{self, LitFloatType, LitKind};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{
BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, PatExpr, PatExprKind, QPath, UnOp,
BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, PatExpr, PatExprKind, QPath, UnOp,
};
use rustc_lexer::tokenize;
use rustc_lint::LateContext;
@ -506,7 +506,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
}),
ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
ExprKind::Binary(op, left, right) => self.binop(op, left, right),
ExprKind::Binary(op, left, right) => self.binop(op.node, left, right),
ExprKind::Call(callee, []) => {
// We only handle a few const functions for now.
if let ExprKind::Path(qpath) = &callee.kind
@ -744,7 +744,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
}
}
fn binop(&self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
fn binop(&self, op: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
let l = self.expr(left)?;
let r = self.expr(right);
match (l, r) {
@ -757,7 +757,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
// Using / or %, where the left-hand argument is the smallest integer of a signed integer type and
// the right-hand argument is -1 always panics, even with overflow-checks disabled
if let BinOpKind::Div | BinOpKind::Rem = op.node
if let BinOpKind::Div | BinOpKind::Rem = op
&& l == ty_min_value
&& r == -1
{
@ -765,7 +765,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
}
let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
match op.node {
match op {
// When +, * or binary - create a value greater than the maximum value, or less than
// the minimum value that can be stored, it panics.
BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(zext),
@ -792,7 +792,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
ty::Uint(ity) => {
let bits = ity.bits();
match op.node {
match op {
BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
BinOpKind::Sub => l.checked_sub(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
BinOpKind::Mul => l.checked_mul(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
@ -815,7 +815,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
_ => None,
},
// FIXME(f16_f128): add these types when binary operations are available on all platforms
(Constant::F32(l), Some(Constant::F32(r))) => match op.node {
(Constant::F32(l), Some(Constant::F32(r))) => match op {
BinOpKind::Add => Some(Constant::F32(l + r)),
BinOpKind::Sub => Some(Constant::F32(l - r)),
BinOpKind::Mul => Some(Constant::F32(l * r)),
@ -829,7 +829,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None,
},
(Constant::F64(l), Some(Constant::F64(r))) => match op.node {
(Constant::F64(l), Some(Constant::F64(r))) => match op {
BinOpKind::Add => Some(Constant::F64(l + r)),
BinOpKind::Sub => Some(Constant::F64(l - r)),
BinOpKind::Mul => Some(Constant::F64(l * r)),
@ -843,7 +843,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None,
},
(l, r) => match (op.node, l, r) {
(l, r) => match (op, l, r) {
(BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
(BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
(BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {