python / python/mypy

Type argument lost when union of collections is passed to generic function

Open
#13,960 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-join-v-union
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Passing a union of collections to a generic function that should preserve the type argument erases it instead. (Or should I say it consolidates it to object?)

To Reproduce

from typing import Union

x: list[int] | list[str]
y: Union[set[int], set[str]]

reveal_type(set(x))
reveal_type(list(y))

Expected Behavior

Revealed type is "Union[builtins.set[builtins.int], builtins.set[builtins.str]]"
Revealed type is "Union[builtins.list[builtins.int], builtins.list[builtins.str]]"

I hope this is reasonable. I mean, the type argument is either one or the other and nothing else.

Actual Behavior

Revealed type is "builtins.set[builtins.object]"
Revealed type is "builtins.list[builtins.object]"

Environment

Python 3.10.8 on Linux; mypy --strict version 0.982

More examples

Clearly mypy is capable of preserving the type argument, when there is no union of iterables passed to set:

reveal_type(set([1, 2]))  # Revealed type is "builtins.set[builtins.int]"

It also does not seem to have anything to do with the wrong typeshed stubs, as the same problem occurs with custom generic functions:

from collections.abc import Iterable
from typing import TypeVar

T = TypeVar("T")

def f(i: Iterable[T]) -> T:
    ...

z: list[int] | list[str]

reveal_type(f(z))  # Revealed type is "builtins.object"

The following gives me an error:

def my_set(a: list[int] | list[str]) -> set[int] | set[str]:
    return set(a)  # Incompatible return value type (got "Set[object]", expected "Union[Set[int], Set[str]]")

And yes, I know this would be better solved with a generic type variable instead of the unions. It is just to provide an additional demonstration of what I consider a bug.


My description of the problem may be poorly worded. Please feel free to correct me, so that I can describe it more precisely.

This issue seems vaguely related: #6463

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the examples with mypy --strict, including the set/list calls and the custom generic function using Iterable and TypeVar. Trace the generic inference and union handling entry points; done means reveal_type preserves the union of int and str collections instead of widening the type argument to object.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.