rustc shouldn't suggest returning `Option<&Option<T>>` in `filter_map`
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
struct NonCopy;
fn main() {
_ = vec![Some(()), None, Some(())].iter().filter_map(|x| x);
_ = vec![Some(NonCopy), None, Some(NonCopy)].iter().filter_map(|x| x);
_ = vec![Some(()), None, Some(())].iter_mut().filter_map(|x| x);
_ = vec![Some(NonCopy), None, Some(NonCopy)].iter_mut().filter_map(|x| x);
}
Current output
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:4:62
|
4 | _ = vec![Some(()), None, Some(())].iter().filter_map(|x| x);
| ^ expected `Option<_>`, found `&Option<()>`
|
= note: expected enum `Option<_>`
found reference `&Option<()>`
help: try wrapping the expression in `Some`
|
4 | _ = vec![Some(()), None, Some(())].iter().filter_map(|x| Some(x));
| +++++ +
error[E0308]: mismatched types
--> src/main.rs:5:72
|
5 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter().filter_map(|x| x);
| ^ expected `Option<_>`, found `&Option<NonCopy>`
|
= note: expected enum `Option<_>`
found reference `&Option<NonCopy>`
help: try wrapping the expression in `Some`
|
5 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter().filter_map(|x| Some(x));
| +++++ +
error[E0308]: mismatched types
--> src/main.rs:6:66
|
6 | _ = vec![Some(()), None, Some(())].iter_mut().filter_map(|x| x);
| ^ expected `Option<_>`, found `&mut Option<()>`
|
= note: expected enum `Option<_>`
found mutable reference `&mut Option<()>`
help: try wrapping the expression in `Some`
|
6 | _ = vec![Some(()), None, Some(())].iter_mut().filter_map(|x| Some(x));
| +++++ +
error[E0308]: mismatched types
--> src/main.rs:7:76
|
7 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter_mut().filter_map(|x| x);
| ^ expected `Option<_>`, found `&mut Option<NonCopy>`
|
= note: expected enum `Option<_>`
found mutable reference `&mut Option<NonCopy>`
help: try wrapping the expression in `Some`
|
7 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter_mut().filter_map(|x| Some(x));
| +++++ +
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (bin "playground") due to 4 previous errors
Desired output
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:4:62
|
4 | _ = vec![Some(()), None, Some(())].iter().filter_map(|x| x);
| ^ expected `Option<_>`, found `&Option<()>`
|
= note: expected enum `Option<_>`
found reference `&Option<()>`
help: try dereferencing `x`
|
4 | _ = vec![Some(()), None, Some(())].iter().filter_map(|&x| x); // or *x
| +
error[E0308]: mismatched types
--> src/main.rs:5:72
|
5 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter().filter_map(|x| x);
| ^ expected `Option<_>`, found `&Option<NonCopy>`
|
= note: expected enum `Option<_>`
found reference `&Option<NonCopy>`
help: try calling `.as_ref()` on `x`
|
5 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter().filter_map(|x| x.as_ref());
| +++++++++
error[E0308]: mismatched types
--> src/main.rs:6:66
|
6 | _ = vec![Some(()), None, Some(())].iter_mut().filter_map(|x| x);
| ^ expected `Option<_>`, found `&mut Option<()>`
|
= note: expected enum `Option<_>`
found mutable reference `&mut Option<()>`
help: try dereferencing `x`
|
6 | _ = vec![Some(()), None, Some(())].iter_mut().filter_map(|&mut x| x); // or *x
| ++++
error[E0308]: mismatched types
--> src/main.rs:7:76
|
7 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter_mut().filter_map(|x| x);
| ^ expected `Option<_>`, found `&mut Option<NonCopy>`
|
= note: expected enum `Option<_>`
found mutable reference `&mut Option<NonCopy>`
help: try calling `.as_mut()` on `x`
|
7 | _ = vec![Some(NonCopy), None, Some(NonCopy)].iter_mut().filter_map(|x| x.as_mut());
| +++++++++
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (bin "playground") due to 4 previous errors
Rationale and extra context
Some(x) is useless in filter_map, and is equivalent to map(|x| x) (which is equivalent to no mapping at all). We shouldn't suggest this at all really, but it's good enough for the general case - but with &Option<T>, we should really be able to tell they want to filter by this option instead.
This could be caused by changing into_iter to iter, as you then have &Option<T>. The user could write this using flatten instead but they're not guided in that (correct) direction - if this change is made, clippy will then suggest flatten (rust-lang/rust-clippy#12501)
Other cases
No response
Rust Version
rustc 1.78.0-nightly (766bdce74 2024-03-16)
binary: rustc
commit-hash: 766bdce744d531267d53ba2a3f9ffcda69fb9b17
commit-date: 2024-03-16
host: x86_64-pc-windows-msvc
release: 1.78.0-nightly
LLVM version: 18.1.2
Anything else?
We could limit this to only |x| x instead of something like |(x, y)| if true { x } else { y }. Both of these should work, although the second case isn't relevant to flatten, but it should still make sense?
Considering how general this error message is (suggest_compatible_variants), I think we could probably generalize this further, instead of only suggesting this in filter_map.
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
Reproduce the examples with rustc and start by tracing the general suggest_compatible_variants diagnostic path, especially its handling of filter_map closures and references. Done means the four cases suggest dereferencing, .as_ref(), or .as_mut() instead of wrapping the reference in Some, while preserving the existing general behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100