Skip to content

Commit 52284b1

Browse files
committed
add support for two nested classes with the same name in multiple inheritance, better error message
1 parent 4871ddb commit 52284b1

File tree

2 files changed

+50
-6
lines changed

2 files changed

+50
-6
lines changed

mypy/checker.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,16 @@ def check_multiple_inheritance(self, typ: TypeInfo) -> None:
16051605
if name in base2.names and base2 not in base.mro:
16061606
self.check_compatibility(name, base, base2, typ)
16071607

1608+
def _determine_type_of_class_member(self, sym: SymbolTableNode) -> Optional[Type]:
1609+
if sym.type is not None:
1610+
return sym.type
1611+
if isinstance(sym.node, FuncBase):
1612+
return self.function_type(sym.node)
1613+
if isinstance(sym.node, TypeInfo):
1614+
# nested class
1615+
return type_object_type(sym.node, self.named_type)
1616+
return None
1617+
16081618
def check_compatibility(self, name: str, base1: TypeInfo,
16091619
base2: TypeInfo, ctx: Context) -> None:
16101620
"""Check if attribute name in base1 is compatible with base2 in multiple inheritance.
@@ -1618,12 +1628,12 @@ def check_compatibility(self, name: str, base1: TypeInfo,
16181628
return
16191629
first = base1[name]
16201630
second = base2[name]
1621-
first_type = first.type
1622-
if first_type is None and isinstance(first.node, FuncBase):
1623-
first_type = self.function_type(first.node)
1624-
second_type = second.type
1625-
if second_type is None and isinstance(second.node, FuncBase):
1626-
second_type = self.function_type(second.node)
1631+
if isinstance(first.node, TypeInfo) and isinstance(second.node, TypeInfo):
1632+
# allow nested classes with the same name
1633+
return
1634+
first_type = self._determine_type_of_class_member(first)
1635+
second_type = self._determine_type_of_class_member(second)
1636+
16271637
# TODO: What if some classes are generic?
16281638
if (isinstance(first_type, FunctionLike) and
16291639
isinstance(second_type, FunctionLike)):

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,37 @@ def dec(f: Callable[..., T]) -> Callable[..., T]:
240240
[out]
241241
main:3: error: Cannot determine type of 'f' in base class 'B'
242242
main:3: error: Cannot determine type of 'f' in base class 'C'
243+
244+
[case testMultipleInheritanceNestedClassesWithSameNameAllowed]
245+
class Mixin1:
246+
class Meta:
247+
pass
248+
class Mixin2:
249+
class Meta:
250+
pass
251+
class A(Mixin1, Mixin2):
252+
pass
253+
[out]
254+
255+
[case testMultipleInheritanceFailIfNestedClassAndAttrHaveSameName]
256+
class Mixin1:
257+
class Nested1:
258+
pass
259+
class Mixin2:
260+
Nested1: str
261+
class A(Mixin1, Mixin2):
262+
pass
263+
[out]
264+
main:6: error: Definition of "Nested1" in base class "Mixin1" is incompatible with definition in base class "Mixin2"
265+
266+
[case testMultipleInheritanceFailIfNestedClassAndFunctionHaveSameName]
267+
class Mixin1:
268+
class Nested1:
269+
pass
270+
class Mixin2:
271+
def Nested1(self) -> str:
272+
pass
273+
class A(Mixin1, Mixin2):
274+
pass
275+
[out]
276+
main:7: error: Definition of "Nested1" in base class "Mixin1" is incompatible with definition in base class "Mixin2"

0 commit comments

Comments
 (0)