python / python/mypy

`mypy` widens multiple type parameters even when only the first one is relevant

Open
#21,903 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-inference
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

When there are two type parameters to widen, mypy widens both to Any, even when the matched overloads agree on the second parameter and only actually disagree on the first.

Related to #19952

To Reproduce

https://mypy-play.net/?gist=6ab5724e788384125e85da02ae0386d3

from collections.abc import Sequence
from typing import Any, Generic, Protocol, assert_type, overload

from typing_extensions import TypeVar

S1 = TypeVar("S1")


class EA: ...


A = TypeVar("A", bound=EA, default=EA, covariant=True)
S2 = TypeVar("S2", bound=EA)
S2_contra = TypeVar("S2_contra", bound=EA, contravariant=True)


class Supports_ProtoAdd(Protocol[S2_contra, S2]):
    def _proto_add(self, other: S2_contra, /) -> "Ser2[S2, EA]": ...


class Ser2(Generic[S1, A]):
    def _proto_add(self, other: Any, /) -> "Ser2[Any, EA]":
        raise NotImplementedError

    @overload
    def __add__(
        self: Supports_ProtoAdd[S2_contra, S2],
        other: "S2_contra | Sequence[S2_contra]",
    ) -> "Ser2[S2]": ...
    @overload
    def __add__(self: "Ser2[bool, EA]", other: Sequence[Any]) -> "Ser2[int]": ...
    def __add__(self, other: Any) -> Any:
        raise NotImplementedError


def f(a2: "Ser2[Any, EA]", seq: "Sequence[Any]") -> None:
    assert_type(a2 + seq, "Ser2[Any, EA]")
    # error: Expression is of type "Ser2[Any, Any]", not "Ser2[Any, EA]"  [assert-type]

Expected Behaviour

Error free, as is the case for pyright, pyrefly and ty

Actual Behaviour

main.py:24: error: Expression is of type "Ser2[Any, Any]", not "Ser2[bool, EA]"  [assert-type]
Found 1 error in 1 file (checked 1 source file)

Your Environment*

mypy 2.3.1 (playground)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the linked mypy-play reproduction and compare the inferred type with the assert_type expectation. Trace the overload matching and type-parameter widening logic involved in the add call, then add a regression test showing that only the disagreeing parameter widens while the shared EA parameter is preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.