Skip to content

Commit e867132

Browse files
authored
Allow omitting implementation for abstract overloads (#18882)
Fixes #11488 This is a little quality of life improvement. Implementation is straightforward. I also update mypyc to give an error instead of crashing.
1 parent 4f284a3 commit e867132

File tree

4 files changed

+42
-3
lines changed

4 files changed

+42
-3
lines changed

mypy/checkmember.py

+3
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@ def validate_super_call(node: FuncBase, mx: MemberContext) -> None:
380380
if node.impl:
381381
impl = node.impl if isinstance(node.impl, FuncDef) else node.impl.func
382382
unsafe_super = impl.is_trivial_body
383+
elif not node.is_property and node.items:
384+
assert isinstance(node.items[0], Decorator)
385+
unsafe_super = node.items[0].func.is_trivial_body
383386
if unsafe_super:
384387
mx.msg.unsafe_super(node.name, node.info.name, mx.context)
385388

mypy/semanal.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1461,8 +1461,15 @@ def handle_missing_overload_implementation(self, defn: OverloadedFuncDef) -> Non
14611461
item.func.abstract_status = IS_ABSTRACT
14621462
else:
14631463
item.abstract_status = IS_ABSTRACT
1464+
elif all(
1465+
isinstance(item, Decorator) and item.func.abstract_status == IS_ABSTRACT
1466+
for item in defn.items
1467+
):
1468+
# Since there is no implementation, it can't be called via super().
1469+
if defn.items:
1470+
assert isinstance(defn.items[0], Decorator)
1471+
defn.items[0].func.is_trivial_body = True
14641472
else:
1465-
# TODO: also allow omitting an implementation for abstract methods in ABCs?
14661473
self.fail(
14671474
"An overloaded function outside a stub file must have an implementation",
14681475
defn,

mypyc/irbuild/prepare.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,12 @@ def prepare_methods_and_attributes(
382382

383383
# Handle case for regular function overload
384384
else:
385-
assert node.node.impl
386-
prepare_method_def(ir, module_name, cdef, mapper, node.node.impl, options)
385+
if not node.node.impl:
386+
errors.error(
387+
"Overloads without implementation are not supported", path, cdef.line
388+
)
389+
else:
390+
prepare_method_def(ir, module_name, cdef, mapper, node.node.impl, options)
387391

388392
if ir.builtin_base:
389393
ir.attributes.clear()

test-data/unit/check-functions.test

+25
Original file line numberDiff line numberDiff line change
@@ -3541,3 +3541,28 @@ def f(x: Callable[[Arg(int, 'x')], None]) -> None: pass
35413541
y: Callable[[Union[int, str]], None]
35423542
f(y) # E: Argument 1 to "f" has incompatible type "Callable[[Union[int, str]], None]"; expected "Callable[[Arg(int, 'x')], None]"
35433543
[builtins fixtures/tuple.pyi]
3544+
3545+
[case testAbstractOverloadsWithoutImplementationAllowed]
3546+
from abc import abstractmethod
3547+
from typing import overload, Union
3548+
3549+
class Foo:
3550+
@overload
3551+
@abstractmethod
3552+
def foo(self, value: int) -> int:
3553+
...
3554+
@overload
3555+
@abstractmethod
3556+
def foo(self, value: str) -> str:
3557+
...
3558+
3559+
class Bar(Foo):
3560+
@overload
3561+
def foo(self, value: int) -> int:
3562+
...
3563+
@overload
3564+
def foo(self, value: str) -> str:
3565+
...
3566+
3567+
def foo(self, value: Union[int, str]) -> Union[int, str]:
3568+
return super().foo(value) # E: Call to abstract method "foo" of "Foo" with trivial body via super() is unsafe

0 commit comments

Comments
 (0)