diff --git a/stdlib/@tests/test_cases/builtins/check_list.py b/stdlib/@tests/test_cases/builtins/check_list.py index 4113f5c66182..07e443c35c12 100644 --- a/stdlib/@tests/test_cases/builtins/check_list.py +++ b/stdlib/@tests/test_cases/builtins/check_list.py @@ -19,3 +19,24 @@ def asd(self) -> int: assert_type(combined, List[Union[Foo, Bar]]) for item in combined: assert_type(item.asd(), int) + +# ignoring this so we can test mypy and pyright separately +# pyright: reportUnnecessaryTypeIgnoreComment=false + +# defining separately so that the value is not inferred at the usage +l_int = [1, 2] +l_str = ["a", "b"] +combined1 = l_int + l_str +assert_type(combined1, List[Union[int, str]]) + +combined2: list[Union[int, str]] +# mypy doesn't support this case +combined2 = l_int + l_str # type: ignore[operator] +assert_type(combined2, List[Union[int, str]]) + +combined2 = l_int + combined1 +assert_type(combined2, List[Union[int, str]]) + +# mypy doesn't support this case +combined3: List[object] = l_int + l_str # type: ignore[operator] +assert_type(combined3, List[object]) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 304e94eafa61..b288f45fd9e5 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -90,6 +90,7 @@ _T2 = TypeVar("_T2") _T3 = TypeVar("_T3") _T4 = TypeVar("_T4") _T5 = TypeVar("_T5") +_Expected = TypeVar("_Expected") _SupportsNextT_co = TypeVar("_SupportsNextT_co", bound=SupportsNext[Any], covariant=True) _SupportsAnextT_co = TypeVar("_SupportsAnextT_co", bound=SupportsAnext[Any], covariant=True) _AwaitableT = TypeVar("_AwaitableT", bound=Awaitable[Any]) @@ -1137,9 +1138,10 @@ class list(MutableSequence[_T]): def __delitem__(self, key: SupportsIndex | slice, /) -> None: ... # Overloading looks unnecessary, but is needed to work around complex mypy problems @overload - def __add__(self, value: list[_T], /) -> list[_T]: ... + # # `__add__` returns a new object, so we capture the expected result type with a type variable + def __add__(self, value: list[_T], /) -> list[_Expected | _T]: ... @overload - def __add__(self, value: list[_S], /) -> list[_S | _T]: ... + def __add__(self, value: list[_S], /) -> list[_Expected | _T | _S]: ... def __iadd__(self, value: Iterable[_T], /) -> Self: ... # type: ignore[misc] def __mul__(self, value: SupportsIndex, /) -> list[_T]: ... def __rmul__(self, value: SupportsIndex, /) -> list[_T]: ...