You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Mypy doesn't seem to like it when you check if an argument with typevar type is checked to see if it is None. It incorrectly reports error: Statement is unreachable [unreachable]
importtypingastT=t.TypeVar("T")
deffoo(arg: T) ->None:
ifargisNone:
returnNone# Do something with argreturnNonefoo(None) ## Allowedfoo(123)
Run mypy with --warn-unreachable flag
Expected Behavior
No errors
Actual Behavior
$ mypy .vscode/scratch.py
.vscode/scratch.py: note: In function "foo":
.vscode/scratch.py:9: error: Statement is unreachable [unreachable]
Found 1 error in 1 file (checked 1 source file)
The error seems to only happen when checking if arg is None, but not with other types. For example, I tired changing if arg is None: line to the following and these were the results.
if arg is True: -> no errors
if isinstance(arg, int): -> no errors
if isinstance(arg, type(None)): -> unreachable error
if arg == None: -> No error
Also, changing the type to T | None removes the error as well.
Your Environment
Mypy version used: mypy 1.13.0 (compiled: yes)
Mypy command-line flags:
Mypy configuration options from mypy.ini (and other config files): warn_unreachable = True
Python version used: 3.12
The text was updated successfully, but these errors were encountered:
Cnoor0171
changed the title
False positive " Statement is unreachable" when checking if typevar is None
False positive "Statement is unreachable" when checking if typevar is None
Nov 7, 2024
There's something wrong with this logic. When checking for narrowing in if clause by is None, we explicitly request to not consider bare TypeVar overlapping with None. The obvious decision is to stop asking for that, but... There's a test asserting this behaviour (introduced in #5476, and if clause is indeed unreachable - using a non-trivial body gives an [unreachable] diagnostic with --warn-unreachable):
# Note: this test (and the following one) are testing checker.conditional_type_map:
# if you set the 'prohibit_none_typevar_overlap' keyword argument to False when calling
# 'is_overlapping_types', the binder will incorrectly infer that 'out' has a type of
# Union[T, None] after the if statement.
from typing import TypeVar
T = TypeVar('T')
def foo(x: T) -> T:
out = None
out = x
if out is None:
pass
return out
[builtins fixtures/isinstance.pyi]
I don't think that this approach is sound: narrowing a lone TypeVar is a common problem, it shouldn't erroneously mark code as unreachable.
binder builds a Union of types after all non-terminating branches when exiting a frame, so here it produces None | T (None from the if clause since it's reachable, and T from a pass-through).
I tried to modify the binder to keep track of whether every type in frame was updated via an isinstance check or by assignment, and this seems to work as expected. I'm not sure, however, that this approach covers all corner cases. We already know that TypeVar + isinstance causes a lot of pain (#9424 and many others), so this probably won't make things marginally worse.
Bug Report
Mypy doesn't seem to like it when you check if an argument with typevar type is checked to see if it is
None
. It incorrectly reportserror: Statement is unreachable [unreachable]
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.12&flags=strict%2Cwarn-unreachable&gist=ceb8193f19f8b53a55dea70fad802469
Run mypy with
--warn-unreachable
flagExpected Behavior
No errors
Actual Behavior
The error seems to only happen when checking if arg is
None
, but not with other types. For example, I tired changingif arg is None:
line to the following and these were the results.if arg is True:
-> no errorsif isinstance(arg, int):
-> no errorsif isinstance(arg, type(None)):
-> unreachable errorif arg == None:
-> No errorAlso, changing the type to
T | None
removes the error as well.Your Environment
mypy.ini
(and other config files):warn_unreachable = True
The text was updated successfully, but these errors were encountered: