From a5e9b0b7fe5f2b5e3b3efac844216159a24ebd9c Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 16 Oct 2024 15:36:09 +0100 Subject: [PATCH] Fix crash when showing partially analyzed type in error message (#17961) Fixes https://github.com/python/mypy/issues/17954 People say something about cache invalidation being one of the hardest problems... --- mypy/semanal.py | 8 ++++++-- test-data/unit/check-recursive-types.test | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 27abf2c1dc4c..00383c010dc9 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -3958,8 +3958,10 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: # so we need to replace it with non-explicit Anys. res = make_any_non_explicit(res) if self.options.disallow_any_unimported and has_any_from_unimported_type(res): - self.msg.unimported_type_becomes_any("Type alias target", res, s) - res = make_any_non_unimported(res) + # Only show error message once, when the type is fully analyzed. + if not has_placeholder(res): + self.msg.unimported_type_becomes_any("Type alias target", res, s) + res = make_any_non_unimported(res) # Note: with the new (lazy) type alias representation we only need to set no_args to True # if the expected number of arguments is non-zero, so that aliases like `A = List` work # but not aliases like `A = TypeAliasType("A", List)` as these need explicit type params. @@ -4013,6 +4015,8 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: existing.node.alias_tvars = alias_tvars existing.node.no_args = no_args updated = True + # Invalidate recursive status cache in case it was previously set. + existing.node._is_recursive = None else: # Otherwise just replace existing placeholder with type alias. existing.node = alias_node diff --git a/test-data/unit/check-recursive-types.test b/test-data/unit/check-recursive-types.test index ac1ea0c0035a..4d7af98204fb 100644 --- a/test-data/unit/check-recursive-types.test +++ b/test-data/unit/check-recursive-types.test @@ -1006,3 +1006,11 @@ ta: Tuple[A] p: Proto p = ta [builtins fixtures/tuple.pyi] + +[case testRecursiveAliasesWithAnyUnimported] +# flags: --disallow-any-unimported +from typing import Callable +from bogus import Foo # type: ignore + +A = Callable[[Foo, "B"], Foo] # E: Type alias target becomes "Callable[[Any, B], Any]" due to an unfollowed import +B = Callable[[Foo, A], Foo] # E: Type alias target becomes "Callable[[Any, A], Any]" due to an unfollowed import