Skip to content

Commit 30d0c99

Browse files
authored
Honor NoReturn as __setitem__ return type to mark unreachable code. (#12572)
In general code that follows any calls to methods annotated with `NoReturn` is considered unreachable. However calls like `variable['foo'] = 'foo'` are not treated this way. Moreover, `variable.__setitem__('foo', 'foo')` is interpreted properly, so this behavior is inconsistent. After this change both variants result in marking remaining part of the branch as unreachable.
1 parent 800e8ff commit 30d0c99

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

mypy/checker.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4047,14 +4047,17 @@ def check_indexed_assignment(
40474047
)
40484048

40494049
lvalue.method_type = method_type
4050-
self.expr_checker.check_method_call(
4050+
res_type, _ = self.expr_checker.check_method_call(
40514051
"__setitem__",
40524052
basetype,
40534053
method_type,
40544054
[lvalue.index, rvalue],
40554055
[nodes.ARG_POS, nodes.ARG_POS],
40564056
context,
40574057
)
4058+
res_type = get_proper_type(res_type)
4059+
if isinstance(res_type, UninhabitedType) and not res_type.ambiguous:
4060+
self.binder.unreachable()
40584061

40594062
def try_infer_partial_type_from_indexed_assignment(
40604063
self, lvalue: IndexExpr, rvalue: Expression

test-data/unit/check-unreachable-code.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,3 +1423,27 @@ def f(value: None) -> None:
14231423

14241424
x = force_forward_ref()
14251425
[builtins fixtures/exception.pyi]
1426+
1427+
[case testSetitemNoReturn]
1428+
# flags: --warn-unreachable
1429+
from typing import NoReturn
1430+
class Foo:
1431+
def __setitem__(self, key: str, value: str) -> NoReturn:
1432+
raise Exception
1433+
Foo()['a'] = 'a'
1434+
x = 0 # E: Statement is unreachable
1435+
[builtins fixtures/exception.pyi]
1436+
1437+
[case TestNoImplicNoReturnFromError]
1438+
# flags: --warn-unreachable
1439+
from typing import TypeVar
1440+
1441+
T = TypeVar("T")
1442+
class Foo:
1443+
def __setitem__(self, key: str, value: str) -> T: # E: A function returning TypeVar should receive at least one argument containing the same TypeVar
1444+
raise Exception
1445+
1446+
def f() -> None:
1447+
Foo()['a'] = 'a'
1448+
x = 0 # This should not be reported as unreachable
1449+
[builtins fixtures/exception.pyi]

0 commit comments

Comments
 (0)