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

Inconsistencies in overload overlapping error message vs actually used overload #9572

Open
Kajiih opened this issue Dec 11, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@Kajiih
Copy link

Kajiih commented Dec 11, 2024

Describe the bug
I am using recursive type definitions, and I encountered inconsistencies in overload parameter overlap error message vs which overload is actually used.

The example should explain more clearly.

Code or Screenshots
Here's the main inconsistency:
In the following code, overload 2 is detected as overlapping with overload 1 (which is the behavior I expected since there is no constraint on V in overload 1), but when testing at the end of the code, the overload used is overload 2 and not overload 1 (unexpected, especially since they are supposed to overlap).

Other unexpected behaviors:
overload 3 is not detected as overlapping, even though, from my understanding, it should be a case similar to overload 2.
It might be a variance-related issue, but since both K and V could be any type (and in particular Any?), I don't understand why some cases overlap and others don't, and why overload 1 is not used when testing at the end of the example.

from collections.abc import Iterator, Mapping
from typing import Any, cast, overload, reveal_type

# Recursive types:
type NestedMapping[K, V] = Mapping[K, NestedMappingNode[K, V]]
type NestedMappingNode[K, V] = V | NestedMapping[K, V]

type NestedDict[K, V] = dict[K, NestedDictNode[K, V]]
type NestedDictNode[K, V] = V | NestedDict[K, V]


@overload
def iter_leaf_containers[K, V](
    nested_dict: NestedDict[K, V],
) -> Iterator[tuple[dict[K, V], K]]: ...


# Overload 2 for "iter_leaf_containers" will never be used because its parameters overlap overload 1
@overload
def iter_leaf_containers[K](
    nested_dict: NestedDict[K, Any],
) -> Iterator[tuple[dict[K, Any], K]]: ...


# Somewhat unexpected: no parameter overlap is detected with either overload 1
@overload
def iter_leaf_containers[V](
    nested_dict: NestedDict[Any, V],
) -> Iterator[tuple[dict[Any, V], Any]]: ...

# As expected: Overload 4 for "iter_leaf_containers" will never be used because its parameters overlap overload 3
@overload
def iter_leaf_containers(
    nested_dict: NestedDict[Any, Any],
) -> Iterator[tuple[dict[Any, Any], Any]]: ...


@overload
def iter_leaf_containers[K, V](
    nested_dict: NestedMapping[K, V],
) -> Iterator[tuple[Mapping[K, V], K]]: ...


def iter_leaf_containers[K, V](
    nested_dict: NestedMapping[K, V],
) -> Iterator[tuple[Mapping[K, V], K]]:
    for key, value in nested_dict.items():
        if isinstance(value, Mapping):
            yield from iter_leaf_containers(cast(NestedMapping[K, V], value))
        else:
            yield cast(Mapping[K, V], nested_dict), key


nested = {"a": {"b": 42}}

# Despite the error message, compatibility is detected with the overload 2
leaf_refs = iter_leaf_containers(nested)
reveal_type(leaf_refs)  # Iterator[tuple[dict[str, Any], str]]

VS Code extension or command-line
Both VS Code extension and command line, Pyright v1.1.390

@Kajiih Kajiih added the bug Something isn't working label Dec 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant