Repository: python/mypy

Issue:
Generic Self classmethod fails for generic types
Repro:

```python
from typing import Generic, TypeVar, Type

_T = TypeVar('_T')
SelfType = TypeVar('SelfType', bound='Friend')

class Friend(Generic[_T]):
    @classmethod
    def make(cls: Type[SelfType]) -> SelfType:  # E: Unsupported type Type["SelfType"]
        return cls()
```

I suspect the issue is that the type _should_ be:

```python
def make(cls: Type[SelfType[T]]) -> SelfType[T]:
        return cls()
```

But there is no way to express that that I can tell.

Using an instance method behaves as expected:
```
from typing import Generic, TypeVar, Type

_T = TypeVar('_T')
SelfType = TypeVar('SelfType', bound='Friend')

class Friend(Generic[_T]):
    other = None  # type: Friend

    def make(self: SelfType) -> SelfType:
        return self
```



Discussion:
I think this is a duplicate of #3363 and #2354 
I think we could leave only one of these three issues open and raise its priority.
@ilevkivskyi I'm fine with that.  AFAICT https://github.com/python/mypy/issues/2354 is effectively fixed, the code example below works great:

```python
from typing import Generic, TypeVar, Type

_T = TypeVar('_T')
SelfType = TypeVar('SelfType', bound='Friend')

class Friend(Generic[_T]):
    other = None  # type: Friend

    def make(self: SelfType) -> SelfType:
        return self

class SuperFriend(Generic[_T], Friend[_T]):
    pass


reveal_type(SuperFriend[int]().make())  # E: Revealed type is 'test_generic_self.SuperFriend[builtins.int]'
```

I'd be fine if `classmethods` had the same behavior.  In fact, @elazarg 's change https://github.com/python/mypy/pull/3633 _mostly_ fixes this issue.  The types (as opposed to `<nothing>`) are correct but declaring the function `make` still throws an error:

```python
from typing import Generic, TypeVar, Type

_T = TypeVar('_T')
SelfType = TypeVar('SelfType', bound='Friend')

class Friend(Generic[_T]):
    other = None  # type: Friend

    @classmethod
    def make(cls: Type[SelfType]) -> SelfType:  # E: Unsupported type Type["SelfType"]
        return cls()

class SuperFriend(Generic[_T], Friend[_T]):
    pass


reveal_type(SuperFriend[int]().make())  # E:  Revealed type is 'test_generic_self.SuperFriend*[builtins.int*]'
```
I think the `Unsupported type Type["SelfType"]` error is a separate issue. It happens even for `staticmethod`, for which there's no specific check for selftype.
@elazarg got it.  If you can land https://github.com/python/mypy/issues/2354 I can debug the `Type["SelfType"]` issue.
Yeah, it gives the same error when `Type[SelfType]` is used outside the
`Friend` class. It's purely because of the use of Type[] with a type
variable that is bound by a generic class.

I've been [sent here](https://stackoverflow.com/questions/51042452/bound-typevar-on-generic-methods-inside-generic-class) by stackoverflow. Issue is still relevant.

Resolving patch:
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -690,16 +690,10 @@ def analyze_type_type_callee(self, item: Type, context: Context) -> Type:
             callee = self.analyze_type_type_callee(item.upper_bound,
                                                    context)  # type: Optional[Type]
             if isinstance(callee, CallableType):
-                if callee.is_generic():
-                    callee = None
-                else:
-                    callee = callee.copy_modified(ret_type=item)
+                callee = callee.copy_modified(ret_type=item)
             elif isinstance(callee, Overloaded):
-                if callee.items()[0].is_generic():
-                    callee = None
-                else:
-                    callee = Overloaded([c.copy_modified(ret_type=item)
-                                         for c in callee.items()])
+                callee = Overloaded([c.copy_modified(ret_type=item)
+                                     for c in callee.items()])
             if callee:
                 return callee
 


Test patch:
diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test
--- a/test-data/unit/check-generics.test
+++ b/test-data/unit/check-generics.test
@@ -1778,6 +1778,16 @@ def f(c: Type[T]) -> T: ...
 x: Any
 reveal_type(f(x))  # E: Revealed type is 'Any'
 
+[case testCallTypeTWithGenericBound]
+from typing import Generic, TypeVar, Type
+T = TypeVar('T')
+S = TypeVar('S', bound='A')
+
+class A(Generic[T]): pass
+
+def f(cls: Type[S]) -> None:
+    cls()
+
 [case testQualifiedTypeVariableName]
 import b
 def f(x: b.T) -> b.T: return x