diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 0c7464246990..c45fddd6aca7 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -354,6 +354,10 @@ def with_additional_msg(self, info: str) -> ErrorMessage: "TypeVar constraint type cannot be parametrized by type variables", codes.MISC ) +TYPE_VAR_REDECLARED_IN_NESTED_CLASS: Final = ErrorMessage( + 'Type variable "{}" is bound by an outer class', codes.VALID_TYPE +) + TYPE_ALIAS_WITH_YIELD_EXPRESSION: Final = ErrorMessage( "Yield expression cannot be used within a type alias", codes.SYNTAX ) diff --git a/mypy/semanal.py b/mypy/semanal.py index 6d0a62070c8e..7f8e58575037 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2387,6 +2387,14 @@ def tvar_defs_from_tvars( tvar_expr.default = tvar_expr.default.accept( TypeVarDefaultTranslator(self, tvar_expr.name, context) ) + # PEP-695 type variables that are redeclared in an inner scope are warned + # about elsewhere. + if not tvar_expr.is_new_style and not self.tvar_scope.allow_binding( + tvar_expr.fullname + ): + self.fail( + message_registry.TYPE_VAR_REDECLARED_IN_NESTED_CLASS.format(name), context + ) tvar_def = self.tvar_scope.bind_new(name, tvar_expr) if last_tvar_name_with_default is not None and not tvar_def.has_default(): self.msg.tvar_without_default_type( diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 7bf21709b863..77d031d8c85b 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -1869,11 +1869,8 @@ def bind_function_type_variables( defs = [] for name, tvar in typevars: if not self.tvar_scope.allow_binding(tvar.fullname): - self.fail( - f'Type variable "{name}" is bound by an outer class', - defn, - code=codes.VALID_TYPE, - ) + err_msg = message_registry.TYPE_VAR_REDECLARED_IN_NESTED_CLASS.format(name) + self.fail(err_msg.value, defn, code=err_msg.code) binding = self.tvar_scope.bind_new(name, tvar) defs.append(binding) diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 52c658c97c3b..45cb5fa0d4b0 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -1015,6 +1015,12 @@ class A(Generic[T]): # E: Free type variable expected in Generic[...] [out] +[case testRedeclaredTypeVarWithinNestedGenericClass] +from typing import Generic, Iterable, TypeVar +T = TypeVar('T') +class A(Generic[T]): + class B(Iterable[T]): pass # E: Type variable "T" is bound by an outer class + [case testIncludingGenericTwiceInBaseClassList] from typing import Generic, TypeVar T = TypeVar('T')