diff --git a/mypy/semanal.py b/mypy/semanal.py index 62ec1c823ec2..555cb749074e 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1103,6 +1103,8 @@ def visit_decorator(self, dec: Decorator) -> None: dec.func.accept(self) if dec.decorators and dec.var.is_property: self.fail('Decorated property not supported', dec) + if dec.func.is_abstract and dec.func.is_final: + self.fail(f"Method {dec.func.name} is both abstract and final", dec) def check_decorated_function_is_method(self, decorator: str, context: Context) -> None: diff --git a/test-data/unit/check-final.test b/test-data/unit/check-final.test index a955d021647d..2f298ad1be3b 100644 --- a/test-data/unit/check-final.test +++ b/test-data/unit/check-final.test @@ -1091,3 +1091,21 @@ class A: b: ClassVar[Final[int]] # E: Final can be only used as an outermost qualifier in a variable annotation c: ClassVar[Final] = 1 # E: Final can be only used as an outermost qualifier in a variable annotation [out] + +[case testFinalClassWithAbstractMethod] +from typing import final +from abc import ABC, abstractmethod + +@final +class A(ABC): # E: Final class __main__.A has abstract attributes "B" + @abstractmethod + def B(self) -> None: ... + +[case testFinalDefiningFuncWithAbstractMethod] +from typing import final +from abc import ABC, abstractmethod + +class A(ABC): + @final # E: Method B is both abstract and final + @abstractmethod + def B(self) -> None: ...