Repository: rune-rs/rune (language: rust)

Issue:
Vec::resize should clone elements being added
When the Vec.resize function is supplied with an empty vector as the initial value, all the slots seem to be sharing a same vector. Is this a bug? 

```rust
let a = [];
a.resize(3, []);
a[0].push(0);
a[1].push(1);
a[2].push(2);
dbg!(a);
// output: [[0, 1, 2], [0, 1, 2], [0, 1, 2]]
```


Discussion / hints:
Thanks for the report! This is a bug. `Vec::resize` should call `CLONE` on the values being added.

Fix patch:
diff --git a/crates/rune/src/modules/vec.rs b/crates/rune/src/modules/vec.rs
index af82bf2d2..bdb649e4b 100644
--- a/crates/rune/src/modules/vec.rs
+++ b/crates/rune/src/modules/vec.rs
@@ -582,6 +582,20 @@ fn index_set(this: &mut Vec, index: usize, value: Value) -> VmResult<()> {
 /// vec.resize(2, 0);
 /// assert_eq!(vec, [1, 2]);
 /// ```
+///
+/// Resizing calls `CLONE` each new element, which means they are not
+/// structurally shared:
+///
+/// ```rune
+/// let inner = [1];
+/// let vec = [2];
+/// vec.resize(3, inner);
+///
+/// inner.push(3);
+/// vec[1].push(4);
+///
+/// assert_eq!(vec, [2, [1, 4], [1]]);
+/// ```
 #[rune::function(instance)]
 fn resize(this: &mut Vec, new_len: usize, value: Value) -> VmResult<()> {
     Vec::resize(this, new_len, value)
diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs
index 56e2a9ea3..24a92769e 100644
--- a/crates/rune/src/runtime/value.rs
+++ b/crates/rune/src/runtime/value.rs
@@ -1617,6 +1617,11 @@ impl Value {
         }
     }
 
+    /// Test if the value is inline.
+    pub(crate) fn is_inline(&self) -> bool {
+        matches!(self.repr, Repr::Any(..) | Repr::Inline(..))
+    }
+
     /// Coerce into a checked [`Inline`] object.
     ///
     /// Any empty value will cause an access error.
diff --git a/crates/rune/src/runtime/vec.rs b/crates/rune/src/runtime/vec.rs
index 3bc18bfec..1f36483b5 100644
--- a/crates/rune/src/runtime/vec.rs
+++ b/crates/rune/src/runtime/vec.rs
@@ -14,6 +14,7 @@ use crate::runtime::slice::Iter;
 use crate::runtime::Hasher;
 use crate::{Any, TypeHash};
 
+use super::EnvProtocolCaller;
 use super::{
     Formatter, FromValue, ProtocolCaller, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo,
     RangeToInclusive, RawAnyGuard, Ref, ToValue, UnsafeToRef, Value, VmErrorKind, VmResult,
@@ -132,7 +133,21 @@ impl Vec {
     /// difference, with each additional slot filled with `value`. If `new_len`
     /// is less than `len`, the `Vec` is simply truncated.
     pub fn resize(&mut self, new_len: usize, value: Value) -> VmResult<()> {
-        vm_try!(self.inner.try_resize(new_len, value));
+        if value.is_inline() {
+            vm_try!(self.inner.try_resize(new_len, value));
+        } else {
+            let len = self.inner.len();
+
+            if new_len > len {
+                for _ in 0..new_len - len {
+                    let value = vm_try!(value.clone_with(&mut EnvProtocolCaller));
+                    vm_try!(self.inner.try_push(value));
+                }
+            } else {
+                self.inner.truncate(new_len);
+            }
+        }
+
         VmResult::Ok(())
     }
 


Test patch: