Skip to content

Report missing required TypedDict keys when unpacking a TypedDict - #5407

Open
akhil9tiet wants to merge 10 commits into
meta:mainfrom
akhil9tiet:fix/5405-typed-dict-unpacking-required-keys
Open

akhil9tiet wants to merge 10 commits into
meta:mainfrom
akhil9tiet:fix/5405-typed-dict-unpacking-required-keys

Conversation

@akhil9tiet

Copy link
Copy Markdown
Contributor

Fixes #5405

AnswersSolver::check_dict_items_against_typed_dict skips the missing-required-key check whenever has_expansion is true; when a TypedDict is unpacked its required keys should count as present, skipping only for unknown-key types like plain dict.

In check_dict_items_against_typed_dict, the blanket has_expansion flag is replaced with has_unknown_expansion: when an unpacked value is a TypedDict, its required keys are added to the known keys set, so a missing required key is still reported; the check is skipped only when unpacking a type whose keys are unknown, such as a plain dict. Added test_typed_dict_unpacking_missing_required_key, which unpacks an open TypedDict and a closed TypedDict into Target (both missing y) and includes the positive case of unpacking Target itself.

@meta-codesync

meta-codesync Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

This pull request has been imported. If you are a Meta employee, you can view this in D127732579. (Because this pull request was imported automatically, there will not be any future comments.)

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

The new missing-required-key diagnostic also fires when unpacking a TypedDict whose required keys don't cover the target's.
@github-actions github-actions Bot added size/s and removed size/s labels Oct 29, 2026
@github-actions

This comment has been minimized.

@stroxler stroxler left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks!

Based on AI review, I think there's one issue we should address before merge:

Anonymous TypedDict fields aren’t counted as present

[typed_dict.rs:185–194](

if let Type::TypedDict(unpacked) = &item_ty {
let unpacked_fields = self.typed_dict_fields(unpacked);
for (key, field) in &unpacked_fields {
if field.required {
keys.insert(key.clone());
}
}
} else {
has_unknown_expansion = true;
}
)

Type::TypedDict(unpacked) matches both declared and anonymous TypedDicts. Pyrefly infers ordinary dictionary literals as anonymous TypedDicts with required: false on every field. The new loop therefore adds no keys, but leaves has_unknown_expansion false.

Source tracing indicates this now reports a missing x:

from typing import TypedDict

class Target(TypedDict):
    x: int

def f() -> Target:
    source = {"x": 1}
    return {**source}  # Newly reports missing required key `x`

Smallest fix: restrict required-field counting to TypedDict::TypedDict, preserving the unknown-expansion fallback for anonymous TypedDicts. Add the example above as a regression test.

The declared-TypedDict behavior otherwise looks correct, and the change is appropriately localized. I’d also add a NotRequired source-field test to protect the distinction between declared optional fields and inferred dictionary entries.

@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@github-actions

This comment has been minimized.

@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@akhil9tiet

Copy link
Copy Markdown
Contributor Author

Fixed — the required-field counting in the unpack arm is now restricted to declared TypedDict::TypedDict; anonymous TypedDicts (e.g. inferred dict literals, all fields required: false) fall through to the unknown-expansion path so no missing-key error fires. Added the dict-literal regression test plus a NotRequired source-field test guarding the declared-optional vs inferred distinction.

@github-actions

This comment has been minimized.

Fix missing required key error in TypedDict conversion.
@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@github-actions

This comment has been minimized.

@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

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

@rchen152 rchen152 added size/xs and removed size/s labels Nov 2, 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing TypedDict required keys aren't reported when a dict literal uses ** unpacking

4 participants