Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1768,7 +1768,47 @@ def require_correct_self_argument(self, func: Type, defn: FuncDef) -> bool:
# This level of erasure matches the one in checkmember.check_self_arg(),
# better keep these two checks consistent.
erased = get_proper_type(erase_typevars(erase_to_bound(arg_type)))
if not is_subtype(ref_type, erased, ignore_type_params=True):

# Generic NamedTuple methods using constrained TypeVars can produce
# false positives here because constrained TypeVars are checked using
# union semantics during subtype comparison.
#
# Example:
# S = TypeVar("S", str, bytes)
#
# class Result(NamedTuple, Generic[S]):
# ...
#
# In this case:
# tuple[S] is compared against tuple[str]
#
# and incorrectly rejected.
#
# Skip this check for constrained generic NamedTuple tuple self types.
has_constrained_typevar = False
namedtuple_ref_type: TupleType | None = None

proper_ref_type = get_proper_type(ref_type)
proper_arg_type = get_proper_type(arg_type)

if isinstance(proper_ref_type, TupleType):
namedtuple_ref_type = proper_ref_type

for item in proper_ref_type.items:
if isinstance(item, TypeVarType) and item.values:
has_constrained_typevar = True
break

skip_namedtuple_constrained_check = (
namedtuple_ref_type is not None
and isinstance(proper_arg_type, TupleType)
and namedtuple_ref_type.partial_fallback.type.is_named_tuple
and has_constrained_typevar
)

if not skip_namedtuple_constrained_check and not is_subtype(
ref_type, erased, ignore_type_params=True
):
if (
isinstance(erased, Instance)
and erased.type.is_protocol
Expand Down
13 changes: 13 additions & 0 deletions test-data/unit/check-selftype.test
Original file line number Diff line number Diff line change
Expand Up @@ -2378,3 +2378,16 @@ class Bar(Enum):
def bar(cls) -> Bar:
...
[builtins fixtures/classmethod.pyi]

[case testNamedTupleConstrainedTypeVarSelfType]
from typing import Generic, NamedTuple, TypeVar

S = TypeVar("S", str, bytes)

class Result(NamedTuple, Generic[S]):
value: S

def get_value(self) -> S:
return self.value

[builtins fixtures/tuple.pyi]
Loading