diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 1a76372d4731..0210f8518434 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -1203,9 +1203,15 @@ def analyze_class_attribute_access( t = get_proper_type(t) if isinstance(t, FunctionLike) and is_classmethod: t = check_self_arg(t, mx.self_type, False, mx.context, name, mx.msg) - result = add_class_tvars( + t = add_class_tvars( t, isuper, is_classmethod, is_staticmethod, mx.self_type, original_vars=original_vars ) + if is_decorated and not is_staticmethod: + t = expand_self_type_if_needed( + t, mx, cast(Decorator, node.node).var, itype, is_class=is_classmethod + ) + + result = t # __set__ is not called on class objects. if not mx.is_lvalue: result = analyze_descriptor_access(result, mx) diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index ffa1a369e883..36a0fde31f19 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -2221,3 +2221,44 @@ class B: class C(A, B): # OK: both methods take Self pass [builtins fixtures/tuple.pyi] + +[case testSelfInFuncDecoratedClassmethod] +from collections.abc import Callable +from typing import Self, TypeVar + +T = TypeVar("T") + +def debug(make: Callable[[type[T]], T]) -> Callable[[type[T]], T]: + return make + +class Foo: + @classmethod + @debug + def make(cls) -> Self: + return cls() + +class Bar(Foo): ... + +reveal_type(Foo.make()) # N: Revealed type is "__main__.Foo" +reveal_type(Foo().make()) # N: Revealed type is "__main__.Foo" +reveal_type(Bar.make()) # N: Revealed type is "__main__.Bar" +reveal_type(Bar().make()) # N: Revealed type is "__main__.Bar" +[builtins fixtures/tuple.pyi] + +[case testSelfInClassDecoratedClassmethod] +from typing import Callable, Generic, TypeVar, Self + +T = TypeVar("T") + +class W(Generic[T]): + def __init__(self, fn: Callable[..., T]) -> None: ... + def __call__(self) -> T: ... + +class Check: + @W + def foo(self) -> Self: + ... + +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]