diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 4d9fb79896..8a4a6adc30 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -88,7 +88,7 @@ fn builtin_bin(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { fn builtin_callable(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(obj, None)]); - let is_callable = objtype::class_has_attr(&obj.type_pyref(), "__call__"); + let is_callable = objtype::class_has_attr(&obj.class(), "__call__"); Ok(vm.new_bool(is_callable)) } @@ -240,7 +240,7 @@ fn make_scope( } else if vm.isinstance(arg, &dict_type)? { Some(arg) } else { - let arg_typ = arg.typ(); + let arg_typ = arg.class(); let actual_type = vm.to_pystr(&arg_typ)?; let expected_type_name = vm.to_pystr(&dict_type)?; return Err(vm.new_type_error(format!( @@ -368,7 +368,7 @@ fn builtin_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(value) => vm.invoke(value, PyFuncArgs::default()), Err(..) => Err(vm.new_type_error(format!( "object of type '{}' has no method {:?}", - objtype::get_type_name(&obj.typ()), + obj.class().name, len_method_name ))), } @@ -605,10 +605,9 @@ fn builtin_reversed(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { match vm.get_method(obj.clone(), "__reversed__") { Ok(value) => vm.invoke(value, PyFuncArgs::default()), // TODO: fallback to using __len__ and __getitem__, if object supports sequence protocol - Err(..) => Err(vm.new_type_error(format!( - "'{}' object is not reversible", - objtype::get_type_name(&obj.typ()), - ))), + Err(..) => { + Err(vm.new_type_error(format!("'{}' object is not reversible", obj.class().name))) + } } } // builtin_reversed @@ -802,9 +801,9 @@ pub fn builtin_build_class_(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResu }; for base in bases.clone() { - if objtype::issubclass(&base.type_pyref(), &metaclass) { - metaclass = base.type_pyref(); - } else if !objtype::issubclass(&metaclass, &base.type_pyref()) { + if objtype::issubclass(&base.class(), &metaclass) { + metaclass = base.class(); + } else if !objtype::issubclass(&metaclass, &base.class()) { 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())); } } diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 3eb962edfe..fb757cd0f3 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -68,7 +68,6 @@ fn exception_str(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { args, required = [(exc, Some(vm.ctx.exceptions.exception_type.clone()))] ); - let type_name = objtype::get_type_name(&exc.typ()); let msg = if let Ok(m) = vm.get_attribute(exc.clone(), "msg") { match vm.to_pystr(&m) { Ok(msg) => msg, @@ -77,7 +76,7 @@ fn exception_str(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { } else { panic!("Error message must be set"); }; - let s = format!("{}: {}", type_name, msg); + let s = format!("{}: {}", exc.class().name, msg); Ok(vm.new_str(s)) } diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 3584a57a81..6fd5cfea80 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -949,7 +949,7 @@ impl Frame { // let args = PyFuncArgs::default(); // TODO: what happens when we got an error during handling exception? let args = if let Some(exc) = exc { - let exc_type = exc.typ(); + let exc_type = exc.class().into_object(); let exc_val = exc.clone(); let exc_tb = vm.ctx.none(); // TODO: retrieve traceback? vec![exc_type, exc_val, exc_tb] @@ -1093,7 +1093,7 @@ impl Frame { Ok(found) => Ok(found), Err(_) => Err(vm.new_type_error(format!( "{} has no __contains__ method", - objtype::get_type_name(&haystack.typ()) + haystack.class().name ))), } } @@ -1103,7 +1103,7 @@ impl Frame { Ok(found) => Ok(vm.ctx.new_bool(!objbool::get_value(&found))), Err(_) => Err(vm.new_type_error(format!( "{} has no __contains__ method", - objtype::get_type_name(&haystack.typ()) + haystack.class().name ))), } } diff --git a/vm/src/function.rs b/vm/src/function.rs index ed959d85c9..1c61ffc87c 100644 --- a/vm/src/function.rs +++ b/vm/src/function.rs @@ -99,7 +99,7 @@ impl PyFuncArgs { Ok(Some(kwarg)) } else { let expected_ty_name = vm.to_pystr(&ty)?; - let actual_ty_name = vm.to_pystr(&kwarg.typ())?; + let actual_ty_name = vm.to_pystr(&kwarg.class())?; Err(vm.new_type_error(format!( "argument of type {} is required for named parameter `{}` (got: {})", expected_ty_name, key, actual_ty_name diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 0c205ffc80..a631867976 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -20,7 +20,7 @@ macro_rules! type_check { let arg = &$args.args[$arg_count]; if !$crate::obj::objtype::isinstance(arg, &expected_type) { - let arg_typ = arg.typ(); + let arg_typ = arg.class(); let expected_type_name = $vm.to_pystr(&expected_type)?; let actual_type = $vm.to_pystr(&arg_typ)?; return Err($vm.new_type_error(format!( diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index 958d368a89..ca6bad9d22 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -190,8 +190,7 @@ impl PyFloatRef { } } } else { - let type_name = objtype::get_type_name(&arg.typ()); - return Err(vm.new_type_error(format!("can't convert {} to float", type_name))); + return Err(vm.new_type_error(format!("can't convert {} to float", arg.class().name))); }; PyFloat { value }.into_ref_with_type(vm, cls) } diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 1488ee79c7..507d7697a9 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -76,7 +76,7 @@ fn bind_method(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(function, None), (obj, None), (cls, None)] ); - if obj.is(&vm.get_none()) && !cls.is(&obj.typ()) { + if obj.is(&vm.get_none()) && !cls.is(&obj.class()) { Ok(function.clone()) } else { Ok(vm.ctx.new_bound_method(function.clone(), obj.clone())) diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index dd40f06a42..c7f0ff5af4 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -211,11 +211,7 @@ impl PyIntRef { fn lshift(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if !objtype::isinstance(&other, &vm.ctx.int_type()) { - return Err(vm.new_type_error(format!( - "unsupported operand type(s) for << '{}' and '{}'", - objtype::get_type_name(&self.as_object().typ()), - objtype::get_type_name(&other.typ()) - ))); + return Ok(vm.ctx.not_implemented()); } if let Some(n_bits) = get_value(&other).to_usize() { @@ -234,11 +230,7 @@ impl PyIntRef { fn rshift(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if !objtype::isinstance(&other, &vm.ctx.int_type()) { - return Err(vm.new_type_error(format!( - "unsupported operand type(s) for >> '{}' and '{}'", - objtype::get_type_name(&self.as_object().typ()), - objtype::get_type_name(&other.typ()) - ))); + return Ok(vm.ctx.not_implemented()); } if let Some(n_bits) = get_value(&other).to_usize() { @@ -420,10 +412,9 @@ pub fn to_int(vm: &VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult PyResult { vm.call_method(iter_target, "__iter__", vec![]) - // let type_str = objstr::get_value(&vm.to_str(iter_target.typ()).unwrap()); + // let type_str = objstr::get_value(&vm.to_str(iter_target.class()).unwrap()); // let type_error = vm.new_type_error(format!("Cannot iterate over {}", type_str)); // return Err(type_error); } diff --git a/vm/src/obj/objnone.rs b/vm/src/obj/objnone.rs index 840b00eccc..aff20f465f 100644 --- a/vm/src/obj/objnone.rs +++ b/vm/src/obj/objnone.rs @@ -12,7 +12,7 @@ pub type PyNoneRef = PyRef; impl PyValue for PyNone { fn class(vm: &VirtualMachine) -> PyClassRef { - vm.ctx.none().type_pyref() + vm.ctx.none().class() } } @@ -44,7 +44,7 @@ impl PyNoneRef { fn get_attribute(self, name: PyStringRef, vm: &VirtualMachine) -> PyResult { trace!("None.__getattribute__({:?}, {:?})", self, name); - let cls = self.typ(); + let cls = self.class(); // Properties use a comparision with None to determine if they are either invoked by am // instance binding or a class binding. But if the object itself is None then this detection @@ -69,7 +69,7 @@ impl PyNoneRef { } if let Some(attr) = class_get_attr(&cls, &name.value) { - let attr_class = attr.type_pyref(); + let attr_class = attr.class(); if class_has_attr(&attr_class, "__set__") { if let Some(get_func) = class_get_attr(&attr_class, "__get__") { return call_descriptor( @@ -88,7 +88,7 @@ impl PyNoneRef { // Ok(obj_attr) // } else if let Some(attr) = class_get_attr(&cls, &name.value) { - let attr_class = attr.type_pyref(); + let attr_class = attr.class(); if let Some(get_func) = class_get_attr(&attr_class, "__get__") { call_descriptor(attr, get_func, self.into_object(), cls.into_object(), vm) } else { @@ -107,7 +107,7 @@ fn none_new(_: PyClassRef, vm: &VirtualMachine) -> PyNoneRef { } pub fn init(context: &PyContext) { - extend_class!(context, &context.none.typ(), { + extend_class!(context, &context.none.class(), { "__new__" => context.new_rustfunc(none_new), "__repr__" => context.new_rustfunc(PyNoneRef::repr), "__bool__" => context.new_rustfunc(PyNoneRef::bool), diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 60473fad03..74ba2dc3d4 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -104,10 +104,10 @@ fn object_setattr( vm: &VirtualMachine, ) -> PyResult<()> { trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value); - let cls = obj.type_pyref(); + let cls = obj.class(); if let Some(attr) = objtype::class_get_attr(&cls, &attr_name.value) { - if let Some(descriptor) = objtype::class_get_attr(&attr.type_pyref(), "__set__") { + if let Some(descriptor) = objtype::class_get_attr(&attr.class(), "__set__") { return vm .invoke(descriptor, vec![attr, obj.clone(), value]) .map(|_| ()); @@ -118,19 +118,19 @@ fn object_setattr( dict.set_item(&vm.ctx, &attr_name.value, value); Ok(()) } else { - let type_name = objtype::get_type_name(obj.type_ref()); Err(vm.new_attribute_error(format!( "'{}' object has no attribute '{}'", - type_name, &attr_name.value + obj.class().name, + &attr_name.value ))) } } fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine) -> PyResult<()> { - let cls = obj.type_pyref(); + let cls = obj.class(); if let Some(attr) = objtype::class_get_attr(&cls, &attr_name.value) { - if let Some(descriptor) = objtype::class_get_attr(&attr.type_pyref(), "__delete__") { + if let Some(descriptor) = objtype::class_get_attr(&attr.class(), "__delete__") { return vm.invoke(descriptor, vec![attr, obj.clone()]).map(|_| ()); } } @@ -139,10 +139,10 @@ fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine) dict.del_item(&attr_name.value); Ok(()) } else { - let type_name = objtype::get_type_name(obj.type_ref()); Err(vm.new_attribute_error(format!( "'{}' object has no attribute '{}'", - type_name, &attr_name.value + obj.class().name, + &attr_name.value ))) } } @@ -154,9 +154,8 @@ fn object_str(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { fn object_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(obj, Some(vm.ctx.object()))]); - let type_name = objtype::get_type_name(&obj.typ()); let address = obj.get_id(); - Ok(vm.new_str(format!("<{} object at 0x{:x}>", type_name, address))) + Ok(vm.new_str(format!("<{} object at 0x{:x}>", obj.class().name, address))) } pub fn object_dir(obj: PyObjectRef, vm: &VirtualMachine) -> PyList { @@ -216,7 +215,7 @@ fn object_init(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult { } fn object_class(obj: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef { - obj.typ() + obj.class().into_object() } fn object_class_setter( @@ -224,7 +223,7 @@ fn object_class_setter( _value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult { - let type_repr = vm.to_pystr(&instance.typ())?; + let type_repr = vm.to_pystr(&instance.class())?; Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr))) } @@ -247,10 +246,10 @@ fn object_getattribute(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { ); let name = objstr::get_value(&name_str); trace!("object.__getattribute__({:?}, {:?})", obj, name); - let cls = obj.type_pyref(); + let cls = obj.class(); if let Some(attr) = objtype::class_get_attr(&cls, &name) { - let attr_class = attr.type_pyref(); + let attr_class = attr.class(); if objtype::class_has_attr(&attr_class, "__set__") { if let Some(descriptor) = objtype::class_get_attr(&attr_class, "__get__") { return vm.invoke(descriptor, vec![attr, obj.clone(), cls.into_object()]); @@ -279,7 +278,7 @@ fn object_getattr(obj: &PyObjectRef, attr_name: &str) -> Option { pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes { // Get class attributes: - let mut attributes = objtype::get_attributes(obj.type_pyref()); + let mut attributes = objtype::get_attributes(obj.class()); // Get instance attributes: if let Some(dict) = &obj.dict { diff --git a/vm/src/obj/objproperty.rs b/vm/src/obj/objproperty.rs index e6b11904eb..9d72171106 100644 --- a/vm/src/obj/objproperty.rs +++ b/vm/src/obj/objproperty.rs @@ -6,7 +6,9 @@ use crate::function::IntoPyNativeFunc; use crate::function::OptionalArg; use crate::obj::objstr::PyStringRef; use crate::obj::objtype::PyClassRef; -use crate::pyobject::{IdProtocol, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue}; +use crate::pyobject::{ + IdProtocol, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, +}; use crate::vm::VirtualMachine; /// Read-only property, doesn't have __set__ or __delete__ @@ -137,7 +139,7 @@ impl PyPropertyRef { setter: self.setter.clone(), deleter: self.deleter.clone(), } - .into_ref_with_type(vm, self.typ()) + .into_ref_with_type(vm, TypeProtocol::class(&self)) } fn setter(self, setter: Option, vm: &VirtualMachine) -> PyResult { @@ -146,7 +148,7 @@ impl PyPropertyRef { setter: setter.or_else(|| self.setter.clone()), deleter: self.deleter.clone(), } - .into_ref_with_type(vm, self.typ()) + .into_ref_with_type(vm, TypeProtocol::class(&self)) } fn deleter(self, deleter: Option, vm: &VirtualMachine) -> PyResult { @@ -155,7 +157,7 @@ impl PyPropertyRef { setter: self.setter.clone(), deleter: deleter.or_else(|| self.deleter.clone()), } - .into_ref_with_type(vm, self.typ()) + .into_ref_with_type(vm, TypeProtocol::class(&self)) } } diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index 80f4bf40f6..a07b2454de 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -163,13 +163,13 @@ pub fn get_item( if sequence.payload::().is_some() { Ok(PyObject::new( PyList::from(elements.to_vec().get_slice_items(vm, &subscript)?), - sequence.type_pyref(), + sequence.class(), None, )) } else if sequence.payload::().is_some() { Ok(PyObject::new( PyTuple::from(elements.to_vec().get_slice_items(vm, &subscript)?), - sequence.type_pyref(), + sequence.class(), None, )) } else { diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 7071cc6e4c..ad82c34de0 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -231,16 +231,16 @@ fn set_new(cls: PyClassRef, iterable: OptionalArg, vm: &VirtualMach fn set_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("set.len called with: {:?}", args); arg_check!(vm, args, required = [(s, None)]); - validate_set_or_frozenset(vm, s.type_pyref())?; + validate_set_or_frozenset(vm, s.class())?; let elements = get_elements(s); Ok(vm.context().new_int(elements.len())) } fn set_copy(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { trace!("set.copy called with: {:?}", obj); - validate_set_or_frozenset(vm, obj.type_pyref())?; + validate_set_or_frozenset(vm, obj.class())?; let elements = get_elements(&obj).clone(); - create_set(vm, elements, obj.type_pyref()) + create_set(vm, elements, obj.class()) } fn set_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -265,7 +265,7 @@ fn set_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { pub fn set_contains(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(set, None), (needle, None)]); - validate_set_or_frozenset(vm, set.type_pyref())?; + validate_set_or_frozenset(vm, set.class())?; for element in get_elements(set).iter() { match vm._eq(needle.clone(), element.1.clone()) { Ok(value) => { @@ -333,8 +333,8 @@ fn set_compare_inner( ) -> PyResult { arg_check!(vm, args, required = [(zelf, None), (other, None)]); - validate_set_or_frozenset(vm, zelf.type_pyref())?; - validate_set_or_frozenset(vm, other.type_pyref())?; + validate_set_or_frozenset(vm, zelf.class())?; + validate_set_or_frozenset(vm, other.class())?; let get_zelf = |swap: bool| -> &PyObjectRef { if swap { @@ -370,13 +370,13 @@ fn set_compare_inner( } fn set_union(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - validate_set_or_frozenset(vm, zelf.type_pyref())?; - validate_set_or_frozenset(vm, other.type_pyref())?; + validate_set_or_frozenset(vm, zelf.class())?; + validate_set_or_frozenset(vm, other.class())?; let mut elements = get_elements(&zelf).clone(); elements.extend(get_elements(&other).clone()); - create_set(vm, elements, zelf.type_pyref()) + create_set(vm, elements, zelf.class()) } fn set_intersection(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { @@ -392,8 +392,8 @@ fn set_symmetric_difference( other: PyObjectRef, vm: &VirtualMachine, ) -> PyResult { - validate_set_or_frozenset(vm, zelf.type_pyref())?; - validate_set_or_frozenset(vm, other.type_pyref())?; + validate_set_or_frozenset(vm, zelf.class())?; + validate_set_or_frozenset(vm, other.class())?; let mut elements = HashMap::new(); for element in get_elements(&zelf).iter() { @@ -410,7 +410,7 @@ fn set_symmetric_difference( } } - create_set(vm, elements, zelf.type_pyref()) + create_set(vm, elements, zelf.class()) } enum SetCombineOperation { @@ -424,8 +424,8 @@ fn set_combine_inner( vm: &VirtualMachine, op: SetCombineOperation, ) -> PyResult { - validate_set_or_frozenset(vm, zelf.type_pyref())?; - validate_set_or_frozenset(vm, other.type_pyref())?; + validate_set_or_frozenset(vm, zelf.class())?; + validate_set_or_frozenset(vm, other.class())?; let mut elements = HashMap::new(); for element in get_elements(&zelf).iter() { @@ -439,7 +439,7 @@ fn set_combine_inner( } } - create_set(vm, elements, zelf.type_pyref()) + create_set(vm, elements, zelf.class()) } fn set_pop(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 67ee8e5e7e..aa62812a24 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -715,7 +715,7 @@ fn str_format(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { let zelf = &args.args[0]; if !objtype::isinstance(&zelf, &vm.ctx.str_type()) { - let zelf_typ = zelf.typ(); + let zelf_typ = zelf.class(); let actual_type = vm.to_pystr(&zelf_typ)?; return Err(vm.new_type_error(format!( "descriptor 'format' requires a 'str' object but received a '{}'", @@ -738,7 +738,7 @@ fn call_object_format(vm: &VirtualMachine, argument: PyObjectRef, format_spec: & let returned_type = vm.ctx.new_str(format_spec.to_string()); let result = vm.call_method(&argument, "__format__", vec![returned_type])?; if !objtype::isinstance(&result, &vm.ctx.str_type()) { - let result_type = result.typ(); + let result_type = result.class(); let actual_type = vm.to_pystr(&result_type)?; return Err(vm.new_type_error(format!("__format__ must return a str, not {}", actual_type))); } @@ -809,7 +809,7 @@ fn str_new( OptionalArg::Present(ref input) => vm.to_str(input)?.into_object(), OptionalArg::Missing => vm.new_str("".to_string()), }; - if string.typ().is(&cls) { + if string.class().is(&cls) { TryFromObject::try_from_object(vm, string) } else { let payload = string.payload::().unwrap(); diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index f04fb66058..24424d265f 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -112,10 +112,9 @@ fn super_new( // Check type argument: if !objtype::isinstance(py_type.as_object(), &vm.get_type()) { - let type_name = objtype::get_type_name(py_type.as_object().type_ref()); return Err(vm.new_type_error(format!( "super() argument 1 must be type, not {}", - type_name + py_type.class().name ))); } diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index d87ca3843c..14958300bf 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -39,12 +39,6 @@ impl PyValue for PyClass { } } -impl TypeProtocol for PyClassRef { - fn type_ref(&self) -> &PyObjectRef { - &self.as_object().type_ref() - } -} - struct IterMro<'a> { cls: &'a PyClassRef, offset: Option, @@ -117,10 +111,10 @@ impl PyClassRef { fn getattribute(self, name_ref: PyStringRef, vm: &VirtualMachine) -> PyResult { let name = &name_ref.value; trace!("type.__getattribute__({:?}, {:?})", self, name); - let mcl = self.type_pyref(); + let mcl = self.class(); if let Some(attr) = class_get_attr(&mcl, &name) { - let attr_class = attr.type_pyref(); + let attr_class = attr.class(); if class_has_attr(&attr_class, "__set__") { if let Some(descriptor) = class_get_attr(&attr_class, "__get__") { return vm.invoke( @@ -132,7 +126,7 @@ impl PyClassRef { } if let Some(attr) = class_get_attr(&self, &name) { - let attr_class = attr.type_pyref(); + let attr_class = attr.class(); if let Some(descriptor) = class_get_attr(&attr_class, "__get__") { let none = vm.get_none(); return vm.invoke(descriptor, vec![attr, none, self.into_object()]); @@ -156,8 +150,8 @@ impl PyClassRef { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - if let Some(attr) = class_get_attr(&self.type_pyref(), &attr_name.value) { - if let Some(descriptor) = class_get_attr(&attr.type_pyref(), "__set__") { + if let Some(attr) = class_get_attr(&self.class(), &attr_name.value) { + if let Some(descriptor) = class_get_attr(&attr.class(), "__set__") { vm.invoke(descriptor, vec![attr, self.into_object(), value])?; return Ok(()); } @@ -218,7 +212,7 @@ fn _mro(cls: &PyClassRef) -> Vec { /// Determines if `obj` actually an instance of `cls`, this doesn't call __instancecheck__, so only /// use this if `cls` is known to have not overridden the base __instancecheck__ magic method. pub fn isinstance(obj: &PyObjectRef, cls: &PyClassRef) -> bool { - issubclass(&obj.type_pyref(), &cls) + issubclass(&obj.class(), &cls) } /// Determines if `subclass` is actually a subclass of `cls`, this doesn't call __subclasscheck__, @@ -229,18 +223,10 @@ pub fn issubclass(subclass: &PyClassRef, cls: &PyClassRef) -> bool { subclass.is(cls) || mro.iter().any(|c| c.is(cls.as_object())) } -pub fn get_type_name(typ: &PyObjectRef) -> String { - if let Some(PyClass { name, .. }) = &typ.payload::() { - name.clone() - } else { - panic!("Cannot get type_name of non-type type {:?}", typ); - } -} - pub fn type_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { debug!("type.__new__ {:?}", args); if args.args.len() == 2 { - Ok(args.args[1].typ()) + Ok(args.args[1].class().into_object()) } else if args.args.len() == 4 { let (typ, name, bases, dict) = args.bind(vm)?; type_new_class(vm, typ, name, bases, dict).map(|x| x.into_object()) diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 78e82c51bd..afee7060e2 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -88,7 +88,7 @@ impl fmt::Display for PyObject { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::TypeProtocol; if let Some(PyClass { ref name, .. }) = self.payload::() { - let type_name = objtype::get_type_name(&self.typ()); + let type_name = self.class().name.clone(); // We don't have access to a vm, so just assume that if its parent's name // is type, it's a type if type_name == "type" { @@ -101,7 +101,7 @@ impl fmt::Display for PyObject { if let Some(PyModule { ref name, .. }) = self.payload::() { return write!(f, "module '{}'", name); } - write!(f, "'{}' object", objtype::get_type_name(&self.typ())) + write!(f, "'{}' object", self.class().name) } } @@ -163,7 +163,7 @@ pub struct PyNotImplemented; impl PyValue for PyNotImplemented { fn class(vm: &VirtualMachine) -> PyClassRef { - vm.ctx.not_implemented().type_pyref() + vm.ctx.not_implemented().class() } } @@ -772,7 +772,7 @@ impl PyRef { pub fn typ(&self) -> PyClassRef { PyRef { - obj: self.obj.typ(), + obj: self.obj.class().into_object(), _payload: PhantomData, } } @@ -802,7 +802,7 @@ where } else { let class = T::class(vm); let expected_type = vm.to_pystr(&class)?; - let actual_type = vm.to_pystr(&obj.typ())?; + let actual_type = vm.to_pystr(&obj.class())?; Err(vm.new_type_error(format!( "Expected type {}, not {}", expected_type, actual_type, @@ -877,18 +877,12 @@ impl IdProtocol for PyRef { } pub trait TypeProtocol { - fn typ(&self) -> PyObjectRef { - self.type_ref().clone() - } - fn type_pyref(&self) -> PyClassRef { - self.typ().downcast().unwrap() - } - fn type_ref(&self) -> &PyObjectRef; + fn class(&self) -> PyClassRef; } impl TypeProtocol for PyObjectRef { - fn type_ref(&self) -> &PyObjectRef { - (**self).type_ref() + fn class(&self) -> PyClassRef { + (**self).class() } } @@ -896,8 +890,14 @@ impl TypeProtocol for PyObject where T: ?Sized + PyObjectPayload, { - fn type_ref(&self) -> &PyObjectRef { - self.typ.as_object() + fn class(&self) -> PyClassRef { + self.typ.clone() + } +} + +impl TypeProtocol for PyRef { + fn class(&self) -> PyClassRef { + self.obj.typ.clone() } } @@ -956,7 +956,7 @@ pub trait BufferProtocol { impl BufferProtocol for PyObjectRef { fn readonly(&self) -> bool { - match objtype::get_type_name(&self.typ()).as_ref() { + match self.class().name.as_str() { "bytes" => false, "bytearray" | "memoryview" => true, _ => panic!("Bytes-Like type expected not {:?}", self), @@ -1249,7 +1249,7 @@ where "must be {} or {}, not {}", A::class(vm), B::class(vm), - obj.type_pyref() + obj.class() )) }) } diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index eac3619c26..b881b7a724 100644 --- a/vm/src/stdlib/json.rs +++ b/vm/src/stdlib/json.rs @@ -74,7 +74,7 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> { } else { Err(serde::ser::Error::custom(format!( "Object of type '{:?}' is not serializable", - self.pyobject.typ() + self.pyobject.class() ))) } } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 0ee9798ab0..41321c2667 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -174,11 +174,11 @@ impl VirtualMachine { b: PyObjectRef, op: &str, ) -> PyObjectRef { - let a_type_name = objtype::get_type_name(&a.typ()); - let b_type_name = objtype::get_type_name(&b.typ()); self.new_type_error(format!( "Unsupported operand types for '{}': '{}' and '{}'", - op, a_type_name, b_type_name + op, + a.class().name, + b.class().name )) } @@ -270,7 +270,7 @@ impl VirtualMachine { pub fn isinstance(&self, obj: &PyObjectRef, cls: &PyClassRef) -> PyResult { // cpython first does an exact check on the type, although documentation doesn't state that // https://github.com/python/cpython/blob/a24107b04c1277e3c1105f98aff5bfa3a98b33a0/Objects/abstract.c#L2408 - if Rc::ptr_eq(&obj.typ(), cls.as_object()) { + if Rc::ptr_eq(&obj.class().into_object(), cls.as_object()) { Ok(true) } else { let ret = self.call_method(cls.as_object(), "__instancecheck__", vec![obj.clone()])?; @@ -286,10 +286,10 @@ impl VirtualMachine { } pub fn call_get_descriptor(&self, attr: PyObjectRef, obj: PyObjectRef) -> PyResult { - let attr_class = attr.type_pyref(); + let attr_class = attr.class(); if let Some(descriptor) = objtype::class_get_attr(&attr_class, "__get__") { - let cls = obj.typ(); - self.invoke(descriptor, vec![attr, obj.clone(), cls]) + let cls = obj.class(); + self.invoke(descriptor, vec![attr, obj.clone(), cls.into_object()]) } else { Ok(attr) } @@ -300,7 +300,7 @@ impl VirtualMachine { T: Into, { // This is only used in the vm for magic methods, which use a greatly simplified attribute lookup. - let cls = obj.type_pyref(); + let cls = obj.class(); match objtype::class_get_attr(&cls, method_name) { Some(func) => { trace!( @@ -583,7 +583,7 @@ impl VirtualMachine { // get_method should be used for internal access to magic methods (by-passing // the full getattribute look-up. pub fn get_method(&self, obj: PyObjectRef, method_name: &str) -> PyResult { - let cls = obj.type_pyref(); + let cls = obj.class(); match objtype::class_get_attr(&cls, method_name) { Some(method) => self.call_get_descriptor(method, obj.clone()), None => Err(self.new_type_error(format!("{} has no method {:?}", obj, method_name))), diff --git a/wasm/lib/src/wasm_builtins.rs b/wasm/lib/src/wasm_builtins.rs index d5bc830dfe..ada0c83f53 100644 --- a/wasm/lib/src/wasm_builtins.rs +++ b/wasm/lib/src/wasm_builtins.rs @@ -25,7 +25,7 @@ pub fn format_print_args(vm: &VirtualMachine, args: PyFuncArgs) -> Result Result