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