Repository: python/mypy

Issue:
Prohibit parameterized generics in isinstance
As @ilevkivskyi commented (https://github.com/python/mypy/pull/3005#discussion_r106779110), it would be nice to fail type check on this code:

```
obj = 1
if isinstance(obj, Iterable[int]):
    1
```
because it fails in runtime with `TypeError`. 

I can easily see this situation inside `checker.py:get_isinstance_type()` by verifying that `len(type.items()[0].ret_type.args) == 0`; but is it the right place to message about type validation problems?




Discussion:
Maybe the right place is in ``visit_call_expr`` in ``checkexpr.py``? If the name of function called is ``builtins.isinstance`` or ``builtins.issubclass``  and there is, for example, any ``CallableType`` argument with ``.is_class_obj()`` returning ``True`` and having type arguments, then you issue a warning.

Resolving patch:
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -178,6 +178,19 @@ def visit_call_expr(self, e: CallExpr, allow_none_return: bool = False) -> Type:
                 e.callee.node.typeddict_type is not None:
             return self.check_typeddict_call(e.callee.node.typeddict_type,
                                              e.arg_kinds, e.arg_names, e.args, e)
+        if isinstance(e.callee, NameExpr) and e.callee.name in ('isinstance', 'issubclass'):
+            for typ in mypy.checker.flatten(e.args[1]):
+                if isinstance(typ, NameExpr):
+                    try:
+                        node = self.chk.lookup_qualified(typ.name)
+                    except KeyError:
+                        # Undefined names should already be reported in semantic analysis.
+                        node = None
+                if (isinstance(typ, IndexExpr)
+                        and isinstance(typ.analyzed, (TypeApplication, TypeAliasExpr))
+                        # node.kind == TYPE_ALIAS only for aliases like It = Iterable[int].
+                        or isinstance(typ, NameExpr) and node and node.kind == nodes.TYPE_ALIAS):
+                    self.msg.type_arguments_not_allowed(e)
         self.try_infer_partial_type(e)
         callee_type = self.accept(e.callee)
         if (self.chk.options.disallow_untyped_calls and
diff --git a/mypy/messages.py b/mypy/messages.py
--- a/mypy/messages.py
+++ b/mypy/messages.py
@@ -881,6 +881,9 @@ def typeddict_item_name_not_found(self,
         self.fail('\'{}\' is not a valid item name; expected one of {}'.format(
             item_name, format_item_name_list(typ.items.keys())), context)
 
+    def type_arguments_not_allowed(self, context: Context) -> None:
+        self.fail('Parameterized generics cannot be used with class or instance checks', context)
+
 
 def capitalize(s: str) -> str:
     """Capitalize the first character of a string."""


Test patch:
diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test
--- a/test-data/unit/check-isinstance.test
+++ b/test-data/unit/check-isinstance.test
@@ -1423,6 +1423,45 @@ def f(x: Union[int, A], a: Type[A]) -> None:
 [builtins fixtures/isinstancelist.pyi]
 
 
+[case testIsinstanceTypeArgs]
+from typing import Iterable, TypeVar
+x = 1
+T = TypeVar('T')
+
+isinstance(x, Iterable)
+isinstance(x, Iterable[int])  # E: Parameterized generics cannot be used with class or instance checks
+isinstance(x, Iterable[T])  # E: Parameterized generics cannot be used with class or instance checks
+isinstance(x, (int, Iterable[int]))  # E: Parameterized generics cannot be used with class or instance checks
+isinstance(x, (int, (str, Iterable[int])))  # E: Parameterized generics cannot be used with class or instance checks
+
+[builtins fixtures/isinstancelist.pyi]
+
+[case testIsinstanceTypeArgsAliases]
+from typing import Iterable, TypeVar
+x = 1
+T = TypeVar('T')
+It = Iterable
+It2 = Iterable[T]
+
+isinstance(x, It[int])  # E: Parameterized generics cannot be used with class or instance checks
+isinstance(x, It)
+isinstance(x, It2[int])  # E: Parameterized generics cannot be used with class or instance checks
+isinstance(x, It2)  # E: Parameterized generics cannot be used with class or instance checks
+
+[builtins fixtures/isinstance.pyi]
+
+
+[case testIssubclassTypeArgs]
+from typing import Iterable, TypeVar
+x = int
+T = TypeVar('T')
+issubclass(x, Iterable)
+issubclass(x, Iterable[int])  # E: Parameterized generics cannot be used with class or instance checks
+issubclass(x, Iterable[T])  # E: Parameterized generics cannot be used with class or instance checks
+issubclass(x, (int, Iterable[int]))  # E: Parameterized generics cannot be used with class or instance checks
+
+[builtins fixtures/isinstance.pyi]
+
 [case testIsinstanceAndNarrowTypeVariable]
 from typing import TypeVar