Open mishamsk opened 1 year ago
Smaller equivalent:
class A:
pass
class B(A):
pass
l1: list[A]
l2: list[B]
x: list[A] = l1 + l2
IIUC, the culprit is the two overloads:
class list(Generic[T], ...):
@overload
def __add__(self, __value: list[_T]) -> list[_T]: ...
@overload
def __add__(self, __value: list[_S]) -> list[_S | _T]: ...
The expression's expected type list[A]
helps select the 1st overload and disqualify the 2nd overload. Maybe if mypy reduced A | B
to A
then it wouldn't disqualify. (Is doing that sound?)
@ikonst Thanks for shorter sample. I'd guess that reduction is not generally possible since list is invariant, and the sum of the operation should be treated as a union. Which btw reminds that in my example passing l3
to foo
should have produced an error but somehow it didn't...
Surprised to learn that mypy uses the target var type to select appropriate overload. Didn't know that it works this way. Why so?
I'd guess that reduction is not generally possible since list is invariant
It seems that if you type-annotate, then mypy would agree with you:
l1: list[A]
l2: list[B]
l3 = l1 + l2
reveal_type(l3) # builtins.list[Union[__main__.B, __main__.A]]
x: list[A] = l3
However, this won't work:
x: list[B] = l3
nor this:
x: list[A] = l2
so invariance is maintained, but list[A | B]
to list[A]
is apparently safe.
Bug Report
Mypy reports
Unsupported operand types for +
when concatenating two lists, when the second operand is a subtype of the first.This was previously mentioned in this comment in #5492
Below is a simple concise example
To Reproduce
gist link
Expected Behavior No error on the last line
Actual Behavior Reports spurious error
Your Environment
mypy.ini
(and other config files): from pyproject.tomlplugins = ["pydantic.mypy"]