What permits `fn(&mut self) -> &Inner`?

So, this is, I think, a borrowchecker terminology question.

The following get_ref method (which, to be clear, compiles just fine) turns an exclusive borrow of self into a shared borrow of self.0:

struct MyStruct(i32);
impl MyStruct {
    fn get_ref(&mut self) -> &i32 {
        &self.0
    }
}

Intuitively, I have no problems with this, it's exactly what I would expect (i.e., the borrow checker won't let you use &mut self again until &i32 reference has been dropped).

My question is: what feature permits me to "downgrade" from an &mut to an & like this? Is it "reborrowing"? "Projection"? Or maybe something involving the Deref/DerefMut traits?

Reborrowing. Or coercion, I guess,[1] but I think of it as reborrowing.


  1. for the simple case not involving fields or dereferences ↩︎

2 Likes

BTW, the returned & reference is a bit magic, because it shares a lifetime with the exclusive reference it came from, which makes the shared reference still restricted by the original loan and not as flexible as if you reborrowed &self.

2 Likes

notice that &mut self doesn't even get it's property of &mut because borrower is smart enough to just say "hey, this is redundant". You will end up with just &self -> &i32. You're returning the ref to self, which is correct, but what about this?: let shared_ref: &i32 = &(*self).0;

If you mean get_ref will act like a fn(&self) -> &i32 to the caller, that is incorrect. The function signature determines the API contract, and a &mut _ is required to call it, no matter what the function body does or doesn't do with the &mut _.

1 Like

It won't even let you use &self while that &mut self -> &_ borrow is active, which is what @kornel was getting at. There have been some ideas about truly downgrading mutability, but we don't have that yet.

And if we get it, it won't replace fn(&mut self) -> &_.

1 Like