Skip to content

Fix reversed() on dicts and dict views returning forward iterator types - #1228

Open
jseop-lim wants to merge 1 commit into
oracle:masterfrom
jseop-lim:GH-1226-dict-reverse-iterators
Open

jseop-lim wants to merge 1 commit into
oracle:masterfrom
jseop-lim:GH-1226-dict-reverse-iterators

Conversation

@jseop-lim

Copy link
Copy Markdown
Contributor

Description

Fixes #1226

The __reversed__ methods of dict, dict_keys, dict_items and dict_values wrapped the reverse storage iterator with the forward factories, so the result was a dict_keyiterator, dict_valueiterator or dict_itemiterator. The PDictReverse*Iterator types are still defined and registered with IteratorBuiltins, but nothing has created them since afc1f12 removed their factories. CPython builds all four from the PyDictRevIter*_Type types (dictobject.c#L4494).

AS-IS

>>> d = {1: 'a'}
>>> type(reversed(d)), type(reversed(d.values())), type(reversed(d.items()))
(<class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'dict_itemiterator'>)
>>> type(reversed(d)) is type(iter(d))
True

TO-BE

>>> type(reversed(d)), type(reversed(d.values())), type(reversed(d.items()))
(<class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>)
>>> type(reversed(d)) is type(iter(d))
False

(matching CPython)

Changes

  • Restore PFactory.createDictReverse{Key,Item,Value}Iterator in their pre-afc1f123e6 shape, building the same Java iterator objects with the reverse types.
  • Call them from DictBuiltins.ReversedNode, DictViewBuiltins.ReversedNode (keys and items) and DictValuesBuiltins.ReversedNode.
  • Add test_reversed_iterator_types to tests/test_dict.py.

The reverse types need no disallowInstantiation(): PythonBuiltinClassType already sets it for a builtin type without tp_new whose base is object, so calling one raises TypeError as in CPython, which the new test checks.

Testing

mx python-jvm on linux-aarch64, then mx graalpytest test_dict.py test_ordered_dict.py test_iterator.py test_map_strategies.py (110 passed). test.test_dict, test.test_dictviews and test.test_ordered_dict from lib-python give the same per-test results as on master. The new test fails on the unpatched build. For all four reversed() calls, the type name, iteration order, __length_hint__, __reduce__, pickling and instantiation now match CPython 3.12.13.

The __reversed__ methods of dict, dict_keys, dict_items and
dict_values wrapped the reverse storage iterator with the forward
factories, so reversed(d) was a dict_keyiterator and
type(reversed(d)) is type(iter(d)) held. The PDictReverse*Iterator
types were still defined and registered with IteratorBuiltins, but
nothing created them since afc1f12 dropped the reverse factories.

Restore createDictReverse{Key,Item,Value}Iterator in their former
shape and use them at the four sites, as CPython builds these
iterators from the PyDictRevIter*_Type types.

Signed-off-by: Jeongseop Lim <jeongseop_lim@korea.ac.kr>
@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Oct 20, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: reversed() on a dict or dict view returns the forward iterator type instead of dict_reverse*iterator

1 participant