diff --git a/mypy/checker.py b/mypy/checker.py index db65660bbfbd..abbba4813618 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4858,8 +4858,13 @@ def get_types_from_except_handler(self, typ: Type, n: Expression) -> list[Type]: """Helper for check_except_handler_test to retrieve handler types.""" typ = get_proper_type(typ) if isinstance(typ, TupleType): - return typ.items + # avoid recursion here, since we can accidentally unpack tuples inside + merged_type = make_simplified_union(typ.items) + if isinstance(merged_type, UnionType): + return merged_type.relevant_items() + return [merged_type] elif isinstance(typ, UnionType): + # recursion is fine here for top-level Union return [ union_typ for item in typ.relevant_items() @@ -4867,7 +4872,11 @@ def get_types_from_except_handler(self, typ: Type, n: Expression) -> list[Type]: ] elif is_named_instance(typ, "builtins.tuple"): # variadic tuple - return [typ.args[0]] + # avoid recursion here too + merged_type = make_simplified_union((typ.args[0],)) + if isinstance(merged_type, UnionType): + return merged_type.relevant_items() + return [merged_type] else: return [typ] diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index d1464423e90f..b6f315e73a29 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -794,6 +794,57 @@ def error_in_variadic(exc: Tuple[int, ...]) -> None: [builtins fixtures/tuple.pyi] +[case testExceptWithMultipleTypes5] +from typing import Tuple, Type, Union + +class E1(BaseException): pass +class E2(BaseException): pass +class E3(BaseException): pass + +def union_in_variadic(exc: Tuple[Union[Type[E1], Type[E2]], ...]) -> None: + try: + pass + except exc as e: + reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2]" + +def nested_union_in_variadic(exc: Tuple[Union[Type[E1], Union[Type[E2], Type[E3]]], ...]) -> None: + try: + pass + except exc as e: + reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2, __main__.E3]" + +def union_in_tuple(exc: Tuple[Union[Type[E1], Type[E2]], Type[E3]]) -> None: + try: + pass + except exc as e: + reveal_type(e) # N: Revealed type is "Union[__main__.E1, __main__.E2, __main__.E3]" + +def error_in_variadic_union(exc: Tuple[Union[Type[E1], int], ...]) -> None: + try: + pass + except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes) + pass + +def error_in_variadic_nested_union(exc: Tuple[Union[Type[E1], Union[Type[E2], int]], ...]) -> None: + try: + pass + except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes) + pass + +def error_in_tuple_inside_variadic_nested_union(exc: Tuple[Union[Type[E1], Union[Type[E2], Tuple[Type[E3]]]], ...]) -> None: + try: + pass + except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes) + pass + +def error_in_tuple_union(exc: Tuple[Union[Type[E1], Type[E2]], Union[Type[E3], int]]) -> None: + try: + pass + except exc as e: # E: Exception type must be derived from BaseException (or be a tuple of exception classes) + pass + +[builtins fixtures/tuple.pyi] + [case testExceptWithAnyTypes] from typing import Any