Skip to content

Commit

Permalink
Compare symbolic lists symbolically
Browse files Browse the repository at this point in the history
  • Loading branch information
pschanely committed Nov 12, 2021
1 parent 2c93585 commit c759d3b
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 8 deletions.
22 changes: 14 additions & 8 deletions crosshair/libimpl/builtinslib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1636,17 +1636,23 @@ def __bool__(self) -> bool:
return SymbolicBool(self._len() != 0).__bool__()

def __eq__(self, other):
if self is other:
return True
(self_arr, self_len) = self.var
if not is_iterable(other):
return False
with NoTracing():
if self is other:
return True
(self_arr, self_len) = self.var
if isinstance(other, SymbolicArrayBasedUniformTuple):
return SymbolicBool(
z3.And(self_len == other._len(), self_arr == other._arr())
)
if not is_iterable(other):
return False
if len(self) != len(other):
return False
for idx, v in enumerate(other):
if self[idx] is v:
for idx, otherval in enumerate(other):
myval = self[idx]
if myval is otherval:
continue
if self[idx] != v:
if myval != otherval:
return False
return True

Expand Down
13 changes: 13 additions & 0 deletions crosshair/libimpl/builtinslib_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
SymbolicArrayBasedUniformTuple,
SymbolicByteArray,
SymbolicBytes,
SymbolicList,
SymbolicType,
)
from crosshair.libimpl.builtinslib import SymbolicBool
Expand Down Expand Up @@ -1496,6 +1497,18 @@ def test_list_copy(space):
assert copy.copy(lst) is not lst


def test_list_copy_compare_without_forking(space):
lst = proxy_for_type(List[int], "lst")
with ResumedTracing():
lst2 = copy.deepcopy(lst)
assert type(lst2) is SymbolicList
assert lst.inner.var is lst2.inner.var
with ResumedTracing():
are_same = lst == lst2
assert type(are_same) is SymbolicBool
assert not space.is_possible(z3.Not(are_same.var))


class DictionariesTest(unittest.TestCase):
def test_dict_basic_fail(self) -> None:
def f(a: Dict[int, int], k: int, v: int) -> None:
Expand Down
7 changes: 7 additions & 0 deletions crosshair/simplestructs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import *

from crosshair.core import CrossHairValue
from crosshair.tracers import NoTracing
from crosshair.tracers import ResumedTracing
from crosshair.util import is_iterable
from crosshair.util import is_hashable
Expand Down Expand Up @@ -521,6 +522,12 @@ def _spawn(self, items: Sequence) -> "ShellMutableSequence":
# For overriding in subclasses.
return ShellMutableSequence(items)

def __eq__(self, other):
with NoTracing():
if isinstance(other, ShellMutableSequence):
other = other.inner
return self.inner.__eq__(other)

def __setitem__(self, k, v):
inner = self.inner
if hasattr(inner, "__setitem__"):
Expand Down

0 comments on commit c759d3b

Please sign in to comment.