Relaxing the borrow checker for fn (&mut self) -> &T

@kvijayan You repeatedly refer to mutations as if mutating something is the only reason for &mut. That is an understandable confusion, and most people (including myself) think of it like that most of the time, but it’s not all there is to mutable borrows. A &mut is also a unique borrow, and as such ca be useful even if you don’t need to mutate anything. For example, consider a stack-like data structure that ensures only the top-most frame on the stack is usable at any point in time:

use std::marker::PhantomData;

struct Stack;
struct Frame<'a>(PhantomData<&'a ()>);

impl Stack {
    fn first_frame(&mut self) -> Frame {
        unimplemented!()
    }
}

impl<'a> Frame<'a> {
    fn sub_frame(&mut self) -> Frame {
        unimplemented!()
    }

    fn do_something(&self) {}
}

fn main() {
    let mut stack = Stack;
    let mut frame1 = stack.first_frame();
    frame1.do_something();
    {
        let frame2 = frame1.sub_frame();
        frame2.do_something();
        // frame1.do_something(); // doesn't compile
    }
    frame1.do_something();
}

There is no mutation in this program, but it still enforces an important semantic invariant through lifetimes. And virtually any semantic invariant can become vital for the memory safety of the whole program when it’s a semantic invariant that unsafe code relies on.

Now, the above example relies on lifetime parameters on structs. I’ve not given it enough thought to say for sure whether one can pull similar tricks using only references. But if this extension would require special pleading for references, then that would be a big mark against it in my mind.