Skip to content

Commit 61b3b5d

Browse files
authored
Remove special case for Union type context (#20610)
Reverts some of #2715. The test cases introduced in that PR still pass Fixes #20608 Test case minimised by A5rocks Codex assisted in diagnosing the issue
1 parent fb0845d commit 61b3b5d

File tree

3 files changed

+42
-30
lines changed

3 files changed

+42
-30
lines changed

mypy/checkexpr.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5941,7 +5941,12 @@ def visit_conditional_expr(self, e: ConditionalExpr, allow_none_return: bool = F
59415941
ctx_else_type = self.analyze_cond_branch(
59425942
else_map, e.else_expr, context=ctx, allow_none_return=allow_none_return
59435943
)
5944-
ctx = make_simplified_union([ctx_if_type, ctx_else_type])
5944+
if has_ambiguous_uninhabited_component(ctx_if_type):
5945+
ctx = ctx_else_type
5946+
elif has_ambiguous_uninhabited_component(ctx_else_type):
5947+
ctx = ctx_if_type
5948+
else:
5949+
ctx = make_simplified_union([ctx_if_type, ctx_else_type])
59455950

59465951
if_type = self.analyze_cond_branch(
59475952
if_map, e.if_expr, context=ctx, allow_none_return=allow_none_return
@@ -6636,6 +6641,20 @@ def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
66366641
return True
66376642

66386643

6644+
def has_ambiguous_uninhabited_component(t: Type) -> bool:
6645+
return t.accept(HasAmbiguousUninhabitedComponentsQuery())
6646+
6647+
6648+
class HasAmbiguousUninhabitedComponentsQuery(types.BoolTypeQuery):
6649+
"""Visitor for querying whether a type has an ambiguous UninhabitedType component."""
6650+
6651+
def __init__(self) -> None:
6652+
super().__init__(types.ANY_STRATEGY)
6653+
6654+
def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
6655+
return t.ambiguous
6656+
6657+
66396658
def arg_approximate_similarity(actual: Type, formal: Type) -> bool:
66406659
"""Return if caller argument (actual) is roughly compatible with signature arg (formal).
66416660

mypy/constraints.py

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
ArgKind,
2121
TypeInfo,
2222
)
23-
from mypy.type_visitor import ALL_STRATEGY, BoolTypeQuery
2423
from mypy.types import (
2524
TUPLE_LIKE_INSTANCE_NAMES,
2625
AnyType,
@@ -397,13 +396,14 @@ def _infer_constraints(
397396
# be a supertype of the potential subtype, some item of the Union
398397
# must be a supertype of it.
399398
if direction == SUBTYPE_OF and isinstance(actual, UnionType):
400-
# If some of items is not a complete type, disregard that.
401-
items = simplify_away_incomplete_types(actual.items)
402399
# We infer constraints eagerly -- try to find constraints for a type
403400
# variable if possible. This seems to help with some real-world
404401
# use cases.
405402
return any_constraints(
406-
[infer_constraints_if_possible(template, a_item, direction) for a_item in items],
403+
[
404+
infer_constraints_if_possible(template, a_item, direction)
405+
for a_item in actual.items
406+
],
407407
eager=True,
408408
)
409409
if direction == SUPERTYPE_OF and isinstance(template, UnionType):
@@ -652,31 +652,6 @@ def _is_similar_constraints(x: list[Constraint], y: list[Constraint]) -> bool:
652652
return True
653653

654654

655-
def simplify_away_incomplete_types(types: Iterable[Type]) -> list[Type]:
656-
complete = [typ for typ in types if is_complete_type(typ)]
657-
if complete:
658-
return complete
659-
else:
660-
return list(types)
661-
662-
663-
def is_complete_type(typ: Type) -> bool:
664-
"""Is a type complete?
665-
666-
A complete doesn't have uninhabited type components or (when not in strict
667-
optional mode) None components.
668-
"""
669-
return typ.accept(CompleteTypeVisitor())
670-
671-
672-
class CompleteTypeVisitor(BoolTypeQuery):
673-
def __init__(self) -> None:
674-
super().__init__(ALL_STRATEGY)
675-
676-
def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
677-
return False
678-
679-
680655
class ConstraintBuilderVisitor(TypeVisitor[list[Constraint]]):
681656
"""Visitor class for inferring type constraints."""
682657

test-data/unit/check-inference-context.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,24 @@ reveal_type(c.f([])) # N: Revealed type is "builtins.list[builtins.int]"
965965
reveal_type(c.f(None)) # N: Revealed type is "builtins.list[builtins.int] | None"
966966
[builtins fixtures/list.pyi]
967967

968+
[case testUnionWithTupleNeverBranch]
969+
# https://github.com/python/mypy/issues/20608
970+
from __future__ import annotations
971+
from typing import Callable, Never, Generic, TypeVar
972+
973+
T = TypeVar('T')
974+
class ValueType(Generic[T]): pass
975+
class Bundle(Generic[T]): pass
976+
977+
F = TypeVar('F')
978+
979+
def fail_value_type_inference(self_bundle: ValueType[F]) -> tuple[Never, Bundle[ValueType[F]]] | tuple[int, Bundle[ValueType[int]]]:
980+
raise
981+
982+
x = fail_value_type_inference
983+
x = fail_value_type_inference
984+
[builtins fixtures/tuple.pyi]
985+
968986
[case testGenericMethodCalledInGenericContext]
969987
from typing import TypeVar, Generic
970988

0 commit comments

Comments
 (0)