@@ -263,15 +263,40 @@ goto_symex_statet::rename(exprt expr, const namespacet &ns)
263263 *it = rename<level>(std::move (*it), ns).get ();
264264
265265 const exprt &c_expr = as_const (expr);
266+
267+ // It may happen that the `old` subexpression of a `with_exprt` expression
268+ // is propagated with a value that has an array type with a size that is a
269+ // symbol with an L2 index that is different. In this case the type of the
270+ // `with_exprt` will not match with the type of the `old` subexpression
271+ // anymore.
272+ // To address this issue we re-canonicalize the `with_exprt` by propagating
273+ // the type of the `old` subexpression to the type of the `with_exprt`.
274+ const auto *c_with_expr = expr_try_dynamic_cast<with_exprt>(c_expr);
275+ if (
276+ c_with_expr && can_cast_type<array_typet>(c_with_expr->type ()) &&
277+ can_cast_type<array_typet>(c_with_expr->old ().type ()) &&
278+ c_with_expr->type () != c_with_expr->old ().type ())
279+ {
280+ expr.type () = to_with_expr (expr).old ().type ();
281+ }
282+ INVARIANT_WITH_DIAGNOSTICS (
283+ expr.id () != ID_with ||
284+ c_expr.type () == to_with_expr (c_expr).old ().type (),
285+ " Type of renamed expr should be the same as operands for with_exprt" ,
286+ c_expr.type ().pretty (),
287+ to_with_expr (c_expr).old ().type ().pretty ());
288+ INVARIANT_WITH_DIAGNOSTICS (
289+ expr.id () != ID_if ||
290+ c_expr.type () == to_if_expr (c_expr).true_case ().type (),
291+ " Type of renamed expr should be the same as operands for if_exprt" ,
292+ c_expr.type ().pretty (),
293+ to_if_expr (c_expr).true_case ().type ().pretty ());
266294 INVARIANT_WITH_DIAGNOSTICS (
267- (expr.id () != ID_with ||
268- c_expr.type () == to_with_expr (c_expr).old ().type ()) &&
269- (expr.id () != ID_if ||
270- (c_expr.type () == to_if_expr (c_expr).true_case ().type () &&
271- c_expr.type () == to_if_expr (c_expr).false_case ().type ())),
272- " Type of renamed expr should be the same as operands for with_exprt and "
273- " if_exprt" ,
274- irep_pretty_diagnosticst{expr});
295+ expr.id () != ID_if ||
296+ c_expr.type () == to_if_expr (c_expr).false_case ().type (),
297+ " Type of renamed expr should be the same as operands for if_exprt" ,
298+ c_expr.type ().pretty (),
299+ to_if_expr (c_expr).false_case ().type ().pretty ());
275300
276301 if (level == L2)
277302 expr = field_sensitivity.apply (ns, *this , std::move (expr), false );
0 commit comments