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

Overloads do not take type: ignore into account #12454

Closed
A5rocks opened this issue Mar 26, 2022 · 6 comments
Closed

Overloads do not take type: ignore into account #12454

A5rocks opened this issue Mar 26, 2022 · 6 comments
Labels
bug mypy got something wrong topic-overloads topic-type-ignore # type: ignore comments

Comments

@A5rocks
Copy link
Contributor

A5rocks commented Mar 26, 2022

Bug Report

When matching overloads, a type: ignore is not passed into the underlying type check.

To Reproduce
Have this code:

from typing import Awaitable, Generic, TypeVar, overload

_R_co = TypeVar("_R_co", covariant=True)
_R = TypeVar("_R")

class Job(Generic[_R_co]):
    ...

@overload
def run_job(job: Job[Awaitable[_R]], a: int) -> _R | None: ...
@overload
def run_job(job: Job[Awaitable[_R] | _R], a: int) -> _R | None: ...

def run_job(job: Job[Awaitable[_R] | _R], a: int) -> _R | None: ...

job: Job[Awaitable[None] | None]

run_job(
    job,
    "",   # type: ignore[arg-type]
)

# "" is a stand-in for an invalid type.
# Passing an int would make the error go away.

Expected Behavior

Type checks fine.

Actual Behavior

repro.py:18: error: No overload variant of "run_job" matches argument types "Job[Optional[Awaitable[None]]]", "str"
repro.py:18: note: Possible overload variants:
repro.py:18: note:     def [_R] run_job(job: Job[Awaitable[_R]], a: int) -> Optional[_R]
repro.py:18: note:     def [_R] run_job(job: Job[Union[Awaitable[_R], _R]], a: int) -> Optional[_R]

Your Environment

  • Mypy version used: 81994f1 (based off master)
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.10.2
  • Operating system and version: Windows 11

Originally reported by @cdce8p in #11847.

@A5rocks A5rocks added the bug mypy got something wrong label Mar 26, 2022
@erictraut
Copy link

A # type: ignore comment simply suppresses errors on that line. It is not intended to "propagate" in any way.

@A5rocks
Copy link
Contributor Author

A5rocks commented Mar 26, 2022

Ah sorry, I was being a bit unclear with my terminology: not sure how to say it exactly but that probably shouldn't fail (function -> overload shouldn't be a breaking change, imo).

Mainly, I'm referring to this that mypy uses to check overloads are ok not taking type ignores into account:

mypy/mypy/checkexpr.py

Lines 1763 to 1771 in 14de8c6

ret_type, infer_type = self.check_call(
callee=typ,
args=args,
arg_kinds=arg_kinds,
arg_names=arg_names,
context=context,
arg_messages=overload_messages,
callable_name=callable_name,
object_type=object_type)

If it should fail, my bad!

@DevilXD
Copy link

DevilXD commented Mar 26, 2022

The error comes from line 18, which starts with run_job(. What about using a # type: ignore on that line instead? Like so:

run_job(  # type: ignore
    job,
    "",
)

@cdce8p
Copy link
Collaborator

cdce8p commented Mar 26, 2022

The error comes from line 18, which starts with run_job(. What about using a # type: ignore on that line instead? Like so:

run_job(  # type: ignore
    job,
    "",
)

That doesn't solve the issue

error: Argument 1 to "run_job" has incompatible type "Job[[int], Optional[Awaitable[None]]]"; expected "Job[[int], Awaitable[None]]"
error: Argument 2 to "run_job" has incompatible type "str"; expected "int"

The first error is still wrong and now mypy doesn't ignore the second one anymore.

The only option other option would be this

    run_job(job, "")  # type: ignore[arg-type]

That would simply hide both errors instead of resolving the underlying issue. In the particular case it wouldn't be possible due to formatting constraints.

--
The tests are done with #11847 since mypy doesn't yet support generic ParamSpec.

@cdce8p
Copy link
Collaborator

cdce8p commented Mar 27, 2022

Thought about this some more. I'm not sure how mypy, or any other type checker, is supposed to choose between overloads if one argument type is incorrect. Overloads simply depend on the arg-types. An even simpler example

@overload
def func(var: int) -> int: ...
@overload
def func(var: float) -> str: ...
def func(var: float) -> int | str: ...

reveal_type(func(
    "Hello"  # type: ignore[arg-type]
))

What should mypy infer here? Currently it's Any, probably the best we can do. Pyright infers Unknown which is also an option.

I think we can close this issue.

@JelleZijlstra
Copy link
Member

Maybe I'm missing something, but I also don't think there's a bug here. mypy passes if you use this instead:

run_job(  # type: ignore[call-overload]
    job,
    "",
)

As @erictraut said, there is no notion of "passing" a type ignore into a call; the comment simply suppresses type errors on that line. In this case, we generate the error on the first line of the call, so that's where you have to put the ignore.

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 topic-type-ignore # type: ignore comments
Projects
None yet
Development

No branches or pull requests

6 participants