Skip to content

Commit f04fd93

Browse files
committed
Only compare the most derived base defining name with all others - following bases needn't be compatible
1 parent e8ccf89 commit f04fd93

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

mypy/checker.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2733,19 +2733,19 @@ def check_multiple_inheritance(self, typ: TypeInfo) -> None:
27332733
return
27342734
# Verify that inherited attributes are compatible.
27352735
mro = typ.mro[1:]
2736-
for i, base in enumerate(mro):
2736+
all_names = {name for base in mro for name in base.names}
2737+
for name in all_names - typ.names.keys():
27372738
# Attributes defined in both the type and base are skipped.
27382739
# Normal checks for attribute compatibility should catch any problems elsewhere.
2739-
non_overridden_attrs = base.names.keys() - typ.names.keys()
2740-
for name in non_overridden_attrs:
2741-
if is_private(name):
2742-
continue
2743-
for base2 in mro[i + 1 :]:
2744-
# We only need to check compatibility of attributes from classes not
2745-
# in a subclass relationship. For subclasses, normal (single inheritance)
2746-
# checks suffice (these are implemented elsewhere).
2747-
if name in base2.names and base2 not in base.mro:
2748-
self.check_compatibility(name, base, base2, typ)
2740+
if is_private(name):
2741+
continue
2742+
# Compare the first base defining a name with the rest.
2743+
# Remaining bases may not be pairwise compatible as the first base provides
2744+
# the used definition.
2745+
i, base = next((i, base) for i, base in enumerate(mro) if name in base.names)
2746+
for base2 in mro[i + 1 :]:
2747+
if name in base2.names and base2 not in base.mro:
2748+
self.check_compatibility(name, base, base2, typ)
27492749

27502750
def determine_type_of_member(self, sym: SymbolTableNode) -> Type | None:
27512751
if sym.type is not None:

test-data/unit/check-multiple-inheritance.test

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,3 +706,29 @@ class C34(B3, B4): ...
706706
class C41(B4, B1): ...
707707
class C42(B4, B2): ...
708708
class C43(B4, B3): ...
709+
710+
[case testMultipleInheritanceExplcitDiamondResolution]
711+
# Adapted from #14279
712+
class A:
713+
class M:
714+
pass
715+
716+
class B0(A):
717+
class M(A.M):
718+
pass
719+
720+
class B1(A):
721+
class M(A.M):
722+
pass
723+
724+
class C(B0,B1):
725+
class M(B0.M, B1.M):
726+
pass
727+
728+
class D0(B0):
729+
pass
730+
class D1(B1):
731+
pass
732+
733+
class D(D0,D1,C):
734+
pass

0 commit comments

Comments
 (0)