diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index e293a2d72ef3..f85b7006614e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -5941,7 +5941,12 @@ def visit_conditional_expr(self, e: ConditionalExpr, allow_none_return: bool = F ctx_else_type = self.analyze_cond_branch( else_map, e.else_expr, context=ctx, allow_none_return=allow_none_return ) - ctx = make_simplified_union([ctx_if_type, ctx_else_type]) + if has_ambiguous_uninhabited_component(ctx_if_type): + ctx = ctx_else_type + elif has_ambiguous_uninhabited_component(ctx_else_type): + ctx = ctx_if_type + else: + ctx = make_simplified_union([ctx_if_type, ctx_else_type]) if_type = self.analyze_cond_branch( 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: return True +def has_ambiguous_uninhabited_component(t: Type) -> bool: + return t.accept(HasAmbiguousUninhabitedComponentsQuery()) + + +class HasAmbiguousUninhabitedComponentsQuery(types.BoolTypeQuery): + """Visitor for querying whether a type has an ambiguous UninhabitedType component.""" + + def __init__(self) -> None: + super().__init__(types.ANY_STRATEGY) + + def visit_uninhabited_type(self, t: UninhabitedType) -> bool: + return t.ambiguous + + def arg_approximate_similarity(actual: Type, formal: Type) -> bool: """Return if caller argument (actual) is roughly compatible with signature arg (formal). diff --git a/mypy/constraints.py b/mypy/constraints.py index cfb627e9f2b5..de3b8cd56560 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -20,7 +20,6 @@ ArgKind, TypeInfo, ) -from mypy.type_visitor import ALL_STRATEGY, BoolTypeQuery from mypy.types import ( TUPLE_LIKE_INSTANCE_NAMES, AnyType, @@ -397,13 +396,14 @@ def _infer_constraints( # be a supertype of the potential subtype, some item of the Union # must be a supertype of it. if direction == SUBTYPE_OF and isinstance(actual, UnionType): - # If some of items is not a complete type, disregard that. - items = simplify_away_incomplete_types(actual.items) # We infer constraints eagerly -- try to find constraints for a type # variable if possible. This seems to help with some real-world # use cases. return any_constraints( - [infer_constraints_if_possible(template, a_item, direction) for a_item in items], + [ + infer_constraints_if_possible(template, a_item, direction) + for a_item in actual.items + ], eager=True, ) if direction == SUPERTYPE_OF and isinstance(template, UnionType): @@ -652,31 +652,6 @@ def _is_similar_constraints(x: list[Constraint], y: list[Constraint]) -> bool: return True -def simplify_away_incomplete_types(types: Iterable[Type]) -> list[Type]: - complete = [typ for typ in types if is_complete_type(typ)] - if complete: - return complete - else: - return list(types) - - -def is_complete_type(typ: Type) -> bool: - """Is a type complete? - - A complete doesn't have uninhabited type components or (when not in strict - optional mode) None components. - """ - return typ.accept(CompleteTypeVisitor()) - - -class CompleteTypeVisitor(BoolTypeQuery): - def __init__(self) -> None: - super().__init__(ALL_STRATEGY) - - def visit_uninhabited_type(self, t: UninhabitedType) -> bool: - return False - - class ConstraintBuilderVisitor(TypeVisitor[list[Constraint]]): """Visitor class for inferring type constraints.""" diff --git a/test-data/unit/check-inference-context.test b/test-data/unit/check-inference-context.test index b9e7e6996ade..a8104a7b3e24 100644 --- a/test-data/unit/check-inference-context.test +++ b/test-data/unit/check-inference-context.test @@ -965,6 +965,24 @@ reveal_type(c.f([])) # N: Revealed type is "builtins.list[builtins.int]" reveal_type(c.f(None)) # N: Revealed type is "builtins.list[builtins.int] | None" [builtins fixtures/list.pyi] +[case testUnionWithTupleNeverBranch] +# https://github.com/python/mypy/issues/20608 +from __future__ import annotations +from typing import Callable, Never, Generic, TypeVar + +T = TypeVar('T') +class ValueType(Generic[T]): pass +class Bundle(Generic[T]): pass + +F = TypeVar('F') + +def fail_value_type_inference(self_bundle: ValueType[F]) -> tuple[Never, Bundle[ValueType[F]]] | tuple[int, Bundle[ValueType[int]]]: + raise + +x = fail_value_type_inference +x = fail_value_type_inference +[builtins fixtures/tuple.pyi] + [case testGenericMethodCalledInGenericContext] from typing import TypeVar, Generic