fn not_equals()

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 }),
        )
    }