From 002e3091b54757161ef4339edc22a376db12649d Mon Sep 17 00:00:00 2001 From: Jannic Warken Date: Tue, 18 Jan 2022 18:10:41 +0100 Subject: [PATCH] Fix handling of NoReturn in Union return types (#11996) There are several discussions and comments describing the following problem (references can be found at the end of the PR summary): ```python def func() -> str | NoReturn: ... func().lower() ``` At the moment the code results in: `"NoReturn" of "Union[str, NoReturn]" has no attribute "lower"` Make `Union[int, NoReturn]` equivalent to `int` in a return type, because in case the function returns it must be `int`. --- mypy/checkexpr.py | 2 ++ test-data/unit/check-unions.test | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 66d8fa4b76960..9bf3ec3a4456c 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -378,6 +378,8 @@ def visit_call_expr_inner(self, e: CallExpr, allow_none_return: bool = False) -> if isinstance(e.callee, MemberExpr) and e.callee.name == 'format': self.check_str_format_call(e) ret_type = get_proper_type(ret_type) + if isinstance(ret_type, UnionType): + ret_type = make_simplified_union(ret_type.items) if isinstance(ret_type, UninhabitedType) and not ret_type.ambiguous: self.chk.binder.unreachable() # Warn on calls to functions that always return None. The check diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index cf1ff5650d49f..6966af289f28f 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -144,6 +144,11 @@ f(1) f(None) f('') # E: Argument 1 to "f" has incompatible type "str"; expected "Optional[int]" +[case testUnionWithNoReturn] +from typing import Union, NoReturn +def f() -> Union[int, NoReturn]: ... +reveal_type(f()) # N: Revealed type is "builtins.int" + [case testUnionSimplificationGenericFunction] from typing import TypeVar, Union, List T = TypeVar('T')