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
{{ message }}
Repository navigation
Detect exhaustiveness in partially-defined variable checks #13926
@JukkaL (or anyone else), I would appreciate some help here because I'm a bit stuck.
I have discovered has two places where it finds unreachable code:
Semantic Analyzer
Conditional Type Binder
Semantic Analyzer marks blocks with is_unreachable = True, so it's pretty easy to use (implemented in #14161). However, the exhaustiveness of type checks logic is located Conditional Type Binder, which is where it handles cases as described in the ticket.
What I would like to do is to store information about unreachable blocks somewhere. My original approach, was to set block.is_unreachable = True in checker.py. This works with cases like:
deff1(x: int|str) ->int:
ifisinstance(x, int):
y=1elifisinstance(x, str):
y=2else:
passreturny# No error any more.
However, this only works if there is a body but not if the body is missing (so the original examples here don't work). We can add special fields to the IfStmt and MatchStmt classes that indicate reachability of different branches but that sounds a bit iffy to me. Not that I have better ideas :)
Can you think of a good way of storing branch reachability information somewhere?
@ilinum I think reusing block.is_unreachable sounds like the best approach. If there is no block, how about just replacing the None value for block with an empty block (Block([]), but only if the flag needs to be set so that this won't increase memory use significantly?
For example, if else_body is None and it's unreachable, we'd assign a Block([]) to else_body during type checking and set is_unreachable = True for this block. If it's reachable (the vast majority of cases), we'd keep the None value, i.e. a None value would implicitly mean "empty but reachable".
Was the "partially-defined" error code ever implemented? I don't see any reference to it in the mypy docs or sources. I'm not able to repro the error with the code sample, but perhaps I'm not configuring mypy correctly. Or maybe this issue has been fixed.
The if/elif example is fixed in #20149 (269e7ee), but the match example is still false-positive as of the latest commit on master:
$ uvx --from "git+https://github.com/python/mypy.git@6fcb8f08ca08bd9c1884c44783d7d93a6584dfe0" mypy -c 'def f1(x: int | str) -> int: if isinstance(x, int): y = 1 elif isinstance(x, str): y = 2 return ydef f(x: int | str) -> int: match x: case int(): y = 1 case str(): y = 2 return y' --enable-error-code=possibly-undefined
<string>:15: error: Name "y" may be undefined [possibly-undefined]
Found 1 error in 1 file (checked 1 source file)
Same with an enum:
$ uvx --from "git+https://github.com/python/mypy.git@6fcb8f08ca08bd9c1884c44783d7d93a6584dfe0" mypy -c 'import enumclass Color(enum.Enum): RED = "red" BLUE = "blue"def with_if(c: Color) -> str: if c is Color.RED: passes = "red" elif c is Color.BLUE: passes = "blue" else: from typing import assert_never assert_never(c) return passesdef with_match(c: Color) -> str: match c: case Color.RED: fails = "red" case Color.BLUE: fails = "blue" return fails' --enable-error-code=exhaustive-match --enable-error-code=possibly-undefined
<string>:26: error: Name "fails" may be undefined [possibly-undefined]
Found 1 error in 1 file (checked 1 source file)
Activity
ilinum commentedon Nov 22, 2022
@JukkaL (or anyone else), I would appreciate some help here because I'm a bit stuck.
I have discovered has two places where it finds unreachable code:
Semantic Analyzer marks blocks with
is_unreachable = True, so it's pretty easy to use (implemented in #14161). However, the exhaustiveness of type checks logic is located Conditional Type Binder, which is where it handles cases as described in the ticket.Logic using conditional type binder:
mypy/mypy/checker.py
Line 459 in 3c5f368
What I would like to do is to store information about unreachable blocks somewhere. My original approach, was to set
block.is_unreachable = Truein checker.py. This works with cases like:However, this only works if there is a body but not if the body is missing (so the original examples here don't work). We can add special fields to the
IfStmtandMatchStmtclasses that indicate reachability of different branches but that sounds a bit iffy to me. Not that I have better ideas :)Can you think of a good way of storing branch reachability information somewhere?
JukkaL commentedon Nov 22, 2022
Nothing comes to mind immediately, but I'll think about this more tomorrow.
[partially defined] handle unreachable blocks (#14161)
ilinum commentedon Feb 24, 2023
@JukkaL would appreciate some pointers here if you have a bit of time! :)
JukkaL commentedon Feb 24, 2023
Sorry, lost track of this. I'll think about this next week (keep pinging me if you don't hear anything by mid next week).
JukkaL commentedon Feb 27, 2023
@ilinum I think reusing
block.is_unreachablesounds like the best approach. If there is no block, how about just replacing theNonevalue for block with an empty block (Block([]), but only if the flag needs to be set so that this won't increase memory use significantly?For example, if
else_bodyis None and it's unreachable, we'd assign aBlock([])toelse_bodyduring type checking and setis_unreachable = Truefor this block. If it's reachable (the vast majority of cases), we'd keep theNonevalue, i.e. aNonevalue would implicitly mean "empty but reachable".erictraut commentedon Aug 13, 2023
Was the "partially-defined" error code ever implemented? I don't see any reference to it in the mypy docs or sources. I'm not able to repro the error with the code sample, but perhaps I'm not configuring mypy correctly. Or maybe this issue has been fixed.
AlexWaygood commentedon Aug 25, 2023
yes, but the name was changed to
possibly-undefined. You need to use--enable-error-code=possibly-undefinedto enable it.Avoid false `possibly-undefined` errors due to omitted unrequired els…
cyphase commentedon Mar 8, 2026
The if/elif example is fixed in #20149 (269e7ee), but the match example is still false-positive as of the latest commit on
master:Same with an enum: