in checker/src/abstract_value.rs [3816:3915]
fn not_equals(&self, other: Rc<AbstractValue>) -> Rc<AbstractValue> {
// [x != c] -> c != x
if !self.is_compile_time_constant() && other.is_compile_time_constant() {
// Normalize binary expressions so that if only one of the operands is a constant, it is
// always the left operand.
return other.not_equals(self.clone());
}
match (&self.expression, &other.expression) {
// true != x -> !x
(Expression::CompileTimeConstant(ConstantDomain::True), _) => {
return other.logical_not();
}
// false != x -> x
(Expression::CompileTimeConstant(ConstantDomain::False), _) => {
return other.clone();
}
// [0 != (1 << x)] -> true (we can assume no overflows occur)
(
Expression::CompileTimeConstant(ConstantDomain::U128(0)),
Expression::Shl { left, .. },
) => {
if let Expression::CompileTimeConstant(ConstantDomain::U128(1)) = left.expression {
return Rc::new(TRUE);
}
}
// [0 != y] -> y when y is a Boolean. Canonicalize it to the latter.
(Expression::CompileTimeConstant(ConstantDomain::U128(0)), y)
if y.infer_type() == ExpressionType::Bool =>
{
return other.clone();
}
// [c1 != (c2 * x)] -> ( c1 / c2) != x
(_, Expression::Mul { left: c2, right: x })
if self.is_compile_time_constant()
&& c2.is_compile_time_constant()
&& self.expression.infer_type().is_integer() =>
{
debug_checked_assume!(!c2.is_zero()); // otherwise constant folding would have reduced the Mul
return self.divide(c2.clone()).not_equals(x.clone());
}
// [c3 != (c ? v1 : v2)] -> !c if v1 == c3 && v2 != c3
// [c3 != (c ? v1 : v2)] -> c if v1 != c3 && v2 == c3
// [c3 != (c ? v1 : v2)] -> true if v1 != c3 && v2 != c3
// [c3 != (c ? v1 : v2)] -> c ? (c3 != v1) : (c3 != v2)
(
Expression::CompileTimeConstant(..),
Expression::ConditionalExpression {
condition: c,
consequent: v1,
alternate: v2,
..
},
) if !v1.is_top()
&& v1.expression_size < k_limits::MAX_EXPRESSION_SIZE / 10
&& !v2.is_top()
&& v2.expression_size < k_limits::MAX_EXPRESSION_SIZE / 10 =>
{
// Don't make self the second operand, since it might be a constant
let v2_ne_self = self
.not_equals(v2.clone())
.as_bool_if_known()
.unwrap_or(false);
if self.equals(v1.clone()).as_bool_if_known().unwrap_or(false) && v2_ne_self {
return c.logical_not();
}
if self
.not_equals(v1.clone())
.as_bool_if_known()
.unwrap_or(false)
{
if self.equals(v2.clone()).as_bool_if_known().unwrap_or(false) {
return c.clone();
} else if v2_ne_self {
return Rc::new(TRUE);
}
}
if self.eq(&other) && !self.expression.infer_type().is_floating_point_number() {
return Rc::new(FALSE);
}
return c.conditional_expression(
self.not_equals(v1.clone()),
self.not_equals(v2.clone()),
);
}
_ => {
// If self and other are the same expression and the expression could not result in
// NaN we can simplify this to false.
if self.eq(&other) && !self.expression.infer_type().is_floating_point_number() {
return Rc::new(FALSE);
}
}
}
self.try_to_constant_fold_and_distribute_binary_op(
other,
ConstantDomain::not_equals,
Self::not_equals,
|l, r| AbstractValue::make_binary(l, r, |left, right| Expression::Ne { left, right }),
)
}