Skip to content

Commit 8e8dc22

Browse files
committed
.
1 parent a7bdffd commit 8e8dc22

File tree

7 files changed

+49
-4
lines changed

7 files changed

+49
-4
lines changed

mypy/erasetype.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,13 @@ def visit_unpack_type(self, t: UnpackType) -> ProperType:
102102
def visit_callable_type(self, t: CallableType) -> ProperType:
103103
# We must preserve the fallback type for overload resolution to work.
104104
any_type = AnyType(TypeOfAny.special_form)
105+
# If we're a type object, make sure we continue to be a valid type object
106+
ret_type = t.ret_type if t.is_type_obj() else any_type
105107
return CallableType(
106108
arg_types=[any_type, any_type],
107109
arg_kinds=[ARG_STAR, ARG_STAR2],
108110
arg_names=[None, None],
109-
ret_type=any_type,
111+
ret_type=ret_type,
110112
fallback=t.fallback,
111113
is_ellipsis_args=True,
112114
implicit=True,

mypy/meet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ def _type_object_overlap(left: Type, right: Type) -> bool:
657657
def is_overlapping_erased_types(
658658
left: Type, right: Type, *, ignore_promotions: bool = False
659659
) -> bool:
660-
"""The same as 'is_overlapping_erased_types', except the types are erased first."""
660+
"""The same as 'is_overlapping_types', except the types are erased first."""
661661
return is_overlapping_types(
662662
erase_type(left), erase_type(right), ignore_promotions=ignore_promotions
663663
)

mypy/subtypes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,11 @@ def g(x: int) -> int: ...
16961696
if right.is_type_obj() and not left.is_type_obj() and not allow_partial_overlap:
16971697
return False
16981698

1699+
if left.is_type_obj():
1700+
left_type_obj = left.type_object()
1701+
if (left_type_obj.is_protocol or left_type_obj.is_abstract) and not right.is_type_obj():
1702+
return False
1703+
16991704
# A callable L is a subtype of a generic callable R if L is a
17001705
# subtype of every type obtained from R by substituting types for
17011706
# the variables of R. We can check this by simply leaving the

mypy/test/testtypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ def test_erase_with_type_object(self) -> None:
318318
arg_types=[self.fx.anyt, self.fx.anyt],
319319
arg_kinds=[ARG_STAR, ARG_STAR2],
320320
arg_names=[None, None],
321-
ret_type=self.fx.anyt,
321+
ret_type=self.fx.b,
322322
fallback=self.fx.type_type,
323323
),
324324
)

test-data/unit/check-abstract.test

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,3 +1688,24 @@ from typing import TYPE_CHECKING
16881688
class C:
16891689
if TYPE_CHECKING:
16901690
def dynamic(self) -> int: ... # OK
1691+
1692+
[case testAbstractCallableSubtyping]
1693+
import abc
1694+
from typing import Callable, Protocol
1695+
1696+
class Proto(Protocol):
1697+
def meth(self): ...
1698+
1699+
def foo(t: Callable[..., Proto]):
1700+
t()
1701+
1702+
foo(Proto) # E: Argument 1 to "foo" has incompatible type "Type[Proto]"; expected "Callable[..., Proto]"
1703+
1704+
class Abstract(abc.ABC):
1705+
@abc.abstractmethod
1706+
def meth(self): ...
1707+
1708+
def bar(t: Callable[..., Abstract]):
1709+
t()
1710+
1711+
bar(Abstract) # E: Argument 1 to "bar" has incompatible type "Type[Abstract]"; expected "Callable[..., Abstract]"

test-data/unit/check-functools.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,8 @@ def f1(cls: type[A]) -> None:
594594

595595
def f2() -> None:
596596
A() # E: Cannot instantiate abstract class "A" with abstract attribute "method"
597-
partial_cls = partial(A) # E: Cannot instantiate abstract class "A" with abstract attribute "method"
597+
partial_cls = partial(A) # E: Cannot instantiate abstract class "A" with abstract attribute "method" \
598+
# E: Argument 1 to "partial" has incompatible type "Type[A]"; expected "Callable[..., A]"
598599
partial_cls() # E: Cannot instantiate abstract class "A" with abstract attribute "method"
599600
[builtins fixtures/tuple.pyi]
600601

test-data/unit/check-optional.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,3 +1355,19 @@ def f(x: object) -> None:
13551355
with C():
13561356
pass
13571357
[builtins fixtures/tuple.pyi]
1358+
1359+
[case testRefineAwayNoneCallbackProtocol]
1360+
# Regression test for issue encountered in https://github.com/python/mypy/pull/18347#issuecomment-2564062070
1361+
from __future__ import annotations
1362+
from typing import Protocol
1363+
1364+
class CP(Protocol):
1365+
def __call__(self, parameters: str) -> str: ...
1366+
1367+
class NotSet: ...
1368+
1369+
class Task:
1370+
def with_opt(self, trn: CP | type[NotSet] | None):
1371+
if trn is not NotSet:
1372+
reveal_type(trn) # N: Revealed type is "Union[__main__.CP, Type[__main__.NotSet], None]"
1373+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)