From 8c949d92829e6f78e12e3436416d02cd1aaca6b6 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Mon, 21 Dec 2015 16:41:12 -0800 Subject: [PATCH] Ban diamond inheritance of generic base classes Fixes #1065. --- mypy/maptype.py | 2 ++ mypy/semanal.py | 3 +++ .../test/data/check-multiple-inheritance.test | 27 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/mypy/maptype.py b/mypy/maptype.py index 5eb6a0d92c310..6b31e549e2391 100644 --- a/mypy/maptype.py +++ b/mypy/maptype.py @@ -50,6 +50,8 @@ def class_derivation_paths(typ: TypeInfo, """ # FIX: Currently we might only ever have a single path, so this could be # simplified + # TODO(gregprice): Not actually true! But all paths are equivalent for + # this module's purposes. result = [] # type: List[List[TypeInfo]] for base in typ.bases: diff --git a/mypy/semanal.py b/mypy/semanal.py index 7cc2bdd042e7e..ae38be9002c40 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -731,6 +731,9 @@ def verify_base_classes(self, defn: ClassDef) -> bool: info.bases = [] return False # ??? for base in nxt.bases: + if base.type in visited and len(base.type.type_vars) > 0: + self.fail('Diamond inheritance of generic base class "%s"' + % base.type.name(), defn) if base.type not in visited: worklist.append(base.type) visited.add(base.type) diff --git a/mypy/test/data/check-multiple-inheritance.test b/mypy/test/data/check-multiple-inheritance.test index 189d50cfc23e2..8260a747ead45 100644 --- a/mypy/test/data/check-multiple-inheritance.test +++ b/mypy/test/data/check-multiple-inheritance.test @@ -219,6 +219,33 @@ main: note: In class "D": main:8: error: Definition of "clear" in base class "A" is incompatible with definition in base class "B" +-- Diamond inheritance hierarchies +-- ------------------------------- + + +[case testDiamondPlain] +class A: pass +class B(A): pass +class C(A): pass +class D(B, C): pass + +a = None # type: A +d = None # type: D +a = d + +[case testDiamondGeneric] +from typing import TypeVar, Generic +T = TypeVar('T') +class A(Generic[T]): pass +class B(Generic[T], A[T]): pass +class C(Generic[T], A[T]): pass +class D(Generic[T], B[T], C[T]): pass # E: Diamond inheritance of generic base class "A" + +a = None # type: A[int] +d = None # type: D[int] +a = d + + -- Special cases -- -------------