in checker/src/abstract_value.rs [3324:3457]
fn join(&self, other: Rc<AbstractValue>) -> Rc<AbstractValue> {
// [{} join y] -> y
if self.is_bottom() {
return other;
}
// [TOP join y] -> TOP
if self.is_top() {
return self.clone();
}
// [x join {}] -> x
if other.is_bottom() {
return self.clone();
}
// [x join x] -> x
if self.eq(&other) {
return other;
}
// [x join TOP] -> TOP
if other.is_top() {
return other;
}
match (&self.expression, &other.expression) {
// [(x join y) join (y join z)] -> x join (y join z)
(
Expression::Join {
left: x, right: y1, ..
},
Expression::Join { left: y2, .. },
) if y1.eq(y2) => {
return x.join(other);
}
// [(x join y) join (z join a)] -> x join (y join (z join a))
(
Expression::Join {
left: x, right: y, ..
},
Expression::Join { .. },
) => {
return x.join(y.join(other));
}
// [x_join_y join widen(x_join_y)] -> widen(x_join_y)
(Expression::Join { .. }, Expression::WidenedJoin { operand, .. })
if self.eq(operand) =>
{
return other;
}
// [(x join y) join y] -> x join y
// [(x join y) join x] -> x join y
(Expression::Join { left: x, right: y }, _) if x.eq(&other) || y.eq(&other) => {
return self.clone();
}
// [x join (x join y)] -> x join y
// [y join (x join y)] -> x join y
(_, Expression::Join { left: x, right: y }) if x.eq(self) || y.eq(self) => {
return other;
}
// [widen(x_join_y) join x_join_y] -> widen(x_join_y)
(Expression::WidenedJoin { operand, .. }, Expression::Join { .. })
if other.eq(operand) =>
{
return self.clone();
}
// [widen(x, p) join widen(y, p)] -> widen(x, p)
(
Expression::WidenedJoin { path: p1, .. },
Expression::WidenedJoin { path: p2, .. },
) if p1.eq(p2) => {
return self.clone();
}
// [widen(x_join_y) join x] -> widen(x_join_y)
// [widen(x_join_y) join y] -> widen(x_join_y)
(Expression::WidenedJoin { operand, .. }, _) => {
if let Expression::Join { left, right } = &operand.expression {
if left.eq(&other) || right.eq(&other) {
return self.clone();
}
}
}
// [x join (if c { x } else { y })] -> x join y
// [x join (if c { y } else { x })] -> x join y
(
_,
Expression::ConditionalExpression {
consequent: x,
alternate: y,
..
},
)
| (
_,
Expression::ConditionalExpression {
consequent: y,
alternate: x,
..
},
) if self.eq(x) => {
return x.join(y.clone());
}
// [x join (y join (x join z))] -> x join (y join z)
(
_,
Expression::Join {
left: y, right: xz, ..
},
) if matches!(&xz.expression, Expression::Join { .. }) => {
if let Expression::Join {
left: x, right: z, ..
} = &xz.expression
{
if self.eq(x) {
return self.join(y.join(z.clone()));
}
}
}
// [x join widened(x join y)] -> widened(x join y)
// [y join widened(x join y)] -> widened(x join y)
(_, Expression::WidenedJoin { operand, .. }) => {
if let Expression::Join { left: x, right: y } = &operand.expression {
if self.eq(x) || self.eq(y) {
return other.clone();
}
}
}
_ => {}
}
let expression_size = self.expression_size.saturating_add(other.expression_size);
AbstractValue::make_from(
Expression::Join {
left: self.clone(),
right: other,
},
expression_size,
)
}