rust-lang / rust-lang/rust-clippy

Applying help message emitted by `if_then_some_else_none` results in compile error

Open
#6,963 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug E-medium I-false-positive
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

Lint name: if_then_some_else_none

I tried this code:

fn main() {
    struct Foo;

    struct Bar<'a> {
        foo: &'a mut Foo,
    }

    let mut xs = vec![Foo];
    let _a = xs
        .iter_mut()
        .filter_map(|x| if foo() { Some(Bar { foo: x }) } else { None });
}

Running clippy on the above code gives me a diagnostic that looks like:

|         .filter_map(|x| if foo() { Some(Bar { foo: x }) } else { None });
|                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using `bool::then` like: `foo().then(|| Bar { foo: x })`

Following this help message, I updated the code to:

    let _a = xs.iter_mut().filter_map(|x| foo().then(|| Bar { foo: x }));

This doesn't compile with the following error:

error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
  --> $DIR/if_then_some_else_none.rs:126:54
   |
LL |     let _a = xs.iter_mut().filter_map(|x| foo().then(|| Bar { foo: x }));
   |                                                      ^^            - `x` is borrowed here
   |                                                      |
   |                                                      may outlive borrowed value `x`
   |
note: closure is returned here
  --> $DIR/if_then_some_else_none.rs:126:43
   |
LL |     let _a = xs.iter_mut().filter_map(|x| foo().then(|| Bar { foo: x }));
   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
   |
LL |     let _a = xs.iter_mut().filter_map(|x| foo().then(move || Bar { foo: x }));
   |                                                      ^^^^^^^

error: aborting due to previous error

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

In this particular case, putting move keyword before the closure will work. But it seems like just putting move keyword doesn't always work; in some cases one might need to fix more code to get the code to compile. I wonder if there's a good way of displaying helpful and accurate message to the users.

Meta

I tried on the latest master 919a1a40fe4ec1118eece46b1f4c03c311ab8cda, using directly clippy's test code.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the if_then_some_else_none lint and the Clippy test code containing the shown filter_map example. Check how the help suggestion is constructed and add coverage for borrowed captures; done means the suggested rewrite compiles or the diagnostic accurately accounts for cases requiring move or other changes.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.