Skip to content

Fix self type check for generic NamedTuple with constrained typevar - #22119

Open
EmmanuelNiyonshuti wants to merge 2 commits into
python:masterfrom
EmmanuelNiyonshuti:fix/constrained-generic-type-params-in-namedtuple
Open

EmmanuelNiyonshuti wants to merge 2 commits into
python:masterfrom
EmmanuelNiyonshuti:fix/constrained-generic-type-params-in-namedtuple

Conversation

@EmmanuelNiyonshuti

Copy link
Copy Markdown
Contributor

Fixes #21453

This PR makes it so that, for generic NamedTuples with a constrained typevar
and an unannotated self, the signature's self type with the substituted typevar
instance is used to substitute the ref_type(the class type seen from inside
the method), and they are the same type.
Otherwise the same-type check was failing, since ref_type would stay a typevar
type.

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

scipy-stubs (https://github.com/scipy/scipy-stubs)
+ tests/misc/test_submodules_empty.pyi:3: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports

@chrikrah chrikrah left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EmmanuelNiyonshuti approving at f7037aa. Expanding ref_type through the self argument's partial_fallback makes the two sides comparable, and nothing else in the checks I ran moves.

Head f7037aa, merge base d22bde6, Python 3.12:

$ python -m pytest -n 4 -q mypy/test/testcheck.py::TypeCheckSuite::check-{namedtuple,selftype,classes,generics,tuples}.test
1141 passed, 2 skipped, 1 xfailed

# same command, checker.py from d22bde6, your test kept
FAILED ...check-namedtuple.test::testGenericNamedTupleWithConstrainedTypeParams
1 failed, 1140 passed, 2 skipped, 1 xfailed

non-blocking: the change also reaches an explicit narrowed self on any generic NamedTuple, constrained or not. Box below, a plain Generic[T] class, already passes on both revisions, and the call-site check still fires:

$ cat -n nt3.py
     1	from typing import Generic, NamedTuple, TypeVar
     2	
     3	T = TypeVar("T")
     4	
     5	class Plain(NamedTuple, Generic[T]):
     6	    value: T
     7	    def only_int(self: "Plain[int]") -> int:
     8	        return self.value
     9	
    10	class Box(Generic[T]):
    11	    value: T
    12	    def only_int(self: "Box[int]") -> int:
    13	        return self.value
    14	
    15	Plain(1).only_int()
    16	Plain("a").only_int()

$ python -m mypy nt3.py   # d22bde6
nt3.py:7: error: The erased type of self "tuple[int, fallback=nt3.Plain[int]]" is not a supertype of its class "tuple[T, fallback=nt3.Plain[T]]"  [misc]
nt3.py:16: error: Invalid self argument "Plain[str]" to attribute function "only_int" with type "Callable[[Plain[int]], int]"  [misc]
$ python -m mypy nt3.py   # f7037aa
nt3.py:16: error: Invalid self argument "Plain[str]" to attribute function "only_int" with type "Callable[[Plain[int]], int]"  [misc]

A second test case for the narrowed self would pin that behaviour.

mypy_self_check.ini on mypy/checker.py, black 26.1.0 and ruff 0.14.3 are clean.

@ilevkivskyi, should the narrowed-self case go in as a second test here, or stay out of this fix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error on generic NamedTuple method that uses constrained type parameter

2 participants