Skip to content

Commit 914d517

Browse files
committed
Emit error if condition can't be inferred
1 parent 3d0397a commit 914d517

File tree

2 files changed

+91
-22
lines changed

2 files changed

+91
-22
lines changed

mypy/fastparse.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,19 @@ def fail(self,
344344
msg: str,
345345
line: int,
346346
column: int,
347-
blocker: bool = True) -> None:
347+
blocker: bool = True,
348+
code: codes.ErrorCode = codes.SYNTAX) -> None:
348349
if blocker or not self.options.ignore_errors:
349-
self.errors.report(line, column, msg, blocker=blocker, code=codes.SYNTAX)
350+
self.errors.report(line, column, msg, blocker=blocker, code=code)
351+
352+
def fail_merge_overload(self, node: IfStmt) -> None:
353+
self.fail(
354+
"Condition can't be inferred, unable to merge overloads",
355+
line=node.line,
356+
column=node.column,
357+
blocker=False,
358+
code=codes.MISC,
359+
)
350360

351361
def visit(self, node: Optional[AST]) -> Any:
352362
if node is None:
@@ -479,10 +489,12 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
479489
last_if_stmt: Optional[IfStmt] = None
480490
last_if_overload: Optional[Union[Decorator, FuncDef, OverloadedFuncDef]] = None
481491
last_if_stmt_overload_name: Optional[str] = None
492+
last_if_unknown_truth_value: Optional[IfStmt] = None
482493
skipped_if_stmts: List[IfStmt] = []
483494
for stmt in stmts:
484495
if_overload_name: Optional[str] = None
485496
if_block_with_overload: Optional[Block] = None
497+
if_unknown_truth_value: Optional[IfStmt] = None
486498
if (
487499
isinstance(stmt, IfStmt)
488500
and len(stmt.body[0].body) == 1
@@ -495,7 +507,8 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
495507
# Check IfStmt block to determine if function overloads can be merged
496508
if_overload_name = self._check_ifstmt_for_overloads(stmt)
497509
if if_overload_name is not None:
498-
if_block_with_overload = self._get_executable_if_block_with_overloads(stmt)
510+
if_block_with_overload, if_unknown_truth_value = \
511+
self._get_executable_if_block_with_overloads(stmt)
499512

500513
if (current_overload_name is not None
501514
and isinstance(stmt, (Decorator, FuncDef))
@@ -510,6 +523,9 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
510523
else:
511524
current_overload.append(last_if_overload)
512525
last_if_stmt, last_if_overload = None, None
526+
if last_if_unknown_truth_value:
527+
self.fail_merge_overload(last_if_unknown_truth_value)
528+
last_if_unknown_truth_value = None
513529
current_overload.append(stmt)
514530
elif (
515531
current_overload_name is not None
@@ -522,6 +538,8 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
522538
# or function definitions.
523539
skipped_if_stmts.append(stmt)
524540
if if_block_with_overload is None:
541+
if if_unknown_truth_value is not None:
542+
self.fail_merge_overload(if_unknown_truth_value)
525543
continue
526544
if last_if_overload is not None:
527545
# Last stmt was an IfStmt with same overload name
@@ -542,6 +560,7 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
542560
ret.append(last_if_stmt)
543561
last_if_stmt_overload_name = current_overload_name
544562
last_if_stmt, last_if_overload = None, None
563+
last_if_unknown_truth_value = None
545564

546565
if current_overload and current_overload_name == last_if_stmt_overload_name:
547566
# Remove last stmt (IfStmt) from ret if the overload names matched
@@ -580,6 +599,7 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
580599
Union[Decorator, FuncDef, OverloadedFuncDef],
581600
if_block_with_overload.body[0]
582601
)
602+
last_if_unknown_truth_value = if_unknown_truth_value
583603
else:
584604
current_overload = []
585605
current_overload_name = None
@@ -630,29 +650,40 @@ def _check_ifstmt_for_overloads(self, stmt: IfStmt) -> Optional[str]:
630650

631651
return None
632652

633-
def _get_executable_if_block_with_overloads(self, stmt: IfStmt) -> Optional[Block]:
653+
def _get_executable_if_block_with_overloads(
654+
self, stmt: IfStmt
655+
) -> Tuple[Optional[Block], Optional[IfStmt]]:
634656
"""Return block from IfStmt that will get executed.
635657
636-
Only returns block if sure that alternative blocks are unreachable.
658+
Return
659+
0 -> A block if sure that alternative blocks are unreachable.
660+
1 -> An IfStmt if the reachability of it can't be inferred,
661+
i.e. the truth value is unknown.
637662
"""
638663
infer_reachability_of_if_statement(stmt, self.options)
664+
if (
665+
stmt.else_body is None
666+
and stmt.body[0].is_unreachable is True
667+
):
668+
# always False condition with no else
669+
return None, None
639670
if (
640671
stmt.else_body is None
641672
or stmt.body[0].is_unreachable is False
642673
and stmt.else_body.is_unreachable is False
643674
):
644675
# The truth value is unknown, thus not conclusive
645-
return None
676+
return None, stmt
646677
if stmt.else_body.is_unreachable is True:
647678
# else_body will be set unreachable if condition is always True
648-
return stmt.body[0]
679+
return stmt.body[0], None
649680
if stmt.body[0].is_unreachable is True:
650681
# body will be set unreachable if condition is always False
651682
# else_body can contain an IfStmt itself (for elif) -> do a recursive check
652683
if isinstance(stmt.else_body.body[0], IfStmt):
653684
return self._get_executable_if_block_with_overloads(stmt.else_body.body[0])
654-
return stmt.else_body
655-
return None
685+
return stmt.else_body, None
686+
return None, stmt
656687

657688
def _strip_contents_from_if_stmt(self, stmt: IfStmt) -> None:
658689
"""Remove contents from IfStmt.

test-data/unit/check-overloading.test

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5463,7 +5463,8 @@ reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C"
54635463
def f3(g: A) -> A: ...
54645464
@overload
54655465
def f3(g: B) -> B: ...
5466-
if maybe_true: # E: Name "maybe_true" is not defined
5466+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5467+
# E: Name "maybe_true" is not defined
54675468
@overload
54685469
def f3(g: C) -> C: ...
54695470
def f3(g): ...
@@ -5777,7 +5778,8 @@ reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C"
57775778

57785779
@overload # E: Single overload definition, multiple required
57795780
def f3(x: A) -> A: ...
5780-
if maybe_true: # E: Name "maybe_true" is not defined
5781+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5782+
# E: Name "maybe_true" is not defined
57815783
@overload
57825784
def f3(x: B) -> B: ...
57835785
elif True:
@@ -5795,7 +5797,8 @@ reveal_type(f3(B())) # E: No overload variant of "f3" matches argument type "B"
57955797

57965798
@overload # E: Single overload definition, multiple required
57975799
def f4(x: A) -> A: ...
5798-
if maybe_true: # E: Name "maybe_true" is not defined
5800+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5801+
# E: Name "maybe_true" is not defined
57995802
@overload
58005803
def f4(x: B) -> B: ...
58015804
else:
@@ -5816,6 +5819,7 @@ class A: ...
58165819
class B: ...
58175820
class C: ...
58185821
class D: ...
5822+
class E: ...
58195823

58205824
# -----
58215825
# Match the first always-true block
@@ -5844,7 +5848,8 @@ def f2(x: A) -> A: ...
58445848
if False:
58455849
@overload
58465850
def f2(x: B) -> B: ...
5847-
elif maybe_true: # E: Name "maybe_true" is not defined
5851+
elif maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5852+
# E: Name "maybe_true" is not defined
58485853
@overload
58495854
def f2(x: C) -> C: ...
58505855
else:
@@ -5859,7 +5864,8 @@ reveal_type(f2(C())) # E: No overload variant of "f2" matches argument type "C"
58595864

58605865
@overload # E: Single overload definition, multiple required
58615866
def f3(x: A) -> A: ...
5862-
if maybe_true: # E: Name "maybe_true" is not defined
5867+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5868+
# E: Name "maybe_true" is not defined
58635869
@overload
58645870
def f3(x: B) -> B: ...
58655871
elif False:
@@ -5875,6 +5881,30 @@ reveal_type(f3(B())) # E: No overload variant of "f3" matches argument type "B"
58755881
# N: def f3(x: A) -> A \
58765882
# N: Revealed type is "Any"
58775883

5884+
def g(bool_var: bool) -> None:
5885+
@overload
5886+
def f4(x: A) -> A: ...
5887+
if bool_var: # E: Condition cannot be inferred, unable to merge overloads
5888+
@overload
5889+
def f4(x: B) -> B: ...
5890+
elif maybe_true: # E: Name "maybe_true" is not defined
5891+
# No 'Condition cannot be inferred' error here since it's already
5892+
# emitted on the first condition, 'bool_var', above.
5893+
@overload
5894+
def f4(x: C) -> C: ...
5895+
else:
5896+
@overload
5897+
def f4(x: D) -> D: ...
5898+
@overload
5899+
def f4(x: E) -> E: ...
5900+
def f4(x): ...
5901+
reveal_type(f4(E())) # N: Revealed type is "__main__.E"
5902+
reveal_type(f4(B())) # E: No overload variant of "f4" matches argument type "B" \
5903+
# N: Possible overload variants: \
5904+
# N: def f4(x: A) -> A \
5905+
# N: def f4(x: E) -> E \
5906+
# N: Revealed type is "Any"
5907+
58785908
[case testOverloadIfSkipUnknownExecution]
58795909
# flags: --always-true True
58805910
from typing import overload
@@ -5891,13 +5921,15 @@ class D: ...
58915921

58925922
@overload # E: Single overload definition, multiple required
58935923
def f1(x: A) -> A: ...
5894-
if maybe_true: # E: Name "maybe_true" is not defined
5924+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5925+
# E: Name "maybe_true" is not defined
58955926
@overload
58965927
def f1(x: B) -> B: ...
58975928
def f1(x): ...
58985929
reveal_type(f1(A())) # N: Revealed type is "__main__.A"
58995930

5900-
if maybe_true: # E: Name "maybe_true" is not defined
5931+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5932+
# E: Name "maybe_true" is not defined
59015933
@overload
59025934
def f2(x: A) -> A: ...
59035935
@overload
@@ -5914,14 +5946,16 @@ reveal_type(f2(A())) # E: No overload variant of "f2" matches argument type "A"
59145946
if True:
59155947
@overload # E: Single overload definition, multiple required
59165948
def f3(x: A) -> A: ...
5917-
if maybe_true: # E: Name "maybe_true" is not defined
5949+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5950+
# E: Name "maybe_true" is not defined
59185951
@overload
59195952
def f3(x: B) -> B: ...
59205953
def f3(x): ...
59215954
reveal_type(f3(A())) # N: Revealed type is "__main__.A"
59225955

59235956
if True:
5924-
if maybe_true: # E: Name "maybe_true" is not defined
5957+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
5958+
# E: Name "maybe_true" is not defined
59255959
@overload
59265960
def f4(x: A) -> A: ...
59275961
@overload
@@ -6178,10 +6212,12 @@ reveal_type(f8(C())) # E: No overload variant of "f8" matches argument type "C"
61786212
# N: def f8(x: B) -> B \
61796213
# N: Revealed type is "Any"
61806214

6181-
if maybe_true: # E: Name "maybe_true" is not defined
6215+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
6216+
# E: Name "maybe_true" is not defined
61826217
@overload
61836218
def f9(x: A) -> A: ...
6184-
if another_maybe_true: # E: Name "another_maybe_true" is not defined
6219+
if another_maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
6220+
# E: Name "another_maybe_true" is not defined
61856221
@overload
61866222
def f9(x: B) -> B: ...
61876223
@overload
@@ -6197,10 +6233,12 @@ reveal_type(f9(A())) # E: No overload variant of "f9" matches argument type "A"
61976233
reveal_type(f9(C())) # N: Revealed type is "__main__.C"
61986234

61996235
if True:
6200-
if maybe_true: # E: Name "maybe_true" is not defined
6236+
if maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
6237+
# E: Name "maybe_true" is not defined
62016238
@overload
62026239
def f10(x: A) -> A: ...
6203-
if another_maybe_true: # E: Name "another_maybe_true" is not defined
6240+
if another_maybe_true: # E: Condition cannot be inferred, unable to merge overloads \
6241+
# E: Name "another_maybe_true" is not defined
62046242
@overload
62056243
def f10(x: B) -> B: ...
62066244
@overload

0 commit comments

Comments
 (0)