Skip to content

Commit bcdb208

Browse files
committed
Add logic for inheriting metaclass from bases.
1 parent 63c4f3b commit bcdb208

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

tests/snippets/derived_mc.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
class MC(type):
2+
pass
3+
4+
class MC2(MC):
5+
pass
6+
7+
class MC3(type):
8+
pass
9+
10+
class A():
11+
pass
12+
13+
assert type(A) == type
14+
15+
class B(metaclass=MC):
16+
pass
17+
18+
assert type(B) == MC
19+
20+
class C(B):
21+
pass
22+
23+
assert type(C) == MC
24+
25+
class D(metaclass=MC2):
26+
pass
27+
28+
assert type(D) == MC2
29+
30+
class E(C, D, metaclass=MC):
31+
pass
32+
33+
assert type(E) == MC2
34+
35+
class F(metaclass=MC3):
36+
pass
37+
38+
assert type(F) == MC3
39+
40+
try:
41+
class G(D, E, F):
42+
pass
43+
assert False
44+
except TypeError:
45+
pass

vm/src/builtins.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,15 @@ pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> Py
638638
let function = args.shift();
639639
let name_arg = args.shift();
640640
let bases = args.args.clone();
641-
let metaclass = args.get_kwarg("metaclass", vm.get_type());
641+
let mut metaclass = args.get_kwarg("metaclass", vm.get_type());
642+
643+
for base in bases.clone() {
644+
if objtype::issubclass(&base.typ(), &metaclass) {
645+
metaclass = base.typ();
646+
} else if !objtype::issubclass(&metaclass, &base.typ()) {
647+
return Err(vm.new_type_error("metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases".to_string()));
648+
}
649+
}
642650

643651
let namespace = vm.new_dict();
644652
&vm.invoke(

0 commit comments

Comments
 (0)