Bug: compile error E0502, I want to mutate a Node inside Vec<Node>, it is a field of my struct

I am working on my side project "rg_explorer". I've written a topic on this forum introducing the project, and I have an error that has been bugging me since many days ago.

I am trying to solve the issue Optimize the wrapper to search context in only the file displayed on "Detail" view of "Nodes" tab. I need to launch ripgrep only in the selected file when I want more or less lines of context around the matches of that file, instead of running ripgrep in the whole source code I'm exploring each time I hit an arrow key.

The error is this:

error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable
  --> src/rip_grep/mod.rs:77:26
   |
76 |         let n: &mut Node = self.nodes.0.get_mut(i).unwrap();
   |                            ----------------------- mutable borrow occurs here
77 |         n.update_context(&self, delta);
   |           -------------- ^^^^^ immutable borrow occurs here
   |           |
   |           mutable borrow later used by call

For more information about this error, try `rustc --explain E0502`.
error: could not compile `rg_explorer` due to previous error

Line 76 is a function of the RipGrep struct, it takes the nodes field that is a Vec, gets a mutable ref to the i element inside the vector and unwraps it.

On line 77 it calls the update_context function from the Node struct and calls it. It needs to send the self argument, because RipGrep struct has a function that launches ripgrep, and I need to launch this function inside the i-node I've got on line 76. I can't figure out how to get rid of this error. I've tried another alternative solution, where I use another path to call the rip grep instance, but I end up anyways with this same error.

Am I approaching this problem the right way? How can I fix this? Why the compiler is highlighting the update_context function? I don't see the mutable borrow being used there.

You can find the code in the branch issue_1-optimize_wrapper_change_context_only_current_file-alt1 of the repository, you can access the repo by clicking the second link, or the reply I'm going to post below (beginners are restricted to only two links, sorry).

Best regards.

PS: If you click the second link, you can see the branch I am

Here is the link to the PR that has the branch issue_1-optimize_wrapper_change_context_only_current_file-alt1 . You can clone the repo and switch to the branch, if you run cargo build you will get the error I copy-pasted on the main post of this thread.

Node::update_context takes a &mut self -- that's the use of the &mut. The Node is contained in the Self = RipGrep, so the &self can observe the same memory as the exclusive &mut Node. That would be instance UB, hence the error.

More generally this looks like a interprocedural conflict.

In this case I suspect you could change your data structure ("factoring as a possible fix"):

 pub struct RipGrep {
     search_term: String,
     pub search_term_buffer: String,
-    pub nodes: Nodes,
     after_context: usize,
     before_context: usize,
     folder: String,
 }
+pub struct RipData {
+    pub nodes: Nodes,
+    pub grep: RipGrep,
+}
+    // n.b. Self = RipData
     pub fn update_context(&mut self, i: usize, delta: isize) {
         let n: &mut Node = self.nodes.0.get_mut(i).unwrap();
-        n.update_context(&self, delta);
+        n.update_context(&self.grep, delta);
     }
3 Likes

Thank you, I didn't thought about that. I already tried the approach you suggested ("factoring as a possible fix), but it is going to take some refactorization work, but I've got the main idea and I'm going to read the Baby Steps article to know the details.

As soon as I made some progress I'll reply here. Thanks.

Resolved, you I've merged the PR I linked above, and it contains the solution to the problem, if you want to take a look.

Thank you.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.