Skip to content

Commit b62957b

Browse files
Fix missing error when redeclaring type variable in nested generic class (#18883)
Closes #10479 Fixes a case where mypy doesn't warn about an inner generic class using a type variable by the same name as an outer generic class if the inner generic class doesn't declare the type variable using `Generic`, `Protocol`, or PEP-695 syntax.
1 parent 5c196d1 commit b62957b

File tree

4 files changed

+20
-5
lines changed

4 files changed

+20
-5
lines changed

mypy/message_registry.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ def with_additional_msg(self, info: str) -> ErrorMessage:
353353
"TypeVar constraint type cannot be parametrized by type variables", codes.MISC
354354
)
355355

356+
TYPE_VAR_REDECLARED_IN_NESTED_CLASS: Final = ErrorMessage(
357+
'Type variable "{}" is bound by an outer class', codes.VALID_TYPE
358+
)
359+
356360
TYPE_ALIAS_WITH_YIELD_EXPRESSION: Final = ErrorMessage(
357361
"Yield expression cannot be used within a type alias", codes.SYNTAX
358362
)

mypy/semanal.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,14 @@ def tvar_defs_from_tvars(
23742374
tvar_expr.default = tvar_expr.default.accept(
23752375
TypeVarDefaultTranslator(self, tvar_expr.name, context)
23762376
)
2377+
# PEP-695 type variables that are redeclared in an inner scope are warned
2378+
# about elsewhere.
2379+
if not tvar_expr.is_new_style and not self.tvar_scope.allow_binding(
2380+
tvar_expr.fullname
2381+
):
2382+
self.fail(
2383+
message_registry.TYPE_VAR_REDECLARED_IN_NESTED_CLASS.format(name), context
2384+
)
23772385
tvar_def = self.tvar_scope.bind_new(name, tvar_expr)
23782386
if last_tvar_name_with_default is not None and not tvar_def.has_default():
23792387
self.msg.tvar_without_default_type(

mypy/typeanal.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,11 +1844,8 @@ def bind_function_type_variables(
18441844
defs = []
18451845
for name, tvar in typevars:
18461846
if not self.tvar_scope.allow_binding(tvar.fullname):
1847-
self.fail(
1848-
f'Type variable "{name}" is bound by an outer class',
1849-
defn,
1850-
code=codes.VALID_TYPE,
1851-
)
1847+
err_msg = message_registry.TYPE_VAR_REDECLARED_IN_NESTED_CLASS.format(name)
1848+
self.fail(err_msg.value, defn, code=err_msg.code)
18521849
binding = self.tvar_scope.bind_new(name, tvar)
18531850
defs.append(binding)
18541851

test-data/unit/semanal-errors.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,12 @@ class A(Generic[T]):
10151015
# E: Free type variable expected in Generic[...]
10161016
[out]
10171017

1018+
[case testRedeclaredTypeVarWithinNestedGenericClass]
1019+
from typing import Generic, Iterable, TypeVar
1020+
T = TypeVar('T')
1021+
class A(Generic[T]):
1022+
class B(Iterable[T]): pass # E: Type variable "T" is bound by an outer class
1023+
10181024
[case testIncludingGenericTwiceInBaseClassList]
10191025
from typing import Generic, TypeVar
10201026
T = TypeVar('T')

0 commit comments

Comments
 (0)