@@ -154,9 +154,9 @@ void code_contractst::check_apply_loop_contracts(
154154 // at the start of and end of a loop body
155155 std::vector<symbol_exprt> old_decreases_vars, new_decreases_vars;
156156
157- replace_symbolt replace;
158- code_contractst::add_quantified_variable ( invariant, replace, mode);
159- replace (invariant);
157+ // replace bound variables by fresh instances
158+ if ( has_subexpr ( invariant, ID_exists) || has_subexpr (invariant, ID_forall))
159+ add_quantified_variable (invariant, mode );
160160
161161 // instrument
162162 //
@@ -567,68 +567,73 @@ void code_contractst::check_apply_loop_contracts(
567567}
568568
569569void code_contractst::add_quantified_variable (
570- const exprt &expression,
571- replace_symbolt &replace,
570+ exprt &expression,
572571 const irep_idt &mode)
573572{
574573 if (expression.id () == ID_not || expression.id () == ID_typecast)
575574 {
576575 // For unary connectives, recursively check for
577576 // nested quantified formulae in the term
578- const auto &unary_expression = to_unary_expr (expression);
579- add_quantified_variable (unary_expression.op (), replace, mode);
577+ auto &unary_expression = to_unary_expr (expression);
578+ add_quantified_variable (unary_expression.op (), mode);
580579 }
581580 if (expression.id () == ID_notequal || expression.id () == ID_implies)
582581 {
583582 // For binary connectives, recursively check for
584583 // nested quantified formulae in the left and right terms
585- const auto &binary_expression = to_binary_expr (expression);
586- add_quantified_variable (binary_expression.lhs (), replace, mode);
587- add_quantified_variable (binary_expression.rhs (), replace, mode);
584+ auto &binary_expression = to_binary_expr (expression);
585+ add_quantified_variable (binary_expression.lhs (), mode);
586+ add_quantified_variable (binary_expression.rhs (), mode);
588587 }
589588 if (expression.id () == ID_if)
590589 {
591590 // For ternary connectives, recursively check for
592591 // nested quantified formulae in all three terms
593- const auto &if_expression = to_if_expr (expression);
594- add_quantified_variable (if_expression.cond (), replace, mode);
595- add_quantified_variable (if_expression.true_case (), replace, mode);
596- add_quantified_variable (if_expression.false_case (), replace, mode);
592+ auto &if_expression = to_if_expr (expression);
593+ add_quantified_variable (if_expression.cond (), mode);
594+ add_quantified_variable (if_expression.true_case (), mode);
595+ add_quantified_variable (if_expression.false_case (), mode);
597596 }
598597 if (expression.id () == ID_and || expression.id () == ID_or)
599598 {
600599 // For multi-ary connectives, recursively check for
601600 // nested quantified formulae in all terms
602- const auto &multi_ary_expression = to_multi_ary_expr (expression);
603- for (const auto &operand : multi_ary_expression.operands ())
601+ auto &multi_ary_expression = to_multi_ary_expr (expression);
602+ for (auto &operand : multi_ary_expression.operands ())
604603 {
605- add_quantified_variable (operand, replace, mode);
604+ add_quantified_variable (operand, mode);
606605 }
607606 }
608607 else if (expression.id () == ID_exists || expression.id () == ID_forall)
609608 {
610- // When a quantifier expression is found,
611- // for each quantified variable ...
612- const auto &quantifier_expression = to_quantifier_expr (expression);
609+ // When a quantifier expression is found, create a fresh symbol for each
610+ // quantified variable and rewrite the expression to use those fresh
611+ // symbols.
612+ auto &quantifier_expression = to_quantifier_expr (expression);
613+ std::vector<symbol_exprt> fresh_variables;
614+ fresh_variables.reserve (quantifier_expression.variables ().size ());
613615 for (const auto &quantified_variable : quantifier_expression.variables ())
614616 {
615- const auto &quantified_symbol = to_symbol_expr (quantified_variable);
616-
617617 // 1. create fresh symbol
618618 symbolt new_symbol = new_tmp_symbol (
619- quantified_symbol .type (),
620- quantified_symbol .source_location (),
619+ quantified_variable .type (),
620+ quantified_variable .source_location (),
621621 mode,
622622 symbol_table);
623623
624624 // 2. add created fresh symbol to expression map
625- symbol_exprt q (
626- quantified_symbol.get_identifier (), quantified_symbol.type ());
627- replace.insert (q, new_symbol.symbol_expr ());
628-
629- // 3. recursively check for nested quantified formulae
630- add_quantified_variable (quantifier_expression.where (), replace, mode);
625+ fresh_variables.push_back (new_symbol.symbol_expr ());
631626 }
627+
628+ // use fresh symbols
629+ exprt where = quantifier_expression.instantiate (fresh_variables);
630+
631+ // recursively check for nested quantified formulae
632+ add_quantified_variable (where, mode);
633+
634+ // replace previous variables and body
635+ quantifier_expression.variables () = fresh_variables;
636+ quantifier_expression.where () = std::move (where);
632637 }
633638}
634639
@@ -831,9 +836,9 @@ void code_contractst::apply_function_contract(
831836 // Insert assertion of the precondition immediately before the call site.
832837 if (!requires .is_true ())
833838 {
834- replace_symbolt replace (common_replace);
835- code_contractst:: add_quantified_variable (requires , replace , mode);
836- replace (requires );
839+ if ( has_subexpr ( requires , ID_exists) || has_subexpr ( requires , ID_forall))
840+ add_quantified_variable (requires , mode);
841+ common_replace (requires );
837842
838843 goto_programt assertion;
839844 converter.goto_convert (code_assertt (requires ), assertion, mode);
@@ -852,9 +857,9 @@ void code_contractst::apply_function_contract(
852857 std::pair<goto_programt, goto_programt> ensures_pair;
853858 if (!ensures.is_false ())
854859 {
855- replace_symbolt replace (common_replace);
856- code_contractst:: add_quantified_variable (ensures, replace , mode);
857- replace (ensures);
860+ if ( has_subexpr (ensures, ID_exists) || has_subexpr (ensures, ID_forall))
861+ add_quantified_variable (ensures, mode);
862+ common_replace (ensures);
858863
859864 auto assumption = code_assumet (ensures);
860865 ensures_pair =
@@ -1430,12 +1435,9 @@ void code_contractst::add_contract_check(
14301435 // Generate: assume(requires)
14311436 if (!requires .is_false ())
14321437 {
1433- // extend common_replace with quantified variables in REQUIRES,
1434- // and then do the replacement
1435- replace_symbolt replace (common_replace);
1436- code_contractst::add_quantified_variable (
1437- requires , replace, function_symbol.mode );
1438- replace (requires );
1438+ if (has_subexpr (requires , ID_exists) || has_subexpr (requires , ID_forall))
1439+ add_quantified_variable (requires , function_symbol.mode );
1440+ common_replace (requires );
14391441
14401442 goto_programt assumption;
14411443 converter.goto_convert (
@@ -1450,12 +1452,9 @@ void code_contractst::add_contract_check(
14501452 // Generate: copies for history variables
14511453 if (!ensures.is_true ())
14521454 {
1453- // extend common_replace with quantified variables in ENSURES,
1454- // and then do the replacement
1455- replace_symbolt replace (common_replace);
1456- code_contractst::add_quantified_variable (
1457- ensures, replace, function_symbol.mode );
1458- replace (ensures);
1455+ if (has_subexpr (ensures, ID_exists) || has_subexpr (ensures, ID_forall))
1456+ add_quantified_variable (ensures, function_symbol.mode );
1457+ common_replace (ensures);
14591458
14601459 // get all the relevant instructions related to history variables
14611460 auto assertion = code_assertt (ensures);
0 commit comments