Skip to content

Solve class-level TypeVarTuples in explicit self-types - #22023

Open
Dextheking1 wants to merge 2 commits into
python:masterfrom
Dextheking1:fix/selftype-typevartuple-21878
Open

Dextheking1 wants to merge 2 commits into
python:masterfrom
Dextheking1:fix/selftype-typevartuple-21878

Conversation

@Dextheking1

@Dextheking1 Dextheking1 commented Sep 22, 2026

Copy link
Copy Markdown

Closes #21878.

A class-level TypeVarTuple cannot take two different values in the same scope (see discussion in #21878). In def add(self: "A[*TS, int, int]"), TS is already bound to the instance's full argument tuple, so the self-type means e.g. A[1, 2, 3, int, int] for an A[1, 2, 3] receiver. Previously the unpack made the self-argument overlap check vacuously succeed, and expand_type_by_instance() then spliced the whole instance argument tuple into *TS, revealing a bogus A[Literal[1]?, Literal[2]?, Literal[3]?, int].

check_self_arg() now substitutes the class type variables in an explicit self-type containing a TypeVarTuple unpack using the receiver, before the overlap/subtype checks, so A(1, 2, 3).add() is rejected with Invalid self argument. Method-level type variables are unaffected, and self-types without an unpack keep the previous behavior.

Adds regression test testTypeVarTupleExplicitSelfTypeWithExtraArgs.

)

When a method of a TypeVarTuple-generic class declares an explicit
self-type with extra arguments around the unpack, e.g.
`def add(self: "A[*TS, int, int]") -> "A[*TS, int]"`, bind_self() left
the class-level *TS alone and expand_type_by_instance() later spliced the
whole instance argument tuple into *TS.  A(1, 2, 3).add() was therefore
revealed as A[Literal[1]?, Literal[2]?, Literal[3]?, int] instead of
A[Literal[1]?, int].

Fix: in bind_self(), also solve class-level TypeVarTuples appearing in the
self-type against the receiver type, and substitute the solutions into the
signature before dropping the self argument.  Class-level type variables
that cannot be solved are left alone for expand_type_by_instance() as
before.  Regular (non-variadic) class type variables are unaffected: their
positions are fixed, so the existing substitution stays correct for them.

Adds regression test testTypeVarTupleExplicitSelfTypeWithExtraArgs.
…ypes (fix python#21878)

A class-level TypeVarTuple cannot take two different values in the same
scope (see discussion in python#21878). In `def add(self: "A[*TS, int, int]")`,
TS is already bound to the instance's full argument tuple, so the self-type
means e.g. A[1, 2, 3, int, int] for an A[1, 2, 3] receiver, and the call must
be rejected with "Invalid self argument" instead of revealing a bogus
A[1, 2, 3, int].

check_self_arg() now substitutes the class type variables in an explicit
self-type containing a TypeVarTuple unpack using the receiver, before the
overlap/subtype checks. Method-level type variables are unaffected, and
self-types without an unpack keep the previous behavior.

This replaces the inference-based approach from the previous commit on this
branch, which solved *TS as the argument prefix.

Adds regression test testTypeVarTupleExplicitSelfTypeWithExtraArgs.
@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

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.

PEP-646 generic with self annotated function gives incorrect result

1 participant