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

New lint: manual_midpoint #13851

Merged
merged 2 commits into from
Feb 28, 2025
Merged

Conversation

samueltardieu
Copy link
Contributor

changelog: [manual_midpoint]: new lint

Closes #13849

@rustbot
Copy link
Collaborator

rustbot commented Dec 17, 2024

r? @dswij

rustbot has assigned @dswij.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Dec 17, 2024
@samueltardieu samueltardieu force-pushed the push-pmstswltutkv branch 4 times, most recently from 906f3bd to 1561476 Compare December 18, 2024 00:06
Copy link
Member

@Urgau Urgau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ Thanks for working on it, appreciate it.

Left a few remarks/nits.

cx,
MANUAL_MIDPOINT,
expr.span,
"manual implementation of `midpoint`",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"manual implementation of `midpoint`",
"manual implementation of `midpoint` which can overflow",

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reluctant to add this on the lint message, because this particular use may well never overflow depending on the context. This is appropriate for the lint short description though, I'll add it there. What do you think?

Copy link
Member

@Urgau Urgau Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add it to the lint short description, but I still think we should mention it in the main message as it's the main issue (not the fact that it's a manual implementation). We could reduce the assertion by saying "which may overflow" (instead of "can").

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any addition may overflow, and we do not suggest using .checked_add(). I'll let other weigh in, but I'm not comfortable saying "which may overflow" on (a + b) / 2 if a and b are indices in a vector for example, they will never overflow as they will be nowhere near usize::MAX/2 for any realistic vector.

Copy link
Member

@Urgau Urgau Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(a + b) / 2 if a and b are indices in a vector for example

u8::MAX = 255, u16::MAX = 65536 are fairly realistic numbers to me (which could be indices of custom containers).

they will never overflow as they will be nowhere near usize::MAX/2 for any realistic vector.

reminder of https://research.google/blog/extra-extra-read-all-about-it-nearly-all-binary-searches-and-mergesorts-are-broken/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was specifically talking about the usize case which is used to index a vector. And let's not confuse the issue: I'm not trying to argue that we should not lint, we will, only that I am not comfortable saying that a particular computation may overflow.

I couldn't find lints that warn about the potential risk when linting an expression if the risk is remote or non-existing for this particular expression, even though they still lint to make it clearer and safer should this code be changed later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I agree that it's a good idea to mention this even in the message. IMO it doesn't particularly hurt to mention even if the user knows it could never overflow, but it can definitely help in cases where that's an edge case the user hadn't considered, and I could see how the lint could otherwise be dismissed as 'just a nit like the other manual_* lints, not that important'.

The fact that it's an incorrect implementation due to overflow is the reason why it's deny-by-default/correctness in the first place, right? The current primary message makes this sound more like a complexity or style lint

--> tests/ui/manual_midpoint.rs:12:13
|
LL | let _ = (f + 5.0) / 2.0;
| ^^^^^^^^^^^^^^^ help: use instead: `f32::midpoint(f, 5.0)`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't if it's in Clippy customs but would be possible to add a help linking to the documentation, something like this (which rustc does to further guide the user):

help: for more information visit <https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.midpoint>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done only for niche or complex situations in the existing codebase, such as implementing a local trait for a foreign type (orphan rule).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a first time for everything. :-)

More seriously, I'm fine if the link it's not included.

let mut app = Applicability::MachineApplicable;
let left_sugg = Sugg::hir_with_applicability(cx, ll_expr, "..", &mut app);
let right_sugg = Sugg::hir_with_applicability(cx, lr_expr, "..", &mut app);
let sugg = format!("{left_ty}::midpoint({left_sugg}, {right_sugg})");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting choice of form, I would have probably use the method syntax (ie. .midpoint(..)) instead, as to not have to much shifts from the original code, but that works as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that linting (a + b) / 2 as a.midpoint(b) introduces an asymmetry between a and b while u32::midpoint(a, b) doesn't. But I'm not opposed to this change.

What do others think? Please upvote if you prefer a.midpoint(b) and downvote if you prefer u32::midpoint(a, b).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't pick between the 2 because the first one is more convenirnt but the second one is more readable...

Well, by writing this comment I realized I prefer more readable code so let's go for 2.

Copy link
Member

@y21 y21 Dec 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially preferred a.midpoint(b) but having thought more about it, the latter has some other advantages: u32::midpoint(a, b) doesn't require parentheses in some cases where the LHS is an expression with low precedence like (a + b + c) / 2, and it also sidesteps type inference issues in cases like

let c: u64 = (10 + 5) / 2;

where 10.midpoint(5) would not compile. So the current suggestion LGTM

@samueltardieu samueltardieu force-pushed the push-pmstswltutkv branch 4 times, most recently from 6e01b0d to 8fc52b4 Compare December 19, 2024 20:07
@samueltardieu
Copy link
Contributor Author

r? @y21

@rustbot rustbot assigned y21 and unassigned dswij Dec 27, 2024
let mut app = Applicability::MachineApplicable;
let left_sugg = Sugg::hir_with_applicability(cx, ll_expr, "..", &mut app);
let right_sugg = Sugg::hir_with_applicability(cx, lr_expr, "..", &mut app);
let sugg = format!("{left_ty}::midpoint({left_sugg}, {right_sugg})");
Copy link
Member

@y21 y21 Dec 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially preferred a.midpoint(b) but having thought more about it, the latter has some other advantages: u32::midpoint(a, b) doesn't require parentheses in some cases where the LHS is an expression with low precedence like (a + b + c) / 2, and it also sidesteps type inference issues in cases like

let c: u64 = (10 + 5) / 2;

where 10.midpoint(5) would not compile. So the current suggestion LGTM

cx,
MANUAL_MIDPOINT,
expr.span,
"manual implementation of `midpoint`",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I agree that it's a good idea to mention this even in the message. IMO it doesn't particularly hurt to mention even if the user knows it could never overflow, but it can definitely help in cases where that's an edge case the user hadn't considered, and I could see how the lint could otherwise be dismissed as 'just a nit like the other manual_* lints, not that important'.

The fact that it's an incorrect implementation due to overflow is the reason why it's deny-by-default/correctness in the first place, right? The current primary message makes this sound more like a complexity or style lint

@samueltardieu
Copy link
Contributor Author

I have eliminated the lint on additions with more than 2 operands, as there is no reason to suggest u32::midpoint(a + b, c) or u32::midpoint(a, b + c) for an expression like (a + b + c) / 2 which is likely not a midpoint computation.

@samueltardieu
Copy link
Contributor Author

I opened a thread on Zulip to discuss how to handle (x + 1) / 2 which might not semantically be a midpoint() operation, as the user might want to compute a div_ceil() here.

@samueltardieu samueltardieu force-pushed the push-pmstswltutkv branch 4 times, most recently from b14c9fc to 7cd170d Compare January 12, 2025 08:37
@samueltardieu samueltardieu force-pushed the push-pmstswltutkv branch 2 times, most recently from a0c770e to de46175 Compare January 15, 2025 08:02
@samueltardieu
Copy link
Contributor Author

Rebasing because of a new conflict in msrvs.rs.

Copy link
Member

@y21 y21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, going to start the FCP in a bit

@y21
Copy link
Member

y21 commented Jan 18, 2025

FCP thread: https://rust-lang.zulipchat.com/#narrow/channel/257328-clippy/topic/FCP.3A.20manual_midpoint

@y21 y21 added S-final-comment-period Status: final comment period it will be merged unless new objections are raised (~1 week) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Jan 18, 2025
@samueltardieu samueltardieu force-pushed the push-pmstswltutkv branch 2 times, most recently from 52d6d79 to 3c13085 Compare January 19, 2025 08:55
@samueltardieu
Copy link
Contributor Author

Rebased

@samueltardieu samueltardieu force-pushed the push-pmstswltutkv branch 2 times, most recently from 3c13085 to 71b6776 Compare February 3, 2025 22:49
@samueltardieu
Copy link
Contributor Author

Rebased

@samueltardieu
Copy link
Contributor Author

samueltardieu commented Feb 21, 2025 via email

@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) label Feb 21, 2025
@samueltardieu
Copy link
Contributor Author

samueltardieu commented Feb 21, 2025

Thanks, I'll add this.

I'll have to wait until the next rustup until the stabilization of manual_midpoint for integer types is visible. It will be in another PR (the code is ready), and I'll let this one untouched.

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties and removed S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) labels Feb 21, 2025
@samueltardieu samueltardieu removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Feb 21, 2025
@samueltardieu
Copy link
Contributor Author

Updated to set the lint version to 1.87.

@samueltardieu
Copy link
Contributor Author

samueltardieu commented Feb 27, 2025

Rebased, category changed to pedantic, signed integer midpoint integrated as well.

@y21 y21 added this pull request to the merge queue Feb 28, 2025
Merged via the queue into rust-lang:master with commit 2cdb90d Feb 28, 2025
11 checks passed
@samueltardieu samueltardieu deleted the push-pmstswltutkv branch February 28, 2025 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-final-comment-period Status: final comment period it will be merged unless new objections are raised (~1 week)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Suggest uN::midpoint over overflow prone (a + b) / 2 expressions
6 participants