Skip to content

Empty collection's subtype evaluates to Unknown when in tuple passed to Iterable with TypeVar parameter #4244

Closed

Description

@Avasam

Describe the bug
An empty set or list inside a tuple used as a function parameter typed as Iterable[_T] (where _T is a TypeVar) will result in reportUnknownArgumentType. This does not happen inside of lists. And does not happen if the empty collection is a tuple (likely because zero-length tuples are their own type). It also only happens with TypeVar.

To Reproduce

from collections.abc import Iterable
from typing import Any
from typing_extensions import TypeVar

_T = TypeVar("_T")
def foo(_: Iterable[Any]) -> None: ...
def bar(_: Iterable[_T]) -> _T: ...

foo(["A", "B", ()])
foo(["A", "B", []])
foo(["A", "B", {}])
foo(("A", "B", ()))
foo(("A", "B", []))
foo(("A", "B", {}))

bar(["A", "B", ()])
bar(["A", "B", []])
bar(["A", "B", {}])
bar(("A", "B", ()))
bar(("A", "B", []))  # error reportUnknownArgumentType
bar(("A", "B", {}))  # error reportUnknownArgumentType

Expected behavior
No error (empty set infered as dict[Any, Any] and empty list as list[Any]), like all the other calls

Screenshots or Code
image

VS Code extension or command-line
Pylance (v2022.11.30) and pyright (1.1.281), strict settings

Activity

  1. erictraut commented on Nov 29, 2022

    @erictraut
    Collaborator
    b1 = bar(["A", "B", ()])
    b2 = bar(["A", "B", []]) # missing error (bug)
    b3 = bar(["A", "B", {}]) # missing error (bug)
    b4 = bar(("A", "B", ()))
    b5 = bar(("A", "B", []))  # error reportUnknownArgumentType
    b6 = bar(("A", "B", {}))  # error reportUnknownArgumentType

    I think pyright is correct to report an "unknown argument type" for the expressions assigned to b5 and b6, so I don't consider that a bug.

    However, I agree that there is an inconsistency here. The expressions b2 and b3 should also generate the same error because they also include an "unknown" type argument. This is a bug.

    Calls to foo will not generate the same error because bidirectional type inference causes [] to be inferred as Iterable[Any] rather than list[Unknown]. Similarly, {} is inferred as Iterable[Any] rather than dict[Unknown, Unknown].

    The expression () always evaluates to tuple[()] and is interpreted as Iterable[Any], so that will never trigger the "unknown" checks.

    This will be addressed in the next release.

  2. Avasam commented on Nov 29, 2022

    @Avasam
    Author

    Not the bug I thought but glad to have found an inconsistency nonetheless.

    How would you recommend dealing with b2, b3, b5, b6?

    Is a cast necessary here?
    Should the empty array be extracted to a constant? (That doesn't seem right. I have no guarantee the method won't mutate it).
    Kindof expected it to be acceptable since it's an anonymous empty array (meaning afaik the subtype does not matter). Kindof how typescript does never[].

  3. erictraut commented on Nov 29, 2022

    @erictraut
    Collaborator

    That depends on what type you expect bar(["A", "B", []]) to return. Do you want the return type _T to evaluate to str | list[str]? Or str | list[Any]? Or something else? Rather than using [], you could use list[str]() or list[Any]().

  4. Avasam commented on Nov 29, 2022

    @Avasam
    Author

    list[expected_subtype]() works great (python 3.9+) and it doesn't rely on casting! That syntax never crossed my mind, I'll have to remember that one. Thanks.
    (in my actual use case the generic wasn't used for a return type, but with another optional parameter that I don't use, so I can really put w/e as the subtype)

  5. erictraut commented on Nov 30, 2022

    @erictraut
    Collaborator

    This is addressed in pyright 1.1.282, which I just published. It will also be included in a future release of pylance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    addressed in next versionIssue is fixed and will appear in next published versionbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions