Repository: RustPython/RustPython (language: rust)

Issue:
Context::empty_str to &'static PyStrInterned
Search for `pub empty_str: PyRef<PyStr>,` to find the definition.

it is currently a `PyRef<PyStr>`, but can be an interned string.




Discussion / hints:
I am new to internals of rustpython-vm, can you please let me know (or refer relevant doc, if any) what does interned string means and why is it better?
will this be helpful? https://docs.python.org/3/library/sys.html#sys.intern
Thanks, got it.

Fix patch:
diff --git a/stdlib/src/sqlite.rs b/stdlib/src/sqlite.rs
index 57ce3dc35d..9fae91fd69 100644
--- a/stdlib/src/sqlite.rs
+++ b/stdlib/src/sqlite.rs
@@ -297,7 +297,7 @@ mod _sqlite {
         timeout: f64,
         #[pyarg(any, default = "0")]
         detect_types: c_int,
-        #[pyarg(any, default = "Some(vm.ctx.empty_str.clone())")]
+        #[pyarg(any, default = "Some(vm.ctx.empty_str.to_owned())")]
         isolation_level: Option<PyStrRef>,
         #[pyarg(any, default = "true")]
         check_same_thread: bool,
diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs
index 6b47642324..022503a416 100644
--- a/vm/src/builtins/str.rs
+++ b/vm/src/builtins/str.rs
@@ -352,7 +352,7 @@ impl PyStr {
         if value == 0 && zelf.class().is(vm.ctx.types.str_type) {
             // Special case: when some `str` is multiplied by `0`,
             // returns the empty `str`.
-            return Ok(vm.ctx.empty_str.clone());
+            return Ok(vm.ctx.empty_str.to_owned());
         }
         if (value == 1 || zelf.is_empty()) && zelf.class().is(vm.ctx.types.str_type) {
             // Special case: when some `str` is multiplied by `1` or is the empty `str`,
diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs
index f4e2e99b58..773ac53cc0 100644
--- a/vm/src/exceptions.rs
+++ b/vm/src/exceptions.rs
@@ -496,7 +496,7 @@ impl PyBaseException {
     pub(super) fn str(&self, vm: &VirtualMachine) -> PyStrRef {
         let str_args = vm.exception_args_as_string(self.args(), true);
         match str_args.into_iter().exactly_one() {
-            Err(i) if i.len() == 0 => vm.ctx.empty_str.clone(),
+            Err(i) if i.len() == 0 => vm.ctx.empty_str.to_owned(),
             Ok(s) => s,
             Err(i) => PyStr::from(format!("({})", i.format(", "))).into_ref(&vm.ctx),
         }
diff --git a/vm/src/frame.rs b/vm/src/frame.rs
index 25ca719d14..842f85f01a 100644
--- a/vm/src/frame.rs
+++ b/vm/src/frame.rs
@@ -1130,7 +1130,7 @@ impl ExecutingFrame<'_> {
 
     #[cfg_attr(feature = "flame-it", flame("Frame"))]
     fn import(&mut self, vm: &VirtualMachine, module: Option<&Py<PyStr>>) -> PyResult<()> {
-        let module = module.unwrap_or(&vm.ctx.empty_str);
+        let module = module.unwrap_or(vm.ctx.empty_str);
         let from_list = <Option<PyTupleTyped<PyStrRef>>>::try_from_object(vm, self.pop_value())?;
         let level = usize::try_from_object(vm, self.pop_value())?;
 
diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs
index ba7d06a724..1fb47f2552 100644
--- a/vm/src/stdlib/io.rs
+++ b/vm/src/stdlib/io.rs
@@ -2609,7 +2609,7 @@ mod _io {
                     }
                 }
                 if chunks.is_empty() {
-                    vm.ctx.empty_str.clone()
+                    vm.ctx.empty_str.to_owned()
                 } else if chunks.len() == 1 {
                     chunks.pop().unwrap()
                 } else {
@@ -2871,7 +2871,7 @@ mod _io {
             } else if let Some(cur_line) = cur_line {
                 cur_line.slice_pystr(vm)
             } else {
-                vm.ctx.empty_str.clone()
+                vm.ctx.empty_str.to_owned()
             };
             Ok(line)
         }
@@ -3030,7 +3030,7 @@ mod _io {
             append: Option<PyStrRef>,
             vm: &VirtualMachine,
         ) -> PyStrRef {
-            let empty_str = || vm.ctx.empty_str.clone();
+            let empty_str = || vm.ctx.empty_str.to_owned();
             let chars_pos = std::mem::take(&mut self.decoded_chars_used).bytes;
             let decoded_chars = match std::mem::take(&mut self.decoded_chars) {
                 None => return append.unwrap_or_else(empty_str),
diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs
index 9680231873..596bd3a932 100644
--- a/vm/src/vm/context.rs
+++ b/vm/src/vm/context.rs
@@ -35,7 +35,7 @@ pub struct Context {
     pub none: PyRef<PyNone>,
     pub empty_tuple: PyTupleRef,
     pub empty_frozenset: PyRef<PyFrozenSet>,
-    pub empty_str: PyRef<PyStr>,
+    pub empty_str: &'static PyStrInterned,
     pub empty_bytes: PyRef<PyBytes>,
     pub ellipsis: PyRef<PyEllipsis>,
     pub not_implemented: PyRef<PyNotImplemented>,
@@ -292,7 +292,7 @@ impl Context {
             types.builtin_function_or_method_type,
         );
 
-        let empty_str = unsafe { string_pool.intern("", types.str_type.to_owned()) }.to_owned();
+        let empty_str = unsafe { string_pool.intern("", types.str_type.to_owned()) };
         let empty_bytes = create_object(PyBytes::from(Vec::new()), types.bytes_type);
         let context = Context {
             true_value,


Test patch: