diff --git a/mypy/messages.py b/mypy/messages.py index e11ee9d0f7f29..ebe76509c1b65 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -2658,6 +2658,7 @@ def get_bad_protocol_flags( if ( IS_CLASSVAR in subflags and IS_CLASSVAR not in superflags + and IS_SETTABLE in superflags or IS_CLASSVAR in superflags and IS_CLASSVAR not in subflags or IS_SETTABLE in superflags diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 9a4982f5b8ecb..b4f948c6a9c1e 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1027,7 +1027,10 @@ def named_type(fullname: str) -> Instance: if not is_subtype(supertype, subtype): return False if not class_obj: - if (IS_CLASSVAR in subflags) != (IS_CLASSVAR in superflags): + if IS_SETTABLE not in superflags: + if IS_CLASSVAR in superflags and IS_CLASSVAR not in subflags: + return False + elif (IS_CLASSVAR in subflags) != (IS_CLASSVAR in superflags): return False else: if IS_VAR in superflags and IS_CLASSVAR not in subflags: diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 113b2000fc227..ec7bf8816f341 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -1153,6 +1153,25 @@ x2 = y2 # E: Incompatible types in assignment (expression has type "PP", variabl # N: Protocol member P.attr expected settable variable, got read-only attribute [builtins fixtures/property.pyi] +[case testClassVarProtocolImmutable] +from typing import Protocol, ClassVar + +class P(Protocol): + @property + def x(self) -> int: ... + +class C: + x: ClassVar[int] + +class Bad: + x: ClassVar[str] + +x: P = C() +y: P = Bad() # E: Incompatible types in assignment (expression has type "Bad", variable has type "P") \ + # N: Following member(s) of "Bad" have conflicts: \ + # N: x: expected "int", got "str" +[builtins fixtures/property.pyi] + [case testSettablePropertyInProtocols] from typing import Protocol