Skip to content

Keep literal string key types when unpacking a conditional mapping (#5632) - #5650

Open
ImBinarry wants to merge 1 commit into
pyrefly-org:mainfrom
ImBinarry:fix/dict-unpack-literalstring-keys
Open

ImBinarry wants to merge 1 commit into
pyrefly-org:mainfrom
ImBinarry:fix/dict-unpack-literalstring-keys

Conversation

@ImBinarry

Copy link
Copy Markdown
Contributor

Summary

Fixes #5632

{**({"left": value} if condition else {"right": value})} was inferred as dict[str, str] and rejected by a Mapping[LiteralString, str] return, even though every key is a literal string. Both simpler spellings work ({**{"left": value}} and the conditional without **), so only the composition was broken. Turns out the ** operand got no hint, so the branches lost their literal keys before unpacking; it now gets that hint, and mapping unions unpack member-wise. This also fixes {**c} for an explicitly annotated union of dicts.

  • I am a human, and I fully understand the code I am submitting.

Test Plan

New test_dict_unpack_conditional_literalstring_keys in pyrefly/lib/test/dict.rs (issue repro + negative controls) fails on main, passes with the fix.

  • cargo test -p pyrefly --lib test::dict and the other ** modules: 1,076 passed
  • cargo fmt -- --check clean; CLI on the repro: 0 errors, negative control still reports bad-return

Not run locally: full lib suite and clippy (CI covers both).

@github-actions

This comment has been minimized.

A dict display with an unpacked conditional mapping, e.g. {**({'a': v} if c else {'b': v})}, was inferred as dict[str, str] even under a Mapping[LiteralString, str] hint, because the unpack operand was inferred without the dict's contextual hint and unions of mappings were unpacked by solving a single Mapping[K, V] against the whole union.

Propagate the decomposed key and value hints into the '**' operand, and fall back to unpacking a union of mappings member-wise only when the ordinary mapping extraction does not recognize the union. This keeps the literal key types of the conditional's dict-literal branches without changing the inferred types of unpacked unions that the existing extraction already handles.
@ImBinarry
ImBinarry force-pushed the fix/dict-unpack-literalstring-keys branch from 9f577e4 to f491fe3 Compare November 14, 2026 08:22
@github-actions github-actions Bot added size/s and removed size/s labels Nov 14, 2026
@github-actions

Copy link
Copy Markdown

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Conditional dictionary unpacking loses LiteralString key types

1 participant