From 443fd7ff085fd659030bc741c4f27701856308df Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Thu, 14 Sep 2023 22:31:35 +0100 Subject: [PATCH] Fix crash on malformed TypedDict in incremental mode --- mypy/semanal_typeddict.py | 14 ++++++++++---- test-data/unit/check-incremental.test | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/mypy/semanal_typeddict.py b/mypy/semanal_typeddict.py index fb3fa713e3fb..a9a4cd868f27 100644 --- a/mypy/semanal_typeddict.py +++ b/mypy/semanal_typeddict.py @@ -366,7 +366,13 @@ def check_typeddict( name, items, types, total, tvar_defs, ok = res if not ok: # Error. Construct dummy return value. - info = self.build_typeddict_typeinfo("TypedDict", [], [], set(), call.line, None) + if var_name: + name = var_name + if is_func_scope: + name += "@" + str(call.line) + else: + name = var_name = "TypedDict@" + str(call.line) + info = self.build_typeddict_typeinfo(name, [], [], set(), call.line, None) else: if var_name is not None and name != var_name: self.fail( @@ -395,9 +401,9 @@ def check_typeddict( name, items, types, required_keys, call.line, existing_info ) info.line = node.line - # Store generated TypeInfo under both names, see semanal_namedtuple for more details. - if name != var_name or is_func_scope: - self.api.add_symbol_skip_local(name, info) + # Store generated TypeInfo under both names, see semanal_namedtuple for more details. + if name != var_name or is_func_scope: + self.api.add_symbol_skip_local(name, info) if var_name: self.api.add_symbol(var_name, info, node) call.analyzed = TypedDictExpr(info) diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 06f87a26e7a1..801bbd4e77b4 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -6479,3 +6479,28 @@ from typing_extensions import TypeVarTuple, Unpack Ts = TypeVarTuple("Ts") class C(Tuple[Unpack[Ts]]): ... [builtins fixtures/tuple.pyi] + +[case testNoIncrementalCrashOnInvalidTypedDict] +import m +[file m.py] +import counts +[file m.py.2] +import counts +# touch +[file counts.py] +from typing_extensions import TypedDict +Counts = TypedDict("Counts", {k: int for k in "abc"}) # type: ignore +[builtins fixtures/dict.pyi] + +[case testNoIncrementalCrashOnInvalidTypedDictFunc] +import m +[file m.py] +import counts +[file m.py.2] +import counts +# touch +[file counts.py] +from typing_extensions import TypedDict +def test() -> None: + Counts = TypedDict("Counts", {k: int for k in "abc"}) # type: ignore +[builtins fixtures/dict.pyi]