Skip to content

Commit 27f51fc

Browse files
authored
[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: mypyc/mypyc#826 (comment)
1 parent 332bb2d commit 27f51fc

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

mypyc/irbuild/prepare.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,12 @@ def prepare_class_def(
275275

276276
# Set up the parent class
277277
bases = [mapper.type_to_ir[base.type] for base in info.bases if base.type in mapper.type_to_ir]
278-
if not all(c.is_trait for c in bases[1:]):
279-
errors.error("Non-trait bases must appear first in parent list", path, cdef.line)
278+
if len(bases) > 1 and any(not c.is_trait for c in bases) and bases[0].is_trait:
279+
# If the first base is a non-trait, don't ever error here. While it is correct
280+
# to error if a trait comes before the next non-trait base (e.g. non-trait, trait,
281+
# non-trait), it's pointless, confusing noise from the bigger issue: multiple
282+
# inheritance is *not* supported.
283+
errors.error("Non-trait base must appear first in parent list", path, cdef.line)
280284
ir.traits = [c for c in bases if c.is_trait]
281285

282286
mro = [] # All mypyc base classes

mypyc/test-data/commandline.test

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class PureTrait:
150150
pass
151151

152152
@trait
153-
class Trait1(Concrete1):
153+
class Trait1:
154154
pass
155155

156156
class Concrete2:
@@ -164,9 +164,23 @@ class Trait2(Concrete2):
164164
class NonExt(Concrete1): # E: Non-extension classes may not inherit from extension classes
165165
pass
166166

167-
class Nope(Trait1, Concrete2): # E: Non-trait bases must appear first in parent list # E: Multiple inheritance is not supported (except for traits)
167+
168+
class NopeMultipleInheritance(Concrete1, Concrete2): # E: Multiple inheritance is not supported (except for traits)
169+
pass
170+
171+
class NopeMultipleInheritanceAndBadOrder(Concrete1, Trait1, Concrete2): # E: Multiple inheritance is not supported (except for traits)
172+
pass
173+
174+
class NopeMultipleInheritanceAndBadOrder2(Concrete1, Concrete2, Trait1): # E: Multiple inheritance is not supported (except for traits)
168175
pass
169176

177+
class NopeMultipleInheritanceAndBadOrder3(Trait1, Concrete1, Concrete2): # E: Non-trait base must appear first in parent list # E: Multiple inheritance is not supported (except for traits)
178+
pass
179+
180+
class NopeBadOrder(Trait1, Concrete2): # E: Non-trait base must appear first in parent list
181+
pass
182+
183+
170184
@decorator
171185
class NonExt2:
172186
@property # E: Property setters not supported in non-extension classes

0 commit comments

Comments
 (0)