From 071f0f37d3cf46a408ccc6c0e331e97ad9903ab0 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Tue, 30 Jul 2024 14:35:17 -0700 Subject: [PATCH] Fix crash on unimported Any with Required/NotRequired Fixes #17604; fixes #17608. (To reproduce the crash without mypyc, replace `cast(ProperType, typ)` with an assertion in `get_proper_type`.) Signed-off-by: Anders Kaseorg --- mypy/checker.py | 7 ++++++- mypy/stats.py | 3 ++- test-data/unit/check-typeddict.test | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 59de599006a8..acfff1db7285 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -198,6 +198,7 @@ Overloaded, PartialType, ProperType, + RequiredType, TupleType, Type, TypeAliasType, @@ -2945,7 +2946,11 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: "A type on this line", AnyType(TypeOfAny.special_form), s ) else: - self.msg.unimported_type_becomes_any("Type of variable", s.type, s) + self.msg.unimported_type_becomes_any( + "Type of variable", + s.type.item if isinstance(s.type, RequiredType) else s.type, + s, + ) check_for_explicit_any(s.type, self.options, self.is_typeshed_stub, self.msg, context=s) if len(s.lvalues) > 1: diff --git a/mypy/stats.py b/mypy/stats.py index 9c69a245741b..af7f4114ca61 100644 --- a/mypy/stats.py +++ b/mypy/stats.py @@ -48,6 +48,7 @@ CallableType, FunctionLike, Instance, + RequiredType, TupleType, Type, TypeOfAny, @@ -205,7 +206,7 @@ def visit_assignment_stmt(self, o: AssignmentStmt) -> None: if o.type: # If there is an explicit type, don't visit the l.h.s. as an expression # to avoid double-counting and mishandling special forms. - self.type(o.type) + self.type(o.type.item if isinstance(o.type, RequiredType) else o.type) o.rvalue.accept(self) return elif self.inferred and not self.all_nodes: diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 1ef08f825e7a..25565bbee171 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -2394,6 +2394,14 @@ class ForceDeferredEval: pass [builtins fixtures/dict.pyi] [typing fixtures/typing-typeddict.pyi] +[case testTypedDictRequiredUnimportedAny] +# flags: --disallow-any-unimported +from typing import NotRequired, TypedDict +from nonexistent import Foo # type: ignore[import-not-found] +class Bar(TypedDict): + foo: NotRequired[Foo] # E: Type of variable becomes "Any" due to an unfollowed import +[typing fixtures/typing-typeddict.pyi] + -- Required[] [case testDoesRecognizeRequiredInTypedDictWithClass]