Skip to content

Commit b48e586

Browse files
committed
fixing hash(-1) == hash(-2) (attempt 2) (#413)
ok so just return the integer does not work because Python will hash that result with a seed implicitly. Here we convert the integer to a byte and float to a hex repr. This is not the most ideal fix due to the fact that Python is using fixpoint/infinite precision numbers. But this should be non-breaking. We will do another fix by switching all `int` to `np.int64` and `float` to `np.float64` and define the hash as their bytes later.
1 parent b8e4528 commit b48e586

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

src/kirin/ir/attrs/py.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ def __init__(self, data: T, pytype: TypeAttribute | None = None):
3636

3737
def __hash__(self):
3838
# Fix hash(-1) == hash(-2) collision
39+
# assume maximum is 8 bytes == 64 bits
3940
if isinstance(self.data, int):
40-
return self.data
41+
return hash(self.data.to_bytes(signed=True, byteorder="big", length=8))
42+
elif isinstance(self.data, float):
43+
return hash(self.data.hex())
4144
return hash(self.data) + hash(self.type)
4245

4346
def print_impl(self, printer: Printer) -> None:

test/ir/test_hash.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from kirin import ir
2+
3+
4+
def test_hash():
5+
# Test hash collision for PyAttr with different values
6+
# This is a regression test for issue #1234
7+
# where hash(-1) == hash(-2) for PyAttr
8+
# This is fixed by using the value as bytes
9+
a = ir.PyAttr(-1)
10+
b = ir.PyAttr(-2)
11+
assert hash(a) != hash(b)
12+
assert hash(a.data) == hash(b.data)
13+
14+
a = ir.PyAttr(-1.0)
15+
b = ir.PyAttr(-2.0)
16+
assert hash(a) != hash(b)
17+
assert hash(a.data) == hash(b.data)

0 commit comments

Comments
 (0)