# Trace mutable borrows across function call boundaries

**URL:** https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713
**Category:** language design
**Created:** [February 5, 2018, 9:24pm UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713 "2018-02-05T21:24:41Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Victor\_Savu](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/victor_savu/32/1115_2.png) [@Victor\_Savu](https://internals.rust-lang.org/u/Victor_Savu)
#### Post date: [February 5, 2018, 9:24pm UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713/1 "2018-02-05T21:24:41Z")

</div>

One day on the #rust-beginners forum someone was having a hard time with the borrow checker (it was one of those special days, yes). I am sorry I cannot remember who the person was, but I found the problem to be very interesting and their intuition about the code was as far as I can tell sound. I would like to discuss the problem here to figure out

- if the intuition about the soundness of the code is correct
- if we can teach the borrow checker new tricks to accept this behavior (or if there is something in the works already that I couldn’t find in my searches)

> **Old example which is just a special case of what NLL already handles**
>
> The problem can be seen in the following piece of code:
> 
> ```rust
> struct Resource {
> accessed: usize
> }
> 
> impl Resource {
> fn access(&mut self) -> &usize {
> self.accessed += 1;
> &self.accessed
> }
> }
> 
> fn main() {
> let mut res = Resource { accessed: 0 };
> // { // uncomment to appease the borrow checker
> let accessed = res.access();
> assert_eq!(*accessed, 1);
> // } // uncomment to appease the borrow checker
> assert_eq!(res.accessed, 1);
> }
> ```
> 
> Method `access` mutably borrows `self` and leaks an immutable reference to one of the sub-fields. Now, my intuition would say that this particular method has no way to leak a mutable reference to `self`, so after calling the method `self` should be just borrowed immutably. However, the borrow checker is not convinced, since it requires the leaked reference to be dropped before ending the mutable borrow on `self`.
> 
> Now, if we just inline the body of `access` into `main`, the borrow checker is happy to notice where the mutability of the borrow ends:
> 
> ```rust
> struct Resource {
> accessed: usize
> }
> 
> fn main() {    
> let mut res = Resource { accessed: 0 };
> let accessed = {
> res.accessed += 1;
> &res.accessed
> };
> assert_eq!(*accessed, 1);
> assert_eq!(res.accessed, 1);
> }
> ```
> 
> Would it be possible (feasible & desirable) to trace the mutability of the borrow across function call boundaries so that the first example would be accepted by the borrow checker as well?

**Later edit:** _The initial example did not correctly present the core problem, as the upcoming non-lexical lifetimes feature would make that code compile. Thanks to the perceptiveness of the first three commenters in this thread (@Ixrec, @kennytm and @atagunov), this error was identified. Moreover, @atagunov provided an accurate example of the problem [in a comment below](https://internals.rust-lang.org/t/trace-mutable-borrow-across-function-call-boundaries/6713/5)._

After further research, I found that very problem presented [in the Rustonomicon](https://doc.rust-lang.org/nomicon/lifetime-mismatch.html) (if you are thinking “you should feel bad for not finding this before posting”, rest assured that I do 🙂).

```rust
struct Foo;

impl Foo {
    fn mutate_and_share(&mut self) -> &Self { &*self }
    fn share(&self) {}
}

fn main() {
    let mut foo = Foo;
    let loan = foo.mutate_and_share();
    foo.share();
}
```

fails with:

```rust
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
  --> src/main.rs:11:5
   |
10 | let _loan = foo.mutate_and_share();
   | --- mutable borrow occurs here
11 | foo.share();
   | ^^^ immutable borrow occurs here
12 | }
   | - mutable borrow ends here
```

As the Rustonomicon explains, the problem is that the lifetime of the borrow `&mut self` which takes place when `mutate_and_share` is called, must last as long as `_loan` in order to avoid `_loan` becoming a dangling reference. And that is great! What is not great is that the borrow stays mutable throughout, and we really don’t need it to be mutable for the lifetime of `_loan` because `_loan` is not mutable.

So I would like to open the discussion regarding the possibility to trace the mutability separately and convert the mutable borrow into an immutable one as soon as it no longer needs to be mutable.

---

<div class="post-metadata">

### Author: ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)
#### Post date: [February 5, 2018, 10:20pm UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713/2 "2018-02-05T22:20:27Z")

</div>

This seems like one of the simplest typical motivating examples for the enhancement we usually call “non-lexical lifetimes”, which is very much in the works. The tracking issue is [https://github.com/rust-lang/rust/issues/43234](https://github.com/rust-lang/rust/issues/43234). For a general introduction to what on earth “non-lexical lifetimes” means and what sort of code it’s supposed to affect, the RFC’s guide-level explanation is probably the best resource: [https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md](https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md) Your example is pretty much identical to “Problem Case #1” from that RFC.

---

<div class="post-metadata">

### Author: ![Victor\_Savu](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/victor_savu/32/1115_2.png) [@Victor\_Savu](https://internals.rust-lang.org/u/Victor_Savu)
#### Post date: [February 6, 2018, 9:19am UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713/3 "2018-02-06T09:19:42Z")

</div>

Thanks! I did read the `nll` RFC before posting, but I couldn’t convince myself that it would handle this case. Sorry for the noise if it already does. I can at least confirm that in its current (partial) implementation the `nll` feature on nightly does not yet solve this problem 🙂 I guess I could wait for the full implementation before bringing this up again, but I am sure curious 🙂

---

<div class="post-metadata">

### Author: ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)
#### Post date: [February 6, 2018, 10:24am UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713/4 "2018-02-06T10:24:39Z")

</div>

The original example does work when NLL is enabled. [https://play.rust-lang.org/?gist=455e16d10ba405660dfda8e227e82607&version=nightly](https://play.rust-lang.org/?gist=455e16d10ba405660dfda8e227e82607&version=nightly)

---

<div class="post-metadata">

### Author: ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)
#### Post date: [February 7, 2018, 11:24pm UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713/5 "2018-02-07T23:24:26Z")

</div>

> [@kennytm](#):
>
> The original example does work when NLL is enabled

Hi, however this does not work

```rust
#![feature(nll)]

struct Resource {
    accessed: usize
}

impl Resource {
    fn access(&mut self) -> &usize {
        self.accessed += 1;
        &self.accessed
    }
}

fn main() {
    let mut res = Resource { accessed: 0 };
    let accessed = res.access();
    assert_eq!(res.accessed, 1);
    assert_eq!(*accessed, 1);
}

```

failing with

```rust
16 | let accessed = res.access();
   | --- mutable borrow occurs here
17 | assert_eq!(res.accessed, 1);
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here

```

...and I think this is the example @Victor_Savu would have liked to enable

---

<div class="post-metadata">

### Author: ![Victor\_Savu](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/victor_savu/32/1115_2.png) [@Victor\_Savu](https://internals.rust-lang.org/u/Victor_Savu)
#### Post date: [February 8, 2018, 7:38am UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713/6 "2018-02-08T07:38:40Z")

</div>

@kennytm, @atagunov yes, you are both right. Sorry for the initial example. I modified it to make the former look more like the latter and forgot to test it with nll again.

In short, I don’t want the borrow to end, I just want it to become immutable. Thanks, @atagunov ! Your correction perfectly represents the issue. May I edit the original question with your version in order to give future readers an easier time?

---

<div class="post-metadata">

### Author: ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)
#### Post date: [March 25, 2019, 8:29am UTC](https://internals.rust-lang.org/t/trace-mutable-borrows-across-function-call-boundaries/6713/7 "2019-03-25T08:29:38Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
