Skip to content

Commit c30c4df

Browse files
committed
Improve CallableType join in simple cases
Fixes #17479 , although as you can see in the test case the logic still remains far from perfect
1 parent 9bf5169 commit c30c4df

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

mypy/join.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -402,23 +402,32 @@ def visit_instance(self, t: Instance) -> ProperType:
402402
return self.default(self.s)
403403

404404
def visit_callable_type(self, t: CallableType) -> ProperType:
405-
if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
406-
if is_equivalent(t, self.s):
407-
return combine_similar_callables(t, self.s)
408-
result = join_similar_callables(t, self.s)
405+
if isinstance(self.s, CallableType):
406+
if is_similar_callables(t, self.s):
407+
if is_equivalent(t, self.s):
408+
return combine_similar_callables(t, self.s)
409+
result = join_similar_callables(t, self.s)
410+
if any(
411+
isinstance(tp, (NoneType, UninhabitedType))
412+
for tp in get_proper_types(result.arg_types)
413+
):
414+
# We don't want to return unusable Callable, attempt fallback instead.
415+
return join_types(t.fallback, self.s)
416+
else:
417+
if is_subtype(self.s, t):
418+
result = t.copy_modified()
419+
elif is_subtype(t, self.s):
420+
result = self.s.copy_modified()
421+
else:
422+
return join_types(t.fallback, self.s)
423+
409424
# We set the from_type_type flag to suppress error when a collection of
410425
# concrete class objects gets inferred as their common abstract superclass.
411426
if not (
412427
(t.is_type_obj() and t.type_object().is_abstract)
413428
or (self.s.is_type_obj() and self.s.type_object().is_abstract)
414429
):
415430
result.from_type_type = True
416-
if any(
417-
isinstance(tp, (NoneType, UninhabitedType))
418-
for tp in get_proper_types(result.arg_types)
419-
):
420-
# We don't want to return unusable Callable, attempt fallback instead.
421-
return join_types(t.fallback, self.s)
422431
return result
423432
elif isinstance(self.s, Overloaded):
424433
# Switch the order of arguments to that we'll get to visit_overloaded.

test-data/unit/check-functions.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3472,3 +3472,19 @@ class Qux(Bar):
34723472
def baz(self, x) -> None:
34733473
pass
34743474
[builtins fixtures/tuple.pyi]
3475+
3476+
[case testCallableJoinWithDefaults]
3477+
from typing import Callable, TypeVar
3478+
3479+
T = TypeVar("T")
3480+
3481+
def join(t1: T, t2: T) -> T: ...
3482+
3483+
def f1() -> None: ...
3484+
def f2(i: int = 0) -> None: ...
3485+
def f3(i: str = "") -> None: ...
3486+
3487+
reveal_type(join(f1, f2)) # N: Revealed type is "def ()"
3488+
reveal_type(join(f1, f3)) # N: Revealed type is "def ()"
3489+
reveal_type(join(f2, f3)) # N: Revealed type is "builtins.function" # TODO: this could be better
3490+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)