Skip to content

Use type context to infer type of empty collections in and/or expressions #6572

Closed

Description

@zunger-humu

Underlying issue: for any generic type, mypy considers GenType[] and GenType[X] to be incompatible classes. These should instead be considered to be of type GenType[X]. (Observed with mypy 0.670 / Python 3.6, no flags passed to mypy)

To illustrate why, consider two common Python idioms where this happens. One is in a function declaration, where None is passed as a default value rather than a class-scoped mutable variable:

def fn(arg: Set[str] = None) -> None:
    arg = arg or set()
    ...

This is reported as an error, "Incompatible types in assignment (expression has type "Union[Set[str], Set[]]", variable has type "Optional[Set[str]]")"

Likewise, if an abstract superclass declares a method which yields an iterator,

def abstractMethod(self) -> Iterator[...]:
    pass

Because the abstract declaration passes, it is actually returning an optional iterator (which mypy correctly understands). Callers of the abstract method then cope with this easily:

for value in (thing.abstractMethod() or []):
   ...

which yields the same error as above, or

yield from (thing.abstractMethod() or [])

which fails with "error: "yield from" can't be applied to "Union[Iterator[type], List[]]".

The expected behavior in all cases is no error: empty iterables should be considered to be valid instances of iterables of any type, without further annotation.

Activity

  1. ilevkivskyi commented on Apr 2, 2019

    @ilevkivskyi
    Member

    List[<nothing>] is not a subtype of List[X] because it is invariant, for example

    x = []  # mypy would complain here, but assume we ignore it, so 'x' is 'List[<nothing>]'
    
    y: List[str] = x  # this is dangerous
    y.append('boom')
    
    z: List[int] = x
    z[0] + 42  # TypeError here

    Instead mypy should use the outer type context to infer the correct type of an empty collection. I will edit the title accordingly.

  2. changed the title [-]mypy doesn't recognize GenType[<nothing>] as a subclass of GenType[X][/-] [+]Use type context to infer type of empty collections in and/or expressions[/+] on Apr 2, 2019
  3. ilevkivskyi commented on Apr 2, 2019

    @ilevkivskyi
    Member

    Also this is low priority since it may be tricky to implement one can instead simply write:

    def func(lst: Optional[List[int]] = None) -> None:
        if lst is None:
            lst = []

    (which is also more readable IMO)

  4. JukkaL commented on Apr 3, 2019

    @JukkaL
    Collaborator

    It might be reasonable to make List[<nothing>] a subtype of List[X] though (#6613).

  5. AlexWaygood commented on Mar 29, 2022

    @AlexWaygood
    Member

    Cannot reproduce any of these false-positive errors on mypy 0.941; mypy seems to cope with these fine now.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions