Skip to content

TypeGuard doesn't propagate information to other branches #13957

@spookylukey

Description

@spookylukey

Bug Report

Type narrowing implemented using TypeGuard doesn't appear to propagate information to other branches, unlike with builtin type narrowing like isinstance.

To Reproduce

from typing import TypeGuard, Any


def is_int(val: Any) -> TypeGuard[int]:
    return isinstance(val, int)


def my_function_1(value: str | int) -> str:
    if isinstance(value, str):
        return value + " hello"
    else:
        return str(value + 1)


def my_function_2(value: str | int) -> str:
    if isinstance(value, int):
        return str(value + 1)
    else:
        return value + " hello"


def my_function_3(value: str | int) -> str:
    if is_int(value):
        return str(value + 1)
    else:
        return value + " hello"

Playground link: https://mypy-play.net/?mypy=master&python=3.10&gist=69794cff9fc522309d8ac034d7d595f4

Expected Behavior
I expected my_function_3 to report no errors, just like my_function_1 and my_function_2. In both those cases, mypy is able to deduce that in the "other" branch, there is only one possible type.

Actual Behavior
mypy reports:

main.py:27: error: Incompatible return value type (got "Union[str, int]", expected "str")  [return-value]
main.py:27: error: Unsupported operand types for + ("int" and "str")  [operator]
main.py:27: note: Left operand is of type "Union[str, int]"
Found 2 errors in 1 file (checked 1 source file)

That is, while it can deduce that value + 1 has no errors in the is_int() branch, which shows the type guard is "working", it can't deduce that value cannot be int in the other branch.

Tested against 0.982 and master, Python 3.10

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions