Skip to content

Clippy suggestion on unnecessary_unwrap not applicable in function taking &mut struct and returning reference to contained element #16182

@danielrainer

Description

@danielrainer

Summary

The following code triggers the unnecessary_unwrap lint, which is understandable, since there is in fact a is_some check followed by an unwrap. However, rewriting the code as suggested by results in the function not compiling (see the commented-out version in the repro):

error[E0502]: cannot borrow `self.opt` as mutable because it is also borrowed as immutable
  --> src/main.rs:19:9
   |
15 |     fn repro(&mut self) -> &String {
   |              - let's call the lifetime of this reference `'1`
16 |         if let Some(val) = &self.opt {
   |                            --------- immutable borrow occurs here
17 |             return val;
   |                    --- returning this value requires that `self.opt` is borrowed for `'1`
18 |         }
19 |         self.opt.insert(String::new())
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

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

If there is a more idiomatic way of writing this, it would be nice to get a corresponding suggestion. Otherwise, it might be better to disable the lint for such cases. If it is not feasible to correctly identify cases where the current suggestion does not work, it might be acceptable to keep the current behavior and require manual deactivation of the lint for the affected code via annotations.

Reproducer

Code:

struct Wrapper {
    opt: Option<String>,
}

impl Wrapper {
    fn repro(&mut self) -> &String {
        if self.opt.is_some() {
            return self.opt.as_ref().unwrap();
        }
        self.opt.insert(String::new())
    }

    /*
     * fn repro(&mut self) -> &String {
     *     if let Some(val) = &self.opt {
     *         return val;
     *     }
     *     self.opt.insert(String::new())
     * }
     */
}

fn main() {
    let mut wrapper = Wrapper { opt: None };
    let _ = wrapper.repro();
}

Current output:

warning: called `unwrap` on `self.opt` after checking its variant with `is_some`
 --> src/main.rs:8:20
  |
7 |         if self.opt.is_some() {
  |         --------------------- help: try: `if let Some(<item>) = &self.opt`
8 |             return self.opt.as_ref().unwrap();
  |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
  = note: `#[warn(clippy::unnecessary_unwrap)]` on by default

Desired output:

a suggestion for more idiomatic code which compiles, or, if that's not possible, no lint for this code

Version

rustc 1.93.0-nightly (1d60f9e07 2025-12-01)
binary: rustc
commit-hash: 1d60f9e070c1039b263e0f035c0f03dfcc610d0f
commit-date: 2025-12-01
host: x86_64-unknown-linux-gnu
release: 1.93.0-nightly
LLVM version: 21.1.5

Additional Labels

@rustbot label +I-suggestion-causes-error

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: Clippy is not doing the correct thingI-suggestion-causes-errorIssue: The suggestions provided by this Lint cause an ICE/error when applied

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions