From 61a9b92297e1363b5bd99855df51e9a84be8da69 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 24 Aug 2022 10:40:56 +0100 Subject: [PATCH] Fix crash when nested class appears in a protocol (#13489) Fixes #6393 This is unspecified behavior in terms of PEP 544, so we just try to do something meaningful (see test case). At least we should not crash. --- mypy/subtypes.py | 5 +++++ test-data/unit/check-protocols.test | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index a7ff37b8a62f..6c0fd6510e7f 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -61,6 +61,7 @@ is_named_instance, ) from mypy.typestate import SubtypeKind, TypeState +from mypy.typevars import fill_typevars_with_any from mypy.typevartuples import extract_unpack, split_with_instance # Flags for detected protocol members @@ -1060,6 +1061,10 @@ def find_member( return getattr_type if itype.type.fallback_to_any: return AnyType(TypeOfAny.special_form) + if isinstance(v, TypeInfo): + # PEP 544 doesn't specify anything about such use cases. So we just try + # to do something meaningful (at least we should not crash). + return TypeType(fill_typevars_with_any(v)) return None diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 9be657257fe1..36e4959852f7 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -3118,3 +3118,23 @@ class P(Protocol): class A(P): ... A() # E: Cannot instantiate abstract class "A" with abstract attribute "f" + +[case testProtocolWithNestedClass] +from typing import TypeVar, Protocol + +class Template(Protocol): + var: int + class Meta: ... + +class B: + var: int + class Meta: ... +class C: + var: int + class Meta(Template.Meta): ... + +def foo(t: Template) -> None: ... +foo(B()) # E: Argument 1 to "foo" has incompatible type "B"; expected "Template" \ + # N: Following member(s) of "B" have conflicts: \ + # N: Meta: expected "Type[__main__.Template.Meta]", got "Type[__main__.B.Meta]" +foo(C()) # OK