Skip to content

Commit 416f57b

Browse files
authored
Try ignoring Anys in type object callables for purposes of overload ambiguity (#10734)
I believe this should help with some issues that come up with #10694.
1 parent a8c32c9 commit 416f57b

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

mypy/checkexpr.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4199,18 +4199,24 @@ def narrow_type_from_binder(self, expr: Expression, known_type: Type,
41994199
return known_type
42004200

42014201

4202-
def has_any_type(t: Type) -> bool:
4202+
def has_any_type(t: Type, ignore_in_type_obj: bool = False) -> bool:
42034203
"""Whether t contains an Any type"""
4204-
return t.accept(HasAnyType())
4204+
return t.accept(HasAnyType(ignore_in_type_obj))
42054205

42064206

42074207
class HasAnyType(types.TypeQuery[bool]):
4208-
def __init__(self) -> None:
4208+
def __init__(self, ignore_in_type_obj: bool) -> None:
42094209
super().__init__(any)
4210+
self.ignore_in_type_obj = ignore_in_type_obj
42104211

42114212
def visit_any(self, t: AnyType) -> bool:
42124213
return t.type_of_any != TypeOfAny.special_form # special forms are not real Any types
42134214

4215+
def visit_callable_type(self, t: CallableType) -> bool:
4216+
if self.ignore_in_type_obj and t.is_type_obj():
4217+
return False
4218+
return super().visit_callable_type(t)
4219+
42144220

42154221
def has_coroutine_decorator(t: Type) -> bool:
42164222
"""Whether t came from a function decorated with `@coroutine`."""
@@ -4408,7 +4414,10 @@ def any_causes_overload_ambiguity(items: List[CallableType],
44084414
]
44094415

44104416
for arg_idx, arg_type in enumerate(arg_types):
4411-
if has_any_type(arg_type):
4417+
# We ignore Anys in type object callables as ambiguity
4418+
# creators, since that can lead to falsely claiming ambiguity
4419+
# for overloads between Type and Callable.
4420+
if has_any_type(arg_type, ignore_in_type_obj=True):
44124421
matching_formals_unfiltered = [(item_idx, lookup[arg_idx])
44134422
for item_idx, lookup in enumerate(actual_to_formal)
44144423
if lookup[arg_idx]]

test-data/unit/check-overloading.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5173,3 +5173,19 @@ def f2(g: G[A, Any]) -> A: ... # E: Overloaded function signatures 1 and 2 over
51735173
@overload
51745174
def f2(g: G[A, B], x: int = ...) -> B: ...
51755175
def f2(g: Any, x: int = ...) -> Any: ...
5176+
5177+
[case testOverloadTypeVsCallable]
5178+
from typing import TypeVar, Type, Callable, Any, overload
5179+
class Foo:
5180+
def __init__(self, **kwargs: Any): pass
5181+
_T = TypeVar('_T')
5182+
@overload
5183+
def register(cls: Type[_T]) -> int: ...
5184+
@overload
5185+
def register(cls: Callable[..., _T]) -> str: ...
5186+
def register(cls: Any) -> Any: return None
5187+
5188+
5189+
x = register(Foo)
5190+
reveal_type(x) # N: Revealed type is "builtins.int"
5191+
[builtins fixtures/dict.pyi]

0 commit comments

Comments
 (0)