From c52885148438a430fd50df770e499db1d9094018 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Wed, 18 Jun 2025 17:34:32 +0200 Subject: [PATCH 1/3] Remove is_staticmethod check altogether: there's no concept of self types for static methods --- mypy/checkmember.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 8f62fee699c0..fb25ce456dcc 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -1227,9 +1227,6 @@ def analyze_class_attribute_access( is_classmethod = (is_decorated and cast(Decorator, node.node).func.is_class) or ( isinstance(node.node, SYMBOL_FUNCBASE_TYPES) and node.node.is_class ) - is_staticmethod = (is_decorated and cast(Decorator, node.node).func.is_static) or ( - isinstance(node.node, SYMBOL_FUNCBASE_TYPES) and node.node.is_static - ) t = get_proper_type(t) is_trivial_self = False if isinstance(node.node, Decorator): @@ -1247,7 +1244,7 @@ def analyze_class_attribute_access( original_vars=original_vars, is_trivial_self=is_trivial_self, ) - if is_decorated and not is_staticmethod: + if is_decorated: t = expand_self_type_if_needed( t, mx, cast(Decorator, node.node).var, itype, is_class=is_classmethod ) From 3bbd0d651096b94cebc45292eeff0f1427327975 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Wed, 18 Jun 2025 17:45:32 +0200 Subject: [PATCH 2/3] Add a testcase Ivan asked for --- test-data/unit/check-selftype.test | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 12d6133ec83f..fcfbb4dd5446 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -2260,3 +2260,40 @@ class Check: reveal_type(Check.foo()) # N: Revealed type is "def () -> __main__.Check" reveal_type(Check().foo()) # N: Revealed type is "__main__.Check" [builtins fixtures/tuple.pyi] + +[case testSelfInClassmethodWithOtherSelfMethod] +from typing import Any, Callable, Self, TypeVar + +_C = TypeVar("_C", bound=Callable[..., Any]) + +def identity(func: _C, /) -> _C: + return func + +class A: + def meth(self) -> Self: ... + + @classmethod + def other_meth(cls) -> Self: + reveal_type(cls.meth) # N: Revealed type is "def [Self <: __main__.A] (self: Self`1) -> Self`1" + reveal_type(A.meth) # N: Revealed type is "def [Self <: __main__.A] (self: Self`2) -> Self`2" + return cls().meth() + +class B: + @identity + def meth(self) -> Self: ... + + @classmethod + def other_meth(cls) -> Self: + reveal_type(cls.meth) # N: Revealed type is "def [Self <: __main__.B] (self: Self`6) -> Self`6" + reveal_type(B.meth) # N: Revealed type is "def [Self <: __main__.B] (self: Self`7) -> Self`7" + return cls().meth() + +class C: + @classmethod + def other_meth(cls) -> Self: ... + + def meth(self) -> Self: + reveal_type(self.other_meth) # N: Revealed type is "def () -> Self`0" + reveal_type(type(self).other_meth) # N: Revealed type is "def () -> Self`0" + return self.other_meth() +[builtins fixtures/tuple.pyi] From 43c27652eefdf1c29e3a39e1a9462ec8718c91dc Mon Sep 17 00:00:00 2001 From: STerliakov Date: Sun, 3 Aug 2025 14:28:25 +0200 Subject: [PATCH 3/3] Sync typevar ids --- test-data/unit/check-selftype.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 71853dcaa515..6481a1766944 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -2306,8 +2306,8 @@ class B: @classmethod def other_meth(cls) -> Self: - reveal_type(cls.meth) # N: Revealed type is "def [Self <: __main__.B] (self: Self`6) -> Self`6" - reveal_type(B.meth) # N: Revealed type is "def [Self <: __main__.B] (self: Self`7) -> Self`7" + reveal_type(cls.meth) # N: Revealed type is "def [Self <: __main__.B] (self: Self`5) -> Self`5" + reveal_type(B.meth) # N: Revealed type is "def [Self <: __main__.B] (self: Self`6) -> Self`6" return cls().meth() class C: