rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.63k stars 12.74k forks source link

Confusing error when borrowing members in an automatic dereference #86219

Open ChrisJefferson opened 3 years ago

ChrisJefferson commented 3 years ago

Given the following code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f3f0df13f266b9a222fbeedc4a8f6168

struct X
{
    pub a: i32,
    pub b: i32,
}

fn main() {
    let y = std::sync::Mutex::new(X{a:1, b: 2});

    let g = &mut (y.lock().unwrap());

    let a = &mut g.a;
    let b = &mut g.b;

    assert!(*a + *b == 3);
}

The current output is:

error[E0499]: cannot borrow `*g` as mutable more than once at a time
  --> src/main.rs:14:18
   |
13 |     let a = &mut g.a;
   |                  - first mutable borrow occurs here
14 |     let b = &mut g.b;
   |                  ^ second mutable borrow occurs here
15 | 
16 |     assert!(*a + *b == 3);
   |             -- first borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground`

Ideally the output should tell the user that g. is not a simple "member access", which is why they can't borrow multiple members. It could even, in principle, tell them to capture *g first, then access it's a and b members, but I suspect that isn't simple (or even legal) in general.

ahrens commented 2 years ago

Several members of my team (myself included) ran into this and I wrote up this very similar example before finding this bug: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=881fa5892e94d0722bb879221578cf64

It would be super awesome if the compiler could suggest a solution like

    let mut guard = locked_point.lock().unwrap();
    let point = &mut *guard;
estebank commented 1 year ago

Triage: no change.