diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 3c1e013899..72b0f19275 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1650,8 +1650,6 @@ class GeneralModuleTests(unittest.TestCase): f = None support.gc_collect() - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_name_closed_socketio(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: fp = sock.makefile("rb") diff --git a/derive-impl/src/pymodule.rs b/derive-impl/src/pymodule.rs index 63bdc33eaf..14717f6728 100644 --- a/derive-impl/src/pymodule.rs +++ b/derive-impl/src/pymodule.rs @@ -458,6 +458,7 @@ impl ModuleItem for ClassItem { let set_attr = match py_names.len() { 0 => quote! { let _ = new_class; // suppress warning + let _ = vm.ctx.intern_str(#class_name); }, 1 => { let py_name = &py_names[0]; diff --git a/stdlib/src/sqlite.rs b/stdlib/src/sqlite.rs index cd8a95cd2c..87578f3c56 100644 --- a/stdlib/src/sqlite.rs +++ b/stdlib/src/sqlite.rs @@ -766,7 +766,7 @@ mod _sqlite { pub(super) fn setup_module(module: &PyObject, vm: &VirtualMachine) { for (name, code) in ERROR_CODES { - let name = vm.ctx.new_str(*name); + let name = vm.ctx.intern_str(*name); let code = vm.new_pyobj(*code); module.set_attr(name, code, vm).unwrap(); } diff --git a/vm/src/builtins/module.rs b/vm/src/builtins/module.rs index 3285027c52..0ecc735e95 100644 --- a/vm/src/builtins/module.rs +++ b/vm/src/builtins/module.rs @@ -1,4 +1,3 @@ -use super::pystr::IntoPyStrRef; use super::{PyDictRef, PyStr, PyStrRef, PyType, PyTypeRef}; use crate::{ builtins::{pystr::AsPyStr, PyStrInterned}, @@ -84,9 +83,9 @@ impl Py { self.getattr_inner(attr_name.as_pystr(&vm.ctx), vm) } - pub fn set_attr( + pub fn set_attr<'a>( &self, - attr_name: impl IntoPyStrRef, + attr_name: impl AsPyStr<'a>, attr_value: impl Into, vm: &VirtualMachine, ) -> PyResult<()> { diff --git a/vm/src/builtins/namespace.rs b/vm/src/builtins/namespace.rs index 49f848c8ef..70bcc40077 100644 --- a/vm/src/builtins/namespace.rs +++ b/vm/src/builtins/namespace.rs @@ -53,7 +53,8 @@ impl Initializer for PyNamespace { return Err(vm.new_type_error("no positional arguments expected".to_owned())); } for (name, value) in args.kwargs.into_iter() { - zelf.as_object().set_attr(name, value, vm)?; + let name = vm.ctx.new_str(name); + zelf.as_object().set_attr(&name, value, vm)?; } Ok(()) } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 515fec3a24..5a7d8dfa91 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -161,19 +161,19 @@ impl PyBaseObject { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - obj.generic_setattr(name, PySetterValue::Assign(value), vm) + obj.generic_setattr(&name, PySetterValue::Assign(value), vm) } /// Implement delattr(self, name). #[pymethod] fn __delattr__(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult<()> { - obj.generic_setattr(name, PySetterValue::Delete, vm) + obj.generic_setattr(&name, PySetterValue::Delete, vm) } #[pyslot] fn slot_setattro( obj: &PyObject, - attr_name: PyStrRef, + attr_name: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index e240eff2ae..36c47ed2b4 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -374,23 +374,30 @@ impl PyType { call_slot_new(zelf, subtype, args, vm) } - pub fn slot_name(&self) -> BorrowedValue { + fn name_inner<'a, R: 'a>( + &'a self, + static_f: impl FnOnce(&'static str) -> R, + heap_f: impl FnOnce(&'a HeapTypeExt) -> R, + ) -> R { if !self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) { - return self.slots.name.load().into(); + static_f(self.slots.name.load()) + } else { + heap_f(self.heaptype_ext.as_ref().unwrap()) } - let name_lock = self.heaptype_ext.as_ref().unwrap().name.read(); - PyRwLockReadGuard::map(name_lock, |_| self.slots.name.load()).into() + } + + pub fn slot_name(&self) -> BorrowedValue { + self.name_inner( + |name| name.into(), + |ext| PyRwLockReadGuard::map(ext.name.read(), |name| name.as_str()).into(), + ) } pub fn name(&self) -> BorrowedValue { - if !self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) { - return self.slots.name.load().into(); - } - let name_lock = self.heaptype_ext.as_ref().unwrap().name.read(); - PyRwLockReadGuard::map(name_lock, |name| { - name.as_str() // = self.slots.name.load().rsplit_once('.').unwrap().1 - }) - .into() + self.name_inner( + |name| name.rsplit_once('.').map_or(name, |(_, name)| name).into(), + |ext| PyRwLockReadGuard::map(ext.name.read(), |name| name.as_str()).into(), + ) } } @@ -438,19 +445,20 @@ impl PyType { #[pygetset] pub fn __name__(&self, vm: &VirtualMachine) -> PyStrRef { - if !self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) { - vm.ctx - .interned_str(self.slots.name.load()) - .unwrap_or_else(|| { - panic!( - "static type name must be already interned but {} is not", - self.slots.name.load() - ) - }) - .to_owned() - } else { - self.heaptype_ext.as_ref().unwrap().name.read().clone() - } + self.name_inner( + |name| { + vm.ctx + .interned_str(name.rsplit_once('.').map_or(name, |(_, name)| name)) + .unwrap_or_else(|| { + panic!( + "static type name must be already interned but {} is not", + self.slots.name.load() + ) + }) + .to_owned() + }, + |ext| ext.name.read().clone(), + ) } #[pygetset(magic)] @@ -1037,7 +1045,7 @@ impl GetAttr for PyType { impl SetAttr for PyType { fn setattro( zelf: &Py, - attr_name: PyStrRef, + attr_name: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { diff --git a/vm/src/builtins/weakproxy.rs b/vm/src/builtins/weakproxy.rs index 9888944105..84697f541d 100644 --- a/vm/src/builtins/weakproxy.rs +++ b/vm/src/builtins/weakproxy.rs @@ -141,7 +141,7 @@ impl GetAttr for PyWeakProxy { impl SetAttr for PyWeakProxy { fn setattro( zelf: &Py, - attr_name: PyStrRef, + attr_name: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index 582a35c691..d398154260 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -3,8 +3,8 @@ use crate::{ builtins::{ - pystr::{AsPyStr, IntoPyStrRef}, - PyBytes, PyDict, PyDictRef, PyGenericAlias, PyInt, PyStr, PyStrRef, PyTupleRef, PyTypeRef, + pystr::AsPyStr, PyBytes, PyDict, PyDictRef, PyGenericAlias, PyInt, PyStr, PyStrRef, + PyTupleRef, PyTypeRef, }, bytesinner::ByteInnerNewOptions, common::{hash::PyHash, str::to_ascii}, @@ -102,7 +102,7 @@ impl PyObject { pub fn call_set_attr( &self, vm: &VirtualMachine, - attr_name: PyStrRef, + attr_name: &Py, attr_value: PySetterValue, ) -> PyResult<()> { let setattro = { @@ -126,13 +126,13 @@ impl PyObject { setattro(self, attr_name, attr_value, vm) } - pub fn set_attr( + pub fn set_attr<'a>( &self, - attr_name: impl IntoPyStrRef, + attr_name: impl AsPyStr<'a>, attr_value: impl Into, vm: &VirtualMachine, ) -> PyResult<()> { - let attr_name = attr_name.into_pystr_ref(vm); + let attr_name = attr_name.as_pystr(&vm.ctx); self.call_set_attr(vm, attr_name, PySetterValue::Assign(attr_value.into())) } @@ -140,14 +140,14 @@ impl PyObject { #[cfg_attr(feature = "flame-it", flame)] pub fn generic_setattr( &self, - attr_name: PyStrRef, // TODO: Py + attr_name: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { vm_trace!("object.__setattr__({:?}, {}, {:?})", self, attr_name, value); if let Some(attr) = vm .ctx - .interned_str(&*attr_name) + .interned_str(attr_name) .and_then(|attr_name| self.get_class_attr(attr_name)) { let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load()); @@ -158,9 +158,9 @@ impl PyObject { if let Some(dict) = self.dict() { if let PySetterValue::Assign(value) = value { - dict.set_item(&*attr_name, value, vm)?; + dict.set_item(attr_name, value, vm)?; } else { - dict.del_item(&*attr_name, vm).map_err(|e| { + dict.del_item(attr_name, vm).map_err(|e| { if e.fast_isinstance(vm.ctx.exceptions.key_error) { vm.new_attribute_error(format!( "'{}' object has no attribute '{}'", @@ -243,8 +243,8 @@ impl PyObject { } } - pub fn del_attr(&self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult<()> { - let attr_name = attr_name.into_pystr_ref(vm); + pub fn del_attr<'a>(&self, attr_name: impl AsPyStr<'a>, vm: &VirtualMachine) -> PyResult<()> { + let attr_name = attr_name.as_pystr(&vm.ctx); self.call_set_attr(vm, attr_name, PySetterValue::Delete) } diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 2c4c266e51..f976d2fc0f 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -50,7 +50,7 @@ mod _ast { ))); } for (name, arg) in fields.iter().zip(args.args) { - zelf.set_attr(name.clone(), arg, vm)?; + zelf.set_attr(name, arg, vm)?; } for (key, value) in args.kwargs { if let Some(pos) = fields.iter().position(|f| f.as_str() == key) { @@ -62,7 +62,7 @@ mod _ast { ))); } } - zelf.set_attr(key, value, vm)?; + zelf.set_attr(vm.ctx.intern_str(key), value, vm)?; } Ok(()) } diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index 6cb1acf9b6..00be9a31eb 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -187,7 +187,7 @@ mod builtins { #[pyfunction] fn delattr(obj: PyObjectRef, attr: PyStrRef, vm: &VirtualMachine) -> PyResult<()> { - obj.del_attr(attr, vm) + obj.del_attr(&attr, vm) } #[pyfunction] @@ -744,7 +744,7 @@ mod builtins { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - obj.set_attr(attr, value, vm)?; + obj.set_attr(&attr, value, vm)?; Ok(()) } diff --git a/vm/src/stdlib/errno.rs b/vm/src/stdlib/errno.rs index c1a487c341..8a0ffd7787 100644 --- a/vm/src/stdlib/errno.rs +++ b/vm/src/stdlib/errno.rs @@ -11,9 +11,11 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "errorcode" => errorcode.clone(), }); for (name, code) in ERROR_CODES { - let name = vm.ctx.new_str(*name); + let name = vm.ctx.intern_str(*name); let code = vm.new_pyobj(*code); - errorcode.set_item(&*code, name.clone().into(), vm).unwrap(); + errorcode + .set_item(&*code, name.to_owned().into(), vm) + .unwrap(); module.set_attr(name, code, vm).unwrap(); } module diff --git a/vm/src/stdlib/thread.rs b/vm/src/stdlib/thread.rs index c8c6c8a2d2..a03f65855e 100644 --- a/vm/src/stdlib/thread.rs +++ b/vm/src/stdlib/thread.rs @@ -5,7 +5,7 @@ pub(crate) use _thread::{make_module, RawRMutex}; #[pymodule] pub(crate) mod _thread { use crate::{ - builtins::{PyDictRef, PyStr, PyStrRef, PyTupleRef, PyTypeRef}, + builtins::{PyDictRef, PyStr, PyTupleRef, PyTypeRef}, convert::ToPyException, function::{ArgCallable, Either, FuncArgs, KwArgs, OptionalArg, PySetterValue}, types::{Constructor, GetAttr, SetAttr}, @@ -381,7 +381,7 @@ pub(crate) mod _thread { impl SetAttr for Local { fn setattro( zelf: &Py, - attr: PyStrRef, + attr: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { @@ -393,9 +393,9 @@ pub(crate) mod _thread { } else { let dict = zelf.ldict(vm); if let PySetterValue::Assign(value) = value { - dict.set_item(&*attr, value, vm)?; + dict.set_item(attr, value, vm)?; } else { - dict.del_item(&*attr, vm)?; + dict.del_item(attr, vm)?; } Ok(()) } diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 0c65c11856..10d2d91cac 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -283,7 +283,7 @@ pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult; pub(crate) type StringifyFunc = fn(&PyObject, &VirtualMachine) -> PyResult; pub(crate) type GetattroFunc = fn(&PyObject, &Py, &VirtualMachine) -> PyResult; pub(crate) type SetattroFunc = - fn(&PyObject, PyStrRef, PySetterValue, &VirtualMachine) -> PyResult<()>; + fn(&PyObject, &Py, PySetterValue, &VirtualMachine) -> PyResult<()>; pub(crate) type AsBufferFunc = fn(&PyObject, &VirtualMachine) -> PyResult; pub(crate) type RichCompareFunc = fn( &PyObject, @@ -418,11 +418,12 @@ fn getattro_wrapper(zelf: &PyObject, name: &Py, vm: &VirtualMachine) -> P fn setattro_wrapper( zelf: &PyObject, - name: PyStrRef, + name: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { let zelf = zelf.to_owned(); + let name = name.to_owned(); match value { PySetterValue::Assign(value) => { vm.call_special_method(zelf, identifier!(vm, __setattr__), (name, value))?; @@ -1241,7 +1242,7 @@ pub trait SetAttr: PyPayload { #[inline] fn slot_setattro( obj: &PyObject, - name: PyStrRef, + name: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()> { @@ -1253,7 +1254,7 @@ pub trait SetAttr: PyPayload { fn setattro( zelf: &Py, - name: PyStrRef, + name: &Py, value: PySetterValue, vm: &VirtualMachine, ) -> PyResult<()>; @@ -1266,13 +1267,13 @@ pub trait SetAttr: PyPayload { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - Self::setattro(&zelf, name, PySetterValue::Assign(value), vm) + Self::setattro(&zelf, &name, PySetterValue::Assign(value), vm) } #[inline] #[pymethod(magic)] fn delattr(zelf: PyRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult<()> { - Self::setattro(&zelf, name, PySetterValue::Delete, vm) + Self::setattro(&zelf, &name, PySetterValue::Delete, vm) } } diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index f19dd01913..bea77a05a4 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -389,8 +389,12 @@ impl Context { pystr::PyStr::new_ref(s, self) } - pub fn interned_or_new_str(&self, s: &str) -> PyRef { - match self.interned_str(s) { + pub fn interned_or_new_str(&self, s: S) -> PyRef + where + S: Into + AsRef, + M: MaybeInternedString, + { + match self.interned_str(s.as_ref()) { Some(s) => s.to_owned(), None => self.new_str(s), } diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index f90dc1191c..a7c00e3438 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -17,7 +17,7 @@ mod vm_ops; use crate::{ builtins::{ code::PyCode, - pystr::{AsPyStr, IntoPyStrRef}, + pystr::AsPyStr, tuple::{PyTuple, PyTupleTyped}, PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStr, PyStrInterned, PyStrRef, PyTypeRef, @@ -270,8 +270,9 @@ impl VirtualMachine { Default::default(), self, )?; + let dunder_name = self.ctx.intern_str(format!("__{name}__")); self.sys_module.set_attr( - format!("__{name}__"), // e.g. __stdin__ + dunder_name, // e.g. __stdin__ stdio.clone(), self, )?; @@ -795,12 +796,12 @@ impl VirtualMachine { pub fn __module_set_attr( &self, module: &PyObject, - attr_name: impl IntoPyStrRef, + attr_name: &str, attr_value: impl Into, ) -> PyResult<()> { let val = attr_value.into(); module.generic_setattr( - attr_name.into_pystr_ref(self), + self.ctx.intern_str(attr_name), PySetterValue::Assign(val), self, ) diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index d34a6cd32b..d70f7b8ba0 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -314,7 +314,7 @@ impl WASMVirtualMachine { let (key, value) = entry?; let key = Object::from(key).to_string(); extend_module!(vm, py_module, { - &vm.ctx.new_str(String::from(key)) => convert::js_to_py(vm, value), + &String::from(key) => convert::js_to_py(vm, value), }); }