Skip to content

Confusing suggestion when doing a conditional destructuring on a field of Deref struct #146995

@Chocorean

Description

@Chocorean

Code

use std::ops::{Deref, DerefMut};

fn main() {
    let mut db = DataBox::new(Complex {
        b: true,
        s: Some(Simple { a: 0, b: false }),
    });

    if let Some(mut s) = db.s {
        s.a = 1;
    }

    #[allow(unused_mut)]
    let mut clone = db.clone();
    if let Some(mut s) = clone.s {
        s.a = 1;
    }
    *db = clone;
}

#[derive(Clone)]
struct Simple {
    a: u8,
    b: bool,
}

#[derive(Clone)]
struct Complex {
    b: bool,
    s: Option<Simple>,
}

struct DataBox<T> {
    d: T,
}

impl<T> DataBox<T> {
    fn new(d: T) -> DataBox<T> {
        DataBox { d }
    }
}

impl<T> Deref for DataBox<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.d
    }
}

impl<T> DerefMut for DataBox<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.d
    }
}

Current output

Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of dereference of `DataBox<Complex>`
 --> src/main.rs:9:26
  |
9 |     if let Some(mut s) = db.s {
  |                 -----    ^^^^
  |                 |
  |                 data moved here
  |                 move occurs because `s` has type `Simple`, which does not implement the `Copy` trait
  |
help: consider borrowing here
  |
9 |     if let Some(mut s) = &db.s {
  |                          +

error[E0382]: use of partially moved value: `clone`
  --> src/main.rs:18:11
   |
15 |     if let Some(mut s) = clone.s {
   |                 ----- value partially moved here
...
18 |     *db = clone;
   |           ^^^^^ value used here after partial move
   |
   = note: partial move occurs because value has type `Simple`, which does not implement the `Copy` trait
help: borrow this binding in the pattern to avoid moving the value
   |
15 |     if let Some(ref mut s) = clone.s {
   |                 +++

Some errors have detailed explanations: E0382, E0507.
For more information about an error, try `rustc --explain E0382`.
error: could not compile `playground` (bin "playground") due to 2 previous errors

Desired output

I think the first output from rustc is misleading: the provided help keeps bringing more new errors.

The correct suggestion would be use `ref`, as mentioned in the second error output.

Rationale and extra context

No response

Other cases

Rust Version

$ rustc --version --verbose
rustc 1.90.0 (1159e78c4 2025-09-14)
binary: rustc
commit-hash: 1159e78c4747b02ef996e55082b704c09b970588
commit-date: 2025-09-14
host: x86_64-unknown-linux-gnu
release: 1.90.0
LLVM version: 20.1.8

Anything else?

Playground 1.90.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsD-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions