Skip to content

Commit 798f754

Browse files
unused_unit: don't lint on closure return types (#15549)
As discussed in [#clippy > #15035](https://rust-lang.zulipchat.com/#narrow/channel/257328-clippy/topic/.2315035) Fixes #15035 changelog: [`unused_unit`] don't lint on closure return types
2 parents f0514d9 + 94d3352 commit 798f754

File tree

5 files changed

+83
-29
lines changed

5 files changed

+83
-29
lines changed

clippy_lints/src/unused_unit.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use rustc_errors::Applicability;
66
use rustc_hir::def_id::LocalDefId;
77
use rustc_hir::intravisit::FnKind;
88
use rustc_hir::{
9-
AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term,
10-
Ty, TyKind,
9+
AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, PolyTraitRef, Term, Ty,
10+
TyKind,
1111
};
1212
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
1313
use rustc_session::declare_lint_pass;
@@ -49,19 +49,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
4949
decl: &'tcx FnDecl<'tcx>,
5050
body: &'tcx Body<'tcx>,
5151
span: Span,
52-
def_id: LocalDefId,
52+
_def_id: LocalDefId,
5353
) {
5454
if let FnRetTy::Return(hir_ty) = decl.output
5555
&& is_unit_ty(hir_ty)
5656
&& !hir_ty.span.from_expansion()
5757
&& get_def(span) == get_def(hir_ty.span)
5858
{
59-
// implicit types in closure signatures are forbidden when `for<...>` is present
60-
if let FnKind::Closure = kind
61-
&& let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id)
62-
&& let ExprKind::Closure(closure) = expr.kind
63-
&& !closure.bound_generic_params.is_empty()
64-
{
59+
// The explicit `-> ()` in the closure signature might be necessary for multiple reasons:
60+
// - Implicit types in closure signatures are forbidden when `for<...>` is present
61+
// - If the closure body ends with a function call, and that function's return type is generic, the
62+
// `-> ()` could be required for it to be inferred
63+
//
64+
// There could be more reasons to have it, and, in general, we shouldn't discourage the users from
65+
// writing more type annotations than strictly necessary, because it can help readability and
66+
// maintainability
67+
if let FnKind::Closure = kind {
6568
return;
6669
}
6770

tests/ui/unused_unit.edition2021.fixed

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,10 @@ mod issue14577 {
127127
trait Unit {}
128128
impl Unit for () {}
129129

130-
fn run<R: Unit>(f: impl FnOnce() -> R) {
131-
f();
132-
}
133-
134130
#[allow(dependency_on_unit_never_type_fallback)]
135131
fn bar() {
136-
run(|| { todo!() });
137132
//~[edition2021]^ unused_unit
133+
panic!()
138134
}
139135

140136
struct UnitStruct;
@@ -150,3 +146,24 @@ mod pr14962 {
150146
type UnusedParensButNoUnit = Box<dyn (Fn())>;
151147
}
152148

149+
150+
mod issue15035 {
151+
152+
trait Convert<T> {
153+
fn from(value: T) -> Self;
154+
}
155+
156+
impl Convert<u64> for () {
157+
fn from(_value: u64) -> Self {}
158+
}
159+
160+
fn handle<T: Convert<u64>>(value: u64) -> T {
161+
Convert::from(value)
162+
}
163+
164+
pub fn f() -> Option<bool> {
165+
let result: Result<bool, u64> = Err(42);
166+
// the `-> ()` is required for the inference of `handle`'s return type
167+
result.map_err(|err| -> () { handle(err) }).ok()
168+
}
169+
}

tests/ui/unused_unit.edition2021.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ LL | fn test3()-> (){}
119119
| ^^^^^ help: remove the `-> ()`
120120

121121
error: unneeded unit return type
122-
--> tests/ui/unused_unit.rs:136:15
122+
--> tests/ui/unused_unit.rs:131:13
123123
|
124-
LL | run(|| -> () { todo!() });
125-
| ^^^^^^ help: remove the `-> ()`
124+
LL | fn bar() -> () {
125+
| ^^^^^^ help: remove the `-> ()`
126126

127127
error: aborting due to 20 previous errors
128128

tests/ui/unused_unit.edition2024.fixed

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,10 @@ mod issue14577 {
127127
trait Unit {}
128128
impl Unit for () {}
129129

130-
fn run<R: Unit>(f: impl FnOnce() -> R) {
131-
f();
132-
}
133-
134130
#[allow(dependency_on_unit_never_type_fallback)]
135-
fn bar() {
136-
run(|| -> () { todo!() });
131+
fn bar() -> () {
137132
//~[edition2021]^ unused_unit
133+
panic!()
138134
}
139135

140136
struct UnitStruct;
@@ -150,3 +146,24 @@ mod pr14962 {
150146
type UnusedParensButNoUnit = Box<dyn (Fn())>;
151147
}
152148

149+
150+
mod issue15035 {
151+
152+
trait Convert<T> {
153+
fn from(value: T) -> Self;
154+
}
155+
156+
impl Convert<u64> for () {
157+
fn from(_value: u64) -> Self {}
158+
}
159+
160+
fn handle<T: Convert<u64>>(value: u64) -> T {
161+
Convert::from(value)
162+
}
163+
164+
pub fn f() -> Option<bool> {
165+
let result: Result<bool, u64> = Err(42);
166+
// the `-> ()` is required for the inference of `handle`'s return type
167+
result.map_err(|err| -> () { handle(err) }).ok()
168+
}
169+
}

tests/ui/unused_unit.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,10 @@ mod issue14577 {
127127
trait Unit {}
128128
impl Unit for () {}
129129

130-
fn run<R: Unit>(f: impl FnOnce() -> R) {
131-
f();
132-
}
133-
134130
#[allow(dependency_on_unit_never_type_fallback)]
135-
fn bar() {
136-
run(|| -> () { todo!() });
131+
fn bar() -> () {
137132
//~[edition2021]^ unused_unit
133+
panic!()
138134
}
139135

140136
struct UnitStruct;
@@ -150,3 +146,24 @@ mod pr14962 {
150146
type UnusedParensButNoUnit = Box<dyn (Fn())>;
151147
}
152148

149+
150+
mod issue15035 {
151+
152+
trait Convert<T> {
153+
fn from(value: T) -> Self;
154+
}
155+
156+
impl Convert<u64> for () {
157+
fn from(_value: u64) -> Self {}
158+
}
159+
160+
fn handle<T: Convert<u64>>(value: u64) -> T {
161+
Convert::from(value)
162+
}
163+
164+
pub fn f() -> Option<bool> {
165+
let result: Result<bool, u64> = Err(42);
166+
// the `-> ()` is required for the inference of `handle`'s return type
167+
result.map_err(|err| -> () { handle(err) }).ok()
168+
}
169+
}

0 commit comments

Comments
 (0)