Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

option_if_let_else suggestion does not compile #6137

Open
lopopolo opened this issue Oct 8, 2020 · 2 comments
Open

option_if_let_else suggestion does not compile #6137

lopopolo opened this issue Oct 8, 2020 · 2 comments
Labels
C-bug Category: Clippy is not doing the correct thing E-medium Call for participation: Medium difficulty level problem and requires some initial experience. I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied L-nursery Lint: Currently in the nursery group

Comments

@lopopolo
Copy link

lopopolo commented Oct 8, 2020

I tried this code:

#![warn(clippy::all)]
#![warn(clippy::pedantic)]

use core::convert::TryFrom;

#[derive(Clone, Copy)]
struct X;

struct Foo;

impl From<X> for Option<Foo> {
    fn from(_: X) -> Self {
        Some(Foo)
    }
}

#[derive(Clone)]
struct Bar;

impl From<X> for Option<Bar> {
    fn from(_: X) -> Self {
        Some(Bar)
    }
}

pub struct NoBlockGiven(X);

impl From<X> for NoBlockGiven {
    fn from(value: X) -> Self {
        Self(value)
    }
}

impl TryFrom<X> for Bar {
    type Error = NoBlockGiven;

    fn try_from(value: X) -> Result<Self, Self::Error> {
        if let Some(block) = value.into() {
            Ok(block)
        } else {
            Err(NoBlockGiven::from(value))
        }
    }
}

Clippy made this suggestion:

$ cargo clippy
    Checking clippy-test v0.1.0 (/Users/lopopolo/Downloads/clippy-test)
warning: use Option::map_or instead of an if let/else
  --> src/lib.rs:38:9
   |
38 | /         if let Some(block) = value.into() {
39 | |             Ok(block)
40 | |         } else {
41 | |             Err(NoBlockGiven::from(value))
42 | |         }
   | |_________^ help: try: `value.into().map_or(Err(NoBlockGiven::from(value)), |block| Ok(block))`
   |
note: the lint level is defined here
  --> src/lib.rs:2:9
   |
2  | #![warn(clippy::pedantic)]
   |         ^^^^^^^^^^^^^^^^
   = note: `#[warn(clippy::option_if_let_else)]` implied by `#[warn(clippy::pedantic)]`
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else

warning: 1 warning emitted

    Finished dev [unoptimized + debuginfo] target(s) in 0.08s

Applying the fix results in code that does not compile:

#![warn(clippy::all)]
#![warn(clippy::pedantic)]

use core::convert::TryFrom;

#[derive(Clone, Copy)]
struct X;

struct Foo;

impl From<X> for Option<Foo> {
    fn from(_: X) -> Self {
        Some(Foo)
    }
}

#[derive(Clone)]
struct Bar;

impl From<X> for Option<Bar> {
    fn from(_: X) -> Self {
        Some(Bar)
    }
}

pub struct NoBlockGiven(X);

impl From<X> for NoBlockGiven {
    fn from(value: X) -> Self {
        Self(value)
    }
}

impl TryFrom<X> for Bar {
    type Error = NoBlockGiven;

    fn try_from(value: X) -> Result<Self, Self::Error> {
        value
            .into()
            .map_or(Err(NoBlockGiven::from(value)), |block| Ok(block))
    }
}
$ cargo clippy
    Checking clippy-test v0.1.0 (/Users/lopopolo/Downloads/clippy-test)
error[E0282]: type annotations needed
  --> src/lib.rs:39:14
   |
38 | /         value
39 | |             .into()
   | |______________^^^^_- this method call resolves to `T`
   |                |
   |                cannot infer type for type parameter `T` declared on the trait `Into`
   |
   = note: type must be known at this point

error: aborting due to previous error

For more information about this error, try `rustc --explain E0282`.
error: could not compile `clippy-test`.

To learn more, run the command again with --verbose.

Meta

  • cargo clippy -V: clippy 0.0.212 (18bf6b4f0 2020-10-07)
  • rustc -Vv:
    rustc 1.47.0 (18bf6b4f0 2020-10-07)
    binary: rustc
    commit-hash: 18bf6b4f01a6feaf7259ba7cdae58031af1b7b39
    commit-date: 2020-10-07
    host: x86_64-apple-darwin
    release: 1.47.0
    LLVM version: 11.0
    
@lopopolo lopopolo added the C-bug Category: Clippy is not doing the correct thing label Oct 8, 2020
@lopopolo
Copy link
Author

lopopolo commented Oct 8, 2020

Despite this bug report, I am planning on disabling this lint since in every case clippy offered the correction, I found the explicit if let ... else more readable than the combinator soup I never remember the argument order for.

A particular suggestion I did not like was replacing an if let .. else that was part of an if else chain.

diff --git a/spinoso-env/src/env/memory.rs b/spinoso-env/src/env/memory.rs
index 00b94517f2..af1ff8cff0 100644
--- a/spinoso-env/src/env/memory.rs
+++ b/spinoso-env/src/env/memory.rs
@@ -98,10 +98,10 @@ impl Memory {
             // MRI accepts names containing '=' on get and should always return
             // `nil` since these names are invalid at the OS level.
             Ok(None)
-        } else if let Some(value) = self.store.get(name) {
-            Ok(Some(Cow::Borrowed(value)))
         } else {
-            Ok(None)
+            self.store
+                .get(name)
+                .map_or(Ok(None), |value| Ok(Some(Cow::Borrowed(value))))
         }
     }

In this case, if this method were const, the suggestion would make the resulting code not const.

lopopolo added a commit to artichoke/artichoke that referenced this issue Oct 8, 2020
Also address new clippy lints and updates.

This commit disables some lints due to rust-lang/rust-clippy#6137 and
rust-lang/rust-clippy#6141.
@flip1995
Copy link
Member

flip1995 commented Oct 9, 2020

One thing you could do to fix the compiler warning would be to use Option::from instead of .into(), which is admittedly worse code IMO.

Despite this bug report, I am planning on disabling this lint since in every case clippy offered the correction

That's totally fine, pedantic lints are meant to be really opinionated and to be allowed more often.

@flip1995 flip1995 added E-medium Call for participation: Medium difficulty level problem and requires some initial experience. I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied labels Oct 9, 2020
bors added a commit that referenced this issue Aug 15, 2021
Downgrade option_if_let_else to nursery

I believe that this lint's loose understanding of ownership (#5822, #6737) makes it unsuitable to be enabled by default in its current state, even as a pedantic lint.

Additionally the lint has known problems with type inference (#6137), though I may be willing to consider this a non-blocker in isolation if it weren't for the ownership false positives.

A fourth false positive involving const fn: #7567.

But on top of these, for me the biggest issue is I basically fully agree with #6137 (comment). In my experience this lint universally makes code worse even when the resulting code does compile.

---

changelog: remove [`option_if_let_else`] from default set of enabled lints
bors added a commit that referenced this issue Aug 30, 2021
Fix `option_if_let_else`

fixes: #5822
fixes: #6737
fixes: #7567

The inference from #6137 still exists so I'm not sure if this should be moved from the nursery. Before doing that though I'd almost want to see this split into two lints. One suggesting `map_or` and the other suggesting `map_or_else`.

`map_or_else` tends to have longer expressions for both branches so it doesn't end up much shorter than a match expression in practice. It also seems most people find it harder to read. `map_or` at least has the terseness benefit of being on one line most of the time, especially when the `None` branch is just a literal or path expression.

changelog: `break` and `continue` statments local to the would-be closure are allowed in `option_if_let_else`
changelog: don't lint in const contexts  in `option_if_let_else`
changelog: don't lint when yield expressions are used  in `option_if_let_else`
changelog: don't lint when the captures made by the would-be closure conflict with the other branch  in `option_if_let_else`
changelog: don't lint when a field of a local is used when the type could be pontentially moved from  in `option_if_let_else`
changelog: in some cases, don't lint when scrutinee expression conflicts with the captures of the would-be closure  in `option_if_let_else`
@J-ZhengLi J-ZhengLi added the L-nursery Lint: Currently in the nursery group label Jul 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing E-medium Call for participation: Medium difficulty level problem and requires some initial experience. I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied L-nursery Lint: Currently in the nursery group
Projects
None yet
Development

No branches or pull requests

3 participants