Cannot borrow `*current_reader` as mutable more than once at a time

impl SamView {
    pub fn read(&mut self) -> Option<&mut bam::Record> {
        let filter = self.filter;
        let record = &mut self.record;

        while let Some(r) = self.iterator.borrow_mut().read(record) {
            if (filter != 0) && ((record.flags() & filter) != 0) {
                continue
            }
            return Some(record)
        }

        return None
    }
}

impl RecordPreprocessor {
    fn next_on_current_reader<'a>(&'a mut self, current_reader: &'a mut SamView) -> Option<&'a mut Record> {
        let mut record:Option<&mut Record>;

        // let current_reader = self.current_reader.as_mut().unwrap();
        loop {
            record = current_reader.read();
            if record.is_none() {
                return None;
            }

            if self.preprocess_record(record.as_ref().unwrap()) {
                break;
            }
        }
        // None
        record
    }
}

error[E0499]: cannot borrow `*current_reader` as mutable more than once at a time
   --> src/modules/RecordPreprocessor.rs:209:22
    |
204 |     fn next_on_current_reader<'a>(&'a mut self, current_reader: &'a mut SamView) -> Option<&'a mut Record> {
    |                               -- lifetime `'a` defined here
...
209 |             record = current_reader.read();
    |                      ^^^^^^^^^^^^^^^^^^^^^ `*current_reader` was mutably borrowed here in the previous iteration of the loop
...
219 |         record
    |         ------ returning this value requires that `*current_reader` is borrowed for `'a`


Hi. I am currently trying to fix this error.
I read several topics about this error and I'm struggling to figure out what to do.

The error message sounds like it's wrong to do a mutable borrowing in a loop.
But if I don't return record and return None instead, the error message goes away.

Can you tell me why? Isn't the mutable borrowing still inside the loop?

it's a limitation of current borrow checker. search polonius.

your code should compile with RUSTFLAGS=-Zpolonius, try it.

3 Likes

This is an error of the type that you can truly blame the borrow checker to be overly simplistic/restrictive, i.e. “too dumb to understand the code”.

There’s a new, experimental borrow checker (called “polonius”) and it does accept your code (see here for a compiler explorer instance that shows how with polonius it doesn’t error anymore).

For stable Rust, there are typically ways to work around the issue though. A good source for some information on workarounds is this crate’s documentation, a crate which also offers its own ultimate solution to solve such borrow-checking problems in case no other workaround works.

2 Likes

On second read, I don’t think any of the workarounds that don’t involve changing your function signature would work here.

Here’s be a way to use the macros from the polonius_the_crab crate to create an implementation following the same logic as the one you posted

use polonius_the_crab::{polonius, polonius_return};
impl RecordPreprocessor {
    fn next_on_current_reader<'a>(
        &mut self,
        mut current_reader: &'a mut SamView,
    ) -> Option<&'a mut Record> {
        loop {
            polonius!(|current_reader| -> Option<&'polonius mut Record> {
                let record = current_reader.read();
                if record.is_none() {
                    polonius_return!(None);
                }

                if self.preprocess_record(record.as_ref().unwrap()) {
                    polonius_return!(record);
                }
            })
        }
    }
}

for adapting different control-flow patterns, e.g. feel free to ask follow-up questions, as the crate can be a bit tricky to use.

1 Like

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.