rust-lang / rust-lang/rust-clippy
Clippy suggestion on `unnecessary_unwrap` not applicable in function taking `&mut` struct and returning reference to contained element
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Rust reproducer in the issue and inspect the unnecessary_unwrap lint and its suggestion. Run Clippy against the example, then verify that the suggested rewrite compiles or that the lint is omitted for this case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100