diff --git a/mypy/semanal.py b/mypy/semanal.py index bad2dfbefae0..4bf342c1e128 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2369,8 +2369,11 @@ def analyze_unbound_tvar_impl( assert isinstance(sym.node, TypeVarExpr) return t.name, sym.node - def find_type_var_likes(self, t: Type) -> TypeVarLikeList: + def find_type_var_likes( + self, t: Type, *, include_bound_tvars: bool = False + ) -> TypeVarLikeList: visitor = FindTypeVarVisitor(self, self.tvar_scope) + visitor.include_bound_tvars = include_bound_tvars t.accept(visitor) return visitor.type_var_likes @@ -5036,9 +5039,15 @@ def analyze_value_types(self, items: list[Expression]) -> list[Type]: result: list[Type] = [] for node in items: try: - analyzed = self.anal_type( - self.expr_to_unanalyzed_type(node), allow_placeholder=True - ) + unanalyzed_type = self.expr_to_unanalyzed_type(node) + if self.find_type_var_likes(unanalyzed_type, include_bound_tvars=True): + self.fail( + "TypeVar constraint type cannot be parametrized by type variables", node + ) + result.append(AnyType(TypeOfAny.from_error)) + continue + + analyzed = self.anal_type(unanalyzed_type, allow_placeholder=True) if analyzed is None: # Type variables are special: we need to place them in the symbol table # soon, even if some value is not ready yet, see process_typevar_parameters() diff --git a/mypy/typeanal.py b/mypy/typeanal.py index daf7ab1951ea..930cc46e44d4 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -2558,6 +2558,7 @@ def __init__(self, api: SemanticAnalyzerCoreInterface, scope: TypeVarLikeScope) self.has_self_type = False self.seen_aliases: set[TypeAliasType] | None = None self.include_callables = True + self.include_bound_tvars = False def _seems_like_callable(self, type: UnboundType) -> bool: if not type.args: @@ -2583,7 +2584,7 @@ def visit_unbound_type(self, t: UnboundType) -> None: if ( node and isinstance(node.node, TypeVarLikeExpr) - and self.scope.get_binding(node) is None + and (self.scope.get_binding(node) is None or self.include_bound_tvars) ): if (name, node.node) not in self.type_var_likes: self.type_var_likes.append((name, node.node)) diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 33c8f9b80aa0..16b35be2deaa 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -1060,6 +1060,19 @@ S = TypeVar('S', covariant=True, contravariant=True) \ # E: TypeVar cannot be both covariant and contravariant [builtins fixtures/bool.pyi] +[case testInvalidTypevarArgumentsGenericConstraint] +from typing import Generic, List, TypeVar + +T = TypeVar("T") + +Bad1 = TypeVar("Bad1", int, T) # E: TypeVar constraint type cannot be parametrized by type variables +Bad2 = TypeVar("Bad2", int, List[T]) # E: TypeVar constraint type cannot be parametrized by type variables +Bad3 = TypeVar("Bad3", int, List[List[T]]) # E: TypeVar constraint type cannot be parametrized by type variables +def f(x: T) -> None: + Bad4 = TypeVar("Bad4", int, List[T]) # E: TypeVar constraint type cannot be parametrized by type variables +class C(Generic[T]): + Bad5 = TypeVar("Bad5", int, List[T]) # E: TypeVar constraint type cannot be parametrized by type variables + [case testInvalidTypevarValues] from typing import TypeVar b = TypeVar('b', *[int]) # E: Unexpected argument to "TypeVar()"