Skip to content

Return intersection instead of Any for ambiguous overload match #665

@dhruvmanila

Description

@dhruvmanila

Consider the following example:

overloaded.pyi:

from typing import overload
from typing_extensions import LiteralString

@overload
def f(x: LiteralString) -> LiteralString: ...
@overload
def f(x: str) -> str: ...
from typing import Any
from typing_extensions import LiteralString

from overloaded import f

def _(literal: LiteralString, string: str, any: Any):
    reveal_type(f(literal))  # revealed: LiteralString
    reveal_type(f(string))  # revealed: str

    # `Any` matches both overloads, but the return types are not equivalent.
    # Pyright and mypy both reveal `str` here, contrary to the spec.
    reveal_type(f(any))  # revealed: Any

For the last call, ty reveals Any while Pyright and mypy reveals str. The reason ty reveals Any is because the overload matching is ambiguous according to the spec. Here's how the algorithm detects that:

  1. Arity does not eliminate any overloads
  2. Type checking does not eliminate any overloads
  3. Step 3 is skipped since step 2 did not result in errors for all overloads
  4. Step 4 has no effect, since neither overload has a variadic parameter
  5. All materialization of Any are not assignable to either of the overloads since it could materialize into anything other than LiteralString or str. The return types of the remaining overloads are not equivalent so the overload matching is ambiguous.

More formally, at the end of step 5, before concluding that the overload matching is ambiguous, ty should check whether the return types are overlapping and return the widest type of them instead of Any.

I'm not exactly sure if this is what Pyright / mypy does so it might be useful to hear from someone who knows about this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-designNeeds further design before implementationoverloadstyping semanticstyping-module features, spec compliance, etc

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions