diff --git a/mypy/checker.py b/mypy/checker.py index 440d0175bc62b..461b45f8df45f 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5298,16 +5298,22 @@ 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 + merged_type = make_simplified_union(typ.items) + if isinstance(merged_type, UnionType): + return merged_type.relevant_items() + return [merged_type] + elif is_named_instance(typ, "builtins.tuple"): + # variadic tuple + merged_type = make_simplified_union((typ.args[0],)) + if isinstance(merged_type, UnionType): + return merged_type.relevant_items() + return [merged_type] elif isinstance(typ, UnionType): return [ union_typ for item in typ.relevant_items() for union_typ in self.get_types_from_except_handler(item, n) ] - elif is_named_instance(typ, "builtins.tuple"): - # variadic tuple - return [typ.args[0]] else: return [typ] diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 0e3805855f41a..a665551fc95c0 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -4,7 +4,7 @@ import sys import warnings from collections.abc import Sequence -from typing import Any, Callable, Final, Literal, TypeVar, Union, cast, overload +from typing import Any, Callable, Final, Literal, TypeVar, cast, overload from mypy import defaults, errorcodes as codes, message_registry from mypy.errors import Errors diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 87d015f3de0f8..477d582c7b7e0 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -801,6 +801,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