Skip to content

Commit 0fc26dc

Browse files
committed
Warn when abstract or protocol type is assigned to a callable, refs python#13171
1 parent 15e4de5 commit 0fc26dc

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed

mypy/checker.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,10 +2431,14 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type
24312431
if (isinstance(rvalue_type, CallableType) and rvalue_type.is_type_obj() and
24322432
(rvalue_type.type_object().is_abstract or
24332433
rvalue_type.type_object().is_protocol) and
2434-
isinstance(lvalue_type, TypeType) and
2435-
isinstance(lvalue_type.item, Instance) and
2436-
(lvalue_type.item.type.is_abstract or
2437-
lvalue_type.item.type.is_protocol)):
2434+
((isinstance(lvalue_type, TypeType) and
2435+
isinstance(lvalue_type.item, Instance) and
2436+
(lvalue_type.item.type.is_abstract or
2437+
lvalue_type.item.type.is_protocol)) or
2438+
(isinstance(lvalue_type, CallableType) and
2439+
isinstance(lvalue_type.ret_type, Instance) and
2440+
(lvalue_type.ret_type.type.is_abstract or
2441+
lvalue_type.ret_type.type.is_protocol)))):
24382442
self.msg.concrete_only_assign(lvalue_type, rvalue)
24392443
return
24402444
if rvalue_type and infer_lvalue_type and not isinstance(lvalue_type, PartialType):

test-data/unit/check-abstract.test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,25 @@ if int():
250250
var_old = C # OK
251251
[out]
252252

253+
[case testInstantiationAbstractsWithCallables]
254+
from typing import Callable, Type
255+
from abc import abstractmethod
256+
257+
class A:
258+
@abstractmethod
259+
def m(self) -> None: pass
260+
class B(A): pass
261+
class C(B):
262+
def m(self) -> None:
263+
pass
264+
265+
var: Callable[[], A]
266+
var() # OK
267+
268+
var = A # E: Can only assign concrete classes to a variable of type "Callable[[], A]"
269+
var = B # E: Can only assign concrete classes to a variable of type "Callable[[], A]"
270+
var = C # OK
271+
253272
[case testInstantiationAbstractsInTypeForClassMethods]
254273
from typing import Type
255274
from abc import abstractmethod

test-data/unit/check-protocols.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,23 @@ if int():
16191619
var_old = B # OK
16201620
var_old = C # OK
16211621

1622+
[case testInstantiationProtocolWithCallables]
1623+
from typing import Callable, Protocol
1624+
1625+
class P(Protocol):
1626+
def m(self) -> None: pass
1627+
class B(P): pass
1628+
class C:
1629+
def m(self) -> None:
1630+
pass
1631+
1632+
var: Callable[[], P]
1633+
var() # OK
1634+
1635+
var = P # E: Can only assign concrete classes to a variable of type "Callable[[], P]"
1636+
var = B # OK
1637+
var = C # OK
1638+
16221639
[case testInstantiationProtocolInTypeForClassMethods]
16231640
from typing import Type, Protocol
16241641

0 commit comments

Comments
 (0)