diff --git a/mypy/checker.py b/mypy/checker.py index 4dabdc6fdfcd..b758af4ad5e6 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1530,7 +1530,11 @@ def bind_and_map_method(self, sym: SymbolTableNode, typ: FunctionLike, """ if (isinstance(sym.node, (FuncDef, OverloadedFuncDef, Decorator)) and not is_static(sym.node)): - bound = bind_self(typ, self.scope.active_self_type()) + if isinstance(sym.node, Decorator): + is_class_method = sym.node.func.is_class + else: + is_class_method = sym.node.is_class + bound = bind_self(typ, self.scope.active_self_type(), is_class_method) else: bound = typ return cast(FunctionLike, map_type_from_supertype(bound, sub_info, super_info)) diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index c7866dbbedee..4a3829200f65 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -2062,3 +2062,52 @@ class A: x, y = A() reveal_type(x) # N: Revealed type is 'Any' reveal_type(y) # N: Revealed type is 'Any' + +[case testSubclassingGenericSelfClassMethod] +from typing import TypeVar, Type + +AT = TypeVar('AT', bound='A') + +class A: + @classmethod + def from_config(cls: Type[AT]) -> AT: + ... + +class B(A): + @classmethod + def from_config(cls: Type[B]) -> B: + return B() +[builtins fixtures/classmethod.pyi] + +[case testSubclassingGenericSelfClassMethodOptional] +# flags: --strict-optional +from typing import TypeVar, Type, Optional + +AT = TypeVar('AT', bound='A') + +class A: + @classmethod + def from_config(cls: Type[AT]) -> Optional[AT]: + return None + +class B(A): + @classmethod + def from_config(cls: Type[B]) -> Optional[B]: + return B() +[builtins fixtures/classmethod.pyi] + +[case testSubclassingGenericSelfClassMethodNonAnnotated] +from typing import TypeVar, Type + +AT = TypeVar('AT', bound='A') + +class A: + @classmethod + def from_config(cls: Type[AT]) -> AT: + ... + +class B(A): + @classmethod + def from_config(cls) -> B: + return B() +[builtins fixtures/classmethod.pyi]