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

[arg-type] "Argument has incompatible type" for TypeVar bound to Union passed to overloaded function #18075

Open
Avasam opened this issue Oct 30, 2024 · 1 comment
Labels
bug mypy got something wrong

Comments

@Avasam
Copy link
Contributor

Avasam commented Oct 30, 2024

Bug Report

If I try to pass a TypeVar bound to a union to a function that overloads for both part of the union, I get a [arg-type] error. But if I pass the same union not as a TypeVar, it works.

Note that pyright has similar behaviour here.

To Reproduce

import os
from typing import TypeVar, Union
from typing_extensions import TypeAlias, reveal_type

_StrPathT = TypeVar("_StrPathT", bound=Union[str, os.PathLike[str]])
_StrPath: TypeAlias = Union[str, os.PathLike[str]]

def foo(file_path: _StrPathT) -> _StrPathT:
    # Mypy:
    # Argument 1 to "dirname" has incompatible type "_StrPathT"; expected "PathLike[str]" [arg-type]
    # Revealed type is "builtins.str"
    # Pyright:
    # No overloads for "dirname" match the provided arguments [reportCallIssue]
    #   posixpath.pyi(88, 5): Overload 2 is the closest match
    # Argument of type "_StrPathT@foo" cannot be assigned to parameter "p" of type "AnyOrLiteralStr@dirname" in function "dirname"
    #   Type "_StrPathT@foo" is not assignable to constrained type variable "AnyOrLiteralStr" [reportArgumentType]
    # Type of "os.path.dirname(file_path)" is "Unknown"
    reveal_type(os.path.dirname(file_path))
    return file_path

def bar(file_path: _StrPath) -> _StrPath:
    # OK, both reveal type as str
    reveal_type(os.path.dirname(file_path))
    return file_path

Expected Behavior

This feels like a bug but I'm not completely certain. If I split the possible types _StrPathT = TypeVar("_StrPathT", str, os.PathLike[str]) it works, but then my method becomes incorrectly typed as it no longer accepts a str | os.PathLike[str]

Actual Behavior
See comments in MRE

Your Environment

  • Mypy version used: mypy 1.13.0 (compiled: yes)
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): (I've replicated this issue with an empty config file)
  • Python version used: 3.9.13

(I searched for similar issues and only found #13596)

@Avasam Avasam added the bug mypy got something wrong label Oct 30, 2024
@exoriente
Copy link

I have stumbled on the same issue and have made a very basic example:

from typing import overload


@overload
def fun(x: int) -> int: ...


@overload
def fun(x: str) -> str: ...


def fun[T](x: T) -> T:
    return x


def example_1[T: (int, str)](x: T) -> T:
    return fun(x)


def example_2(x: int | str) -> int | str:
    return fun(x)


def example_3[T: int | str](x: T) -> T:
    return fun(x)

Result

Error on example_3:

main.py:28: error: Incompatible return value type (got "int", expected "T")  [return-value]
main.py:28: error: Argument 1 to "fun" has incompatible type "T"; expected "int"  [arg-type]
Found 2 errors in 1 file (checked 1 source file)

See: https://mypy-play.net/?mypy=latest&python=3.12&gist=dcc284998239c8917dfc1c8ec1007bf3

Expectation

All example functions are ok. Not just 1 and 2.

Workaround

In our case we were able to avoid the problem by switching from approach 3 to approach 1. But using the union as a bound as in example_3 seems intuitive and sufficient. Developers in our team were stumped by the error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

2 participants