KEMBAR78
Misleading error message when using ParamSpec with higher-order decorators and async functions · Issue #18493 · python/mypy · GitHub
Skip to content

Misleading error message when using ParamSpec with higher-order decorators and async functions #18493

@wesleywright

Description

@wesleywright

Bug Report

There seems to be a niche edge case where mypy detects a mismatch between parameter names for a ParamSpec but doesn't actually report the difference in parameter names. In my reproducible example, it actually prints a confusing error about the return types, even though the return types actually unify just fine. I've only been able to reproduce it with an async function, but I'm not sure if it's limited to async functions.

This is probably a relatively rare issue for users to hit because it involves a higher-order function that returns a decorator, ParamSpec, and async — all of which are somewhat niche on their own. However, the error output still seems very misleading to me.

To Reproduce

https://mypy-play.net/?mypy=latest&python=3.12&gist=12a1a49ced24294d0d1395f9317afcc1

from typing import Any, Awaitable, Callable, ParamSpec, TypeVar, Iterator

P = ParamSpec("P")
R = TypeVar("R")


def decorator2(f: Callable[P, None]) -> Callable[
    [Callable[P, Awaitable[None]]],
    Callable[P, Awaitable[None]],
]:
    return lambda f: f


def key2(x: int) -> None:
    ...


@decorator2(key2)
async def foo2(y: int) -> None:
    ...

Expected Behavior

Mypy should print an error pointing out that key2 takes a parameter named x while foo2 takes a parameter named y. For example, if you rewrote this example so that the foo2 is non-async and the decorator doesn't use Awaitable, you would get this error message:

error: Argument 1 has incompatible type "Callable[[Arg(int, 'y')], None]"; expected "Callable[[Arg(int, 'x')], None]"  [arg-type]

Actual Behavior

Mypy gives an error that does not describe the difference in argument names, but which does describe a difference in return types (even though these return types actually unify just fine!):

error: Argument 1 has incompatible type "Callable[[int], Coroutine[Any, Any, None]]"; expected "Callable[[int], Awaitable[None]]"  [arg-type]

Your Environment

Discovered while testing latest master to prepare the 1.15 release, but this behavior seems to be longstanding; I see the same error message when using the code from mypy v1.0.0. It seems to reproduce out of the box in Mypy, as demonstrated by the vanilla mypy playground link above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions