-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Uplift clippy::precedence
lint
#117161
Uplift clippy::precedence
lint
#117161
Conversation
Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
This comment has been minimized.
This comment has been minimized.
bfbb3b5
to
75af01b
Compare
This comment has been minimized.
This comment has been minimized.
Should unary fn main() {
let x = !10_i32.abs();
println!("{:#034b}", x);
let x = (!10_i32).abs();
println!("{:#034b}", x);
}
I'm not sure what most people's expectations are of |
75af01b
to
c6e8f62
Compare
This comment has been minimized.
This comment has been minimized.
c6e8f62
to
e1d7f4a
Compare
Regarding the nomination, the question that will come up in the T-lang call is whether or not this is an appropriate lint for |
e1d7f4a
to
a366196
Compare
This comment has been minimized.
This comment has been minimized.
a366196
to
c9d8201
Compare
I'm not sure, I've implemented it locally, but almost every time it was triggered, I've had the impression that it was a false positive. So I don't think so, at least for the time being.
I don't have much to say, other than clippy's |
This lint is a bit slippery to define because there is a sliding scale of how much a human might know the precedence rules. A lesser experienced programmer might prefer parenthesis to clarify precedence of
|
To be clear this lint as implemented in this PR only lints on:
@camsteffen Aside from the lint name, this lint only lints on ambiguous case, I don't think |
I had to read your statement 3 times until I realized you meant bitwise operator (as opposed to arithmetic operator). |
So, for nomination... My main case in point is that I wrote this code and then assumed that This is, of course, only anecdotal evidence. But it shows that even someone who is experienced in Rust, PL theory, and mathematics, can still be led completely astray by the parser behavior. There also is a clear way to disambiguate, so IMO this is a good case for a warn-by-default lint. |
Agreed. That's why it is a lint, not a hard error of any sort. We'll have to make judgment calls on which cases are sufficiently surprising that we want to lint about them by default. To me, |
Hmm I take back my idea about "uncommon operators". Maybe I'm being too pedantic but I don't like the name |
c9d8201
to
8e0d8b6
Compare
Note that lint names should be in plural form, e.g. "unclear_precedences". |
If the focus is on the human, perhaps |
If Rust is a language meant to be written and reviewed by humans, I think the focus would always be on the human 😅. imo |
The word |
"clear"/"unambiguous" is also often used to mean "obvious to the reader, does not require further context". By that standard, the precedence is not clear: I can't just show the code to someone and they will know what it means; they have to first learn the rules. After all we also talk about APIs being unclear when they use poorly chosen names or things like that, even though in a technical sense everything is well-defined and hence "clear". |
☔ The latest upstream changes (presumably #117979) made this pull request unmergeable. Please resolve the merge conflicts. |
8e0d8b6
to
0fd29ec
Compare
This comment has been minimized.
This comment has been minimized.
0fd29ec
to
41e125b
Compare
☔ The latest upstream changes (presumably #118134) made this pull request unmergeable. Please resolve the merge conflicts. |
(Just speaking for me; hasn't come up in lang triage yet.) Hmm, I feel like the two parts of this lint should be split since even though they're both about precedence, the mistakes that happen from them feel very different to me. I'd actually like to go further for the first part, and make Basically, I think it's weird that So I'd be a fan of a proposal like "we deny-by-default lint anywhere you have something that looks like a negative literal but isn't acting like a negative literal": For the second category, I'm really torn. I've worked places that required parens for
Perhaps it's fine to leave "here's the technically-unnecessary ones you should write anyway" to things like (I could probably be convinced in different directions here, though.) |
As another demonstration of why I think the negative-literal case is so important to lint about, notice how using literal vs tt makes a huge difference here, in a way that I'd say isn't intuitive: #![allow(warnings)]
macro_rules! foo {
( $a:literal $($t:tt)* ) => { ($a $($t)+) };
}
fn main() {
dbg!(foo!( -1.0_f32.cos() ));
dbg!( ( -1.0_f32.cos() ));
} https://rust.godbolt.org/z/MxM95zPr5
|
The negative literal case is being FCP-ed in #121364 (comment). The "binary operation" case is much less useful. @rustbot label -I-lang-nominated |
…-errors Implement lint against ambiguous negative literals This PR implements a lint against ambiguous negative literals with a literal and method calls right after it. ## `ambiguous_negative_literals` (deny-by-default) The `ambiguous_negative_literals` lint checks for cases that are confusing between a negative literal and a negation that's not part of the literal. ### Example ```rust,compile_fail -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 ``` ### Explanation Method calls take precedence over unary precedence. Setting the precedence explicitly makes the code clearer and avoid potential bugs. <details> <summary>Old proposed lint</summary> ## `ambiguous_unary_precedence` (deny-by-default) The `ambiguous_unary_precedence` lint checks for use the negative unary operator with a literal and method calls. ### Example ```rust -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 ``` ### Explanation Unary operations take precedence on binary operations and method calls take precedence over unary precedence. Setting the precedence explicitly makes the code clearer and avoid potential bugs. </details> ----- Note: This is a strip down version of rust-lang#117161, without the binary op precedence. Fixes rust-lang#117155 `@rustbot` labels +I-lang-nominated cc `@scottmcm` r? compiler
Rollup merge of rust-lang#121364 - Urgau:unary_precedence, r=compiler-errors Implement lint against ambiguous negative literals This PR implements a lint against ambiguous negative literals with a literal and method calls right after it. ## `ambiguous_negative_literals` (deny-by-default) The `ambiguous_negative_literals` lint checks for cases that are confusing between a negative literal and a negation that's not part of the literal. ### Example ```rust,compile_fail -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 ``` ### Explanation Method calls take precedence over unary precedence. Setting the precedence explicitly makes the code clearer and avoid potential bugs. <details> <summary>Old proposed lint</summary> ## `ambiguous_unary_precedence` (deny-by-default) The `ambiguous_unary_precedence` lint checks for use the negative unary operator with a literal and method calls. ### Example ```rust -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 ``` ### Explanation Unary operations take precedence on binary operations and method calls take precedence over unary precedence. Setting the precedence explicitly makes the code clearer and avoid potential bugs. </details> ----- Note: This is a strip down version of rust-lang#117161, without the binary op precedence. Fixes rust-lang#117155 `@rustbot` labels +I-lang-nominated cc `@scottmcm` r? compiler
Implement lint against ambiguous negative literals This PR implements a lint against ambiguous negative literals with a literal and method calls right after it. ## `ambiguous_negative_literals` (deny-by-default) The `ambiguous_negative_literals` lint checks for cases that are confusing between a negative literal and a negation that's not part of the literal. ### Example ```rust,compile_fail -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 ``` ### Explanation Method calls take precedence over unary precedence. Setting the precedence explicitly makes the code clearer and avoid potential bugs. <details> <summary>Old proposed lint</summary> ## `ambiguous_unary_precedence` (deny-by-default) The `ambiguous_unary_precedence` lint checks for use the negative unary operator with a literal and method calls. ### Example ```rust -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 ``` ### Explanation Unary operations take precedence on binary operations and method calls take precedence over unary precedence. Setting the precedence explicitly makes the code clearer and avoid potential bugs. </details> ----- Note: This is a strip down version of rust-lang/rust#117161, without the binary op precedence. Fixes rust-lang/rust#117155 `@rustbot` labels +I-lang-nominated cc `@scottmcm` r? compiler
This PR aims at uplifting the
clippy::precedence
lint into rustc.ambiguous_precedence
(warn-by-default)
The
ambiguous_precedence
lint checks for operations where precedence may be unclear and suggests adding parentheses.Example
Explanation
Unary operations take precedence on binary operations and method calls take precedence over unary precedence these precedence may be unexpected without parentheses.
Setting the precedence explicitly makes the code clearer and avoid potential bugs.
As implemented in this PR, the lint only lints on
<<
,>>
...) where either the left and/or right expression is a non-bitwise operation (*
,+
,/
...)-
(minus operator) and followed by some method callsFixes #117155 (cc @RalfJung)
@rustbot labels +I-lang-nominated
r? compiler