Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,15 +666,15 @@ def _remove_redundant_union_items(items: list[Type], keep_erased: bool) -> list[
else:
# If not, check if we've seen a supertype of this type
for j, tj in enumerate(new_items):
tj = get_proper_type(tj)
proper_tj = get_proper_type(tj)
# If tj is an Instance with a last_known_value, do not remove proper_ti
# (unless it's an instance with the same last_known_value)
if (
isinstance(tj, Instance)
and tj.last_known_value is not None
isinstance(proper_tj, Instance)
and proper_tj.last_known_value is not None
and not (
isinstance(proper_ti, Instance)
and tj.last_known_value == proper_ti.last_known_value
and proper_tj.last_known_value == proper_ti.last_known_value
)
):
continue
Expand Down
6 changes: 5 additions & 1 deletion mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4159,7 +4159,11 @@ def flatten_nested_unions(
tp = t
if isinstance(tp, ProperType) and isinstance(tp, UnionType):
flat_items.extend(
flatten_nested_unions(tp.items, handle_type_alias_type=handle_type_alias_type)
flatten_nested_unions(
tp.items,
handle_type_alias_type=handle_type_alias_type,
handle_recursive=handle_recursive,
)
)
else:
# Must preserve original aliases when possible.
Expand Down
12 changes: 12 additions & 0 deletions test-data/unit/check-python312.test
Original file line number Diff line number Diff line change
Expand Up @@ -2192,3 +2192,15 @@ y3: A3[int] # E: Type argument "int" of "A3" must be a subtype of "B3"
z3: A3[None]
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testPEP695TypeAliasRecursiveTupleUnionNoCrash]
from collections.abc import Hashable

type HashableArg = int | tuple[Hashable | HashableArg]
x: HashableArg
reveal_type(x) # N: Revealed type is "Union[builtins.int, tuple[Union[typing.Hashable, ...]]]"
if isinstance(x, tuple):
y, = x
reveal_type(y) # N: Revealed type is "Union[typing.Hashable, Union[builtins.int, tuple[Union[typing.Hashable, ...]]]]"
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]
1 change: 1 addition & 0 deletions test-data/unit/fixtures/tuple.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class type:
def __init__(self, *a: object) -> None: pass
def __call__(self, *a: object) -> object: pass
class tuple(Sequence[_Tco], Generic[_Tco]):
def __hash__(self) -> int: ...
def __new__(cls: Type[_T], iterable: Iterable[_Tco] = ...) -> _T: ...
def __iter__(self) -> Iterator[_Tco]: pass
def __contains__(self, item: object) -> bool: pass
Expand Down