Could compiler borrow error message could be improved?

Here is a working function ( from here ):

    fn trim(&mut self, time: u64) {
        let (s, r) = (self.start(time), self.retain(time));
        if s != r {
            let mut empty = Vec::new();
            for (t, pl) in self.vers.range_mut(s..r) {
                let mut done = Vec::new();
                for pnum in pl.iter() {
                    let p = self.pages.get(pnum).unwrap();
                    let mut p = p.d.lock().unwrap();
                    if p.trim(*t, r, self.time) {
                        done.push(*pnum);
                    }
                }
                for pnum in done {
                    pl.remove(&pnum);
                }
                if pl.is_empty() {
                    empty.push(*t);
                }
            }
            for t in empty {
                self.vers.remove(&t);
            }
        }
    }

However if the * in empty.push(*t); is omitted, there is a borrow error. The trouble is the compile error message is:

error[E0499]: cannot borrow `self.vers` as mutable more than once at a time
   --> src\pstore.rs:295:17
    |
278 |             for (t, pl) in self.vers.range_mut(s..r) {
    |                            ------------------------- first mutable borrow occurs here
...
294 |             for t in empty {
    |                      ----- first borrow later used here
295 |                 self.vers.remove(&t);
    |                 ^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here

For more information about this error, try `rustc --explain E0499`.

The line with the actual mistake is not highlighted. I was wondering if this situation could be improved.

That's a bit tricky, because the "mistake" here is totally valid. empty gets inferred to be a Vec of references instead of a Vec of the value behind the reference.

It's probably possible to write a diagnostic that detects this case where theres an inference involved. It seems like it could be pretty confusing if it triggers in a situation where the programmer didn't mean to dereference/clone though.

I wonder if adding some additional information about the type of the bindings involved in the diagnostic might help? Seeing empty has type Vec<&T> which borrows from self.vers or something would probably clue you in to what your mistake was a little faster at least.

3 Likes