Skip to content

Conversation

@carljm
Copy link
Contributor

@carljm carljm commented Oct 31, 2025

Summary

In general, when we have an invalid assignment (inferred assigned type is not assignable to declared type), we fall back to inferring the declared type, since the declared type is a more explicit declaration of the programmer's intent. This also maintains the invariant that our inferred type for a name is always assignable to the declared type for that same name. For example:

x: str = 1
reveal_type(x)  # revealed: str

We weren't following this pattern for dictionary literals inferred (via type context) as a typed dictionary; if the literal was not valid for the annotated TypedDict type, we would just fall back to the normal inferred type of the dict literal, effectively ignoring the annotation, and resulting in inferred type not assignable to declared type.

Test Plan

Added mdtest assertions.

@carljm carljm requested a review from AlexWaygood as a code owner October 31, 2025 14:54
@carljm carljm added the ty Multi-file analysis & type inference label Oct 31, 2025
@github-actions
Copy link
Contributor

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-10-31 14:56:30.742757677 +0000
+++ new-output.txt	2025-10-31 14:56:33.878763195 +0000
@@ -927,6 +927,7 @@
 typeddicts_operations.py:29:42: error[invalid-argument-type] Invalid argument to key "year" with declared type `int` on TypedDict `Movie`: value of type `float`
 typeddicts_operations.py:32:36: error[invalid-key] Invalid key for TypedDict `Movie`: Unknown key "other"
 typeddicts_operations.py:37:20: error[missing-typed-dict-key] Missing required key 'name' in TypedDict `Movie` constructor
+typeddicts_operations.py:47:1: error[unresolved-attribute] Object of type `Movie` has no attribute `clear`
 typeddicts_operations.py:62:1: error[unresolved-attribute] Object of type `MovieOptional` has no attribute `clear`
 typeddicts_readonly.py:24:4: error[invalid-assignment] Cannot assign to key "members" on TypedDict `Band`: key is marked read-only
 typeddicts_readonly.py:50:4: error[invalid-assignment] Cannot assign to key "title" on TypedDict `Movie1`: key is marked read-only
@@ -946,5 +947,5 @@
 typeddicts_usage.py:28:17: error[missing-typed-dict-key] Missing required key 'name' in TypedDict `Movie` constructor
 typeddicts_usage.py:28:18: error[invalid-key] Invalid key for TypedDict `Movie`: Unknown key "title"
 typeddicts_usage.py:40:24: error[invalid-type-form] The special form `typing.TypedDict` is not allowed in type expressions. Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?
-Found 948 diagnostics
+Found 949 diagnostics
 WARN A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details.

@github-actions
Copy link
Contributor

mypy_primer results

Changes were detected when running on open source projects
cloud-init (https://github.com/canonical/cloud-init)
+ cloudinit/net/ephemeral.py:140:13: warning[possibly-missing-attribute] Attribute `get` may be missing on object of type `str | Unknown`
- cloudinit/net/ephemeral.py:140:13: error[unresolved-attribute] Object of type `str` has no attribute `get`
+ cloudinit/net/ephemeral.py:140:36: error[not-iterable] Object of type `Interface | None` may not be iterable
- Found 1139 diagnostics
+ Found 1140 diagnostics
No memory usage changes detected ✅

@carljm
Copy link
Contributor Author

carljm commented Oct 31, 2025

Conformance suite change is positive (we are supposed to error on that line).

Ecosystem change looks like we have a TypedDict type where we previously didn't.

@carljm carljm merged commit 1d111c8 into main Oct 31, 2025
41 checks passed
@carljm carljm deleted the cjm/invalidtd branch October 31, 2025 15:12
@carljm carljm added the internal An internal refactor or improvement label Oct 31, 2025
carljm added a commit that referenced this pull request Oct 31, 2025
…21169)

## Summary

Discussion with @ibraheemdev clarified that
#21168 was incorrect. In a case of
failed inference of a dict literal as a `TypedDict`, we should store the
context-less inferred type of the dict literal as the type of the dict
literal expression itself; the fallback to declared type should happen
at the level of the overall assignment definition.

The reason the latter isn't working yet is because currently we
(wrongly) consider a homogeneous dict type as assignable to a
`TypedDict`, so we don't actually consider the assignment itself as
failed. So the "bug" I observed (and tried to fix) will naturally be
fixed by implementing TypedDict assignability rules.

Rollback #21168 except for the
tests, and modify the tests to include TODOs as needed.

## Test Plan

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

Labels

internal An internal refactor or improvement ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants