Skip to content

Commit 0a72409

Browse files
Merge pull request RustPython#187 from RustPython/oo_fixes
Oo fixes
2 parents 0199137 + ff4e8da commit 0a72409

File tree

3 files changed

+71
-24
lines changed

3 files changed

+71
-24
lines changed

tests/snippets/derived_mc.py

+45
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

+17-14
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,13 @@ fn builtin_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
459459

460460
pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
461461
trace!("print called with {:?}", args);
462+
let mut first = true;
462463
for a in args.args {
464+
if first {
465+
first = false;
466+
} else {
467+
print!(" ");
468+
}
463469
let v = vm.to_str(&a)?;
464470
let s = objstr::get_value(&v);
465471
print!("{}", s);
@@ -638,10 +644,17 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
638644
pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
639645
let function = args.shift();
640646
let name_arg = args.shift();
641-
let mut bases = args.args.clone();
642-
let metaclass = args.get_kwarg("metaclass", vm.get_type());
647+
let bases = args.args.clone();
648+
let mut metaclass = args.get_kwarg("metaclass", vm.get_type());
649+
650+
for base in bases.clone() {
651+
if objtype::issubclass(&base.typ(), &metaclass) {
652+
metaclass = base.typ();
653+
} else if !objtype::issubclass(&metaclass, &base.typ()) {
654+
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()));
655+
}
656+
}
643657

644-
bases.push(vm.context().object());
645658
let bases = vm.context().new_tuple(bases);
646659

647660
// Prepare uses full __getattribute__ resolution chain.
@@ -663,15 +676,5 @@ pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> Py
663676
},
664677
);
665678

666-
// Special case: __new__ must be looked up on the metaclass, not the meta-metaclass as
667-
// per vm.call(metaclass, "__new__", ...)
668-
let new = metaclass.get_attr("__new__").unwrap();
669-
let wrapped = vm.call_get_descriptor(new, metaclass)?;
670-
vm.invoke(
671-
wrapped,
672-
PyFuncArgs {
673-
args: vec![name_arg, bases, namespace],
674-
kwargs: vec![],
675-
},
676-
)
679+
vm.call_method(&metaclass, "__call__", vec![name_arg, bases, namespace])
677680
}

vm/src/obj/objtype.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,15 @@ pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
115115

116116
pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
117117
debug!("type_call: {:?}", args);
118-
let typ = args.shift();
119-
let new = typ.get_attr("__new__").unwrap();
120-
let obj = vm.invoke(new, args.insert(typ.clone()))?;
121-
122-
if let Some(init) = obj.typ().get_attr("__init__") {
123-
let res = vm.invoke(init, args.insert(obj.clone()))?;
124-
// TODO: assert that return is none?
125-
if !isinstance(&res, &vm.get_none()) {
126-
// panic!("__init__ must return none");
127-
// return Err(vm.new_type_error("__init__ must return None".to_string()));
118+
let cls = args.shift();
119+
let new = cls.get_attr("__new__").unwrap();
120+
let new_wrapped = vm.call_get_descriptor(new, cls)?;
121+
let obj = vm.invoke(new_wrapped, args.clone())?;
122+
123+
if let Ok(init) = vm.get_method(obj.clone(), "__init__") {
124+
let res = vm.invoke(init, args)?;
125+
if !res.is(&vm.get_none()) {
126+
return Err(vm.new_type_error("__init__ must return None".to_string()));
128127
}
129128
}
130129
Ok(obj)

0 commit comments

Comments
 (0)