From 9274a07bfa3c92b38fe35cf9736beb068ae9196b Mon Sep 17 00:00:00 2001 From: Stanislav Terliakov <50529348+sterliakov@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:48:00 +0100 Subject: [PATCH] Fix parent generics mapping when overriding generic attribute with property (#18441) Fixes #18189. Following #18415, this fixes one more place where parent class generics aren't mapped to attributes correctly. --------- Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- mypy/checker.py | 7 ++ test-data/unit/check-generic-subtyping.test | 120 ++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 80de4254766b..6a53d12791c5 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 03a0654520fd..89465869f09d 100644 --- a/test-data/unit/check-generic-subtyping.test +++ b/test-data/unit/check-generic-subtyping.test @@ -1066,6 +1066,126 @@ 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 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] + +[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 + +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] + [case testMultipleInheritanceCompatibleTypeVar] from typing import Generic, TypeVar