-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
[overload][intersection-types] undetected LSP violation in multiple inheritance #15790
Comments
… base classes that are combined using multiple inheritance implement the same method in an incompatible way. The bug caused the check to be skipped if the child class also implemented the same method as the two base classes. This addresses python/mypy#15790.
… base classes that are combined using multiple inheritance implement the same method in an incompatible way. The bug caused the check to be skipped if the child class also implemented the same method as the two base classes. This addresses python/mypy#15790. (#5617) Co-authored-by: Eric Traut <erictr@microsoft.com>
I don't think this is a bug. A subclass defined this way is replaceably usable with each parent class. There is ongoing discussion about this in the intersection pep, this may be prematurely calling something a bug |
Here is an example where it can clearly be used as a drop in replacement for either base: class ParamA:
...
class ParamB:
...
class ParamAB(ParamA, ParamB):
...
class A:
def foo(self, x: ParamA) -> ParamA:
...
class B:
def foo(self, x: ParamB) -> ParamB:
...
class AB(A, B):
@overload
def foo(self, x: ParamA) -> ParamA:
...
@overload
def foo(self, x: ParamB) -> ParamB:
...
def foo(self, x):
if isinstance(x, ParamA):
if isinstance(x, ParamB):
raise RuntimeError("Ambiguous use")
return ParamA()
else:
return ParamB() |
There is disucssion about the soundness of this and the need for |
Copying the relevant comment portion: (note & for Intersection, ~ for Not) a more expressive overload set for AB.foo would be (overload) (ParamA & ParamB) -> Never But if someone had an implementation that was (overload) (ParamA & ParamB) -> ParamA & ParamB it would also be valid. As we don't currently have a way to express this, this should not be treated as incorrect, as it is possible to implement both of the behaviors the overload sets express. |
…ther two base classes that are combined using multiple inheritance implement the same method in an incompatible way. The bug caused the check to be skipped if the child class also implemented the same method as the two base classes. This addresses python/mypy#15790. (#5617)" This reverts commit fb56dcc.
Bug Report
Essentially, the bug occurs when trying to define a subclass of
C≤A&B
, and implementing a shared method via@overload
:C
is not a proper subclass ofA & B
sinceC.foo(Hashable & Sized)
yieldsHashable
, violating LSP forB
.mypy
does not detect this issue. To resolve this, an extra overload of the formdef foo(x: Hashable & Sized) -> ...
is needed.To Reproduce
A concrete demo with non-trivial types.
This file parses even using
--strict
without raising any warnings/errors. (mypy-playground)However, the inconsistency becomes obvious as
c.foo(<tuple>)
reveals asint
, which is incompatible withb.foo(<tuple>)
.Expected Behavior
Are not type-safe overloads to satisfy LSP for both superclasses. Mypy should notice this and issue a warning. Likely, to solve this issue in a satisfactory manner, intersection-types are needed (python/typing#213).
The text was updated successfully, but these errors were encountered: