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: Unintentional return of unit from closures expecting Ord #5348

Closed
wants to merge 1 commit into from

Conversation

rabisg0
Copy link
Contributor

@rabisg0 rabisg0 commented Mar 21, 2020

This lint catches cases where the last statement of a closure expecting
an instance of Ord has a trailing semi-colon. It compiles since the
closure ends up return () which also implements Ord but causes
unexpected results in cases such as sort_by_key.

Fixes #5080

changelog: none

@rabisg0 rabisg0 force-pushed the unit-for-ord branch 3 times, most recently from 5a3624b to 418179d Compare March 21, 2020 18:21
@bors
Copy link
Contributor

bors commented Mar 23, 2020

☔ The latest upstream changes (presumably #5319) made this pull request unmergeable. Please resolve the merge conflicts.

@flip1995 flip1995 self-requested a review March 30, 2020 17:41
@flip1995 flip1995 added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Mar 30, 2020
This lint catches cases where the last statement of a closure expecting
an instance of Ord has a trailing semi-colon. It compiles since the
closure ends up return () which also implements Ord but causes
unexpected results in cases such as sort_by_key.

Fixes rust-lang#5080
@bors
Copy link
Contributor

bors commented Apr 8, 2020

☔ The latest upstream changes (presumably #5438) made this pull request unmergeable. Please resolve the merge conflicts.

@rabisg0
Copy link
Contributor Author

rabisg0 commented Apr 13, 2020

gentle reminder for review

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

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

Can you add some documentation what the get_* functions are trying to get. You could just copy the debug output of these types.

Comment on lines +133 to +134
if_chain! {
if let ExprKind::MethodCall(_, _, ref args) = expr.kind;
Copy link
Member

Choose a reason for hiding this comment

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

No need for if_chain if there is only one if

// Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
// The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]`
let inputs_output = cx.tcx.erase_late_bound_regions(&fn_sig.inputs_and_output());
inputs_output.iter().enumerate().for_each(|(i, inp)| {
Copy link
Member

Choose a reason for hiding this comment

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

This can be done with

Suggested change
inputs_output.iter().enumerate().for_each(|(i, inp)| {
inputs_output.iter().rev().skip(1).rev().enumerate().for_each(|(i, inp)| {

if i == inputs_output.len() - 1 {
return;
}
fn_mut_preds.iter().for_each(|pred| {
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer a normal for loop here, since this is not in an iterator chain and for_each is less readable IMO.

Suggested change
fn_mut_preds.iter().for_each(|pred| {
for pred in &fn_mut_preds {

@@ -71,6 +72,7 @@ pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARTIAL_ORD: [&str; 3] = ["std", "cmp", "PartialOrd"];
Copy link
Member

Choose a reason for hiding this comment

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

You don't need this, since PartialOrd is a LangItem, which you can get with cx.tcx.lang_items().partial_ord_trait()

Comment on lines +118 to +127
if let ExprKind::Closure(_, _fn_decl, body_id, _span, _) = arg.kind {
if_chain! {
let body = cx.tcx.hir().body(body_id);
if let ExprKind::Block(block, _) = body.value.kind;
if let Some(stmt) = block.stmts.last();
if let StmtKind::Semi(_) = stmt.kind;
then { return Some(stmt) }
}
}
return None;
Copy link
Member

Choose a reason for hiding this comment

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

Can be simplified to

Suggested change
if let ExprKind::Closure(_, _fn_decl, body_id, _span, _) = arg.kind {
if_chain! {
let body = cx.tcx.hir().body(body_id);
if let ExprKind::Block(block, _) = body.value.kind;
if let Some(stmt) = block.stmts.last();
if let StmtKind::Semi(_) = stmt.kind;
then { return Some(stmt) }
}
}
return None;
if_chain! {
if let ExprKind::Closure(_, _fn_decl, body_id, _span, _) = arg.kind;
let body = cx.tcx.hir().body(body_id);
if let ExprKind::Block(block, _) = body.value.kind;
if let Some(stmt) = block.stmts.last();
if let StmtKind::Semi(_) = stmt.kind;
then {
Some(stmt)
} else {
None
}
}

if_chain! {
let body = cx.tcx.hir().body(body_id);
if let ExprKind::Block(block, _) = body.value.kind;
if let Some(stmt) = block.stmts.last();
Copy link
Member

Choose a reason for hiding this comment

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

You also have to check for block.expr.is_none()

trait_path: &[&str],
) -> Vec<&'tcx Predicate<'tcx>> {
let mut preds = Vec::new();
generics.predicates.iter().for_each(|(pred, _)| {
Copy link
Member

Choose a reason for hiding this comment

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

Also here, I'd prefer a for loop

Suggested change
generics.predicates.iter().for_each(|(pred, _)| {
for (pred, _) in &generics.predicates {

Comment on lines +54 to +55
preds.push(pred);
}
Copy link
Member

Choose a reason for hiding this comment

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

Formatting

Suggested change
preds.push(pred);
}
preds.push(pred);
}

@@ -37,6 +37,7 @@ pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FN_MUT: [&str; 3] = ["std", "ops", "FnMut"];
Copy link
Member

Choose a reason for hiding this comment

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

This is also a LangItem

@flip1995
Copy link
Member

Sorry for taking so long for the review. I don't have an excuse, just wasn't really motivated to review PRs recently.

@flip1995
Copy link
Member

Thanks for contributing to Clippy! Sadly this PR was not updated in quite some time. If you waited on input from a reviewer, we're sorry that this fell under the radar. If you want to continue to work on this, just reopen the PR and/or ping a reviewer.

@flip1995 flip1995 closed this May 25, 2020
@flip1995 flip1995 added S-inactive-closed Status: Closed due to inactivity and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels May 25, 2020
@Uriopass
Copy link

Since this PR is inactive and was open because of a problem I had initially I'm going to try and finish it :-)

bors added a commit that referenced this pull request Jul 13, 2020
Reprise: new lint: Unintentional return of unit from closures expecting Ord

This lint catches cases where the last statement of a closure expecting
an instance of Ord has a trailing semi-colon. It compiles since the
closure ends up return () which also implements Ord but causes
unexpected results in cases such as sort_by_key.

Fixes #5080

Reprise of #5348 where I addressed all the comments there
bors added a commit that referenced this pull request Jul 14, 2020
Reprise: new lint: Unintentional return of unit from closures expecting Ord

This lint catches cases where the last statement of a closure expecting
an instance of Ord has a trailing semi-colon. It compiles since the
closure ends up return () which also implements Ord but causes
unexpected results in cases such as sort_by_key.

Fixes #5080

Reprise of #5348 where I addressed all the comments there

changelog: add lint [`unit_return_expecting_ord`]
@blyxyas blyxyas removed the S-inactive-closed Status: Closed due to inactivity label Oct 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New lint: Returning unit type when expecting Ord
5 participants