From 4aff6a2e6e601ca4ba96a3dbe2aceffd1da13cee Mon Sep 17 00:00:00 2001 From: PGray Date: Fri, 9 Oct 2026 21:36:11 +0100 Subject: [PATCH 1/2] Don't cache partial protocol checks that skip __call__ (fixes #22151) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- mypy/subtypes.py | 3 +++ test-data/unit/check-protocols.test | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index d9c1b47c317f..451a5e4ebbe5 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1381,6 +1381,9 @@ def f(self) -> A: ... if IS_CLASS_OR_STATIC in superflags and IS_CLASS_OR_STATIC not in subflags: return False + if skip: + # The result is only valid for the partial check, don't pollute the subtype cache. + return True if not proper_subtype: # Nominal check currently ignores arg names, but __call__ is special for protocols ignore_names = right.type.protocol_members != ["__call__"] diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 75a0dfe2f5f4..dabb3c0b0ad8 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -4819,3 +4819,25 @@ class Bad(Generic[T]): bad: Bad[str] = Bad() fail: SupportsFoo = bad # E: Incompatible types in assignment (expression has type "Bad[str]", variable has type "SupportsFoo") [builtins fixtures/tuple.pyi] + +[case testCallbackProtocolUnionInferenceOrderIndependent] +from typing import Protocol, TypeVar + +T = TypeVar("T") +PT = TypeVar("PT", contravariant=True) + +class OneArg(Protocol[PT]): + def __call__(self, x: PT, /) -> None: ... + +class TwoArgs(Protocol[PT]): + def __call__(self, x: PT, y: int, /) -> None: ... + +def first_arg(fn: OneArg[T] | TwoArgs[T]) -> T: ... + +def one(x: int) -> None: ... +def two(x: str, y: int) -> None: ... + +reveal_type(first_arg(one)) # N: Revealed type is "builtins.int" +reveal_type(first_arg(two)) # N: Revealed type is "builtins.str" +reveal_type(first_arg(one)) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] \ No newline at end of file From 05916e7cadca2d7b6ce343f71fd5efa8a40d6646 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 9 Oct 2026 20:38:32 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- test-data/unit/check-protocols.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index dabb3c0b0ad8..7b69c1bb84d7 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -4840,4 +4840,4 @@ def two(x: str, y: int) -> None: ... reveal_type(first_arg(one)) # N: Revealed type is "builtins.int" reveal_type(first_arg(two)) # N: Revealed type is "builtins.str" reveal_type(first_arg(one)) # N: Revealed type is "builtins.int" -[builtins fixtures/tuple.pyi] \ No newline at end of file +[builtins fixtures/tuple.pyi]