Skip to content

Wrapped overloaded function drops all but the first overload #15737

@maffoo

Description

@maffoo

Bug Report

When wrapping an overloaded function and using ParamSpec to preserve the call signature, only the first overload is preserved on the resulting function.

To Reproduce

See:

from typing import Callable, overload, TypeVar
from typing_extensions import ParamSpec

P = ParamSpec("P")
T = TypeVar("T")

def transform(func: Callable[P, list[T]]) -> Callable[P, T]:
    def wrapped(*args: P.args, **kwargs: P.kwargs) -> T:
        return func(*args, **kwargs)[0]

    return wrapped

@overload
def foo(x: int) -> list[float]:
    pass

@overload
def foo(x: str) -> list[str]:
    pass

def foo(x: int | str) -> list[float] | list[str]:
    if isinstance(x, int):
        return [1 / x]
    return [x[::-1]]

bar = transform(foo)

assert bar(2) == 0.5
assert bar("abc") == "cba"

reveal_type(foo)
reveal_type(bar)

Expected Behavior

I would expect the overloads to be preserved on the decorated function, e.g.

main.py:31: note: Revealed type is "Overload(def (x: builtins.int) -> builtins.list[builtins.float], def (x: builtins.str) -> builtins.list[builtins.str])"
main.py:32: note: Revealed type is Overload(def (x: builtins.int) -> builtins.float, def (x: builtins.str) -> builtins.str)"

Actual Behavior

main.py:29: error: Argument 1 has incompatible type "str"; expected "int"  [arg-type]
main.py:31: note: Revealed type is "Overload(def (x: builtins.int) -> builtins.list[builtins.float], def (x: builtins.str) -> builtins.list[builtins.str])"
main.py:32: note: Revealed type is "def (x: builtins.int) -> builtins.float"

Your Environment

  • Mypy version used: 1.4.1
  • Python version used: 3.10.10

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-paramspecPEP 612, ParamSpec, Concatenate

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions