fn add_overflows()

in checker/src/abstract_value.rs [1041:1105]


    fn add_overflows(
        &self,
        other: Rc<AbstractValue>,
        target_type: ExpressionType,
    ) -> 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.add_overflows(self.clone(), target_type);
        }
        if self.is_bottom() || self.is_top() || other.is_bottom() || other.is_top() {
            return AbstractValue::make_typed_unknown(
                ExpressionType::Bool,
                Path::new_computed(TOP.into()),
            );
        }
        if let Expression::CompileTimeConstant(c1) = &self.expression {
            // [0 + x] -> x
            if c1.is_zero() {
                return Rc::new(FALSE);
            }
            // [c1 + (c2 + x)] -> c3 + x where c3 = c1 + c2
            if let Expression::Add { left, right: x } = &other.expression {
                if let Expression::CompileTimeConstant(c2) = &left.expression {
                    let c3 = c1.add(c2);
                    if c3 != ConstantDomain::Bottom {
                        let c3val: Rc<AbstractValue> = Rc::new(c3.into());
                        return c3val.add_overflows(x.clone(), target_type);
                    }
                }
            }
        }
        // [x + x] -> 2 * x
        if self.eq(&other) {
            let t = self.expression.infer_type();
            if t.is_unsigned_integer() {
                let two: Rc<AbstractValue> = Rc::new(ConstantDomain::U128(2).into());
                return two.mul_overflows(other, target_type);
            } else if t.is_signed_integer() {
                let two: Rc<AbstractValue> = Rc::new(ConstantDomain::I128(2).into());
                return two.mul_overflows(other, target_type);
            }
        }

        let interval = self.get_cached_interval().add(&other.get_cached_interval());
        if interval.is_contained_in(target_type) {
            return Rc::new(FALSE);
        }
        self.try_to_constant_fold_and_distribute_typed_binary_op(
            other,
            target_type,
            ConstantDomain::add_overflows,
            Self::add_overflows,
            |l, r, t| {
                AbstractValue::make_typed_binary(l, r, t, |left, right, result_type| {
                    Expression::AddOverflows {
                        left,
                        right,
                        result_type,
                    }
                })
            },
        )
    }