Skip to content

Commit ac24ed3

Browse files
authored
Reject fake TypeInfos for TypedDict fallbacks (#7195)
This avoids possible crashes during calculations of meets and joins on a cold update. We do this by rejecting a fake ad-hoc `TypeInfo` created by `fixup.py` if a file containing the typed dict fallback was deleted, and instead using the generic `typing._TypedDict` fallback.
1 parent e479b6d commit ac24ed3

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

mypy/fixup.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ def visit_typeddict_type(self, tdt: TypedDictType) -> None:
209209
for it in tdt.items.values():
210210
it.accept(self)
211211
if tdt.fallback is not None:
212+
if tdt.fallback.type_ref is not None:
213+
if lookup_qualified(self.modules, tdt.fallback.type_ref,
214+
self.allow_missing) is None:
215+
# We reject fake TypeInfos for TypedDict fallbacks because
216+
# the latter are used in type checking and must be valid.
217+
tdt.fallback.type_ref = 'typing._TypedDict'
212218
tdt.fallback.accept(self)
213219

214220
def visit_literal_type(self, lt: LiteralType) -> None:

test-data/unit/fine-grained.test

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9061,3 +9061,69 @@ def f() -> str: pass
90619061
[builtins fixtures/classmethod.pyi]
90629062
[out]
90639063
==
9064+
9065+
[case testTypedDictCrashFallbackAfterDeletedMeet]
9066+
# flags: --ignore-missing-imports
9067+
9068+
from z import get_data
9069+
from a import Data
9070+
9071+
for it in get_data()['things']:
9072+
it['id']
9073+
9074+
[file z.py]
9075+
from a import Data
9076+
9077+
def get_data() -> Data: ...
9078+
9079+
[file a.py]
9080+
from typing import TypedDict, List, Union
9081+
9082+
class File(TypedDict):
9083+
id: int
9084+
name: str
9085+
9086+
class User(TypedDict):
9087+
id: int
9088+
path: str
9089+
9090+
class Data(TypedDict):
9091+
things: List[Union[File, User]]
9092+
9093+
[delete a.py.2]
9094+
[builtins fixtures/dict.pyi]
9095+
[typing fixtures/typing-full.pyi]
9096+
[out]
9097+
==
9098+
9099+
[case testTypedDictCrashFallbackAfterDeletedJoin]
9100+
# flags: --ignore-missing-imports
9101+
9102+
from z import get_data
9103+
from a import Data
9104+
9105+
x = [get_data()[0], get_data()[1]]
9106+
9107+
[file z.py]
9108+
from a import Data
9109+
9110+
def get_data() -> Data: ...
9111+
9112+
[file a.py]
9113+
from typing import TypedDict, Tuple
9114+
9115+
class File(TypedDict):
9116+
id: int
9117+
name: str
9118+
9119+
class User(TypedDict):
9120+
id: int
9121+
path: str
9122+
9123+
Data = Tuple[User, File]
9124+
9125+
[delete a.py.2]
9126+
[builtins fixtures/dict.pyi]
9127+
[typing fixtures/typing-full.pyi]
9128+
[out]
9129+
==

0 commit comments

Comments
 (0)