-- Test cases for type variables with values restriction.


[case testCallGenericFunctionWithTypeVarValueRestriction]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> None: pass
f(1)
f('x')
f(object()) # E: Value of type variable "T" of "f" cannot be "object"

[case testCallGenericFunctionWithTypeVarValueRestrictionUsingContext]
from typing import TypeVar, List
T = TypeVar('T', int, str)
def f(x: T) -> List[T]: pass
i = [1]
s = ['x']
o = [object()]
i = f(1)
s = f('')
o = f(1) # E: Value of type variable "T" of "f" cannot be "object"
[builtins fixtures/list.pyi]

[case testCallGenericFunctionWithTypeVarValueRestrictionAndAnyArgs]
from typing import TypeVar, Any, cast
T = TypeVar('T', int, str)
def f(x: T) -> None: pass
f(cast(Any, object()))
[out]

[case testCallGenericFunctionWithTypeVarValueRestrictionInDynamicFunc]
from typing import TypeVar, Any
T = TypeVar('T', int, str)
def f(x: T) -> None: pass
def g():
    f(object())
[out]

[case testCallGenericFunctionWithTypeVarValueRestrictionUsingSubtype]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> None: pass
class S(str): pass
f(S())
[out]

[case testCheckGenericFunctionBodyWithTypeVarValues]
from typing import TypeVar
class A:
    def f(self, x: int) -> A: return self
class B:
    def f(self, x: int) -> B: return self
AB = TypeVar('AB', A, B)
def f(x: AB) -> AB:
    x = x.f(1)
    return x.f(1)

[case testCheckGenericFunctionBodyWithTypeVarValues2]
from typing import TypeVar
class A:
    def f(self) -> A: return A()
    def g(self) -> B: return B()
class B:
    def f(self) -> A: return A()
    def g(self) -> B: return B()
AB = TypeVar('AB', A, B)
def f(x: AB) -> AB:
    return x.f() # Error
def g(x: AB) -> AB:
    return x.g() # Error
[out]
main:10: error: Incompatible return value type (got "A", expected "B")
main:12: error: Incompatible return value type (got "B", expected "A")

[case testTypeInferenceAndTypeVarValues]
from typing import TypeVar
class A:
    def f(self) -> A: return self
    def g(self) -> B: return B()
class B:
    def f(self) -> B: return self
    def g(self) -> B: return B()
AB = TypeVar('AB', A, B)
def f(x: AB) -> AB:
    y = x
    if y:
        return y.f()
    else:
        return y.g() # E: Incompatible return value type (got "B", expected "A")
[out]

[case testTypeDeclaredBasedOnTypeVarWithValues]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> T:
    a = None  # type: T
    b = None # type: T
    a = x
    b = x
    a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
    b = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
    return x
[out]

[case testIsinstanceAndTypeVarValues]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> T:
    if isinstance(x, int):
        return 2
    return x
def g(x: T) -> T:
    if isinstance(x, str):
        return ''
    return x
def h(x: T) -> T:
    if isinstance(x, int):
        return '' # E: Incompatible return value type (got "str", expected "int")
    return x
[builtins fixtures/isinstance.pyi]
[out]

[case testIsinstanceAndTypeVarValues2]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> T:
    if isinstance(x, int):
        return 2
    else:
        return ''
def g(x: T) -> T:
    if isinstance(x, int):
        return '' # E: Incompatible return value type (got "str", expected "int")
    else:
        return 2  # E: Incompatible return value type (got "int", expected "str")
    return x
[builtins fixtures/isinstance.pyi]
[out]

[case testIsinstanceAndTypeVarValues3]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> T:
    if isinstance(x, int):
        y = 1
    else:
        y = ''
    return y
[builtins fixtures/isinstance.pyi]

[case testIsinstanceAndTypeVarValues4]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> T:
    if isinstance(x, int):
        y = 1
    else:
        y = object()
    return y # E: Incompatible return value type (got "object", expected "str")
[builtins fixtures/isinstance.pyi]
[out]

[case testIsinstanceAndTypeVarValues5]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(x: T) -> T:
    if isinstance(x, int):
        y = object()
    else:
        y = ''
    return y # E: Incompatible return value type (got "object", expected "int")
[builtins fixtures/isinstance.pyi]
[out]

[case testIsinstanceWithUserDefinedTypeAndTypeVarValues]
from typing import TypeVar
class A: pass
class B: pass
T = TypeVar('T', A, B)
def f(x: T) -> None:
    y = x
    if isinstance(x, A):
        # This is only checked when x is A, since A and B are not considered overlapping.
        x = y
        x = A()
    else:
        x = B()
        x = y
        x.foo() # E: "B" has no attribute "foo"
S = TypeVar('S', int, str)
def g(x: S) -> None:
    y = x
    if isinstance(x, int):
        x = y
[builtins fixtures/isinstance.pyi]
[out]

[case testIsinstanceWithUserDefinedTypeAndTypeVarValues2]
from typing import TypeVar
class S(str): pass
T = TypeVar('T', S, int)
def f(x: T) -> None:
    y = x
    if isinstance(x, S):
        # This is checked only when type of x is str.
        x = y
        x = S()
        x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "S")
    else:
        x = y
        x = 1
        x = S() # E: Incompatible types in assignment (expression has type "S", variable has type "int")
[builtins fixtures/isinstance.pyi]
[out]

[case testTypeVarValuesAndNestedCalls]
from typing import TypeVar
T = TypeVar('T', int, str)
def f(m: T) -> int: pass
def h(x: int) -> int: pass
def g(a: T) -> None:
    h(f(a))
[out]

[case testGenericTypeWithTypevarValues]
from typing import TypeVar, Generic, Any
X = TypeVar('X', int, str)
class A(Generic[X]): pass
a = None  # type: A[int]
b = None  # type: A[str]
d = None  # type: A[object] # E: Value of type variable "X" of "A" cannot be "object"
c = None  # type: A[Any]

[case testConstructGenericTypeWithTypevarValuesAndTypeInference]
from typing import TypeVar, Generic, Any, cast
X = TypeVar('X', int, str)
class A(Generic[X]):
    def __init__(self, x: X) -> None: pass
A(1)
A('x')
A(cast(Any, object()))
A(object()) # E: Value of type variable "X" of "A" cannot be "object"

[case testGenericTypeWithTypevarValuesAndTypevarArgument]
from typing import TypeVar, Generic
class C: pass
X = TypeVar('X', int, str)
Y = TypeVar('Y', int, C)
Z = TypeVar('Z')
class D(Generic[X]):
    def __init__(self, x: X) -> None: pass
def f(x: X) -> None:
    a = None  # type: D[X]
def g(x: Y) -> None:
    a = None  # type: D[Y]
def h(x: Z) -> None:
    a = None  # type: D[Z]
[out]
main:11: error: Invalid type argument value for "D"
main:13: error: Type variable "Z" not valid as type argument value for "D"

[case testGenericTypeWithTypevarValuesAndSubtypePromotion]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class S(str): pass
class C(Generic[X]):
    def __init__(self, x: X) -> None: pass
x = None  # type: C[str]
y = C(S())
x = y
y = x
c_int = C(1) # type: C[int]
y = c_int # E: Incompatible types in assignment (expression has type "C[int]", variable has type "C[str]")

[case testGenericTypeBodyWithTypevarValues]
from typing import TypeVar, Generic
class A:
    def f(self, x: int) -> None: pass
    def g(self, x: int) -> None: pass
    def h(self, x: str) -> None: pass
class B:
    def f(self, x: int) -> None: pass
    def g(self, x: str) -> None: pass
    def h(self, x: int) -> None: pass
X = TypeVar('X', A, B)
class C(Generic[X]):
    def f(self, x: X) -> None:
        x.f(1)
        x.g(1) # E: Argument 1 to "g" of "B" has incompatible type "int"; expected "str"
        x.h(1) # E: Argument 1 to "h" of "A" has incompatible type "int"; expected "str"
[out]

[case testAttributeInGenericTypeWithTypevarValues1]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class C(Generic[X]):
    x = None  # type: X
    def f(self, x: X) -> None:
        self.x = x
        self.x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str")
[out]

[case testAttributeInGenericTypeWithTypevarValues2]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class C(Generic[X]):
    x = None  # type: X
cn = C() # type: C[int]
cn.x = 1
cn.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
cs = C() # type: C[str]
cs.x = ''
cs.x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str")

[case testAttributeInGenericTypeWithTypevarValues3]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class C(Generic[X]):
    def f(self, x: X) -> None:
        self.x = x  # type: X
ci: C[int]
cs: C[str]
reveal_type(ci.x) # E: Revealed type is 'builtins.int*'
reveal_type(cs.x) # E: Revealed type is 'builtins.str*'

[case testAttributeInGenericTypeWithTypevarValuesUsingInference1]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class C(Generic[X]):
    def f(self, x: X) -> None:
        self.x = x # E: Need type annotation for 'x'
ci: C[int]
cs: C[str]
reveal_type(ci.x) # E: Revealed type is 'Any'
reveal_type(cs.x) # E: Revealed type is 'Any'

[case testAttributeInGenericTypeWithTypevarValuesUsingInference2]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class C(Generic[X]):
    def f(self, x: X) -> None:
        self.x = 1
        reveal_type(self.x) # E: Revealed type is 'builtins.int'
ci: C[int]
cs: C[str]
reveal_type(ci.x) # E: Revealed type is 'builtins.int'
reveal_type(cs.x) # E: Revealed type is 'builtins.int'

[case testAttributeInGenericTypeWithTypevarValuesUsingInference3]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class C(Generic[X]):
    x: X
    def f(self) -> None:
        self.y = self.x # E: Need type annotation for 'y'
ci: C[int]
cs: C[str]
reveal_type(ci.y) # E: Revealed type is 'Any'
reveal_type(cs.y) # E: Revealed type is 'Any'

[case testInferredAttributeInGenericClassBodyWithTypevarValues]
from typing import TypeVar, Generic
X = TypeVar('X', int, str)
class C(Generic[X]):
    x = 1
C.x = 1
C.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")

[case testMultipleClassTypevarsWithValues1]
from typing import TypeVar, Generic
class A:
    def f(self, x: int) -> None: pass
class B:
    def f(self, x: str) -> None: pass
X = TypeVar('X', A, B)
Y = TypeVar('Y', int, str)
class C(Generic[X, Y]):
    def f(self, x: X, y: Y) -> None:
        x.f(y)
[out]
main:10: error: Argument 1 to "f" of "A" has incompatible type "str"; expected "int"
main:10: error: Argument 1 to "f" of "B" has incompatible type "int"; expected "str"

[case testMultipleClassTypevarsWithValues2]
from typing import TypeVar, Generic
class A: pass
class B: pass
X = TypeVar('X', A, B)
Y = TypeVar('Y', int, str)
class C(Generic[X, Y]): pass
a = None  # type: C[A, int]
b = None  # type: C[B, str]
c = None  # type: C[int, int] # E: Value of type variable "X" of "C" cannot be "int"
d = None  # type: C[A, A]     # E: Value of type variable "Y" of "C" cannot be "A"

[case testCallGenericFunctionUsingMultipleTypevarsWithValues]
from typing import TypeVar
class A: pass
class B: pass
X = TypeVar('X', A, B)
Y = TypeVar('Y', int, str)
def f(x: X, y: Y) -> None: pass
f(A(), '')
f(B(), 1)
f(A(), A())  # E: Value of type variable "Y" of "f" cannot be "A"
f(1, 1)  # E: Value of type variable "X" of "f" cannot be "int"

[case testGenericFunctionWithNormalAndRestrictedTypevar]
from typing import TypeVar, Generic
X = TypeVar('X')
Y = TypeVar('Y', int, str)
class C(Generic[Y]):
    def __init__(self, y: Y) -> None: pass
def f(x: X, y: Y, z: int) -> None:
    C(y)
    C(x)  # Error
    z = x # Error
    z = y # Error
    y.foo # Error
[out]
main:8: error: Value of type variable "Y" of "C" cannot be "X"
main:9: error: Incompatible types in assignment (expression has type "X", variable has type "int")
main:10: error: Incompatible types in assignment (expression has type "str", variable has type "int")
main:11: error: "int" has no attribute "foo"
main:11: error: "str" has no attribute "foo"

[case testTypeVarWithValueInferredFromObjectReturnTypeContext]
from typing import TypeVar
T = TypeVar('T', int, str)
def c1(x: object) -> None: pass
def c2(x: int) -> None: pass
def c3(x: str) -> None: pass
def g(x: T) -> T: pass
c1(g(''))
c2(g(1))
c3(g(''))
c2(g(''))  # E: Argument 1 to "c2" has incompatible type "str"; expected "int"
c3(g(1))   # E: Argument 1 to "c3" has incompatible type "int"; expected "str"

[case testTypeVarWithValueInferredFromObjectReturnTypeContext2]
from typing import TypeVar
T = TypeVar('T', int, str)
class ss(str): pass
def c(x: ss) -> None: pass
def g(x: T) -> T: pass
c(g(''))
c(g(1))
[out]
main:6: error: Argument 1 to "c" has incompatible type "str"; expected "ss"
main:7: error: Argument 1 to "c" has incompatible type "int"; expected "ss"

[case testDefineAttributeInGenericMethodUsingTypeVarWithValues]
from typing import TypeVar
T = TypeVar('T', int, str)
class A:
    def f(self, x: T) -> None:
        self.x = x # E: Need type annotation for 'x'
        self.y = [x] # E: Need type annotation for 'y'
        self.z = 1
reveal_type(A().x)  # E: Revealed type is 'Any'
reveal_type(A().y)  # E: Revealed type is 'Any'
reveal_type(A().z)  # E: Revealed type is 'builtins.int'
[builtins fixtures/list.pyi]


-- Special cases
-- -------------


[case testTypevarValuesSpecialCase1]
from typing import TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T', int, str)
class A(Generic[T]):
    @abstractmethod
    def f(self) -> 'A[T]': pass
class B(A[str]):
    @abstractmethod
    def f(self) -> 'B': pass
class C(A[str]):
    @abstractmethod
    def f(self) -> int: # E: Return type of "f" incompatible with supertype "A"
        pass
[out]

[case testDefaultArgumentValueInGenericClassWithTypevarValues]
from typing import TypeVar, Generic
T = TypeVar('T', int, str)
class C(Generic[T]):
    def f(self, x: int = None) -> None: pass

[case testTypevarValuesWithOverloadedFunctionSpecialCase]
from foo import *
[file foo.pyi]
from typing import TypeVar, overload, Callable

T = TypeVar('T', int, str)
def f(x: T) -> None:
     y = m(g, x)
     x = y
     y = object()

A = TypeVar('A')
R = TypeVar('R')
def m(f: Callable[[A], R], it: A) -> A: pass

@overload
def g(x: int) -> int: return x
@overload
def g(x: str) -> str: return x
[out]
tmp/foo.pyi:7: error: Incompatible types in assignment (expression has type "object", variable has type "int")
tmp/foo.pyi:7: error: Incompatible types in assignment (expression has type "object", variable has type "str")

[case testGenericFunctionSubtypingWithTypevarValues]
from typing import TypeVar
class A: pass
T = TypeVar('T', int, str)
U = TypeVar('U', str, A, int)
def f(x: T) -> T: pass
def g(x: U) -> U: pass
a = f
a = f
a = g
b = g
b = g
b = f # E: Incompatible types in assignment (expression has type "Callable[[T], T]", variable has type "Callable[[U], U]")

[case testInnerFunctionWithTypevarValues]
from typing import TypeVar
T = TypeVar('T', int, str)
U = TypeVar('U', int, str)
def outer(x: T) -> T:
    def inner(y: T) -> T:
        return x
    def inner2(y: U) -> U:
        return y
    inner(x)
    inner(3) # E: Argument 1 to "inner" has incompatible type "int"; expected "str"
    inner2(x)
    inner2(3)
    outer(3)
    return x
[out]

[case testInnerFunctionMutualRecursionWithTypevarValues]
from typing import TypeVar
T = TypeVar('T', int, str)
def outer(x: T) -> T:
    def inner1(y: T) -> T:
        return inner2(y)
    def inner2(y: T) -> T:
        return inner1('a') # E: Argument 1 to "inner1" has incompatible type "str"; expected "int"
    return inner1(x)
[out]

[case testClassMemberTypeVarInFunctionBody]
from typing import TypeVar, List
S = TypeVar('S')
class C:
    T = TypeVar('T', bound=int)
    def f(self, x: T) -> T:
        L = List[S]
        y: L[C.T] = [x]
        C.T  # E: Type variable "C.T" cannot be used as an expression
        A = C.T  # E: Type variable "C.T" cannot be used as an expression
        return y[0]

[builtins fixtures/list.pyi]

[case testParameterLessGenericAsRestriction]
from typing import Sequence, Iterable, TypeVar
S = TypeVar('S', Sequence, Iterable)
def my_len(s: S) -> None: pass
def crash() -> None: my_len((0,))

[case testReferenceToDecoratedFunctionAndTypeVarValues]
from typing import TypeVar, Callable

T = TypeVar('T')
S = TypeVar('S', int, str)

def dec(f: Callable[..., T]) -> Callable[..., T]: ...

@dec
def g(s: S) -> Callable[[S], None]: ...

def f(x: S) -> None:
    h = g(x)
    h(x)
