Skip to content

Generator[T] is falsely marked as incompatible with Iterator[T] when implementing an overload #6616

@jshumphrey

Description

@jshumphrey

High-level problem: A method is overloaded such that one possible return type is Iterator[T]. In this overload situation, I'm returning a Generator[T], and this is marked as incompatible with Iterator[T].

I'm running pyright as part of Pylance in VS Code; I can also reproduce this behavior in the Pyright Playground.

I do not believe this to be a duplicate of #1289, since that issue was traced to typeshed settings, whereas this behavior is reproducible in the Playground.


I've got a method where you can either provide a single value as an input, or a Sequence of values. If you provide a single value, you get a single result. If you provide a Sequence of values, you get an Iterator with one result for each input value. I've added typing.overload definitions to indicate this.

The problem is that I want to return a generator for the second use-case; when I try to do so, I get a typing warning.

import typing
from collections.abc import Iterator, Sequence

FooDict: typing.TypeAlias = dict[int, str]

class Bar:
    # Assume that list(Bar) returns a list of str
    def __iter__(self) -> Iterator[str]: ...

    @typing.overload
    def foo(self, i: int) -> FooDict: ...

    @typing.overload
    def foo(self, i: Sequence[int]) -> Iterator[FooDict]: ...  # Typing error on this line

    def foo(self, i: int | Sequence[int]):
        if isinstance(i, int):
            return {i: list(self)[i]}
        if isinstance(i, Sequence):
            return ({x: list(self)[x]} for x in i)
        raise TypeError

This gives a typing error:

Overloaded implementation is not consistent with signature of overload 2
Function return type "Iterator[FooDict] is incompatible with type "dict[int, str] | Generator[dict[int, str], None, None]"
"Iterator[FooDict]" is incompatible with "dict[int, str]"
"Iterator[FooDict]" is incompatible with "Generator[dict[int, str], None, None"

However, adjusting the type annotation for the (real) implementation of def foo so that it explicitly unions the two possible return types (def foo(self, i: int | Sequence[int]) -> FooDict | Iterator[FooDict]:) gets rid of the error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    as designedNot a bug, working as intendedbugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions