diff --git a/mypy/semanal.py b/mypy/semanal.py index 8771fb768d80..675ea9681c19 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1544,7 +1544,7 @@ def process_typevar_declaration(self, s: AssignmentStmt) -> None: res = self.process_typevar_parameters(call.args[1 + n_values:], call.arg_names[1 + n_values:], call.arg_kinds[1 + n_values:], - bool(values), + n_values, s) if res is None: return @@ -1591,8 +1591,9 @@ def get_typevar_declaration(self, s: AssignmentStmt) -> Optional[CallExpr]: def process_typevar_parameters(self, args: List[Expression], names: List[Optional[str]], kinds: List[int], - has_values: bool, + num_values: int, context: Context) -> Optional[Tuple[int, Type]]: + has_values = (num_values > 0) covariant = False contravariant = False upper_bound = self.object_type() # type: Type @@ -1642,6 +1643,9 @@ def process_typevar_parameters(self, args: List[Expression], if covariant and contravariant: self.fail("TypeVar cannot be both covariant and contravariant", context) return None + elif num_values == 1: + self.fail("TypeVar cannot have only a single constraint", context) + return None elif covariant: variance = COVARIANT elif contravariant: diff --git a/test-data/unit/check-bound.test b/test-data/unit/check-bound.test index ee935aed8bdd..bfe04e0cfb67 100644 --- a/test-data/unit/check-bound.test +++ b/test-data/unit/check-bound.test @@ -142,12 +142,12 @@ class A(A0): class B(A): def baz(self) -> None: pass -T = TypeVar('T', A) +T = TypeVar('T', bound=A) def f(x: T) -> T: x.foo() x.bar() - x.baz() # E: "A" has no attribute "baz" + x.baz() # E: "T" has no attribute "baz" x.a x.b return x diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index bdfa2de9b340..7db2c2b88d66 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -1458,13 +1458,12 @@ main:6: error: Signatures of "__radd__" of "B" and "__add__" of "X" are unsafely [case testUnsafeOverlappingWithLineNo] from typing import TypeVar -T = TypeVar('T', Real) class Real: def __add__(self, other): ... class Fraction(Real): - def __radd__(self, other: T) -> T: ... + def __radd__(self, other: Real) -> Real: ... [out] -main:6: error: Signatures of "__radd__" of "Fraction" and "__add__" of "Real" are unsafely overlapping +main:5: error: Signatures of "__radd__" of "Fraction" and "__add__" of "Real" are unsafely overlapping [case testOverlappingNormalAndInplaceOperatorMethod] import typing diff --git a/test-data/unit/check-typevar-values.test b/test-data/unit/check-typevar-values.test index 69feab2059e4..34f5501f0a23 100644 --- a/test-data/unit/check-typevar-values.test +++ b/test-data/unit/check-typevar-values.test @@ -493,7 +493,7 @@ def outer(x: T) -> T: [case testClassMemberTypeVarInFunctionBody] from typing import TypeVar class C: - T = TypeVar('T', int) + T = TypeVar('T', bound=int) def f(self, x: T) -> T: A = C.T return x diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 06fd3d0dd226..f7de00d1a40b 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -968,10 +968,11 @@ a = TypeVar() # E: Too few arguments for TypeVar() b = TypeVar(x='b') # E: TypeVar() expects a string literal as first argument c = TypeVar(1) # E: TypeVar() expects a string literal as first argument d = TypeVar('D') # E: String argument 1 'D' to TypeVar(...) does not match variable name 'd' -e = TypeVar('e', int, str, x=1) # E: Unexpected argument to TypeVar(): x -f = TypeVar('f', (int, str)) # E: Type expected -g = TypeVar('g', x=(int, str)) # E: Unexpected argument to TypeVar(): x -h = TypeVar('h', bound=1) # E: TypeVar 'bound' must be a type +e = TypeVar('e', int, str, x=1) # E: Unexpected argument to TypeVar(): x +f = TypeVar('f', (int, str), int) # E: Type expected +g = TypeVar('g', int) # E: TypeVar cannot have only a single constraint +h = TypeVar('h', x=(int, str)) # E: Unexpected argument to TypeVar(): x +i = TypeVar('i', bound=1) # E: TypeVar 'bound' must be a type [out] [case testMoreInvalidTypevarArguments]