// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.inspections;

import com.jetbrains.python.fixtures.PyInspectionTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NotNull;

public class PyTypeHintsInspectionTest extends PyInspectionTestCase {

  // PY-28243
  public void testTypeVarAndTargetName() {
    doTestByText("""
                   from typing import TypeVar

                   T0 = TypeVar('T0')
                   T1 = TypeVar(<warning descr="The argument to 'TypeVar()' must be a string equal to the variable name to which it is assigned">'T2'</warning>)""");
  }

  // PY-28243
  public void testTypeVarPlacement() {
    doTestByText("""
                   from typing import List, TypeVar

                   T0 = TypeVar('T0')
                   a: List[<warning descr="Unbound type variable">T0</warning>]
                   b: List[<warning descr="A 'TypeVar()' expression must always directly be assigned to a variable">TypeVar('T1')</warning>]""");
  }

  // PY-28243
  public void testTypeVarRedefinition() {
    doTestByText("""
                   from typing import TypeVar

                   T0 = TypeVar('T0')
                   print(T0)
                   <warning descr="Type variables must not be redefined">T0</warning> = TypeVar('T0')""");
  }

  // PY-28124
  public void testTypeVarBivariant() {
    doTestByText("""
                   from typing import TypeVar

                   T1 = <error descr="Bivariant type variables are not supported">TypeVar('T1', contravariant=True, covariant=True)</error>
                   true = True
                   T2 = <error descr="Bivariant type variables are not supported">TypeVar('T2', contravariant=true, covariant=true)</error>""");
  }

  // PY-28124
  public void testTypeVarConstraintsAndBound() {
    doTestByText("""
                   from typing import TypeVar

                   T2 = <error descr="Constraints cannot be combined with bound=...">TypeVar('T2', int, str, bound=str)</error>""");
  }

  // PY-28124
  public void testTypeVarConstraintsNumber() {
    doTestByText("""
                   from typing import TypeVar

                   T1 = <error descr="A single constraint is not allowed">TypeVar('T1', int)</error>
                   T2 = TypeVar('T2', int, str)""");
  }

  // PY-28124
  public void testTypeVarNameAsLiteral() {
    doTestByText("""
                   from typing import TypeVar

                   name = 'T0'
                   T0 = TypeVar(<warning descr="'TypeVar()' expects a string literal as first argument">name</warning>)
                   T1 = TypeVar('T1')""");
  }

  // PY-28243
  public void testTypeVarParameterizedConstraints() {
    doTestByText("""
                   from typing import TypeVar, List

                   T1 = TypeVar('T1', int, str)

                   T2 = TypeVar('T2', int, <warning descr="Constraints cannot be parametrized by type variables">List[<warning descr="Unbound type variable">T1</warning>]</warning>)
                   T3 = TypeVar('T3', bound=<warning descr="Constraints cannot be parametrized by type variables">List[<warning descr="Unbound type variable">T1</warning>]</warning>)

                   T4 = TypeVar('T4', int, List[int])
                   T5 = TypeVar('T5', bound=List[int])

                   my_int = int
                   my_str = str
                   T11 = TypeVar('T11', my_int, my_str)

                   my_list_t1 = List[T1]
                   T22 = TypeVar('T22', int, my_list_t1)
                   T33 = TypeVar('T33', bound=my_list_t1)

                   my_list_int = List[int]
                   T44 = TypeVar('T44', int, my_list_int)
                   T55 = TypeVar('T55', bound=my_list_int)""");
  }

  // PY-28227
  public void testPlainGenericInheritance() {
    doTestByText("""
                   from typing import Generic

                   class A(<error descr="Cannot inherit from plain 'Generic'">Generic</error>):
                       pass

                   B = Generic
                   class C(<error descr="Cannot inherit from plain 'Generic'">B</error>):
                       pass""");
  }

  // PY-28227
  public void testGenericParametersTypes() {
    doTestByText("""
                   from typing import Generic, Protocol, TypeVar

                   class A1(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">0</error>]):
                       pass

                   class B1(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">int</error>]):
                       pass
                   
                   class B11(Protocol[<error descr="Parameters to 'Protocol[...]' must all be type variables">int</error>]):
                       pass

                   class A2(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">0</error>, <error descr="Parameters to 'Generic[...]' must all be type variables">0</error>]):
                       pass

                   class B2(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">int</error>, <error descr="Parameters to 'Generic[...]' must all be type variables">int</error>]):
                       pass

                   null = 0
                   class A3(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">null</error>]):
                       pass

                   my_int = int
                   class B3(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">my_int</error>]):
                       pass

                   T = TypeVar('T')
                   S = TypeVar('S')

                   class C1(Generic[T]):
                       pass

                   class C2(Generic[T, S]):
                       pass

                   my_t = T
                   class C3(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">my_t</error>]):
                       pass

                   class D1:
                       pass

                   class D2:
                       pass

                   class E1(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">D1</error>]):
                       pass

                   class F1(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">D1</error>, <error descr="Parameters to 'Generic[...]' must all be type variables">D2</error>]):
                       pass

                   my_d = D1
                   class E2(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">my_d</error>]):
                       pass""");
  }

  // PY-28227
  public void testGenericParametersDuplication() {
    doTestByText("""
                   from typing import Generic, TypeVar

                   T = TypeVar('T')

                   class C(Generic[T, <error descr="Parameters to 'Generic[...]' must all be unique">T</error>]):
                       pass

                   B = Generic
                   class A(B[T, <error descr="Parameters to 'Generic[...]' must all be unique">T</error>]):
                       pass

                   T1 = T
                   class D(Generic[<error descr="Parameters to 'Generic[...]' must all be type variables">T1</error>, T]):
                       pass""");
  }

  // PY-28227
  public void testGenericDuplication() {
    doTestByText("""
                   from typing import Generic, TypeVar

                   T = TypeVar('T')
                   S = TypeVar('S')

                   class C(Generic[T], <error descr="Cannot inherit from 'Generic[...]' multiple times">Generic[S]</error>):
                       pass

                   B = Generic
                   class D(B[T], <error descr="Cannot inherit from 'Generic[...]' multiple times">Generic[S]</error>):
                       pass

                   E = Generic[T]
                   class A(E, <error descr="Cannot inherit from 'Generic[...]' multiple times">Generic[S]</error>):
                       pass""");
  }

  // PY-28227
  public void testGenericCompleteness() {
    doTestByText("""
                   from typing import Generic, TypeVar, Iterable, Protocol

                   T = TypeVar('T')
                   S = TypeVar('S')

                   class C<error descr="'Generic[...]' or 'Protocol[...]' should list all type variables (S)">(Generic[T], Iterable[S])</error>:
                       pass
                   
                   class P<error descr="'Generic[...]' or 'Protocol[...]' should list all type variables (S)">(Iterable[S], Protocol[T])</error>:
                       pass

                   B = Generic
                   D = T
                   class A<error descr="'Generic[...]' or 'Protocol[...]' should list all type variables (S)">(B[<error descr="Parameters to 'Generic[...]' must all be type variables">D</error>], Iterable[S])</error>:
                       pass

                   class E(Generic[T], Iterable[T]):
                       pass

                   class F(B[<error descr="Parameters to 'Generic[...]' must all be type variables">D</error>]):
                       pass
                   
                   class G(Iterable[T]):
                       pass
                   """);
  }

  // PY-31147
  public void testGenericCompletenessPartiallySpecialized() {
    doTestByText("""
                   from typing import TypeVar, Generic, Dict

                   T = TypeVar("T")

                   class C(Generic[T], Dict[int, T]):
                       pass""");
  }

  // PY-78767
  public void testGenericMetaClassesAreNotSupported() {
    doTestByText("""
                   from typing import Any, Generic, TypeVar
                   
                   T = TypeVar("T")
                   
                   class MyMetaClass(type, Generic[T]): ...
                   
                   class MyClass1(Generic[T], metaclass=<warning descr="Metaclass cannot be generic">MyMetaClass[T]</warning>): ...
                   class MyClass2(metaclass=MyMetaClass[Any]): ...""");
  }

  // PY-76866
  public void testUnboundTypeParameter() {
    doTestByText(
      """
        from typing import Generic, TypeVar, TypeVarTuple, ParamSpec, TypeAlias, Unpack
        
        T = TypeVar('T')
        S = TypeVar('S')
        
        T1 = TypeVar('T1', default=T)
        T2 = TypeVarTuple('T2', default=Unpack[tuple[S, T]])
        T3 = ParamSpec('T3', default=[S, T])
        
        Alias1 = T
        Alias2 = dict[S, T]
        Alias3: TypeAlias = list[T]
        type Alias4[K, V] = dict[K, V]
        
        v1: <warning descr="Unbound type variable">T</warning>
        v2: list[<warning descr="Unbound type variable">T</warning>]
        
        list[<warning descr="Unbound type variable">T</warning>]()
        
        def f1(x: T) -> None:
            a1: T
            a2: list[T] = []
            a3: <warning descr="Unbound type variable">S</warning>
            a4: list[<warning descr="Unbound type variable">S</warning>] = []
        
            list[T]()
            list[<warning descr="Unbound type variable">S</warning>]()
        
        def f2() -> T:
            x: T
            raise Exception()
        
        class Bar(Generic[T]):
            attr1: T
            attr2: list[T] = []
            attr3: <warning descr="Unbound type variable">S</warning>
            attr4: list[<warning descr="Unbound type variable">S</warning>] = []
        
            def do_something(self, x: S) -> S:
                ...
            def do_something_else(self, other: 'Bar[T]'):
                ...""");
  }

  // PY-78878
  public void testGenericClassCannotUseTypeVariablesFromOuterScope() {
    doTestByText("""
                   from typing import TypeVar, Generic, Iterable
                   
                   T = TypeVar('T')
                   S = TypeVar('S')
                   
                   def a_fun(x: T) -> None:
                       a_list: list[T] = []
                   
                       class <warning descr="Some type variables (T) are already in use by an outer scope">MyGeneric</warning>(Generic[T]):
                           ...
                   
                   def a_fun_new_syntax1[U]() -> None:
                       class <warning descr="Some type variables (U) are already in use by an outer scope">MyGeneric</warning>(Generic[U]):
                           ...
                   
                   def a_fun_new_syntax2[U](u: U) -> None:
                       class <warning descr="Some type variables (U) are already in use by an outer scope">MyGeneric</warning>(Generic[U]):
                           ...
                   
                   class Outer(Generic[T]):
                       class <warning descr="Some type variables (T) are already in use by an outer scope">Bad</warning>(Iterable[T]):
                           ...
                       class AlsoBad:
                           x: list[<warning descr="Unbound type variable">T</warning>]
                   
                       class Inner(Iterable[S]):
                           ...
                       attr: Inner[T]
                   
                   class OuterNewSyntax[U]:
                       class <warning descr="Some type variables (U) are already in use by an outer scope">Bad</warning>(Generic[U]):
                           ...""");
  }

  // PY-82835
  public void testTypeParameterIsAlreadyInUseByOuterScope() {
    doTestByText("""
                   from typing import Sequence, TypeAlias
                   
                   T = 0
                   
                   
                   class ClassA[T](Sequence[T]):
                       T = 1
                   
                       def method1[<warning descr="Type parameter 'T' is already in use by an outer scope">T</warning>](self):
                           ...
                   
                       def method2[<warning descr="Type parameter 'T' is already in use by an outer scope">T</warning>](self, x=T):
                           ...
                   
                       def method3[<warning descr="Type parameter 'T' is already in use by an outer scope">T</warning>](self, x: T):
                           ...
                   
                       class Inner[<warning descr="Type parameter 'T' is already in use by an outer scope">T</warning>]:
                           ...
                   """);
  }

  public void testSelfAnnotationUsesClassScopedTypeParameters() {
    doTestByText("""
                   class MyClass[T1, T2]:
                       def __init__(self: <warning descr="Class-scoped type variables should not be used in the annotation for 'self' parameter of '__init__' method">MyClass[T2, T1]</warning>) -> None: ...
                   """);
  }

  // PY-28249
  public void testInstanceAndClassChecksOnAny() {
    doTestByText("""
                   from typing import Any

                   class A:
                       pass

                   assert isinstance(A(), <error descr="'Any' cannot be used with instance and class checks">Any</error>)
                   B = Any
                   assert issubclass(A, <error descr="'Any' cannot be used with instance and class checks">B</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnNoReturn() {
    doTestByText("""
                   from typing import NoReturn

                   class A:
                       pass

                   assert isinstance(A(), <error descr="'NoReturn' cannot be used with instance and class checks">NoReturn</error>)
                   B = NoReturn
                   assert issubclass(A, <error descr="'NoReturn' cannot be used with instance and class checks">B</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnTypeVar() {
    doTestByText("""
                   from typing import TypeVar

                   T = TypeVar("T")

                   class A:
                       pass

                   assert isinstance(A(), TypeVar)
                   assert issubclass(A, TypeVar)

                   assert isinstance(A(), <error descr="Type variables cannot be used with instance and class checks">T</error>)
                   assert issubclass(A, <error descr="Type variables cannot be used with instance and class checks">T</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnUnionBefore310() {
    runWithLanguageLevel(LanguageLevel.PYTHON39, () -> {
      doTestByText("""
                     from typing import Union

                     class A:
                         pass

                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union</error>)
                     B = Union
                     assert issubclass(A, <error descr="'Union' cannot be used with instance and class checks">B</error>)

                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union[int, str]</error>)
                     assert issubclass(A, <error descr="'Union' cannot be used with instance and class checks">B[int, str]</error>)
                     C = B[int, str]
                     assert issubclass(A, <error descr="'Union' cannot be used with instance and class checks">C</error>)
                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union[str, Union[str, Union[list, dict]]]</error>)
                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union[str, Union[str, Union[list[int], dict]]]</error>)
                     assert isinstance(A(), <error descr="Python version 3.9 does not allow writing union types as X | Y">int | str</error>)
                     assert isinstance(A(), <error descr="Python version 3.9 does not allow writing union types as X | Y">int | list[str]</error>)
                     assert issubclass(A, <error descr="Python version 3.9 does not allow writing union types as X | Y">int | str</error>)
                     assert issubclass(A, <error descr="Python version 3.9 does not allow writing union types as X | Y">int | list[str]</error>)""");
    });
  }

  // PY-44974
  public void testInstanceAndClassChecksOnUnionFromFutureAnnotations() {
    runWithLanguageLevel(LanguageLevel.PYTHON39, () -> {
      doTestByText("""
                     from typing import Union
                     from __future__ import annotations

                     class A:
                         pass

                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union</error>)
                     B = Union
                     assert issubclass(A, <error descr="'Union' cannot be used with instance and class checks">B</error>)

                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union[int, str]</error>)
                     assert issubclass(A, <error descr="'Union' cannot be used with instance and class checks">B[int, str]</error>)
                     C = B[int, str]
                     assert issubclass(A, <error descr="'Union' cannot be used with instance and class checks">C</error>)
                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union[str, Union[str, Union[list, dict]]]</error>)
                     assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union[str, Union[str, Union[list[int], dict]]]</error>)
                     assert isinstance(A(), <error descr="Python version 3.9 does not allow writing union types as X | Y">int | str</error>)
                     assert isinstance(A(), <error descr="Python version 3.9 does not allow writing union types as X | Y">int | list[str]</error>)
                     assert issubclass(A, <error descr="Python version 3.9 does not allow writing union types as X | Y">int | str</error>)
                     assert issubclass(A, <error descr="Python version 3.9 does not allow writing union types as X | Y">int | list[str]</error>)""");
    });
  }

  // PY-44974
  public void testInstanceAndClassChecksOnUnion() {
    doTestByText("""
                   from typing import Union

                   class A:
                       pass

                   assert isinstance(A(), <error descr="'Union' cannot be used with instance and class checks">Union</error>)
                   B = Union
                   assert issubclass(A, <error descr="'Union' cannot be used with instance and class checks">B</error>)

                   assert isinstance(A(), Union[int, str])
                   assert issubclass(A, B[int, str])
                   C = B[int, str]
                   assert issubclass(A, C)
                   assert isinstance(A(), Union[str, Union[str, Union[list, dict]]])
                   assert isinstance(A(), Union[str, Union[str, Union[<error descr="Parameterized generics cannot be used with instance and class checks">list[int]</error>, dict]]])
                   assert isinstance(A(), int | str)
                   assert isinstance(A(), int | <error descr="Parameterized generics cannot be used with instance and class checks">list[str]</error>)
                   assert issubclass(A, int | str)
                   assert issubclass(A, int | <error descr="Parameterized generics cannot be used with instance and class checks">list[str]</error>)
                   """);
  }

  // PY-28249
  public void testInstanceAndClassChecksOnOptionalBefore310() {
    runWithLanguageLevel(LanguageLevel.PYTHON39, () -> {
      doTestByText("""
                     from typing import Optional

                     class A:
                         pass

                     assert isinstance(A(), <error descr="'Optional' cannot be used with instance and class checks">Optional</error>)
                     B = Optional
                     assert issubclass(A, <error descr="'Optional' cannot be used with instance and class checks">B</error>)

                     assert isinstance(A(), <error descr="'Optional' cannot be used with instance and class checks">Optional[int]</error>)
                     assert issubclass(A, <error descr="'Optional' cannot be used with instance and class checks">B[int]</error>)
                     C = B[int]
                     assert issubclass(A, <error descr="'Optional' cannot be used with instance and class checks">C</error>)""");
    });
  }

  // PY-28249
  public void testInstanceAndClassChecksOnOptionalFromFutureAnnotations() {
    runWithLanguageLevel(LanguageLevel.PYTHON39, () -> {
      doTestByText("""
                     from typing import Optional
                     from __future__ import annotations

                     class A:
                         pass

                     assert isinstance(A(), <error descr="'Optional' cannot be used with instance and class checks">Optional</error>)
                     B = Optional
                     assert issubclass(A, <error descr="'Optional' cannot be used with instance and class checks">B</error>)

                     assert isinstance(A(), <error descr="'Optional' cannot be used with instance and class checks">Optional[int]</error>)
                     assert issubclass(A, <error descr="'Optional' cannot be used with instance and class checks">B[int]</error>)
                     C = B[int]
                     assert issubclass(A, <error descr="'Optional' cannot be used with instance and class checks">C</error>)""");
    });
  }

  // PY-28249
  public void testInstanceAndClassChecksOnOptional() {
    doTestByText("""
                   from typing import Optional

                   class A:
                       pass

                   assert isinstance(A(), <error descr="'Optional' cannot be used with instance and class checks">Optional</error>)
                   B = Optional
                   assert issubclass(A, <error descr="'Optional' cannot be used with instance and class checks">B</error>)

                   assert isinstance(A(), Optional[int])
                   assert issubclass(A, B[int])
                   C = B[int]
                   assert issubclass(A, C)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnClassVar() {
    doTestByText("""
                   from typing import ClassVar

                   class A:
                       pass

                   assert isinstance(A(), <error descr="'ClassVar' cannot be used with instance and class checks">ClassVar</error>)
                   B = ClassVar
                   assert issubclass(A, <error descr="'ClassVar' cannot be used with instance and class checks">B</error>)

                   assert isinstance(A(), <error descr="'ClassVar' cannot be used with instance and class checks">ClassVar[int]</error>)
                   assert issubclass(A, <error descr="'ClassVar' cannot be used with instance and class checks">B[int]</error>)
                   C = B[int]
                   assert issubclass(A, <error descr="'ClassVar' cannot be used with instance and class checks">C</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnGeneric() {
    doTestByText("""
                   from typing import TypeVar, Generic

                   T = TypeVar("T")

                   class A:
                       pass

                   assert isinstance(A(), Generic)
                   B = Generic
                   assert issubclass(A, B)

                   assert isinstance(A(), <error descr="'Generic' cannot be used with instance and class checks">Generic[T]</error>)
                   assert issubclass(A, <error descr="'Generic' cannot be used with instance and class checks">B[T]</error>)
                   C = B[T]
                   assert issubclass(A, <error descr="'Generic' cannot be used with instance and class checks">C</error>)""");
  }

  // PY-34945
  public void testInstanceAndClassChecksOnFinal() {
    doTestByText("""
                   from typing import TypeVar
                   from typing_extensions import Final

                   T = TypeVar("T")

                   class A:
                       pass

                   assert isinstance(A(), <error descr="'Final' cannot be used with instance and class checks">Final</error>)
                   B = Final
                   assert issubclass(A, <error descr="'Final' cannot be used with instance and class checks">B</error>)

                   assert isinstance(A(), <error descr="'Final' cannot be used with instance and class checks">Final[T]</error>)
                   assert issubclass(A, <error descr="'Final' cannot be used with instance and class checks">B[T]</error>)
                   C = B[T]
                   assert issubclass(A, <error descr="'Final' cannot be used with instance and class checks">C</error>)""");
  }

  // PY-35235
  public void testInstanceAndClassChecksOnLiteral() {
    doTestByText("""
                   from typing_extensions import Literal

                   class A:
                       pass

                   assert isinstance(A(), <error descr="'Literal' cannot be used with instance and class checks">Literal</error>)
                   B = Literal
                   assert issubclass(A, <error descr="'Literal' cannot be used with instance and class checks">B</error>)

                   assert isinstance(A(), <error descr="'Literal' cannot be used with instance and class checks">Literal[1]</error>)
                   assert issubclass(A, <error descr="'Literal' cannot be used with instance and class checks">B[1]</error>)
                   C = B[1]
                   assert issubclass(A, <error descr="'Literal' cannot be used with instance and class checks">C</error>)""");
  }

  // PY-42334
  public void testInstanceAndClassChecksOnTypeAlias() {
    doTestByText("""
                   from typing import TypeAlias

                   class A:
                       pass
                      \s
                   assert isinstance(A(), <error descr="'TypeAlias' cannot be used with instance and class checks">TypeAlias</error>)
                   assert issubclass(A, <error descr="'TypeAlias' cannot be used with instance and class checks">TypeAlias</error>)
                   B = TypeAlias
                   assert isinstance(A(), <error descr="'TypeAlias' cannot be used with instance and class checks">B</error>)
                   assert issubclass(A, <error descr="'TypeAlias' cannot be used with instance and class checks">B</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnGenericInheritor() {
    doTestByText("""
                   from typing import TypeVar, List

                   T = TypeVar("T")

                   class A:
                       pass

                   assert isinstance(A(), List)
                   B = List
                   assert issubclass(A, B)

                   assert isinstance(A(), <error descr="Parameterized generics cannot be used with instance and class checks">List[T]</error>)
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">B[T]</error>)
                   C = B[T]
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">C</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnTuple() {
    doTestByText("""
                   from typing import Tuple

                   class A:
                       pass

                   assert isinstance(A(), Tuple)
                   B = Tuple
                   assert issubclass(A, B)

                   assert isinstance(A(), <error descr="Parameterized generics cannot be used with instance and class checks">Tuple[int, str]</error>)
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">B[int, str]</error>)
                   C = B[int, str]
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">C</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnType() {
    doTestByText("""
                   from typing import Type

                   class A:
                       pass

                   assert isinstance(A(), Type)
                   B = Type
                   assert issubclass(A, B)

                   assert isinstance(A(), <error descr="Parameterized generics cannot be used with instance and class checks">Type[int]</error>)
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">B[int]</error>)
                   C = B[int]
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">C</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnCallable() {
    doTestByText("""
                   from typing import Callable

                   class A:
                       pass

                   assert isinstance(A(), Callable)
                   B = Callable
                   assert issubclass(A, B)

                   assert isinstance(A(), <error descr="Parameterized generics cannot be used with instance and class checks">Callable[..., str]</error>)
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">B[..., str]</error>)
                   C = B[..., str]
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">C</error>)""");
  }

  // PY-28249
  public void testInstanceAndClassChecksOnProtocol() {
    doTestByText("""
                   from typing import Protocol, TypeVar

                   class A:
                       pass
                      \s
                   T = TypeVar("T")

                   assert isinstance(A(), Protocol)
                   B = Protocol
                   assert issubclass(A, B)

                   assert isinstance(A(), <error descr="Parameterized generics cannot be used with instance and class checks">Protocol[T]</error>)
                   assert issubclass(A, <error descr="Parameterized generics cannot be used with instance and class checks">B[T]</error>)
