Repository: python/mypy

Issue:
typevars becoming types with typevars doesn't work
``` python
from typing import TypeVar
T = TypeVar('T')
V = TypeVar('V')

def identity(x: T) -> T: ...
def type_var_using_fn(x: V) -> None: ...
identity(type_var_using_fn)
```

has the confusing error:

```
test.py:10: error: Argument 1 to "identity" has incompatible type Callable[[V], None]; expected Callable[[V], None]
```

This is most commonly seen when decorating functions with TypeVars.



Discussion:
This could be another manifestation of the old type variable renaming bug (#230 or #603 may be related.)

Here's what's happening here:
- We need to typecheck the expression `identity(type_var_using_fn)`.
- Since `identity` is a generic function, we have to infer the correct `T` to pick for the call based on the argument. mypy correctly determines that `T = def [V] (x: V`-1)`, the type of the generic function `type_var_using_fn`.
- Having chosen `T`, we need to check that the arguments are actually valid. In this case, this means checking that the actual argument type `def [V] (x: V`-1)` is a subtype of the formal argument type `T = def [V] (x: V`-1)`. Of course it is, but [checking whether a callable is a subtype of a generic callable is not yet supported by mypy](https://github.com/python/mypy/blob/dda38dca533ba323c9f9013291cb9c2524b2615f/mypy/subtypes.py#L205), resulting in the confusing error message.

I think the mypythonic thing to do here is to just implement this subtyping check: A callable is a subtype of a generic callable if it is so after the generic callable is instantiated at fresh ("skolem") types.

Thanks for tracking this down!  I agree, implementing that subtyping check sounds like the right fix here.  

Thanks! That sounds like a great analysis. Can you pull of the fix without
more help?

I have what should be a fix, but encountered #1335 while testing it.


Resolving patch:
diff --git a/mypy/subtypes.py b/mypy/subtypes.py
--- a/mypy/subtypes.py
+++ b/mypy/subtypes.py
@@ -202,9 +202,18 @@ def is_callable_subtype(left: CallableType, right: CallableType,
     # Non-type cannot be a subtype of type.
     if right.is_type_obj() and not left.is_type_obj():
         return False
-    if right.variables:
-        # Subtyping is not currently supported for generic function as the supertype.
-        return False
+
+    # A callable L is a subtype of a generic callable R if L is a
+    # subtype of every type obtained from R by substituting types for
+    # the variables of R. We can check this by simply leaving the
+    # generic variables of R as type variables, effectively varying
+    # over all possible values.
+
+    # It's okay even if these variables share ids with generic
+    # type variables of L, because generating and solving
+    # constraints for the variables of L to make L a subtype of R
+    # (below) treats type variables on the two sides as independent.
+
     if left.variables:
         # Apply generic type variables away in left via type inference.
         left = unify_generic_callable(left, right, ignore_return=ignore_return)


Test patch:
diff --git a/mypy/test/data/check-generics.test b/mypy/test/data/check-generics.test
--- a/mypy/test/data/check-generics.test
+++ b/mypy/test/data/check-generics.test
@@ -640,6 +640,81 @@ a = '' # E: Incompatible types in assignment (expression has type "str", variabl
 -- -----------------------------------------
 
 
+[case testSubtypingWithGenericFunctions]
+from typing import TypeVar
+A = TypeVar('A')
+B = TypeVar('B')
+
+def f1(x: A) -> A: ...
+def f2(x: A) -> B: ...
+def f3(x: B) -> B: ...
+def f4(x: int) -> A: ...
+
+y1 = f1
+y1 = f1
+y1 = f2
+y1 = f3
+y1 = f4 # E: Incompatible types in assignment (expression has type Callable[[int], A], variable has type Callable[[A], A])
+
+y2 = f2
+y2 = f2
+y2 = f1 # E: Incompatible types in assignment (expression has type Callable[[A], A], variable has type Callable[[A], B])
+y2 = f3 # E: Incompatible types in assignment (expression has type Callable[[B], B], variable has type Callable[[A], B])
+y2 = f4 # E: Incompatible types in assignment (expression has type Callable[[int], A], variable has type Callable[[A], B])
+
+y3 = f3
+y3 = f3
+y3 = f1
+y3 = f2
+y3 = f4 # E: Incompatible types in assignment (expression has type Callable[[int], A], variable has type Callable[[B], B])
+
+y4 = f4
+y4 = f4
+y4 = f1 # E: Incompatible types in assignment (expression has type Callable[[A], A], variable has type Callable[[int], A])
+y4 = f2
+y4 = f3 # E: Incompatible types in assignment (expression has type Callable[[B], B], variable has type Callable[[int], A])
+
+[case testSubtypingWithGenericInnerFunctions]
+from typing import TypeVar
+A = TypeVar('A')
+B = TypeVar('B')
+T = TypeVar('T')
+def outer(t: T) -> None:
+    def f1(x: A) -> A: ...
+    def f2(x: A) -> B: ...
+    def f3(x: T) -> A: ...
+    def f4(x: A) -> T: ...
+    def f5(x: T) -> T: ...
+
+    y1 = f1
+    y1 = f2
+    y1 = f3 # E: Incompatible types in assignment (expression has type Callable[[T], A], variable has type Callable[[A], A])
+    y1 = f4 # E: Incompatible types in assignment (expression has type Callable[[A], T], variable has type Callable[[A], A])
+    y1 = f5 # E: Incompatible types in assignment (expression has type Callable[[T], T], variable has type Callable[[A], A])
+
+    y2 = f2
+    y2 = f1 # E: Incompatible types in assignment (expression has type Callable[[A], A], variable has type Callable[[A], B])
+
+    y3 = f3
+    y3 = f1 # E: Incompatible types in assignment (expression has type Callable[[A], A], variable has type Callable[[T], A])
+    y3 = f2
+    y3 = f4 # E: Incompatible types in assignment (expression has type Callable[[A], T], variable has type Callable[[T], A])
+    y3 = f5 # E: Incompatible types in assignment (expression has type Callable[[T], T], variable has type Callable[[T], A])
+
+    y4 = f4
+    y4 = f1 # E: Incompatible types in assignment (expression has type Callable[[A], A], variable has type Callable[[A], T])
+    y4 = f2
+    y4 = f3 # E: Incompatible types in assignment (expression has type Callable[[T], A], variable has type Callable[[A], T])
+    y4 = f5 # E: Incompatible types in assignment (expression has type Callable[[T], T], variable has type Callable[[A], T])
+
+    y5 = f5
+    y5 = f1
+    y5 = f2
+    y5 = f3
+    y5 = f4
+[out]
+main: note: In function "outer":
+
 [case testSubtypingWithGenericFunctionUsingTypevarWithValues]
 from typing import TypeVar, Callable
 T = TypeVar('T', int, str)
@@ -652,6 +727,13 @@ def g3(f: Callable[[object], object]) -> None: pass
 g3(f) # E: Argument 1 to "g3" has incompatible type Callable[[T], T]; \
            expected Callable[[object], object]
 
+[case testSubtypingWithGenericFunctionUsingTypevarWithValues2-skip]
+from typing import TypeVar, Callable
+T = TypeVar('T', int, str)
+def f(x: T) -> T: pass
+g = f
+g = f
+
 
 --Operations on type variable types
 -- ---------------------------------
@@ -729,8 +811,29 @@ def identity(f: Callable[[A], None]) -> Callable[[A], None]:
     return f
 identity(voidify)(3)
 
+[case testIdentityHigherOrderFunction3]
+from typing import Callable, TypeVar
+A = TypeVar('A')
+B = TypeVar('B')
+def fn(n: B) -> None: pass
+def identity(f: A) -> A:
+    return f
+identity(fn)
+identity(fn)('x')
+
 [case testTypeVariableUnionAndCallableInTypeInference]
 from typing import Union, Callable, TypeVar
 T = TypeVar('T')
 def f(x: T, y: Union[T, Callable[[T], None]]) -> None: pass
 f('', '')
+
+[case testGenericFunctionsWithUnalignedIds]
+from typing import TypeVar
+A = TypeVar('A')
+B = TypeVar('B')
+def f1(x: int, y: A) -> A: ...
+def f2(x: int, y: A) -> B: ...
+def f3(x: A, y: B) -> B: ...
+g = f1
+g = f2
+g = f3