Auto merge of #11135 - smoelius:unwrap_or_else_default-fp, r=Centri3
Fix `unwrap_or_else_default` false positive
This PR fixes a false positive in the handling of `unwrap_or_else` with a default value when the value is needed for type inference.
An easy example to exhibit the false positive is the following:
```rust
let option = None;
option.unwrap_or_else(Vec::new).push(1);
```
The following code would not compile, because the fact that the value is a `Vec` has been lost:
```rust
let option = None;
option.unwrap_or_default().push(1);
```
The fix is to:
- implement a heuristic to tell whether an expression's type can be determined purely from its subexpressions, and the arguments and locals they use;
- apply the heuristic to `unwrap_or_else`'s receiver.
The heuristic returns false when applied to `option` in the above example, but it returns true when applied to `option` in either of the following examples:
```rust
let option: Option<Vec<u64>> = None;
option.unwrap_or_else(Vec::new).push(1);
```
```rust
let option = None::<Vec<u64>>;
option.unwrap_or_else(Vec::new).push(1);
```
(Aside: https://github.com/rust-lang/rust-clippy/pull/10120 unfairly contained multiple changes in one PR. I am trying to break that PR up into smaller pieces.)
---
changelog: FP: [`unwrap_or_else_default`]: No longer lints if the default value is needed for type inference
This commit is contained in:
commit
7a34143fa3
7 changed files with 568 additions and 2 deletions
|
|
@ -74,4 +74,41 @@ fn unwrap_or_else_default() {
|
|||
empty_string.unwrap_or_default();
|
||||
}
|
||||
|
||||
fn type_certainty(option: Option<Vec<u64>>) {
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
let option: std::option::Option<std::vec::Vec<u64>> = None;
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
let option: Option<Vec<u64>> = None;
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
let option = std::option::Option::<std::vec::Vec<u64>>::None;
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
let option = Option::<Vec<u64>>::None;
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
let option = std::option::Option::None::<std::vec::Vec<u64>>;
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
let option = Option::None::<Vec<u64>>;
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
let option = None::<Vec<u64>>;
|
||||
option.unwrap_or_default().push(1);
|
||||
|
||||
// should not be changed: type annotation with infer, unconcretized initializer
|
||||
let option: Option<Vec<_>> = None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
// should not be changed: no type annotation, unconcretized initializer
|
||||
let option = Option::None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
// should not be changed: no type annotation, unconcretized initializer
|
||||
let option = None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -74,4 +74,41 @@ fn unwrap_or_else_default() {
|
|||
empty_string.unwrap_or_else(|| "".to_string());
|
||||
}
|
||||
|
||||
fn type_certainty(option: Option<Vec<u64>>) {
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
let option: std::option::Option<std::vec::Vec<u64>> = None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
let option: Option<Vec<u64>> = None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
let option = std::option::Option::<std::vec::Vec<u64>>::None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
let option = Option::<Vec<u64>>::None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
let option = std::option::Option::None::<std::vec::Vec<u64>>;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
let option = Option::None::<Vec<u64>>;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
let option = None::<Vec<u64>>;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
// should not be changed: type annotation with infer, unconcretized initializer
|
||||
let option: Option<Vec<_>> = None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
// should not be changed: no type annotation, unconcretized initializer
|
||||
let option = Option::None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
|
||||
// should not be changed: no type annotation, unconcretized initializer
|
||||
let option = None;
|
||||
option.unwrap_or_else(Vec::new).push(1);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -36,5 +36,53 @@ error: use of `.unwrap_or_else(..)` to construct default value
|
|||
LL | empty_string.unwrap_or_else(|| "".to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:78:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:81:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:84:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:87:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:90:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:93:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:96:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:99:5
|
||||
|
|
||||
LL | option.unwrap_or_else(Vec::new).push(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue