1

I recently upgraded mypy from 1.17.0 to 1.18.2 The following code was successfully validated in the old mypy version (1.17.0), but fails in the new one (1.18.2):

_T = TypeVar('_T')


class Foo(Generic[_T], ABC):
    pass


def to_foo(value: _T | Foo[_T],
           checker: Callable[[Any], TypeIs[_T]],
           factory: Callable[[_T], Foo[_T]]) -> Foo[_T]:
    if checker(value):
        return factory(value)
    else:
        return value

This is the error:

error: Incompatible return value type (got "_T | Foo[_T]", expected "Foo[_T]")  [return-value]

mypy seems unhappy with the second return statement. It seems, it can not deduce, that if value is _T | Foo[_T] to begin with, and is not _T (the else case), that is has to be of type Foo[_T].

Although, I thought that is exactly what TypeIs does:

Type narrowing is applied in both the positive and negative case

When I reduce the problem further, I end up with the following function which still fails:

_T = TypeVar('_T')


def mypy_fails(x: _T | int, checker: Callable[[Any], TypeIs[_T]], default: int) -> int:
    if checker(x):
        return default
    else:
        return x

It seems to be related to the TypeVar, since the following function (with int and _T switched) still validates:

def mypy_validates(x: int | _T, checker: Callable[[Any], TypeIs[int]], default: _T) -> _T:
    if checker(x):
        return default
    else:
        return x

What is wrong with my initial code? Why does mypy_validates work? And why was it fine in the old mypy version, but not the newer one?

2
  • 2
    This was changed in github.com/python/mypy/pull/18193, and I'd say it is a bug. Please open an issue with your snippet and a reference to #18193. This code looks safe to me: else branch of if checker(T) should narrow x to the intersection of _T | int and ~_T (not-_T). The problem is likely that T has no upper bound, so we cannot compute this intersection reasonably, but at least removing the _T itself from union members would make sense. Commented yesterday
  • @STerliakov Thanks! I did github.com/python/mypy/issues/20330 Commented 7 hours ago

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.