Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #5705 #8866

Merged
merged 1 commit into from May 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions mypy/messages.py
Expand Up @@ -772,6 +772,14 @@ def argument_incompatible_with_supertype(
.format(arg_num, name, target, arg_type_in_supertype_f),
context,
code=codes.OVERRIDE)
self.note(
'This violates the Liskov substitution principle',
context,
code=codes.OVERRIDE)
self.note(
'See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides',
context,
code=codes.OVERRIDE)

if name == "__eq__" and type_name:
multiline_msg = self.comparison_method_example_msg(class_name=type_name)
Expand Down
18 changes: 14 additions & 4 deletions test-data/unit/check-abstract.test
Expand Up @@ -311,7 +311,9 @@ class A(metaclass=ABCMeta):
def g(self, x: int) -> int: pass
class B(A):
def f(self, x: str) -> int: \
# E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int"
# E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
pass
def g(self, x: int) -> int: pass
[out]
Expand All @@ -327,7 +329,9 @@ class J(metaclass=ABCMeta):
def g(self, x: str) -> str: pass
class A(I, J):
def f(self, x: str) -> int: pass \
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "int"
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "int" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
def g(self, x: str) -> int: pass \
# E: Return type "int" of "g" incompatible with return type "str" in supertype "J"
def h(self) -> int: pass # Not related to any base class
Expand All @@ -342,7 +346,9 @@ class J(metaclass=ABCMeta):
class I(J): pass
class A(I):
def f(self, x: str) -> int: pass \
# E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "int"
# E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "int" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
[out]

[case testInvalidOverridingAbstractMethod]
Expand All @@ -353,7 +359,9 @@ class J(metaclass=ABCMeta):
def f(self, x: 'J') -> None: pass
class I(J):
@abstractmethod
def f(self, x: 'I') -> None: pass # E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "J"
def f(self, x: 'I') -> None: pass # E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "J" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
[out]

[case testAbstractClassCoAndContraVariance]
Expand All @@ -375,6 +383,8 @@ class A(I):
pass
[out]
main:11: error: Argument 1 of "h" is incompatible with supertype "I"; supertype defines the argument type as "I"
main:11: note: This violates the Liskov substitution principle
main:11: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
main:11: error: Return type "I" of "h" incompatible with return type "A" in supertype "I"


Expand Down
24 changes: 20 additions & 4 deletions test-data/unit/check-classes.test
Expand Up @@ -282,6 +282,8 @@ class B(A):
def h(self, x: A, y: 'B') -> object: pass # Fail
[out]
main:7: error: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "A"
main:7: note: This violates the Liskov substitution principle
main:7: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
main:9: error: Return type "object" of "h" incompatible with return type "A" in supertype "A"

[case testEqMethodsOverridingWithNonObjects]
Expand All @@ -290,6 +292,8 @@ class A:
[builtins fixtures/attr.pyi]
[out]
main:2: error: Argument 1 of "__eq__" is incompatible with supertype "object"; supertype defines the argument type as "object"
main:2: note: This violates the Liskov substitution principle
main:2: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
main:2: note: It is recommended for "__eq__" to work with arbitrary objects, for example:
main:2: note: def __eq__(self, other: object) -> bool:
main:2: note: if not isinstance(other, A):
Expand Down Expand Up @@ -318,6 +322,8 @@ class C(B): # with gap in implementations
pass
[out]
main:6: error: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "B"
main:6: note: This violates the Liskov substitution principle
main:6: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides

[case testMethodOverridingAcrossDeepInheritanceHierarchy2]
import typing
Expand Down Expand Up @@ -459,7 +465,9 @@ class B(A):
@staticmethod
def f(x: int, y: str) -> None: pass
@staticmethod
def g(x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int"
def g(x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
[builtins fixtures/classmethod.pyi]

[case testOverrideClassMethodWithClassMethod]
Expand All @@ -473,7 +481,9 @@ class B(A):
@classmethod
def f(cls, x: int, y: str) -> None: pass
@classmethod
def g(cls, x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int"
def g(cls, x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
[builtins fixtures/classmethod.pyi]

[case testOverrideClassMethodWithStaticMethod]
Expand All @@ -489,7 +499,9 @@ class B(A):
@staticmethod
def f(x: int) -> None: pass
@staticmethod
def g(x: str) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int"
def g(x: str) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
@staticmethod
def h() -> int: pass
[builtins fixtures/classmethod.pyi]
Expand All @@ -507,7 +519,9 @@ class B(A):
@classmethod
def f(cls, x: int) -> None: pass
@classmethod
def g(cls, x: int) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "str"
def g(cls, x: int) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "str" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
@classmethod
def h(cls) -> int: pass
[builtins fixtures/classmethod.pyi]
Expand Down Expand Up @@ -2478,6 +2492,8 @@ class D(A):
[out]
main:6: error: Return type "A" of "__iadd__" incompatible with return type "B" in "__add__" of supertype "A"
main:8: error: Argument 1 of "__iadd__" is incompatible with "__add__" of supertype "A"; supertype defines the argument type as "A"
main:8: note: This violates the Liskov substitution principle
main:8: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
main:8: error: Signatures of "__iadd__" and "__add__" are incompatible

[case testGetattribute]
Expand Down
4 changes: 3 additions & 1 deletion test-data/unit/check-columns.test
Expand Up @@ -262,7 +262,9 @@ if int():
class A:
def f(self, x: int) -> None: pass
class B(A):
def f(self, x: str) -> None: pass # E:5: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int"
def f(self, x: str) -> None: pass # E:5: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" \
# N:5: This violates the Liskov substitution principle \
# N:5: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
class C(A):
def f(self, x: int) -> int: pass # E:5: Return type "int" of "f" incompatible with return type "None" in supertype "A"
class D(A):
Expand Down
4 changes: 3 additions & 1 deletion test-data/unit/check-dynamic-typing.test
Expand Up @@ -704,7 +704,9 @@ class C:
class B(C):
def f(self, a): pass
class A(B):
def f(self, a: 'D') -> None: # E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "A"
def f(self, a: 'D') -> None: # E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "A" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
pass
class D: pass
[out]
Expand Down
4 changes: 3 additions & 1 deletion test-data/unit/check-errorcodes.test
Expand Up @@ -279,7 +279,9 @@ class D:
def f(self, x: int) -> int:
return 0
class E(D):
def f(self, x: str) -> int: # E: Argument 1 of "f" is incompatible with supertype "D"; supertype defines the argument type as "int" [override]
def f(self, x: str) -> int: # E: Argument 1 of "f" is incompatible with supertype "D"; supertype defines the argument type as "int" [override] \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
return 0

class O:
Expand Down
5 changes: 4 additions & 1 deletion test-data/unit/check-functions.test
Expand Up @@ -46,7 +46,10 @@ class A(object):
def f(self, a: int, b: str) -> None: pass

class B(A):
def f(self, b: str, a: int) -> None: pass # E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" # E: Argument 2 of "f" is incompatible with supertype "A"; supertype defines the argument type as "str"
def f(self, b: str, a: int) -> None: pass # E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides \
# E: Argument 2 of "f" is incompatible with supertype "A"; supertype defines the argument type as "str"

class C(A):
def f(self, foo: int, bar: str) -> None: pass
Expand Down
30 changes: 23 additions & 7 deletions test-data/unit/check-generic-subtyping.test
Expand Up @@ -189,7 +189,9 @@ class C: pass
class D: pass
class A(B[C]):
def f(self, a: D) -> None: pass \
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C"
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
def g(self, a: C) -> None: pass
[out]

Expand All @@ -202,7 +204,9 @@ class B:
def g(self, a: C) -> None: pass
class A(B, Generic[T]):
def f(self, a: T) -> None: pass \
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C"
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
def g(self, a: 'C') -> None: pass
[out]

Expand All @@ -215,7 +219,9 @@ class B(Generic[T]):
def g(self, a: T) -> None: pass
class A(B[S], Generic[T, S]):
def f(self, a: T) -> None: pass \
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "S"
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "S" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
def g(self, a: S) -> None: pass
[out]

Expand All @@ -233,7 +239,9 @@ class C(Generic[T, U, V]):
class B(C[D, D, T], Generic[T]): pass
class A(B[S], Generic[T, S]):
def f(self, a: T) -> None: pass \
# E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "S"
# E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "S" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
def g(self, a: S) -> None: pass
[out]

Expand Down Expand Up @@ -283,6 +291,8 @@ class D(A):
def f(self, x: T1, y: S) -> None: pass # TODO: This error could be more specific.
[out]
main:12: error: Argument 2 of "f" is incompatible with supertype "A"; supertype defines the argument type as "S"
main:12: note: This violates the Liskov substitution principle
main:12: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
main:14: error: Signature of "f" incompatible with supertype "A"


Expand Down Expand Up @@ -538,7 +548,9 @@ class I(Generic[T]):
def g(self, a: T) -> None: pass
class A(I[C]):
def f(self, a: 'D') -> None: pass \
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C"
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
def g(self, a: 'C') -> None: pass
class C: pass
class D: pass
Expand Down Expand Up @@ -570,7 +582,9 @@ class B(I[C]):
def g(self, a: 'C', b: Any) -> None: pass
class A(B):
def g(self, a: 'C', b: 'C') -> None: pass \
# E: Argument 2 of "g" is incompatible with supertype "I"; supertype defines the argument type as "D"
# E: Argument 2 of "g" is incompatible with supertype "I"; supertype defines the argument type as "D" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
def f(self, a: 'C', b: 'C') -> None: pass
class C: pass
class D: pass
Expand All @@ -587,7 +601,9 @@ class B(I[C]):
def f(self, a: 'C', b: Any) -> None: pass
class A(B):
def f(self, a: 'C', b: 'D') -> None: pass \
# E: Argument 2 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C"
# E: Argument 2 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C" \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
class C: pass
class D: pass
[out]
Expand Down
2 changes: 2 additions & 0 deletions test-data/unit/check-multiple-inheritance.test
Expand Up @@ -539,6 +539,8 @@ class IntFlag(int, Flag):
def __or__(self: _T, other: str) -> _T: ...
[out]
main:8: error: Argument 1 of "__or__" is incompatible with supertype "Flag"; supertype defines the argument type as "IntFlag"
main:8: note: This violates the Liskov substitution principle
main:8: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides

[case testMultipleInheritance_MethodDefinitionsCompatibleNoOverride]
from typing import TypeVar, Union
Expand Down