From b5ad828e7e451b67971ea491096585efb6c4f64a Mon Sep 17 00:00:00 2001 From: KotlinIsland <65446343+kotlinisland@users.noreply.github.com> Date: Sun, 21 Sep 2025 20:29:15 +1000 Subject: [PATCH 1/2] fix `list.__add__` to use the expected type --- .../@tests/test_cases/builtins/check_list.py | 21 +++++++++++++++++++ stdlib/builtins.pyi | 5 +++-- 2 files changed, 24 insertions(+), 2 deletions(-) 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..8afc8f432e7e 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1137,9 +1137,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[_T1 | _T]: ... @overload - def __add__(self, value: list[_S], /) -> list[_S | _T]: ... + def __add__(self, value: list[_S], /) -> list[_T1 | _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]: ... From d8db8975102cf35dfcc4e84320f0f6045a6ecddf Mon Sep 17 00:00:00 2001 From: KotlinIsland <65446343+kotlinisland@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:25:25 +1000 Subject: [PATCH 2/2] better name for the typevar --- stdlib/builtins.pyi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 8afc8f432e7e..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]) @@ -1138,9 +1139,9 @@ class list(MutableSequence[_T]): # Overloading looks unnecessary, but is needed to work around complex mypy problems @overload # # `__add__` returns a new object, so we capture the expected result type with a type variable - def __add__(self, value: list[_T], /) -> list[_T1 | _T]: ... + def __add__(self, value: list[_T], /) -> list[_Expected | _T]: ... @overload - def __add__(self, value: list[_S], /) -> list[_T1 | _T | _S]: ... + 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]: ...