-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Upgrade equatable_if_let
to style
#7777
Conversation
r? @Manishearth (rust-highfive has picked a reviewer for you, use r? to override) |
Not sure if this should be a warn-by-default lint. Doing something like if let Some(42) = some_very.long().expr.chain[1..4].that_is().hard_to.read() { ... } Is pretty common in Rust, especially for if some_very.long().expr.chain[1..4].that_is().hard_to.read() == Some(42) { ... } because I can see at the start of the line what the expected value is, before reading the whole expression. I would even make this argument for other types than So I rather tend towards |
What about if Some(42) == some_very.long().expr.chain[1..4].that_is().hard_to.read() { ... } in this case? And also what do you think about if let 42 = some_very.long().expr.chain[1..4].that_is().hard_to.read() { ... } I'm agree that in the long case it doesn't make much difference. In these cases bottleneck of readablity is somewhere else. Also there is a good amount of data in the dogfooding fixes of previous PR which we can see for deciding. By the way, I don't now why CI is unhappy. It pass tests on my local system. |
The first would go against the "yoda condition" argument in the lint documentation. It might be better, but the difference is 2 characters. Maybe it's just that I'm more used to seeing The second example looks weird to me, because you usually don't pattern match on just integers. Looking thorugh the dogfood fixes, I especially liked the changes from Matching on a unit-variant is more like comparing ( |
Going to r? @flip1995 on this one since he's already posted a bit. I agree with him on this though. |
I see two things here:
Generally, writing value first and pattern after reads better (When nine hundred years old you reach), but since in your example subject isn't readable itself, it doesn't improve anything. And yes, since we see About the second point, I agree that there are some values that are more like patterns, but not all non unit variants. I feel cc authors of issues @adamchalmers @clarfonthey if they have more to say. |
I like the idea of I have a theory that this may be a minor perf issue, if only for unoptimized builds. Using enum MyEnum {
LittleGuy,
BigGuy([u8; 100]),
}
|
Code generated by #[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for MyEnum {
#[inline]
fn eq(&self, other: &MyEnum) -> bool {
{
let __self_vi = ::core::intrinsics::discriminant_value(&*self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
if true && __self_vi == __arg_1_vi {
match (&*self, &*other) {
(&MyEnum::BigGuy(ref __self_0),
&MyEnum::BigGuy(ref __arg_1_0)) =>
(*__self_0) == (*__arg_1_0),
_ => true,
}
} else { false }
}
}
#[inline]
fn ne(&self, other: &MyEnum) -> bool {
{
let __self_vi = ::core::intrinsics::discriminant_value(&*self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
if true && __self_vi == __arg_1_vi {
match (&*self, &*other) {
(&MyEnum::BigGuy(ref __self_0),
&MyEnum::BigGuy(ref __arg_1_0)) =>
(*__self_0) != (*__arg_1_0),
_ => false,
}
} else { true }
}
}
} So if your point is it would compare 100 byte in debug builds, it doesn't seems so. |
No my point is that it adds another 100 byte variable to the stack. But I also think the non-unit cases may be too controversial for pedantic purely from a readability/style standpoint. |
hmm yes it seems pattern matching has better performance without optimization. So I will change both of them to restriction. |
I don't really see a blocker of a perf impact on unoptimized builds, as long as there is no perf impact for optimzed builds. So if the only argument for not putting the unit-variant-only version into style, then I would say put it into style anyway. That is, if we really want to split up the lint on the unit-variant boundary. If we want to keep everything in one lint, I don't have a strong opinion about pedantic vs restriction. |
Forgot to reply to this yesterday: If you run the tests with To run the same tests that are ran in CI, use |
Or maybe a sensitivity configuration with some levels like "primitive", "unit-variant" and "all", with "unit-variant" as default? |
Well maybe my "unoptimized" point is kinda moot - that is actually a common tradeoff for abstractions in Rust.
Just noticed this. Don't forget to write a "changelog:".
I guess that makes sense considering that it affects multiple lints? I'd be okay with that and |
Yes, I agree. A configuration for those lints is probably a good idea. The question is what the default should be. unit-variant (which I would just call |
I think that's a good default. I'm a little unsure about just "unit". |
Ah right, that can be confusing. I think |
I added a configuration.
There is a changelog, but it needs update after we decide about style and pedantic. |
☔ The latest upstream changes (presumably #7788) made this pull request unmergeable. Please resolve the merge conflicts. |
bfcc766
to
c614402
Compare
☔ The latest upstream changes (presumably #7895) made this pull request unmergeable. Please resolve the merge conflicts. |
298c8ed
to
21dce73
Compare
Oh wow, this discussion is already 3 weeks old. Sorry for the late reply! I would say, keep the configuration, but put this lint into pedantic anyway. I just read through the discussion again and noticed that most arguments for putting this as warn-by-default started with "some people". And I also have the feeling that this is really opinionated and not clear that |
@@ -278,7 +278,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { | |||
}, | |||
(Trait(box TraitKind(la, lu, lg, lb, li)), Trait(box TraitKind(ra, ru, rg, rb, ri))) => { | |||
la == ra | |||
&& matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No) | |||
&& matches!(lu, Unsafe::Yes(_)) == matches!(ru, Unsafe::Yes(_)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, all the conditions are reversed in this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I at first changed it to lu == ru
which was wrong (I assumed there is Unsafe::No
and Unsafe::Yes
), and this style better shows why it is wrong so next person won't try lu == ru
.
@@ -0,0 +1,136 @@ | |||
// run-rustfix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be a 1:1 copy of the original test file. But this file should rather test that the lint also works for the All
variant and not so much that it still works for all other cases (one or two test cases are fine for that, but copying everything doesn't make much sense).
pub exp: &'tcx Expr<'tcx>, | ||
} | ||
|
||
impl MatchesExpn<'tcx> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, we don't really want to keep doing this: #7843
Is this only required to generate the suggestion? If so, I'd prefer to just have a non-auto-applicable suggestion in the matches
case with Applicability::HasPlaceholder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parameters of matches!
macro are needed to detect if this pattern is equatable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that's unfortunate. We really have to figure out how to do this without relying on the exact expansion of the macro...
I made it pedantic, but style with sensitivity = primitive is also an option. I think it is clear that |
I agree. I think the |
☔ The latest upstream changes (presumably #7897) made this pull request unmergeable. Please resolve the merge conflicts. |
Yet another option is to make a Also I would put "aggregate primitives" in the "simple" category. Don't know if that has been considered. |
I don't know how many people use pedantic lints, but primitive+style would be better for default users than simple+pedantic.
There are currently in "all". |
Continue of #7762
Fix #1716
changelog: upgrade
equatable_if_let
to style and add pedantic lintequatable_matches
After reading some more about
StructuralPartialEq
I got that my previous understanding of it was completely wrong and it should be checked recursively. So now it can detect which pattern supports equality and that false positive is fixed.Also I added a separate lint for
matches!
based on this comment. Lint forif let
is style and lint formatches!
is pedantic, but probably both of them need discussion.