mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Join computed suboptimally with multiple inheritance

Open gvanrossum opened this issue 8 years ago • 6 comments

class Base:
    def foo(self): pass

class Mix: pass

class A(Mix, Base): pass

class B(Mix, Base): pass

def foo() -> None:
    a = [A(), B()]
    reveal_type(a)  # Shows Mix
    a.foo()  # E: "Mix" has no attribute "foo"

Could we do something better here? Ideally the inferred type of a should be an anonymous subclass of Mix and Base.

gvanrossum avatar Dec 15 '17 21:12 gvanrossum

Note that this can't be fixed by adding an annotation for a -- neither annotating it as Union[A, B] nor Base helps. (Basically you have to use a cast or rework the inheritance pattern.)

gvanrossum avatar Dec 15 '17 22:12 gvanrossum

I think this is another symptom of https://github.com/python/mypy/issues/3257

ilevkivskyi avatar Dec 15 '17 22:12 ilevkivskyi

Also this is yet another reason to have intersections.

ilevkivskyi avatar Dec 15 '17 22:12 ilevkivskyi

(modified the example to force the join given #17427 )

hauntsaninja avatar Jul 03 '24 07:07 hauntsaninja

Another example, distilled from mypy-primer output on python/typeshed#12740:

class A: pass
class B: pass
class C: pass

class Cls1(A, B, C): pass
class Cls2(A, B, C): pass

def func(cond: bool, c1: Cls1, c2: Cls2) -> None:
    a: A = c1 if cond else c2
    b: B = c1 if cond else c2  # error
    c: C = c1 if cond else c2  # error
    print(a, b, c)

JelleZijlstra avatar Oct 06 '24 21:10 JelleZijlstra

I think mypy latest no longer joins for ternary, so the specific primer hit should go away when 1.12 is released

hauntsaninja avatar Oct 06 '24 21:10 hauntsaninja