@@ -2088,26 +2088,47 @@ static void update_index_set(
2088
2088
// / Finds an index on `str` used in `expr` that contains `qvar`, for instance
2089
2089
// / with arguments ``(str[k]=='a')``, `str`, and `k`, the function should
2090
2090
// / return `k`.
2091
+ // / If two different such indexes exist, an invariant will fail.
2091
2092
// / \param [in] expr: the expression to search
2092
2093
// / \param [in] str: the string which must be indexed
2093
2094
// / \param [in] qvar: the universal variable that must be in the index
2094
- // / \return an index expression in `expr` on `str` containing `qvar`
2095
- static exprt find_index (
2096
- const exprt &expr, const exprt &str, const symbol_exprt &qvar)
2095
+ // / \return an index expression in `expr` on `str` containing `qvar`. Returns
2096
+ // / an empty optional when `expr` does not contain `str`.
2097
+ static optionalt<exprt>
2098
+ find_index (const exprt &expr, const exprt &str, const symbol_exprt &qvar)
2097
2099
{
2098
- const auto it=std::find_if (
2099
- expr.depth_begin (),
2100
- expr.depth_end (),
2101
- [&] (const exprt &e) -> bool
2100
+ auto index_str_containing_qvar = [&](const exprt &e) { // NOLINT
2101
+ if (auto index_expr = expr_try_dynamic_cast<index_exprt>(e))
2102
2102
{
2103
- return e.id ()==ID_index
2104
- && to_index_expr (e).array ()==str
2105
- && find_qvar (to_index_expr (e).index (), qvar);
2106
- });
2103
+ const auto &arr = index_expr->array ();
2104
+ const auto str_it = std::find (arr.depth_begin (), arr.depth_end (), str);
2105
+ return str_it != arr.depth_end () && find_qvar (index_expr->index (), qvar);
2106
+ }
2107
+ return false ;
2108
+ };
2109
+
2110
+ auto it = std::find_if (
2111
+ expr.depth_begin (), expr.depth_end (), index_str_containing_qvar);
2112
+ if (it == expr.depth_end ())
2113
+ return {};
2114
+ const exprt &index = to_index_expr (*it).index ();
2115
+
2116
+ // Check that there are no two such indexes
2117
+ it.next_sibling_or_parent ();
2118
+ while (it != expr.depth_end ())
2119
+ {
2120
+ if (index_str_containing_qvar (*it))
2121
+ {
2122
+ INVARIANT (
2123
+ to_index_expr (*it).index () == index ,
2124
+ " string should always be indexed by same value in a given formula" );
2125
+ it.next_sibling_or_parent ();
2126
+ }
2127
+ else
2128
+ ++it;
2129
+ }
2107
2130
2108
- return it==expr.depth_end ()
2109
- ?nil_exprt ()
2110
- :to_index_expr (*it).index ();
2131
+ return index ;
2111
2132
}
2112
2133
2113
2134
// / Instantiates a string constraint by substituting the quantifiers.
@@ -2128,11 +2149,11 @@ static exprt instantiate(
2128
2149
const exprt &str,
2129
2150
const exprt &val)
2130
2151
{
2131
- const exprt idx = find_index (axiom.body (), str, axiom.univ_var ());
2132
- if (idx.is_nil ())
2152
+ const optionalt< exprt> idx = find_index (axiom.body (), str, axiom.univ_var ());
2153
+ if (! idx.has_value ())
2133
2154
return true_exprt ();
2134
2155
2135
- const exprt r = compute_inverse_function (stream, axiom.univ_var (), val, idx);
2156
+ const exprt r = compute_inverse_function (stream, axiom.univ_var (), val, * idx);
2136
2157
implies_exprt instance (
2137
2158
and_exprt (
2138
2159
binary_relation_exprt (axiom.univ_var (), ID_ge, axiom.lower_bound ()),
0 commit comments