diff --git a/source/analysis/test/integration/methodTest.ml b/source/analysis/test/integration/methodTest.ml index df6604a8be2..37bcd489a72 100644 --- a/source/analysis/test/integration/methodTest.ml +++ b/source/analysis/test/integration/methodTest.ml @@ -2610,7 +2610,7 @@ let test_check_override_decorator context = let assert_type_errors = assert_type_errors ~context in assert_type_errors {| - from pyre_extensions import override + from typing import override class Foo: def different_method(self, input: int) -> int: @@ -2627,7 +2627,7 @@ let test_check_override_decorator context = ]; assert_type_errors {| - from pyre_extensions import override + from typing import override class Foo: @staticmethod @@ -2645,7 +2645,7 @@ let test_check_override_decorator context = ]; assert_type_errors {| - from pyre_extensions import override + from typing import override class Foo: @classmethod @@ -2660,7 +2660,7 @@ let test_check_override_decorator context = []; assert_type_errors {| - from pyre_extensions import override + from typing import override @override def foo(input: int) -> int: @@ -2672,7 +2672,7 @@ let test_check_override_decorator context = ]; assert_type_errors {| - from pyre_extensions import override + from typing import override def foo_outer(input: int) -> int: @override @@ -2688,7 +2688,7 @@ let test_check_override_decorator context = ]; assert_type_errors {| - from pyre_extensions import override + from typing import override class Foo1: def foo(self, input: int) -> int: @@ -2704,7 +2704,7 @@ let test_check_override_decorator context = []; assert_type_errors {| - from pyre_extensions import override + from typing import override class Foo: def foo(self, input: int) -> str: @@ -2719,7 +2719,7 @@ let test_check_override_decorator context = needs to be checked. *) ]; assert_type_errors {| - from pyre_extensions import override + from typing import override class Foo: foo: int = 3 @@ -2729,6 +2729,24 @@ let test_check_override_decorator context = foo: str = "hello world" |} ["Parsing failure [404]: invalid syntax"]; + assert_type_errors + {| + import typing_extensions + import pyre_extensions + + class Bar: + @pyre_extensions.override + def method0(self) -> None: ... + + @pyre_extensions.override + def method1(self) -> None: ... + |} + [ + "Invalid override [40]: `test.Bar.method0` is decorated with @override, but no method of the \ + same name exists in superclasses of `Bar`."; + "Invalid override [40]: `test.Bar.method1` is decorated with @override, but no method of the \ + same name exists in superclasses of `Bar`."; + ]; () diff --git a/source/ast/statement.ml b/source/ast/statement.ml index 2c6dc972c88..a0e01fab96c 100644 --- a/source/ast/statement.ml +++ b/source/ast/statement.ml @@ -665,7 +665,11 @@ end = struct let is_final_method signature = has_decorator signature "typing.final" - let is_override_method signature = has_decorator signature "pyre_extensions.override" + let is_override_method signature = + has_decorator signature "typing.override" + || has_decorator signature "typing_extensions.override" + || has_decorator signature "pyre_extensions.override" + let is_dunder_method signature = let name = unqualified_name signature in diff --git a/source/test/test.ml b/source/test/test.ml index c96a967a8a9..0738a3fc82f 100644 --- a/source/test/test.ml +++ b/source/test/test.ml @@ -1080,6 +1080,7 @@ let typeshed_stubs ?(include_helper_builtins = true) () = Literal: _SpecialForm = ... # TypedDict is a (non-subscriptable) special form. TypedDict: object + def override(f: _F) -> _F: ... Callable: _SpecialForm = ... Protocol: _SpecialForm = ... @@ -1482,7 +1483,13 @@ let typeshed_stubs ?(include_helper_builtins = true) () = |}; ( "typing_extensions.pyi", {| - from typing import Final as Final, ParamSpec as ParamSpec, _SpecialForm, overload as overload + from typing import ( + _SpecialForm, + Final as Final, + ParamSpec as ParamSpec, + overload as overload, + override as override + ) Literal: _SpecialForm = ... LiteralString: _SpecialForm = ...