Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type narrowing not found for combination of overloaded optional argument and null guard #11661

Open
dfoerster-athene opened this issue Dec 3, 2021 · 0 comments
Labels
bug mypy got something wrong topic-overloads

Comments

@dfoerster-athene
Copy link

dfoerster-athene commented Dec 3, 2021

Bug Report

Mypy fails to find type narrowings that use a combination of overloading and null checks.

To Reproduce

from __future__ import annotations
import typing as t


@t.overload
def func2(a: int,
          b: str,
          x: t.Callable[[int], int],
          y: t.Callable[[str], int]) -> tuple[int, int]: ...
@t.overload
def func2(a: int,
          b: str,
          x: t.Callable[[t.Union[int, str]], int]) -> tuple[int, int]: ...


def func2(a: int,
          b: str,
          x: t.Callable[[int], int],
          y: t.Optional[t.Callable[[str], int]] = None):
    y = y or x
    return x(a), y(b)


@t.overload
def func3(a: int,
          b: str,
          x: t.Callable[[int], int],
          y: t.Callable[[str], int]) -> tuple[int, int]: ...
@t.overload
def func3(a: int,
          b: str,
          x: t.Callable[[t.Union[int, str]], int]) -> tuple[int, int]: ...


def func3(a: int,
          b: str,
          x: t.Union[t.Callable[[int], int], t.Callable[[t.Union[int, str]], int]],
          y: t.Optional[t.Callable[[str], int]] = None):
    if y:
        y2 = y
    else:
        y2 = x
    return x(a), y2(b)


@t.overload
def func4(a: int,
          b: str,
          x: list[int],
          y: list[str]): ...
@t.overload
def func4(a: int,
          b: str,
          x: list[t.Union[int, str]]): ...


def func4(a: int,
          b: str,
          x: t.Union[list[int], list[t.Union[int, str]]],
          y: t.Optional[list[str]] = None):
    if y:
        y2 = y
    else:
        y2 = x
    x.append(a)
    y2.append(b)

Expected Behavior

My expectation is that in func2-func4, the Union type of x will always narrow down to support b as well as a when y is not supplied and x must be assigned to y/y2.

Actual Behavior

mypy==0.910:

$ mypy --show-error-codes _scratch.py 
_scratch.py:20: error: Incompatible types in assignment (expression has type "Union[Callable[[str], int], Callable[[int], int]]", variable has type "Optional[Callable[[str], int]]")  [assignment]
_scratch.py:21: error: "None" not callable  [misc]
_scratch.py:42: error: Incompatible types in assignment (expression has type "Union[Callable[[int], int], Callable[[Union[int, str]], int]]", variable has type "Callable[[str], int]")  [assignment]
_scratch.py:64: error: Incompatible types in assignment (expression has type "Union[List[int], List[Union[int, str]]]", variable has type "List[str]")  [assignment]

mypy==0.920.dev:

_scratch.py:20: error: Incompatible types in assignment (expression has type "Union[Callable[[str], int], Callable[[int], int]]", variable has type "Optional[Callable[[str], int]]")  [assignment]
_scratch.py:21: error: "None" not callable  [misc]
_scratch.py:42: error: Incompatible types in assignment (expression has type "Union[Callable[[int], int], Callable[[Union[int, str]], int]]", variable has type "Callable[[str], int]")  [assignment]
_scratch.py:64: error: Incompatible types in assignment (expression has type "Union[List[int], List[Union[int, str]]]", variable has type "List[str]")  [assignment]
_scratch.py:72: error: Cannot call function of unknown type  [operator]

Instead, no narrowing occurs and mypy declares the types incompatible, both when Callable is used and when a standard collection is used.

Your Environment

  • Mypy version used: 0.910 and 0.920+dev.cee5d3e9a29f43a10a8eeca760976657bf1689c9
  • Mypy command-line flags: --show-error-codes
  • Python version used: Python 3.8.0
  • Operating system and version: Microsoft Windows 10 [Version 10.0.19043.1348]
@dfoerster-athene dfoerster-athene added the bug mypy got something wrong label Dec 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-overloads
Projects
None yet
Development

No branches or pull requests

2 participants