From 9d03abf652dca9f1606121570a82d63527b458c2 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 7 Mar 2019 20:05:32 +1300 Subject: [PATCH 1/4] Move __class__ attribute to object to make it work in more situations --- tests/snippets/types_snippet.py | 9 +++++++++ vm/src/obj/objfunction.rs | 34 +++++++++++++++++++++++++++++++++ vm/src/obj/objobject.rs | 20 +++++++++++++++++++ vm/src/obj/objtype.rs | 5 ----- vm/src/pyobject.rs | 22 +++++++++++++++++++++ 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/tests/snippets/types_snippet.py b/tests/snippets/types_snippet.py index 3fc27b71c0..ac715751ef 100644 --- a/tests/snippets/types_snippet.py +++ b/tests/snippets/types_snippet.py @@ -15,5 +15,14 @@ assert type(cls) is metaclass assert type(metaclass) is type +assert issubclass(metaclass, type) +assert isinstance(cls, type) + +assert inst.__class__ is cls +assert cls.__class__ is metaclass +assert metaclass.__class__ is type +assert type.__class__ is type +assert None.__class__ is type(None) + assert isinstance(type, type) assert issubclass(type, type) diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index a2092c308f..82c06fac63 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -27,6 +27,18 @@ pub fn init(context: &PyContext) { context.new_rustfunc(member_get), ); + let data_descriptor_type = &context.data_descriptor_type; + context.set_attr( + &data_descriptor_type, + "__get__", + context.new_rustfunc(data_get), + ); + context.set_attr( + &data_descriptor_type, + "__set__", + context.new_rustfunc(data_set), + ); + let classmethod_type = &context.classmethod_type; context.set_attr( &classmethod_type, @@ -83,6 +95,28 @@ fn member_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { } } +fn data_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { + match args.shift().get_attr("fget") { + Some(function) => vm.invoke(function, args), + None => { + println!("A"); + let attribute_error = vm.context().exceptions.attribute_error.clone(); + Err(vm.new_exception(attribute_error, String::from("Attribute Error"))) + } + } +} + +fn data_set(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { + match args.shift().get_attr("fset") { + Some(function) => vm.invoke(function, args), + None => { + println!("B"); + let attribute_error = vm.context().exceptions.attribute_error.clone(); + Err(vm.new_exception(attribute_error, String::from("Attribute Error"))) + } + } +} + // Classmethod type methods: fn classmethod_get(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("classmethod.__get__ {:?}", args.args); diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index a387028cbb..99df1f28dd 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -161,6 +161,11 @@ pub fn init(context: &PyContext) { context.set_attr(&object, "__new__", context.new_rustfunc(new_instance)); context.set_attr(&object, "__init__", context.new_rustfunc(object_init)); + context.set_attr( + &object, + "__class__", + context.new_data_descriptor(object_class, object_class_setter), + ); context.set_attr(&object, "__eq__", context.new_rustfunc(object_eq)); context.set_attr(&object, "__ne__", context.new_rustfunc(object_ne)); context.set_attr(&object, "__lt__", context.new_rustfunc(object_lt)); @@ -190,6 +195,21 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { Ok(vm.ctx.none()) } +fn object_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(_obj, None), (owner, Some(vm.ctx.type_type()))] + ); + Ok(owner.clone()) +} + +fn object_class_setter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(instance, None), (_value, None)]); + let type_repr = vm.to_pystr(&instance.typ())?; + Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr))) +} + fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { match args.args[0].payload { PyObjectPayload::Class { ref dict, .. } | PyObjectPayload::Instance { ref dict, .. } => { diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index b30c77226d..dfe11510bc 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -39,11 +39,6 @@ pub fn init(context: &PyContext) { "__mro__", context.new_member_descriptor(type_mro), ); - context.set_attr( - &type_type, - "__class__", - context.new_member_descriptor(type_new), - ); context.set_attr(&type_type, "__repr__", context.new_rustfunc(type_repr)); context.set_attr( &type_type, diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 6a618cd7b6..34a27548f5 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -150,6 +150,7 @@ pub struct PyContext { pub module_type: PyObjectRef, pub bound_method_type: PyObjectRef, pub member_descriptor_type: PyObjectRef, + pub data_descriptor_type: PyObjectRef, pub object: PyObjectRef, pub exceptions: exceptions::ExceptionZoo, } @@ -199,6 +200,8 @@ impl PyContext { let bound_method_type = create_type("method", &type_type, &object_type, &dict_type); let member_descriptor_type = create_type("member_descriptor", &type_type, &object_type, &dict_type); + let data_descriptor_type = + create_type("data_descriptor", &type_type, &object_type, &dict_type); let str_type = create_type("str", &type_type, &object_type, &dict_type); let list_type = create_type("list", &type_type, &object_type, &dict_type); let set_type = create_type("set", &type_type, &object_type, &dict_type); @@ -285,6 +288,7 @@ impl PyContext { module_type, bound_method_type, member_descriptor_type, + data_descriptor_type, type_type, exceptions, }; @@ -449,6 +453,10 @@ impl PyContext { pub fn member_descriptor_type(&self) -> PyObjectRef { self.member_descriptor_type.clone() } + pub fn data_descriptor_type(&self) -> PyObjectRef { + self.data_descriptor_type.clone() + } + pub fn type_type(&self) -> PyObjectRef { self.type_type.clone() } @@ -658,6 +666,20 @@ impl PyContext { self.new_instance(self.member_descriptor_type(), Some(dict)) } + pub fn new_data_descriptor< + G: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult, + S: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult, + >( + &self, + getter: G, + setter: S, + ) -> PyObjectRef { + let mut dict = PyAttributes::new(); + dict.insert("fget".to_string(), self.new_rustfunc(getter)); + dict.insert("fset".to_string(), self.new_rustfunc(setter)); + self.new_instance(self.data_descriptor_type(), Some(dict)) + } + pub fn new_instance(&self, class: PyObjectRef, dict: Option) -> PyObjectRef { let dict = if let Some(dict) = dict { dict From 720bec2f4f480b8520736b7c5a95fa4b406855a9 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 7 Mar 2019 20:46:07 +1300 Subject: [PATCH 2/4] Convert __class__ descriptor to use new style functions --- vm/src/obj/objobject.rs | 16 +++++++--------- vm/src/pyobject.rs | 6 ++++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 99df1f28dd..6b01fd662d 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -195,17 +195,15 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { Ok(vm.ctx.none()) } -fn object_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [(_obj, None), (owner, Some(vm.ctx.type_type()))] - ); - Ok(owner.clone()) +fn object_class(_obj: PyObjectRef, owner: PyObjectRef, _vm: &mut VirtualMachine) -> PyObjectRef { + owner } -fn object_class_setter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(instance, None), (_value, None)]); +fn object_class_setter( + instance: PyObjectRef, + _value: PyObjectRef, + vm: &mut VirtualMachine, +) -> PyResult { let type_repr = vm.to_pystr(&instance.typ())?; Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr))) } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 34a27548f5..accab331a1 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -667,8 +667,10 @@ impl PyContext { } pub fn new_data_descriptor< - G: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult, - S: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult, + G: IntoPyNativeFunc<(I, PyObjectRef), T>, + S: IntoPyNativeFunc<(I, T), PyResult>, + T, + I, >( &self, getter: G, From f2f0f1d7429d01dc434de122c4293c5bf1d1d673 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 8 Mar 2019 06:03:13 +1300 Subject: [PATCH 3/4] Remove debug statements --- vm/src/obj/objfunction.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 82c06fac63..26fee403fa 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -99,7 +99,6 @@ fn data_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { match args.shift().get_attr("fget") { Some(function) => vm.invoke(function, args), None => { - println!("A"); let attribute_error = vm.context().exceptions.attribute_error.clone(); Err(vm.new_exception(attribute_error, String::from("Attribute Error"))) } @@ -110,7 +109,6 @@ fn data_set(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { match args.shift().get_attr("fset") { Some(function) => vm.invoke(function, args), None => { - println!("B"); let attribute_error = vm.context().exceptions.attribute_error.clone(); Err(vm.new_exception(attribute_error, String::from("Attribute Error"))) } From 4b1cd723558227c7d053e91263a75a6c51715f90 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 8 Mar 2019 17:04:32 +1300 Subject: [PATCH 4/4] Add todo for using PyClassRef when that lands --- vm/src/obj/objobject.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 6b01fd662d..bf659b2c72 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -195,6 +195,7 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { Ok(vm.ctx.none()) } +// TODO Use PyClassRef for owner to enforce type fn object_class(_obj: PyObjectRef, owner: PyObjectRef, _vm: &mut VirtualMachine) -> PyObjectRef { owner }