Why did my code borrow *self more than once

I have try to code a BST from scratch but there is some problem I found in my code that I don't understand, namely:
why this section resulted in error

fn _check_node(&mut self,checkval:i32)-> &mut Self{
        if let Node::Cons(
            ref curval,
            ref mut high,
            ref mut lows,
        ) = self{
            if *curval > checkval{
                return lows._check_node(checkval);
            }else if *curval < checkval{
                return high._check_node(checkval);
            }
        }
        //high and lows should be out of scope here thus the previous borrow should no longer exist
        //There is still comply error for some reason
        //cannot borrow `*self` as mutable more than once at a time
        return self;
    }

even though this section work perfectly fine

    pub fn add_node(&mut self,newval:i32){
        if let Node::Cons(
            ref curval,
            ref mut high,
            ref mut lows,
        ) = self{
            if *curval > newval{
                lows.add_node(newval);
            }else{
                high.add_node(newval);
            }
        }else{
            *self = Node::create(newval);
        }
    }

Thank you,

You are right, this should be fine. This is a limitation of the current borrow checker. However, it will be made smarter in the future so that code like this can compile. (Search for "polonius" here.)

Is there anything I could do to fix this?
Thanks by the way!

It's always a bit of a struggle to escape these issues but this seems to work. (I don't know exactly what your Node definition is, so I guessed). The first thing that is usually needed is to avoid the destructure match because that reborrows self, which is what causes the issues for the current version of the compiler. So changing that first conditional to return a bool avoids that. Similarly, the helper methods I added make it possible to get the inner data without using a destructure match.

playground

enum Node {
    Cons(i32, Box<Node>, Box<Node>),
}



impl Node {
    fn cons_curval(&self) -> Option<i32> {
        match self {
            Node::Cons(curval,_,_) => Some(*curval),
            _ => None
        }
    }
    fn cons_lows(&mut self) -> Option<&mut Box<Node>> {
        match self {
            Node::Cons(_,lows,_) => Some(lows),
            _ => None
        }
    }
    fn cons_highs(&mut self) -> Option<&mut Box<Node>> {
        match self {
            Node::Cons(_,highs,_) => Some(highs),
            _ => None
        }
    }
    fn _check_node(&mut self, checkval: i32) -> &mut Self {
        if matches!(self, Node::Cons(_,_,_)) {
            let curval = self.cons_curval().unwrap();
            if curval > checkval {
                return self.cons_lows().unwrap()._check_node(checkval)
            } else if curval < checkval {
                return self.cons_highs().unwrap()._check_node(checkval)
            }
        }
        self
    }
}

Edited to match the original structure of the conditional since that change wasn't actually necessary to compile

2 Likes