From 27f51fc667e9ceaba12496276fce1db577221bcb Mon Sep 17 00:00:00 2001 From: Richard Si Date: Sun, 5 Feb 2023 06:09:56 -0500 Subject: [PATCH] [mypyc] Raise "non-trait base must be first..." error less frequently (#14468) 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-negatives when there's more than one non-trait base, but in that case, it's better to only tell the user that multiple inheritance is not supported. See also: https://github.com/mypyc/mypyc/issues/826#issuecomment-1383215915 --- 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 48a37de518b7..b3d10887ce21 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -275,8 +275,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 e7ba11192d28..672e879fbe1e 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