Skip to content

Commit b41157b

Browse files
committed
Fix false positive for constrained NamedTuple self types
1 parent 938dbe2 commit b41157b

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

mypy/checker.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1768,7 +1768,37 @@ def require_correct_self_argument(self, func: Type, defn: FuncDef) -> bool:
17681768
# This level of erasure matches the one in checkmember.check_self_arg(),
17691769
# better keep these two checks consistent.
17701770
erased = get_proper_type(erase_typevars(erase_to_bound(arg_type)))
1771-
if not is_subtype(ref_type, erased, ignore_type_params=True):
1771+
1772+
# Generic NamedTuple methods using constrained TypeVars can produce
1773+
# false positives here because constrained TypeVars are checked using
1774+
# union semantics during subtype comparison.
1775+
#
1776+
# Example:
1777+
# S = TypeVar("S", str, bytes)
1778+
#
1779+
# class Result(NamedTuple, Generic[S]):
1780+
# ...
1781+
#
1782+
# In this case:
1783+
# tuple[S] is compared against tuple[str]
1784+
#
1785+
# and incorrectly rejected.
1786+
#
1787+
# Skip this check for constrained generic NamedTuple tuple self types.
1788+
skip_namedtuple_constrained_check = (
1789+
isinstance(ref_type, TupleType)
1790+
and isinstance(arg_type, TupleType)
1791+
and ref_type.partial_fallback.type.tuple_type is not None
1792+
and any(
1793+
isinstance(item, TypeVarType) and item.values
1794+
for item in ref_type.items
1795+
)
1796+
)
1797+
1798+
if (
1799+
not skip_namedtuple_constrained_check
1800+
and not is_subtype(ref_type, erased, ignore_type_params=True)
1801+
):
17721802
if (
17731803
isinstance(erased, Instance)
17741804
and erased.type.is_protocol

test-data/unit/check-selftype.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,3 +2378,16 @@ class Bar(Enum):
23782378
def bar(cls) -> Bar:
23792379
...
23802380
[builtins fixtures/classmethod.pyi]
2381+
2382+
[case testNamedTupleConstrainedTypeVarSelfType]
2383+
from typing import Generic, NamedTuple, TypeVar
2384+
2385+
S = TypeVar("S", str, bytes)
2386+
2387+
class Result(NamedTuple, Generic[S]):
2388+
value: S
2389+
2390+
def get_value(self) -> S:
2391+
return self.value
2392+
2393+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)