gh-149676: Fix hash(frozendict | frozendict) (#149675)

Fix new_dict_impl() to properly initialize ma_hash on frozendict.

Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Thomas Kowalski 2026-05-12 12:47:39 +02:00 committed by GitHub
parent b546cc10f5
commit f5fb491341
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 12 additions and 3 deletions

View file

@ -1868,6 +1868,11 @@ def test_merge(self):
self.assertEqual(fd | {}, fd)
self.assertEqual(frozendict() | fd, fd)
# gh-149676: Test hash(frozendict | frozendict)
a = frozendict({"a": 1})
b = frozendict({"b": 2})
self.assertEqual(hash(a | b), hash(frozendict({"a": 1, "b": 2})))
def test_update(self):
# test "a |= b" operator
d = frozendict(x=1)

View file

@ -0,0 +1 @@
Fix ``frozendict | frozendict`` hash.

View file

@ -900,7 +900,7 @@ free_values(PyDictValues *values, bool use_qsbr)
static inline PyObject *
new_dict_impl(PyDictObject *mp, PyDictKeysObject *keys,
PyDictValues *values, Py_ssize_t used,
int free_values_on_failure)
int free_values_on_failure, int frozendict)
{
assert(keys != NULL);
if (mp == NULL) {
@ -915,6 +915,9 @@ new_dict_impl(PyDictObject *mp, PyDictKeysObject *keys,
mp->ma_values = values;
mp->ma_used = used;
mp->_ma_watcher_tag = 0;
if (frozendict) {
((PyFrozenDictObject *)mp)->ma_hash = -1;
}
ASSERT_CONSISTENT(mp);
_PyObject_GC_TRACK(mp);
return (PyObject *)mp;
@ -931,7 +934,7 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values,
}
assert(mp == NULL || Py_IS_TYPE(mp, &PyDict_Type));
return new_dict_impl(mp, keys, values, used, free_values_on_failure);
return new_dict_impl(mp, keys, values, used, free_values_on_failure, 0);
}
/* Consumes a reference to the keys object */
@ -940,7 +943,7 @@ new_frozendict(PyDictKeysObject *keys, PyDictValues *values,
Py_ssize_t used, int free_values_on_failure)
{
PyDictObject *mp = PyObject_GC_New(PyDictObject, &PyFrozenDict_Type);
return new_dict_impl(mp, keys, values, used, free_values_on_failure);
return new_dict_impl(mp, keys, values, used, free_values_on_failure, 1);
}
static PyObject *