Skip to content

Unable to use match with a borrowed value which will be mutated and returned within the match statement #115390

@ProbstDJakob

Description

@ProbstDJakob

When trying to mutate a value within a match statement which is borrowed by the statement and returned as the result of the function, the compiler fails with the error E0506.

I tried this code:

struct LazyItem {
    item: Option<String>
}

impl LazyItem {
    fn get_item(&mut self) -> &str {
        match &self.item {
            None => {
                self.item = Some("Greetings".to_string());
                let Some(content) = &self.item else { unreachable!() };
                content
            },
            Some(content) => content,
        }
    }
}

fn main() {
    let mut instance = LazyItem { item: None };
    assert_eq!(instance.get_item(), "Greetings");
}

I expected to see this happen: That the code compiles and runs successfully.

Instead, this happened: The compilation failed with the following error:

error[E0506]: cannot assign to `self.item` because it is borrowed
  --> src/main.rs:9:17
   |
6  |       fn get_item(&mut self) -> &str {
   |                   - let's call the lifetime of this reference `'1`
7  |           match &self.item {
   |           -     ---------- `self.item` is borrowed here
   |  _________|
   | |
8  | |             None => {
9  | |                 self.item = Some("Greetings".to_string());
   | |                 ^^^^^^^^^ `self.item` is assigned to here but it was already borrowed
10 | |                 let Some(content) = &self.item else { unreachable!() };
...  |
13 | |             Some(content) => content,
14 | |         }
   | |_________- returning this value requires that `self.item` is borrowed for `'1`

For more information about this error, try `rustc --explain E0506`.

Using if syntax the code compiles and runs successfully.

Code

struct LazyItem {
    item: Option<String>
}

impl LazyItem {
    fn get_item(&mut self) -> &str {
        if let None = &self.item {
            self.item = Some("Greetings".to_string());
            let Some(content) = &self.item else { unreachable!() };
            content
        } else if let Some(content) = &self.item {
            content
        } else {
            unreachable!()
        }
    }
}

fn main() {
    let mut instance = LazyItem { item: None };
    assert_eq!(instance.get_item(), "Greetings");
}

Meta

rustc --version --verbose:

rustc 1.72.0 (5680fa18f 2023-08-23)
binary: rustc
commit-hash: 5680fa18feaa87f3ff04063800aec256c3d4b4be
commit-date: 2023-08-23
host: x86_64-unknown-linux-gnu
release: 1.72.0
LLVM version: 16.0.5

Nigthly version with the same result:

rustc 1.74.0-nightly (4e78abb43 2023-08-28)
binary: rustc
commit-hash: 4e78abb437a0478d1f42115198ee45888e5330fd
commit-date: 2023-08-28
host: x86_64-unknown-linux-gnu
release: 1.74.0-nightly
LLVM version: 17.0.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.fixed-by-poloniusCompiling with `-Zpolonius` fixes this issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions