Skip to content

Overlapping overloads attempting to separate awaitable from non-awaitable #12759

@flaeppe

Description

@flaeppe

I'll try to show a similar but smaller implementation of a decorator I've tried to throw together:

import asyncio
from typing import Awaitable, Callable, TypeVar, overload, cast, Generic

T = TypeVar("T", bound=object)


class Async(Generic[T]):
    def __init__(self, f: Callable[[int], Awaitable[T]]):
        ...


class Sync(Generic[T]):
    def __init__(self, f: Callable[[int], T]):
        ...


@overload
def supposed_overlap(f: Callable[[int], Awaitable[T]]) -> Async[T]:
    ...

@overload
def supposed_overlap(f: Callable[[int], T]) -> Sync[T]:
    ...

def supposed_overlap(f: Callable[[int], Awaitable[T] | T]) -> Async[T] | Sync[T]:
    if asyncio.iscoroutinefunction(f):
        return Async(cast(Callable[[int], Awaitable[T]], f))
    else:
        return Sync(cast(Callable[[int], T], f))


@supposed_overlap
async def something_async(value: int) -> float:
    return 1.1


@supposed_overlap
def something_sync(value: int) -> str:
    return "1.1"


reveal_type(something_async)
reveal_type(something_sync)

Resulting in:

18: error: Overloaded function signatures 1 and 2 overlap with incompatible return types  [misc]

While the revealed types are correct (as long as the overloads are specified in the order above)

42: note: Revealed type is "Async[builtins.float*]"
43: note: Revealed type is "Sync[builtins.str*]"

I can see why I get this error, that Awaitable could match with (or be included by) T as well. But I'd like to express that kind of difference, the naive version being:

  1. Match only on being Awaitable
  2. Everything else

Which mypy already seem to do for me (seeing that reveal_type is correct) while overlaps doesn't consider ordering

Sorry if I'm just piling to the already existing list of overlap-issues from @overload, or I'm missing something.. But I had a hard time matching my issue with any of the open ones.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions