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..7b69c1bb84d7 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]