diff --git a/vm/src/builtins/namespace.rs b/vm/src/builtins/namespace.rs index a29d55f9f..36edb1ef6 100644 --- a/vm/src/builtins/namespace.rs +++ b/vm/src/builtins/namespace.rs @@ -24,7 +24,7 @@ impl Constructor for PyNamespace { fn py_new(cls: PyTypeRef, kwargs: Self::Args, vm: &VirtualMachine) -> PyResult { let zelf = PyNamespace.into_ref_with_type(vm, cls)?; for (name, value) in kwargs.into_iter() { - vm.set_attr(zelf.as_object(), name, value)?; + zelf.as_object().set_attr(name, value, vm)?; } Ok(zelf.into_pyobject(vm)) } diff --git a/vm/src/builtins/weakproxy.rs b/vm/src/builtins/weakproxy.rs index 129d75280..281d6acee 100644 --- a/vm/src/builtins/weakproxy.rs +++ b/vm/src/builtins/weakproxy.rs @@ -66,7 +66,7 @@ impl SetAttr for PyWeakProxy { vm: &VirtualMachine, ) -> PyResult<()> { match zelf.weak.upgrade() { - Some(obj) => vm.call_set_attr(&obj, attr_name, value), + Some(obj) => obj.call_set_attr(vm, attr_name, value), None => Err(vm.new_exception_msg( vm.ctx.exceptions.reference_error.clone(), "weakly-referenced object no longer exists".to_owned(), diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 4b87dcef6..53e733748 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -1079,16 +1079,16 @@ pub(super) mod types { args: FuncArgs, vm: &VirtualMachine, ) -> PyResult<()> { - let exc_self = zelf.into(); - vm.set_attr( - &exc_self, + let zelf: PyObjectRef = zelf.into(); + zelf.set_attr( "name", vm.unwrap_or_none(args.kwargs.get("name").cloned()), + vm, )?; - vm.set_attr( - &exc_self, + zelf.set_attr( "path", vm.unwrap_or_none(args.kwargs.get("path").cloned()), + vm, )?; Ok(()) } diff --git a/vm/src/frame.rs b/vm/src/frame.rs index e9748618c..24a2885ee 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -1651,14 +1651,14 @@ impl ExecutingFrame<'_> { ) .into_object(vm); - vm.set_attr(&func_obj, "__doc__", vm.ctx.none())?; + func_obj.set_attr("__doc__", vm.ctx.none(), vm)?; let name = qualified_name.as_str().split('.').next_back().unwrap(); - vm.set_attr(&func_obj, "__name__", vm.new_pyobj(name))?; - vm.set_attr(&func_obj, "__qualname__", qualified_name)?; + func_obj.set_attr("__name__", vm.new_pyobj(name), vm)?; + func_obj.set_attr("__qualname__", qualified_name, vm)?; let module = vm.unwrap_or_none(self.globals.get_item_option("__name__", vm)?); - vm.set_attr(&func_obj, "__module__", module)?; - vm.set_attr(&func_obj, "__annotations__", annotations)?; + func_obj.set_attr("__module__", module, vm)?; + func_obj.set_attr("__annotations__", annotations, vm)?; self.push_value(func_obj); Ok(None) @@ -1803,7 +1803,7 @@ impl ExecutingFrame<'_> { let attr_name = self.code.names[attr as usize].clone(); let parent = self.pop_value(); let value = self.pop_value(); - vm.set_attr(&parent, attr_name, value)?; + parent.set_attr(attr_name, value, vm)?; Ok(None) } diff --git a/vm/src/import.rs b/vm/src/import.rs index 2205715ca..d690e4db0 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -57,7 +57,7 @@ pub(crate) fn init_importlib( magic = rand::thread_rng().gen::<[u8; 4]>().to_vec(); } let magic: PyObjectRef = vm.ctx.new_bytes(magic).into(); - vm.set_attr(&importlib_external, "MAGIC_NUMBER", magic)?; + importlib_external.set_attr("MAGIC_NUMBER", magic, vm)?; let zipimport_res = (|| -> PyResult<()> { let zipimport = vm.import("zipimport", None, 0)?; let zipimporter = zipimport.get_attr("zipimporter", vm)?; diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index b572b2006..940512d0e 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -35,6 +35,30 @@ impl PyObjectRef { getattro(self, attr_name, vm) } + pub fn call_set_attr( + &self, + vm: &VirtualMachine, + attr_name: PyStrRef, + attr_value: Option, + ) -> PyResult<()> { + let setattro = { + let cls = self.class(); + cls.mro_find_map(|cls| cls.slots.setattro.load()) + .ok_or_else(|| { + let assign = attr_value.is_some(); + let has_getattr = cls.mro_find_map(|cls| cls.slots.getattro.load()).is_some(); + vm.new_type_error(format!( + "'{}' object has {} attributes ({} {})", + cls.name(), + if has_getattr { "only read-only" } else { "no" }, + if assign { "assign to" } else { "del" }, + attr_name + )) + })? + }; + setattro(self, attr_name, attr_value, vm) + } + // PyObject *PyObject_GenericGetAttr(PyObject *o, PyObject *name) pub fn set_attr( @@ -43,7 +67,8 @@ impl PyObjectRef { attr_value: impl Into, vm: &VirtualMachine, ) -> PyResult<()> { - vm.set_attr(self, attr_name, attr_value) + let attr_name = attr_name.into_pystr_ref(vm); + self.call_set_attr(vm, attr_name, Some(attr_value.into())) } // int PyObject_GenericSetAttr(PyObject *o, PyObject *name, PyObject *value) diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index ee56d7a85..eeac00984 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -59,7 +59,7 @@ impl AstNode { ))); } for (name, arg) in fields.iter().zip(args.args) { - vm.set_attr(&zelf, name.clone(), arg)?; + zelf.set_attr(name.clone(), arg, vm)?; } for (key, value) in args.kwargs { if let Some(pos) = fields.iter().position(|f| f.as_str() == key) { @@ -71,7 +71,7 @@ impl AstNode { ))); } } - vm.set_attr(&zelf, key, value)?; + zelf.set_attr(key, value, vm)?; } Ok(()) } diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index 7c0caf028..763f272d1 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -732,7 +732,7 @@ mod builtins { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - vm.set_attr(&obj, attr, value)?; + obj.set_attr(attr, value, vm)?; Ok(()) } diff --git a/vm/src/stdlib/errno.rs b/vm/src/stdlib/errno.rs index 221a86857..6dac3e8e4 100644 --- a/vm/src/stdlib/errno.rs +++ b/vm/src/stdlib/errno.rs @@ -16,7 +16,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { errorcode .set_item(code.clone(), name.clone().into(), vm) .unwrap(); - vm.set_attr(&module, name, code).unwrap(); + module.set_attr(name, code, vm).unwrap(); } module } diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index d7a77c14d..4f7f436a0 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -542,7 +542,7 @@ mod _io { pub(super) fn iobase_close(file: &PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { if !file_closed(file, vm)? { let res = vm.call_method(file, "flush", ()); - vm.set_attr(file, "__closed", vm.new_pyobj(true))?; + file.set_attr("__closed", vm.new_pyobj(true), vm)?; res?; } Ok(()) @@ -3622,7 +3622,7 @@ mod _io { line_buffering, ), )?; - vm.set_attr(&wrapper, "mode", vm.new_pyobj(mode_string))?; + wrapper.set_attr("mode", vm.new_pyobj(mode_string), vm)?; Ok(wrapper) } EncodeMode::Bytes => Ok(buffered), @@ -3876,7 +3876,7 @@ mod fileio { zelf.closefd.store(args.closefd); #[cfg(windows)] crate::stdlib::msvcrt::setmode_binary(fd); - vm.set_attr(zelf.as_object(), "name", name)?; + zelf.as_object().set_attr("name", name, vm)?; Ok(()) } diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 725165eeb..c2e3507de 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -296,11 +296,13 @@ impl IntoPyException for IOErrorBuilder { let excp = self.error.into_pyexception(vm); if let Some(filename) = self.filename { - vm.set_attr(excp.as_object(), "filename", filename.filename(vm)) + excp.as_object() + .set_attr("filename", filename.filename(vm), vm) .unwrap(); } if let Some(filename2) = self.filename2 { - vm.set_attr(excp.as_object(), "filename2", filename2.filename(vm)) + excp.as_object() + .set_attr("filename2", filename2.filename(vm), vm) .unwrap(); } excp diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index b87dabcf3..dc815d965 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -289,11 +289,11 @@ mod sys { return Ok(()); } // set to none to avoid recursion while printing - vm.set_attr(&vm.builtins, "_", vm.ctx.none())?; + vm.builtins.set_attr("_", vm.ctx.none(), vm)?; // TODO: catch encoding errors let repr = vm.to_repr(&obj)?.into(); builtins::print(PosArgs::new(vec![repr]), Default::default(), vm)?; - vm.set_attr(&vm.builtins, "_", obj)?; + vm.builtins.set_attr("_", obj, vm)?; Ok(()) } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 9908df60b..bb60bd7e0 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -360,12 +360,12 @@ impl VirtualMachine { Default::default(), self, )?; - self.set_attr( - &self.sys_module, + self.sys_module.set_attr( format!("__{}__", name), // e.g. __stdin__ stdio.clone(), + self, )?; - self.set_attr(&self.sys_module, name, stdio)?; + self.sys_module.set_attr(name, stdio, self)?; Ok(()) }; set_stdio("stdin", 0, "r")?; @@ -373,7 +373,7 @@ impl VirtualMachine { set_stdio("stderr", 2, "w")?; let io_open = io.get_attr("open", self)?; - self.set_attr(&self.builtins, "open", io_open)?; + self.builtins.set_attr("open", io_open, self)?; } Ok(()) @@ -778,29 +778,34 @@ impl VirtualMachine { let syntax_error = self.new_exception_msg(syntax_error_type, error.to_string()); let lineno = self.ctx.new_int(error.location.row()); let offset = self.ctx.new_int(error.location.column()); - self.set_attr(syntax_error.as_object(), "lineno", lineno) + syntax_error + .as_object() + .set_attr("lineno", lineno, self) .unwrap(); - self.set_attr(syntax_error.as_object(), "offset", offset) + syntax_error + .as_object() + .set_attr("offset", offset, self) + .unwrap(); + syntax_error + .as_object() + .set_attr("text", error.statement.clone().into_pyobject(self), self) + .unwrap(); + syntax_error + .as_object() + .set_attr( + "filename", + self.ctx.new_str(error.source_path.clone()), + self, + ) .unwrap(); - self.set_attr( - syntax_error.as_object(), - "text", - error.statement.clone().into_pyobject(self), - ) - .unwrap(); - self.set_attr( - syntax_error.as_object(), - "filename", - self.ctx.new_str(error.source_path.clone()), - ) - .unwrap(); syntax_error } pub fn new_import_error(&self, msg: String, name: impl IntoPyStrRef) -> PyBaseExceptionRef { let import_error = self.ctx.exceptions.import_error.clone(); let exc = self.new_exception_msg(import_error, msg); - self.set_attr(exc.as_object(), "name", name.into_pystr_ref(self)) + exc.as_object() + .set_attr("name", name.into_pystr_ref(self), self) .unwrap(); exc } @@ -1408,42 +1413,9 @@ impl VirtualMachine { } } - pub fn call_set_attr( - &self, - obj: &PyObjectRef, - attr_name: PyStrRef, - attr_value: Option, - ) -> PyResult<()> { - let setattro = { - let cls = obj.class(); - cls.mro_find_map(|cls| cls.slots.setattro.load()) - .ok_or_else(|| { - let assign = attr_value.is_some(); - let has_getattr = cls.mro_find_map(|cls| cls.slots.getattro.load()).is_some(); - self.new_type_error(format!( - "'{}' object has {} attributes ({} {})", - cls.name(), - if has_getattr { "only read-only" } else { "no" }, - if assign { "assign to" } else { "del" }, - attr_name - )) - })? - }; - setattro(obj, attr_name, attr_value, self) - } - - pub fn set_attr(&self, obj: &PyObjectRef, attr_name: K, attr_value: V) -> PyResult<()> - where - K: IntoPyStrRef, - V: Into, - { - let attr_name = attr_name.into_pystr_ref(self); - self.call_set_attr(obj, attr_name, Some(attr_value.into())) - } - pub fn del_attr(&self, obj: &PyObjectRef, attr_name: impl IntoPyStrRef) -> PyResult<()> { let attr_name = attr_name.into_pystr_ref(self); - self.call_set_attr(obj, attr_name, None) + obj.call_set_attr(self, attr_name, None) } // get_method should be used for internal access to magic methods (by-passing diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index 31e979e73..f8dde590c 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -246,7 +246,7 @@ impl WASMVirtualMachine { } else { return Err(error()); }; - vm.set_attr(&vm.sys_module, "stdout", stdout).unwrap(); + vm.sys_module.set_attr("stdout", stdout, vm).unwrap(); Ok(()) })? }