Repository: python/mypy

Issue:
0.940: Condition can't be inferred, unable to merge overloads
**Bug Report**
This might be an issue with beartype, it has been reported there https://github.com/beartype/beartype/issues/112. Since mypy reports an overload error at a line that has no overloads, it might be a mypy error (edit: there are overloads around).

**To Reproduce**

```py
from beartype import beartype

@beartype
def test(x: int) -> int:
    return x
```

> /home/twoertwe/.cache/pypoetry/virtualenvs/python-tools-sgDWaTGJ-py3.10/lib/python3.10/site-packages/beartype/_decor/main.py:294: error: Condition can't be inferred, unable to merge overloads [misc]

The line in question is here:
https://github.com/beartype/beartype/blob/main/beartype/_decor/main.py#L294

**Expected Behavior**
Either no error or a better indication at which line the error occurs.

**Your Environment**

- Mypy version used: 0.940
- Mypy command-line flags: - 
- Mypy configuration options from `mypy.ini` (and other config files): - 
- Python version used: 3.10.2
- Operating system and version: Ubuntu

<!--
You can freely edit this text, please remove all the lines
you believe are unnecessary.
-->



Discussion:
Thanks for the message. I'll take a look

Resolving patch:
diff --git a/mypy/fastparse.py b/mypy/fastparse.py
--- a/mypy/fastparse.py
+++ b/mypy/fastparse.py
@@ -486,6 +486,7 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
         ret: List[Statement] = []
         current_overload: List[OverloadPart] = []
         current_overload_name: Optional[str] = None
+        seen_unconditional_func_def = False
         last_if_stmt: Optional[IfStmt] = None
         last_if_overload: Optional[Union[Decorator, FuncDef, OverloadedFuncDef]] = None
         last_if_stmt_overload_name: Optional[str] = None
@@ -498,6 +499,7 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
             if (
                 isinstance(stmt, IfStmt)
                 and len(stmt.body[0].body) == 1
+                and seen_unconditional_func_def is False
                 and (
                     isinstance(stmt.body[0].body[0], (Decorator, OverloadedFuncDef))
                     or current_overload_name is not None
@@ -527,6 +529,8 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
                     self.fail_merge_overload(last_if_unknown_truth_value)
                     last_if_unknown_truth_value = None
                 current_overload.append(stmt)
+                if isinstance(stmt, FuncDef):
+                    seen_unconditional_func_def = True
             elif (
                 current_overload_name is not None
                 and isinstance(stmt, IfStmt)
@@ -583,6 +587,7 @@ def fix_function_overloads(self, stmts: List[Statement]) -> List[Statement]:
                 # most of mypy/mypyc assumes that all the functions in an OverloadedFuncDef are
                 # related, but multiple underscore functions next to each other aren't necessarily
                 # related
+                seen_unconditional_func_def = False
                 if isinstance(stmt, Decorator) and not unnamed_function(stmt.name):
                     current_overload = [stmt]
                     current_overload_name = stmt.name


Test patch:
diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test
--- a/test-data/unit/check-overloading.test
+++ b/test-data/unit/check-overloading.test
@@ -6302,3 +6302,29 @@ if True:
     def f12(x): ...
 reveal_type(f12(A()))  # N: Revealed type is "__main__.A"
 [typing fixtures/typing-medium.pyi]
+
+[case testOverloadIfUnconditionalFuncDef]
+# flags: --always-true True --always-false False
+from typing import overload
+
+class A: ...
+class B: ...
+
+# -----
+# Don't merge conditional FuncDef after unconditional one
+# -----
+
+@overload
+def f1(x: A) -> A: ...
+@overload
+def f1(x: B) -> B: ...
+def f1(x): ...
+
+@overload
+def f2(x: A) -> A: ...
+if True:
+    @overload
+    def f2(x: B) -> B: ...
+def f2(x): ...
+if True:
+    def f2(x): ...  # E: Name "f2" already defined on line 17