Skip to content

Commit ad14b5b

Browse files
Resolve possibly-used-before-assignment false positives from match block assignments (#10393)
2 parents 222ab20 + acdf505 commit ad14b5b

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix false positives for `possibly-used-before-assignment` when variables are exhaustively
2+
assigned within a `match` block.
3+
4+
Closes #9668

pylint/checkers/variables.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,12 @@ def _inferred_to_define_name_raise_or_return(
674674
if isinstance(node, (nodes.With, nodes.For, nodes.While)):
675675
return NamesConsumer._defines_name_raises_or_returns_recursive(name, node)
676676

677+
if isinstance(node, nodes.Match):
678+
return all(
679+
NamesConsumer._defines_name_raises_or_returns_recursive(name, case)
680+
for case in node.cases
681+
)
682+
677683
if not isinstance(node, nodes.If):
678684
return False
679685

@@ -723,6 +729,7 @@ def _branch_handles_name(self, name: str, body: Iterable[nodes.NodeNG]) -> bool:
723729
nodes.With,
724730
nodes.For,
725731
nodes.While,
732+
nodes.Match,
726733
),
727734
)
728735
and self._inferred_to_define_name_raise_or_return(name, if_body_stmt)
@@ -975,6 +982,11 @@ def _defines_name_raises_or_returns_recursive(
975982
and NamesConsumer._defines_name_raises_or_returns_recursive(name, stmt)
976983
):
977984
return True
985+
if isinstance(stmt, nodes.Match):
986+
return all(
987+
NamesConsumer._defines_name_raises_or_returns_recursive(name, case)
988+
for case in stmt.cases
989+
)
978990
return False
979991

980992
@staticmethod

tests/functional/u/used/used_before_assignment_py310.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def check_value_if_then_match_return(example: Example, should_check: bool) -> st
3333
case _:
3434
return None
3535

36-
return result # [possibly-used-before-assignment] FALSE POSITIVE
36+
return result
3737

3838
def check_value_if_then_match_raise(example: Example, should_check: bool) -> str | None:
3939
if should_check:
@@ -47,7 +47,7 @@ def check_value_if_then_match_raise(example: Example, should_check: bool) -> str
4747
case _:
4848
raise ValueError("Not a valid enum")
4949

50-
return result # [possibly-used-before-assignment] FALSE POSITIVE
50+
return result
5151

5252
def check_value_if_then_match_assert_never(example: Example, should_check: bool) -> str | None:
5353
if should_check:
@@ -61,7 +61,7 @@ def check_value_if_then_match_assert_never(example: Example, should_check: bool)
6161
case _:
6262
assert_never(example)
6363

64-
return result # [possibly-used-before-assignment] FALSE POSITIVE
64+
return result
6565

6666
def g(x):
6767
if x is None:
@@ -73,4 +73,36 @@ def g(x):
7373
case _:
7474
raise TypeError(type(x))
7575

76-
return y # [possibly-used-before-assignment] FALSE POSITIVE
76+
return y
77+
78+
def check_value_if_then_match_nested(
79+
example: Example, example_inner: Example, should_check: bool
80+
) -> str | None:
81+
if should_check:
82+
result = None
83+
else:
84+
match example:
85+
case Example.FOO:
86+
match example_inner:
87+
case Example.BAR:
88+
result = "bar"
89+
case _:
90+
return None
91+
case _:
92+
return None
93+
94+
return result
95+
96+
def check_value_if_then_match_non_exhaustive(example: Example, should_check: bool) -> str | None:
97+
if should_check:
98+
result = None
99+
else:
100+
match example:
101+
case Example.FOO:
102+
result = "foo"
103+
case Example.BAR:
104+
pass
105+
case _:
106+
return None
107+
108+
return result # [possibly-used-before-assignment]
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
possibly-used-before-assignment:36:11:36:17:check_value_if_then_match_return:Possibly using variable 'result' before assignment:CONTROL_FLOW
2-
possibly-used-before-assignment:50:11:50:17:check_value_if_then_match_raise:Possibly using variable 'result' before assignment:CONTROL_FLOW
3-
possibly-used-before-assignment:64:11:64:17:check_value_if_then_match_assert_never:Possibly using variable 'result' before assignment:CONTROL_FLOW
4-
possibly-used-before-assignment:76:11:76:12:g:Possibly using variable 'y' before assignment:CONTROL_FLOW
1+
possibly-used-before-assignment:108:11:108:17:check_value_if_then_match_non_exhaustive:Possibly using variable 'result' before assignment:CONTROL_FLOW

0 commit comments

Comments
 (0)