Skip to content

dictmultiobject: keep typed strategy in move_to_end for native-type keys - #959

Merged
youknowone merged 1 commit into
mainfrom
call-slot-descr-protocol
Aug 2, 2026
Merged

dictmultiobject: keep typed strategy in move_to_end for native-type keys#959
youknowone merged 1 commit into
mainfrom
call-slot-descr-protocol

Conversation

@youknowone

@youknowone youknowone commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Follow-up to #957. w_dict_move_to_end_checked previously routed every non-Object dict through switch_to_object_strategy before reordering, de-specializing Int/Bytes/Unicode dicts on any move_to_end.

  • Int and Bytes dicts reorder in their native IndexMap<i64> / IndexMap<Vec<u8>> storage for an exact int / bytes key (typed_move_to_end), matching AbstractTypedStrategy.move_to_end (dictmultiobject.py:1170). The lookup compares native keys, so it stays callback-free and needs no reentrant fallback.
  • Unicode already shares ObjectDictStrategy's IndexMap<ObjectKey> representation, so it reorders in place.
  • Only a foreign-type key on a typed store, or the Kwargs/Map/Empty strategies, still convert to Object.

keys_version is bumped only on a real move (the index != target guard), preserving the existing no-op behavior.

Verification

Byte-identical across CPython 3.14, PyPy3, and pyre via bench/synth/pypy_dict_primitives_nonbinding.py, extended (section 7) with int- and bytes-keyed move_to_end (both directions) and reversed_dict over an int dict. cargo build --release clean.

Follow-up

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved dictionary entry reordering for integer- and bytes-key dictionaries.
    • Avoided unnecessary internal conversions when moving entries to the beginning or end.
    • Prevented version updates when an entry’s position does not change.
  • Tests

    • Added coverage for moving entries and reverse iteration across supported dictionary types.

w_dict_move_to_end_checked previously switched every non-Object dict to
ObjectDictStrategy before reordering. Int and Bytes dicts now reorder in
their native IndexMap<i64> / IndexMap<Vec<u8>> storage when the key is an
exact int / bytes (typed_move_to_end), matching AbstractTypedStrategy.
move_to_end (dictmultiobject.py:1170). Unicode already shares Object's
IndexMap<ObjectKey> representation, so it reorders in place too; only a
foreign-type key on a typed store, or the Kwargs/Map/Empty strategies,
still convert to Object.

Extend the synth check with int- and bytes-keyed move_to_end (both
directions) and reversed_dict over an int dict.

Assisted-by: Claude
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 801f4c8c-92d3-49ab-94dc-33825c0ea3bc

📥 Commits

Reviewing files that changed from the base of the PR and between f3bddb3 and 0a2df44.

📒 Files selected for processing (2)
  • pyre/bench/synth/pypy_dict_primitives_nonbinding.py
  • pyre/pyre-object/src/dictmultiobject.rs

Walkthrough

The change adds native move_to_end handling for integer and bytes dictionaries. It preserves typed storage, updates keys_version only after actual movement, and adds coverage for movement and reverse iteration behavior.

Changes

Typed dictionary reordering

Layer / File(s) Summary
Native typed-storage reordering
pyre/pyre-object/src/dictmultiobject.rs
The implementation locates typed keys in the native IndexMap, moves entries to the front or back when needed, and preserves the existing fallback paths for other strategies.
Typed dictionary behavior coverage
pyre/bench/synth/pypy_dict_primitives_nonbinding.py
The benchmark tests integer-key and bytes-key dictionaries for both movement directions. Integer-key dictionaries also test reverse iteration.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • youknowone/pyre#560: Updates dictmultiobject.rs for native dictionary storage and typed-storage paths.
  • youknowone/pyre#663: Updates dictmultiobject.rs and keys_version handling for typed dictionary storage.

Poem

A rabbit hops where typed keys play,
Moving entries night and day.
Front or back, the maps now glide,
With version counts kept by their side.
Reverse the trail—then bound away! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: preserving typed dictionary strategies during move_to_end for native-type keys.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch call-slot-descr-protocol

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit 0a2df44).
Updated: 2026-08-01T16:27:08.691Z

Files in the reviewed diff
pyre/bench/synth/pypy_dict_primitives_nonbinding.py
pyre/pyre-object/src/dictmultiobject.rs

1. Regressions to PyPy parity introduced by this patch

  • pyre/pyre-object/src/dictmultiobject.rs:3634 ↔ pypy/objspace/std/dictmultiobject.py:1170: Pyre preserves UnicodeDictStrategy for every lookup key; PyPy’s typed path preserves it only when is_correct_type(w_key), otherwise it promotes and redispatches (:1178-1180; Unicode requires exact type at :1298-1300). Thus move_to_end with a str subclass or another foreign key no longer promotes a Unicode dict to Object strategy, regressing upstream/main’s promotion behavior.

2. Other mismatches introduced by this patch

None.

3. Pre-existing mismatches (already present before this patch)

None.

4. Structural adaptations

  • pyre/pyre-object/src/dictmultiobject.rs:3539 ↔ pypy/objspace/std/dictmultiobject.py:1170: Rust’s IndexMap<K, _>::move_index is the native-storage equivalent of PyPy’s typed r_dict/objectmodel.move_to_end path. This is a fundamental Rust-container adaptation; native int and bytes key behavior otherwise matches PyPy.
  • pyre/pyre-interpreter/src/baseobjspace.rs:15418 ↔ pypy/objspace/std/dictmultiobject.py:819: Pyre’s pre-existing explicit keys_version iterator invalidation compensates for IndexMap compaction, whereas PyPy’s wrapper checks length and relies on its underlying RPython-dict iterator state. This is outside the authoritative changed-file list and is a structural Rust-storage adaptation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

https://github.com/youknowone/pyre/blob/0a2df445d9f7a2335b9de723a8229409575cdbad/pyre-object/src/dictmultiobject.rs#L3634-L3635
P1 Badge Route foreign Unicode keys through the object strategy

This condition exempts every Unicode-strategy dictionary from conversion, but PyPy's AbstractTypedStrategy.move_to_end preserves the typed strategy only when is_correct_type(w_key) and otherwise calls switch_to_object_strategy. Consequently, a lookup with a foreign key such as a str subclass leaves the dictionary tagged as Unicode, bypassing the expected strategy transition and violating the required line-by-line port; exempt Unicode here only for an exact STR_TYPE key, or dispatch this operation through the strategy implementation.

AGENTS.md reference: AGENTS.md:L194-L196

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@youknowone
youknowone merged commit 5c4115f into main Aug 2, 2026
16 of 19 checks passed
@youknowone
youknowone deleted the call-slot-descr-protocol branch August 2, 2026 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant