From 97684e234fb62f5de36d66473564fb9e92054e83 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Fri, 10 Jan 2025 21:51:12 +0100 Subject: [PATCH 1/3] Add missing `map_type_from_supertype` when checking attr override with property --- mypy/checker.py | 7 +++ test-data/unit/check-generic-subtyping.test | 63 +++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 3d0f40283606..cf21500af29a 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2095,6 +2095,13 @@ def check_method_override_for_base_with_name( if original_node and is_property(original_node): original_type = get_property_type(original_type) + if isinstance(original_node, Var): + expanded_type = map_type_from_supertype(original_type, defn.info, base) + expanded_type = expand_self_type( + original_node, expanded_type, fill_typevars(defn.info) + ) + original_type = get_proper_type(expanded_type) + if is_property(defn): inner: FunctionLike | None if isinstance(typ, FunctionLike): diff --git a/test-data/unit/check-generic-subtyping.test b/test-data/unit/check-generic-subtyping.test index 90180e0f83f6..f882865dcf77 100644 --- a/test-data/unit/check-generic-subtyping.test +++ b/test-data/unit/check-generic-subtyping.test @@ -1065,3 +1065,66 @@ class F(E[T_co], Generic[T_co]): ... # E: Variance of TypeVar "T_co" incompatib class G(Generic[T]): ... class H(G[T_contra], Generic[T_contra]): ... # E: Variance of TypeVar "T_contra" incompatible with variance in parent type + +[case testParameterizedGenericOverrideWithProperty] +from typing import TypeVar, Generic + +T = TypeVar("T") + +class A(Generic[T]): + def __init__(self, val: T): + self.member: T = val + +class B(A[str]): + member: str + +class GoodPropertyOverride(A[str]): + @property + def member(self) -> str: ... + + @member.setter + def member(self, val: str): ... + +class BadPropertyOverride(A[str]): + @property # E: Signature of "member" incompatible with supertype "A" \ + # N: Superclass: \ + # N: str \ + # N: Subclass: \ + # N: int + def member(self) -> int: ... + + @member.setter + def member(self, val: int): ... + +class BadGenericPropertyOverride(A[str], Generic[T]): + @property # E: Signature of "member" incompatible with supertype "A" \ + # N: Superclass: \ + # N: str \ + # N: Subclass: \ + # N: T + def member(self) -> T: ... + + @member.setter + def member(self, val: T): ... +[builtins fixtures/property.pyi] + +[case testParameterizedGenericOverrideWithSelfProperty] +from typing import TypeVar, Generic +from typing_extensions import Self + +T = TypeVar("T") + +class A(Generic[T]): + def __init__(self, val: T): + self.member: T = val + +class B(A["B"]): + member: Self + +class GoodPropertyOverride(A["GoodPropertyOverride"]): + @property + def member(self) -> Self: ... + + @member.setter + def member(self, val: Self): ... +[builtins fixtures/property.pyi] From 66a51488adfd96d8bd30bd3d48d7e5b16ea3140b Mon Sep 17 00:00:00 2001 From: STerliakov Date: Fri, 10 Jan 2025 22:21:10 +0100 Subject: [PATCH 2/3] Add explicit testcase with Self in parent --- test-data/unit/check-generic-subtyping.test | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test-data/unit/check-generic-subtyping.test b/test-data/unit/check-generic-subtyping.test index f882865dcf77..2395b1aa614d 100644 --- a/test-data/unit/check-generic-subtyping.test +++ b/test-data/unit/check-generic-subtyping.test @@ -1108,6 +1108,28 @@ class BadGenericPropertyOverride(A[str], Generic[T]): def member(self, val: T): ... [builtins fixtures/property.pyi] +[case testParameterizedGenericOverrideSelfWithProperty] +from typing_extensions import Self + +class A: + def __init__(self, val: Self): + self.member: Self = val + +class GoodPropertyOverride(A): + @property + def member(self) -> "GoodPropertyOverride": ... + + @member.setter + def member(self, val: "GoodPropertyOverride"): ... + +class GoodPropertyOverrideSelf(A): + @property + def member(self) -> Self: ... + + @member.setter + def member(self, val: Self): ... +[builtins fixtures/property.pyi] + [case testParameterizedGenericOverrideWithSelfProperty] from typing import TypeVar, Generic from typing_extensions import Self From e77b8a54b069347bac462d110582f2b2241487d1 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Fri, 10 Jan 2025 22:23:02 +0100 Subject: [PATCH 3/3] And property/property override with typevar --- test-data/unit/check-generic-subtyping.test | 45 ++++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/test-data/unit/check-generic-subtyping.test b/test-data/unit/check-generic-subtyping.test index 2395b1aa614d..ee5a9c8ac7bb 100644 --- a/test-data/unit/check-generic-subtyping.test +++ b/test-data/unit/check-generic-subtyping.test @@ -1081,7 +1081,6 @@ class B(A[str]): class GoodPropertyOverride(A[str]): @property def member(self) -> str: ... - @member.setter def member(self, val: str): ... @@ -1092,7 +1091,6 @@ class BadPropertyOverride(A[str]): # N: Subclass: \ # N: int def member(self) -> int: ... - @member.setter def member(self, val: int): ... @@ -1103,7 +1101,47 @@ class BadGenericPropertyOverride(A[str], Generic[T]): # N: Subclass: \ # N: T def member(self) -> T: ... + @member.setter + def member(self, val: T): ... +[builtins fixtures/property.pyi] + +[case testParameterizedGenericPropertyOverrideWithProperty] +from typing import TypeVar, Generic + +T = TypeVar("T") + +class A(Generic[T]): + @property + def member(self) -> T: ... + @member.setter + def member(self, val: T): ... + +class B(A[str]): + member: str + +class GoodPropertyOverride(A[str]): + @property + def member(self) -> str: ... + @member.setter + def member(self, val: str): ... + +class BadPropertyOverride(A[str]): + @property # E: Signature of "member" incompatible with supertype "A" \ + # N: Superclass: \ + # N: str \ + # N: Subclass: \ + # N: int + def member(self) -> int: ... + @member.setter + def member(self, val: int): ... +class BadGenericPropertyOverride(A[str], Generic[T]): + @property # E: Signature of "member" incompatible with supertype "A" \ + # N: Superclass: \ + # N: str \ + # N: Subclass: \ + # N: T + def member(self) -> T: ... @member.setter def member(self, val: T): ... [builtins fixtures/property.pyi] @@ -1118,14 +1156,12 @@ class A: class GoodPropertyOverride(A): @property def member(self) -> "GoodPropertyOverride": ... - @member.setter def member(self, val: "GoodPropertyOverride"): ... class GoodPropertyOverrideSelf(A): @property def member(self) -> Self: ... - @member.setter def member(self, val: Self): ... [builtins fixtures/property.pyi] @@ -1146,7 +1182,6 @@ class B(A["B"]): class GoodPropertyOverride(A["GoodPropertyOverride"]): @property def member(self) -> Self: ... - @member.setter def member(self, val: Self): ... [builtins fixtures/property.pyi]