Repository: python/mypy

Issue:
A callable typed function is not recognised as a TypeVar-ed argument
**Bug Report**

I give my function a typed Callable, I get an error:

**To Reproduce**

```
def type_guard(x: Any, type_check_func: Callable[[Any], TypeGuard[T]]) -> T:
      if not type_check_func(x):
              raise TypeError("failed type assetion")
          return x

def is_string(x: Any) -> TypeGuard[str]:
    return isinstance(x, str)

data = "helloworld"
val = type_guard(data, is_string)
```

**Expected Behavior**

Should not error

**Actual Behavior**

A function returning TypeVar should receive at least one argument containing the same TypeVar  [type-var]
**Your Environment**

<!-- Include as many relevant details about the environment you experienced the bug in -->

- Mypy version used: 1.4.1


A callable typed function is not recognised as a TypeVar-ed argument
**Bug Report**

I give my function a typed Callable, I get an error:

**To Reproduce**

```
def type_guard(x: Any, type_check_func: Callable[[Any], TypeGuard[T]]) -> T:
      if not type_check_func(x):
              raise TypeError("failed type assetion")
          return x

def is_string(x: Any) -> TypeGuard[str]:
    return isinstance(x, str)

data = "helloworld"
val = type_guard(data, is_string)
```

**Expected Behavior**

Should not error

**Actual Behavior**

A function returning TypeVar should receive at least one argument containing the same TypeVar  [type-var]
**Your Environment**

<!-- Include as many relevant details about the environment you experienced the bug in -->

- Mypy version used: 1.4.1




Discussion:
Still reproduces on 1.9.0: https://mypy-play.net/?mypy=latest&python=3.10&gist=bd80437034ccf2a3142a5dc74b1fb7b1

I imagine the code that produces that error doesn't know to look inside the TypeGuard. If so, this should be an easy fix.
Still reproduces on 1.9.0: https://mypy-play.net/?mypy=latest&python=3.10&gist=bd80437034ccf2a3142a5dc74b1fb7b1

I imagine the code that produces that error doesn't know to look inside the TypeGuard. If so, this should be an easy fix.

Patch:
diff --git a/mypy/typetraverser.py b/mypy/typetraverser.py
--- a/mypy/typetraverser.py
+++ b/mypy/typetraverser.py
@@ -86,6 +86,12 @@ def visit_callable_type(self, t: CallableType) -> None:
         t.ret_type.accept(self)
         t.fallback.accept(self)
 
+        if t.type_guard is not None:
+            t.type_guard.accept(self)
+
+        if t.type_is is not None:
+            t.type_is.accept(self)
+
     def visit_tuple_type(self, t: TupleType) -> None:
         self.traverse_types(t.items)
         t.partial_fallback.accept(self)


Test patch:
diff --git a/test-data/unit/check-typeguard.test b/test-data/unit/check-typeguard.test
--- a/test-data/unit/check-typeguard.test
+++ b/test-data/unit/check-typeguard.test
@@ -54,6 +54,18 @@ def main(a: object, b: object) -> None:
         reveal_type(b)  # N: Revealed type is "builtins.object"
 [builtins fixtures/tuple.pyi]
 
+[case testTypeGuardTypeVarReturn]
+from typing import Callable, Optional, TypeVar
+from typing_extensions import TypeGuard
+T = TypeVar('T')
+def is_str(x: object) -> TypeGuard[str]: pass
+def main(x: object, type_check_func: Callable[[object], TypeGuard[T]]) -> T:
+    if not type_check_func(x):
+        raise Exception()
+    return x
+reveal_type(main("a", is_str))  # N: Revealed type is "builtins.str"
+[builtins fixtures/exception.pyi]
+
 [case testTypeGuardIsBool]
 from typing_extensions import TypeGuard
 def f(a: TypeGuard[int]) -> None: pass
diff --git a/test-data/unit/check-typeis.test b/test-data/unit/check-typeis.test
--- a/test-data/unit/check-typeis.test
+++ b/test-data/unit/check-typeis.test
@@ -92,6 +92,18 @@ def main(a: Tuple[object, ...]):
         reveal_type(a)  # N: Revealed type is "builtins.tuple[builtins.int, ...]"
 [builtins fixtures/tuple.pyi]
 
+[case testTypeIsTypeVarReturn]
+from typing import Callable, Optional, TypeVar
+from typing_extensions import TypeIs
+T = TypeVar('T')
+def is_str(x: object) -> TypeIs[str]: pass
+def main(x: object, type_check_func: Callable[[object], TypeIs[T]]) -> T:
+    if not type_check_func(x):
+        raise Exception()
+    return x
+reveal_type(main("a", is_str))  # N: Revealed type is "builtins.str"
+[builtins fixtures/exception.pyi]
+
 [case testTypeIsUnionIn]
 from typing import Union
 from typing_extensions import TypeIs