in checker/src/abstract_value.rs [1875:1969]
fn cast(&self, target_type: ExpressionType) -> Rc<AbstractValue> {
match &self.expression {
Expression::Bottom => self.clone(),
Expression::ConditionalExpression {
condition,
consequent,
alternate,
} => condition
.conditional_expression(consequent.cast(target_type), alternate.cast(target_type)),
Expression::Join { left, right } => {
left.cast(target_type).join(right.cast(target_type))
}
Expression::Switch {
discriminator,
cases,
default,
} => discriminator.switch(
cases
.iter()
.map(|(case_val, result_val)| (case_val.clone(), result_val.cast(target_type)))
.collect(),
default.cast(target_type),
),
_ => {
match &self.expression {
// [(x as t1) as target_type] -> x as target_type if t1.max_value() >= target_type.max_value()
Expression::Cast {
operand,
target_type: t1,
} => {
if t1.is_integer()
&& target_type.is_unsigned_integer()
&& t1
.max_value()
.greater_or_equal(&target_type.max_value())
.as_bool_if_known()
.unwrap_or(false)
{
return operand.cast(target_type);
}
}
// [(x % c1) as t] -> (x as t) if c1 == t.modulo_value()
Expression::Rem { left, right } => {
if right
.equals(target_type.modulo_value())
.as_bool_if_known()
.unwrap_or(false)
{
return left.cast(target_type);
}
}
// [(v : t1) as target_type] -> (v: t1) if t1.max_value() == target_type.max_value()
Expression::Variable { var_type: t1, .. }
| Expression::InitialParameterValue { var_type: t1, .. } => {
if t1.is_integer()
&& target_type.is_unsigned_integer()
&& t1
.max_value()
.equals(&target_type.max_value())
.as_bool_if_known()
.unwrap_or(false)
{
return self.clone();
}
}
_ => (),
}
let source_type = self.expression.infer_type();
if source_type != target_type {
if source_type == ExpressionType::NonPrimitive
&& target_type == ExpressionType::ThinPointer
{
let field0 = Path::new_field(Path::get_as_path(self.clone()), 0);
AbstractValue::make_typed_unknown(target_type, field0)
} else {
self.try_to_constant_fold_and_distribute_typed_unary_op(
target_type,
ConstantDomain::cast,
Self::cast,
|o, t| {
AbstractValue::make_typed_unary(o, t, |operand, target_type| {
Expression::Cast {
operand,
target_type,
}
})
},
)
}
} else {
self.clone()
}
}
}
}