8000 (🐞) `Protocol` compatibility of `Unpack`ed `TypeVarTuple` is broken when signature is not a trivial `*args: Any` · Issue #16567 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content
8000

(🐞) Protocol compatibility of Unpacked TypeVarTuple is broken when signature is not a trivial *args: Any #16567

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
KotlinIsland opened this issue Nov 26, 2023 · 0 comments · Fixed by #18643
Labels
bug mypy got something wrong topic-pep-646 PEP 646 (TypeVarTuple, Unpack)

Comments

@KotlinIsland
Copy link
Contributor
KotlinIsland commented Nov 26, 2023
# mypy: disable-error-code=empty-body
from typing import Any, Protocol, Unpack, TypeVarTuple

Ts = TypeVarTuple("Ts")


class A1(Protocol[Unpack[Ts]]):
    def f(self, *args: Unpack[Ts]) -> None: ...

class B1:
    def f(self, x: str) -> None: ...

def f1(x: A1[Unpack[Ts]]) -> None: ...

f1(B1())

class A2(Protocol[Unpack[Ts]]):
    def f(self, z: str, *args: Unpack[Ts]) -> None: ...

class B2(A2[str]):
    def f(self, z: str, x: str) -> None: ...

class C2:
    def f(self, z: str, x: str) -> None: ...


def f2(x: A2[Unpack[Ts]]) -> None: ...

f2(B2())
f2(C2())
# error: Argument 1 to "f2" has incompatible type "C2"; expected "A2[*tuple[Never, ...]]"  [arg-type]
# note: Following member(s) of "C2" have conflicts:
# note:     Expected:
# note:         def f(self, z: str, *args: Never) -> None
# note:     Got:
# note:         def f(self, z: str, x: str) -> None

I believe this is caused by:

mypy/mypy/subtypes.py

Lines 1597 to 1607 in 1200d1d

if (
right.arg_kinds == [ARG_STAR]
and isinstance(get_proper_type(right.arg_types[0]), AnyType)
and not is_proper_subtype
):
# Similar to how (*Any, **Any) is considered a supertype of all callables, we consider
# (*Any) a supertype of all callables with positional arguments. This is needed in
# particular because we often refuse to try type inference if actual type is not
# a subtype of erased template type.
if all(k.is_positional() for k in left.arg_kinds) and ignore_pos_arg_names:
return True

@ilevkivskyi

@KotlinIsland KotlinIsland added the bug mypy got something wrong label Nov 26, 2023
@KotlinIsland KotlinIsland changed the title (🐞) Protocol compatibility of Unpacked TypeVarTuple is broken when signature is not a trivial ARG_STAR (🐞) Protocol compatibility of Unpacked TypeVarTuple is broken when signature is not a trivial *args: Any Nov 26, 2023
@ilevkivskyi ilevkivskyi added the topic-pep-646 PEP 646 (TypeVarTuple, Unpack) label Jun 23, 2024
ericmarkmartin pushed a commit to ericmarkmartin/mypy that referenced this issue Feb 19, 2025
Fixes python#18407
Fixes python#17184
Fixes python#16567

There are three things here:
* Allow erased variadic callables with non-empty prefix to be supertypes
of the non-erased ones. This relaxes a bit callable subtyping in
general, but IMO this makes sense, people who want to be strict should
simply use `*args: object` instead. An alternative would be to track
erased variadic callables explicitly, which is ugly and fragile.
* Add important missing case in `subtypes.py` for `*Ts` w.r.t.
`Any`/`object` that handles similar situations for variadic instances
and tuples (here however there is nothing special about `Any` vs
`object`).
* I also fix inconsistency in join uncovered by the above two.

The changes in `expandtype.py` are no-op, I just noticed potential
danger while playing with this, so wanted to highlight it with comments
for the future.
ericmarkmartin pushed a commit to ericmarkmartin/mypy that referenced this issue Feb 19, 2025
Fixes python#18407
Fixes python#17184
Fixes python#16567

There are three things here:
* Allow erased variadic callables with non-empty prefix to be supertypes
of the non-erased ones. This relaxes a bit callable subtyping in
general, but IMO this makes sense, people who want to be strict should
simply use `*args: object` instead. An alternative would be to track
erased variadic callables explicitly, which is ugly and fragile.
* Add important missing case in `subtypes.py` for `*Ts` w.r.t.
`Any`/`object` that handles similar situations for variadic instances
and tuples (here however there is nothing special about `Any` vs
`object`).
* I also fix inconsistency in join uncovered by the above two.

The changes in `expandtype.py` are no-op, I just noticed potential
danger while playing with this, so wanted to highlight it with comments
for the future.
x612skm pushed a commit to x612skm/mypy-dev that referenced this issue Feb 24, 2025
Fixes python#18407
Fixes python#17184
Fixes python#16567

There are three things here:
* Allow erased variadic callables with non-empty prefix to be supertypes
of the non-erased ones. This relaxes a bit callable subtyping in
general, but IMO this makes sense, people who want to be strict should
simply use `*args: object` instead. An alternative would be to track
erased variadic callables explicitly, which is ugly and fragile.
* Add important missing case in `subtypes.py` for `*Ts` w.r.t.
`Any`/`object` that handles similar situations for variadic instances
and tuples (here however there is nothing special about `Any` vs
`object`).
* I also fix inconsistency in join uncovered by the above two.

The changes in `expandtype.py` are no-op, I just noticed potential
danger while playing with this, so wanted to highlight it with comments
for the future.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-pep-646 PEP 646 (TypeVarTuple, Unpack)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants
0