From 50cc9fa91f9640e0b7b97c39643ab62576936c39 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Mon, 18 Mar 2019 21:56:54 +0200 Subject: [PATCH 1/2] super works in class methods --- tests/snippets/class.py | 26 +++++++++++++++++---- vm/src/obj/objsuper.rs | 51 +++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/tests/snippets/class.py b/tests/snippets/class.py index ba2d423ea..42144d720 100644 --- a/tests/snippets/class.py +++ b/tests/snippets/class.py @@ -50,12 +50,30 @@ class Bar2(Bar): def __init__(self): super().__init__(101) +bar2 = Bar2() +assert bar2.get_x() == 101 -# TODO: make this work: -# bar2 = Bar2() -# assert bar2.get_x() == 101 +class A(): + def test(self): + return 100 -a = super(int, 2) +class B(): + def test1(self): + return 200 + +class C(A,B): + def test(self): + return super().test() + + def test1(self): + return super().test1() + +c = C() +assert c.test() == 100 +assert c.test1() == 200 + +a = super(bool, True) assert isinstance(a, super) assert type(a) is super +assert a.conjugate() == 1 diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index a3d877e14..46ac5628a 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -7,7 +7,8 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/ */ use crate::function::PyFuncArgs; -use crate::pyobject::{PyContext, PyResult, TypeProtocol}; +use crate::obj::objtype::PyClass; +use crate::pyobject::{DictProtocol, PyContext, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; use super::objtype; @@ -30,6 +31,11 @@ pub fn init(context: &PyContext) { super().cmeth(arg)\n"; context.set_attr(&super_type, "__init__", context.new_rustfunc(super_init)); + context.set_attr( + &super_type, + "__getattribute__", + context.new_rustfunc(super_getattribute), + ); context.set_attr( &super_type, "__doc__", @@ -37,6 +43,33 @@ pub fn init(context: &PyContext) { ); } +fn super_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [ + (obj, Some(vm.ctx.object())), + (name_str, Some(vm.ctx.str_type())) + ] + ); + + match vm.ctx.get_attr(obj, "obj") { + Some(inst) => match inst.typ().payload::() { + Some(PyClass { ref mro, .. }) => { + for class in mro { + if let Ok(item) = vm.get_attribute(class.as_object().clone(), name_str.clone()) + { + return Ok(vm.ctx.new_bound_method(item, inst.clone())); + } + } + Err(vm.new_attribute_error(format!("{} has no attribute '{}'", inst, name_str))) + } + _ => panic!("not Class"), + }, + None => panic!("No obj"), + } +} + fn super_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("super.__init__ {:?}", args.args); arg_check!( @@ -50,11 +83,10 @@ fn super_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let py_type = if let Some(ty) = py_type { ty.clone() } else { - // TODO: implement complex logic here.... - unimplemented!("TODO: get frame and determine instance and class?"); - // let frame = vm.get_current_frame(); - // - // vm.get_none() + match vm.get_locals().get_item("self") { + Some(obj) => obj.typ().clone(), + _ => panic!("No self"), + } }; // Check type argument: @@ -70,7 +102,10 @@ fn super_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let py_obj = if let Some(obj) = py_obj { obj.clone() } else { - vm.get_none() + match vm.get_locals().get_item("self") { + Some(obj) => obj, + _ => panic!("No self"), + } }; // Check obj type: @@ -80,8 +115,6 @@ fn super_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { )); } - // TODO: how to store those types? - vm.ctx.set_attr(inst, "type", py_type); vm.ctx.set_attr(inst, "obj", py_obj); Ok(vm.get_none()) From c3d0fddfcf556b46152fbbb45632c23648786d91 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Tue, 19 Mar 2019 18:00:43 +0200 Subject: [PATCH 2/2] Add PySuper --- vm/src/obj/objsuper.rs | 55 ++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index 46ac5628a..594624213 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -8,11 +8,24 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/ use crate::function::PyFuncArgs; use crate::obj::objtype::PyClass; -use crate::pyobject::{DictProtocol, PyContext, PyResult, TypeProtocol}; +use crate::pyobject::{ + DictProtocol, PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol, +}; use crate::vm::VirtualMachine; use super::objtype; +#[derive(Debug)] +pub struct PySuper { + obj: PyObjectRef, +} + +impl PyValue for PySuper { + fn class(vm: &mut VirtualMachine) -> PyObjectRef { + vm.ctx.super_type() + } +} + pub fn init(context: &PyContext) { let super_type = &context.super_type; @@ -30,7 +43,7 @@ pub fn init(context: &PyContext) { def cmeth(cls, arg):\n \ super().cmeth(arg)\n"; - context.set_attr(&super_type, "__init__", context.new_rustfunc(super_init)); + context.set_attr(&super_type, "__new__", context.new_rustfunc(super_new)); context.set_attr( &super_type, "__getattribute__", @@ -48,37 +61,39 @@ fn super_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { vm, args, required = [ - (obj, Some(vm.ctx.object())), + (super_obj, Some(vm.ctx.super_type())), (name_str, Some(vm.ctx.str_type())) ] ); - match vm.ctx.get_attr(obj, "obj") { - Some(inst) => match inst.typ().payload::() { - Some(PyClass { ref mro, .. }) => { - for class in mro { - if let Ok(item) = vm.get_attribute(class.as_object().clone(), name_str.clone()) - { - return Ok(vm.ctx.new_bound_method(item, inst.clone())); - } + let inst = super_obj.payload::().unwrap().obj.clone(); + + match inst.typ().payload::() { + Some(PyClass { ref mro, .. }) => { + for class in mro { + if let Ok(item) = vm.get_attribute(class.as_object().clone(), name_str.clone()) { + return Ok(vm.ctx.new_bound_method(item, inst.clone())); } - Err(vm.new_attribute_error(format!("{} has no attribute '{}'", inst, name_str))) } - _ => panic!("not Class"), - }, - None => panic!("No obj"), + Err(vm.new_attribute_error(format!("{} has no attribute '{}'", inst, name_str))) + } + _ => panic!("not Class"), } } -fn super_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - trace!("super.__init__ {:?}", args.args); +fn super_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + trace!("super.__new__ {:?}", args.args); arg_check!( vm, args, - required = [(inst, None)], + required = [(cls, None)], optional = [(py_type, None), (py_obj, None)] ); + if !objtype::issubclass(cls, &vm.ctx.super_type()) { + return Err(vm.new_type_error(format!("{:?} is not a subtype of super", cls))); + } + // Get the type: let py_type = if let Some(ty) = py_type { ty.clone() @@ -115,7 +130,5 @@ fn super_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { )); } - vm.ctx.set_attr(inst, "obj", py_obj); - - Ok(vm.get_none()) + Ok(PyObject::new(PySuper { obj: py_obj }, cls.clone())) }