Skip to content

Accessing fields through a Deref impl leads to confusing error messages #81365

Closed

Description

The following code:

use std::ops::Deref;

struct DerefTarget {
    target_field: bool
}
struct Container {
    target: DerefTarget,
    container_field: bool,
}

impl Deref for Container {
    type Target = DerefTarget;
    fn deref(&self) -> &Self::Target {
        &self.target
    }
}

impl Container {
    fn bad_borrow(&mut self) {
        let first = &self.target_field;
        self.container_field = true;
        first;
    }
}

causes the following error message:

error[E0506]: cannot assign to `self.container_field` because it is borrowed
  --> src/lib.rs:21:9
   |
20 |         let first = &self.target_field;
   |                      ---- borrow of `self.container_field` occurs here
21 |         self.container_field = true;
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
22 |         first;
   |         ----- borrow later used here

This error is caused by the fact that &self.target_field does through the Deref impl on Container. As a result, &self is borrowed, not just the desired field. Changing this line to let first = &self.target.target_field makes the code compile.

However, the error message doesn't explain any of this. It claims that the usage of self is a borrow of self.container_field, without noting that this is due to the Deref impl.

We should do something similar to #75304 for borrows, and make it clear when lifetimes are being affected by implicit Deref calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Labels

A-borrow-checkerArea: The borrow checkerA-diagnosticsArea: Messages for errors, warnings, and lintsC-bugCategory: This is a bug.D-confusingDiagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions