Confused about Borrow Lifetimes

I'm currently working on a linked list exercise. While implementing the push_tail method, I wrote the following code:

pub struct LinkedList<T> {
    head: Link<T>,
    len: usize,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    data: T,
    next: Link<T>,
}
// ...
impl<T> LinkedList<T> {
    // ...
    fn pop_tail(&mut self) -> Option<T> {
        let mut current = &mut self.head;
        while let Some(node) = current {
            if node.next.is_none() {
                break;
            }

            current = &mut node.next;
        }

        current.take().map(|node| {
            self.len -= 1;
            node.data
        })
    }
}

And the compiler reported the following error:

error[E0499]: cannot borrow `*current` as mutable more than once at a time
...
   |
72 |         while let Some(node) = current {
   |                        ---- first mutable borrow occurs here
...
80 |         current.take().map(|node| {
   |         ^^^^^^^
   |         |
   |         second mutable borrow occurs here
   |         first borrow later used here

I initially believed that the lifetime of the variable node would end after the loop finishes, but it appears to be affecting the subsequent code. I even consulted an AI for help, but the explanation I received didn't make sense to me.

Could someone please help me understand what's going wrong?

this implementation looks right to me, it's probably yet another case for "polonius".

if you are on nightly, try add -Zpolonius to rustflags and see if it compiles.

you can read about this limitation of current borrow checker here:

1 Like

Also, see this answer: Borrow Checker issue when returning from a while let loop - #2 by SkiFire13

Applying the suggestion seems to work:

fn push_tail(&mut self) -> Option<T> {
    let mut current = &mut self.head;
    loop {
        match current {
            Some(node) if node.next.is_none() => break,
            Some(node) => current = &mut node.next,
            None => break,
        }
    }

    current.take().map(|node| {
        self.len -= 1;
        node.data
    })
}
1 Like