From 405c2728a4927a17451bbe9040c5271b41bd0cc4 Mon Sep 17 00:00:00 2001 From: Richard Si Date: Mon, 16 Jan 2023 20:16:30 -0500 Subject: [PATCH] [mypyc] Raise "non-trait base must be first..." error less frequently It would raise even if there were only non-trait bases, leading to this slightly confusing situation: class A: pass class B: pass class C(A, B): pass # E: Non-trait bases must appear first in parent list # E: Multiple inheritance is not supported (except for traits) Now the bases must include a non-trait *and* the first base must be a trait to error. This leads to some false-negative when there's more than one non-trait base, but in that case, it's better to only tell the user multiple inheritance is not supported. --- mypyc/irbuild/prepare.py | 8 ++++++-- mypyc/test-data/commandline.test | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index eb8288b84818..3800137a3f55 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -256,8 +256,12 @@ def prepare_class_def( # Set up the parent class bases = [mapper.type_to_ir[base.type] for base in info.bases if base.type in mapper.type_to_ir] - if not all(c.is_trait for c in bases[1:]): - errors.error("Non-trait bases must appear first in parent list", path, cdef.line) + if len(bases) > 1 and any(not c.is_trait for c in bases) and bases[0].is_trait: + # If the first base is a non-trait, don't ever error here. While it is correct + # to error if a trait comes before the next non-trait base (e.g. non-trait, trait, + # non-trait), it's pointless, confusing noise from the bigger issue: multiple + # inheritance is *not* supported. + errors.error("Non-trait base must appear first in parent list", path, cdef.line) ir.traits = [c for c in bases if c.is_trait] mro = [] # All mypyc base classes diff --git a/mypyc/test-data/commandline.test b/mypyc/test-data/commandline.test index bc2713a20f7d..1ba4b2f4aa04 100644 --- a/mypyc/test-data/commandline.test +++ b/mypyc/test-data/commandline.test @@ -150,7 +150,7 @@ class PureTrait: pass @trait -class Trait1(Concrete1): +class Trait1: pass class Concrete2: @@ -164,9 +164,23 @@ class Trait2(Concrete2): class NonExt(Concrete1): # E: Non-extension classes may not inherit from extension classes pass -class Nope(Trait1, Concrete2): # E: Non-trait bases must appear first in parent list # E: Multiple inheritance is not supported (except for traits) + +class NopeMultipleInheritance(Concrete1, Concrete2): # E: Multiple inheritance is not supported (except for traits) + pass + +class NopeMultipleInheritanceAndBadOrder(Concrete1, Trait1, Concrete2): # E: Multiple inheritance is not supported (except for traits) + pass + +class NopeMultipleInheritanceAndBadOrder2(Concrete1, Concrete2, Trait1): # E: Multiple inheritance is not supported (except for traits) pass +class NopeMultipleInheritanceAndBadOrder3(Trait1, Concrete1, Concrete2): # E: Non-trait base must appear first in parent list # E: Multiple inheritance is not supported (except for traits) + pass + +class NopeBadOrder(Trait1, Concrete2): # E: Non-trait base must appear first in parent list + pass + + @decorator class NonExt2: @property # E: Property setters not supported in non-extension classes