diff --git a/misc/typeshed_patches/0001-Revert-dict.__or__-typeshed-change.patch b/misc/typeshed_patches/0001-Revert-dict.__or__-typeshed-change.patch new file mode 100644 index 0000000000000..890b2782abedd --- /dev/null +++ b/misc/typeshed_patches/0001-Revert-dict.__or__-typeshed-change.patch @@ -0,0 +1,30 @@ +From d88a4b774fc59ecd0f2d0fdda8e0e61092adafd3 Mon Sep 17 00:00:00 2001 +From: Ivan Levkivskyi +Date: Wed, 8 Apr 2026 00:01:44 +0100 +Subject: [PATCH] Revert dict.__or__ typeshed change + +--- + mypy/typeshed/stdlib/builtins.pyi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/mypy/typeshed/stdlib/builtins.pyi b/mypy/typeshed/stdlib/builtins.pyi +index 674142d70..25b21ba97 100644 +--- a/mypy/typeshed/stdlib/builtins.pyi ++++ b/mypy/typeshed/stdlib/builtins.pyi +@@ -1142,7 +1142,13 @@ class dict(MutableMapping[_KT, _VT]): + def __reversed__(self) -> Iterator[_KT]: ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... ++ @overload ++ def __or__(self, value: dict[_KT, _VT], /) -> dict[_KT, _VT]: ... ++ @overload + def __or__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... ++ @overload ++ def __ror__(self, value: dict[_KT, _VT], /) -> dict[_KT, _VT]: ... ++ @overload + def __ror__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... + # dict.__ior__ should be kept roughly in line with MutableMapping.update() + @overload # type: ignore[misc] +-- +2.25.1 + diff --git a/mypy/typeshed/stdlib/builtins.pyi b/mypy/typeshed/stdlib/builtins.pyi index 674142d709a29..25b21ba971540 100644 --- a/mypy/typeshed/stdlib/builtins.pyi +++ b/mypy/typeshed/stdlib/builtins.pyi @@ -1142,7 +1142,13 @@ class dict(MutableMapping[_KT, _VT]): def __reversed__(self) -> Iterator[_KT]: ... __hash__: ClassVar[None] # type: ignore[assignment] def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + @overload + def __or__(self, value: dict[_KT, _VT], /) -> dict[_KT, _VT]: ... + @overload def __or__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... + @overload + def __ror__(self, value: dict[_KT, _VT], /) -> dict[_KT, _VT]: ... + @overload def __ror__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... # dict.__ior__ should be kept roughly in line with MutableMapping.update() @overload # type: ignore[misc] diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 618c49572afae..4303477549cf3 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -2229,3 +2229,17 @@ def f(x: int, y: list[str]): x in y [out] _testStrictEqualityWithList.py:3: error: Non-overlapping container check (element type: "int", container item type: "str") + +[case testDictOrUnionEdgeCases] +from typing import Mapping, Sequence, Union + +d: dict[str, list[str]] +m: Mapping[str, Sequence[str]] = d | d + +A = dict[str, Union[A, int]] +d1: A +d2: A +d3: A = d1 | d2 +reveal_type(d1 | d2) +[out] +_testDictOrUnionEdgeCases.py:10: note: Revealed type is "dict[str, dict[str, ... | int] | int]"