Skip to content

Commit 6fd9b86

Browse files
authored
fixes issue 17162 false positive for never type impls (#17163)
*[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust-clippy/pull/17163)* Do not lint `unused_async_trait_impl` for `impl Trait for !` blocks. The never type `!` can never be instantiated, so any method implemented for it can never be called. Flagging these as having an "unused async" is a false positive since the async keyword has no practical impact. fixes #17162 changelog: [`unused_async_trait_impl`]: do not lint when the trait is implemented for the never type `!` I ran the tests locally and pass, also did uibless and formatted the code
2 parents d234f95 + d8923b5 commit 6fd9b86

4 files changed

Lines changed: 88 additions & 13 deletions

File tree

clippy_lints/src/unused_async.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
284284
&& let ExprKind::Block(block, _) = inner.kind
285285
&& let Some(tail_expr) = block.expr
286286
{
287+
// check the impl method self type/item
288+
if let Ok(args) = cx.tcx.try_normalize_erasing_regions(
289+
cx.typing_env(),
290+
cx.tcx
291+
.fn_sig(impl_item.owner_id.def_id)
292+
.instantiate_identity()
293+
.map(|x| cx.tcx.instantiate_bound_regions_with_erased(x.inputs_and_output())),
294+
) && args[..args.len() - 1].iter().any(|&x| {
295+
!x.peel_refs().is_inhabited_from(
296+
cx.tcx,
297+
cx.tcx.parent_module_from_def_id(impl_item.owner_id.def_id),
298+
cx.typing_env(),
299+
)
300+
}) {
301+
return;
302+
}
303+
287304
span_lint_and_then(
288305
cx,
289306
UNUSED_ASYNC_TRAIT_IMPL,

tests/ui/unused_async_trait_impl.fixed

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::unused_async_trait_impl)]
2+
#![feature(never_type)]
23

34
trait HasAsyncMethod {
45
async fn do_something() -> u32;
@@ -115,23 +116,20 @@ mod issue17179 {
115116
fn do_something() -> impl Future<Output = u32> {
116117
//~^ unused_async_trait_impl
117118

118-
// Test that local functions are not touched by the suggestion.
119119
fn local_func() -> u32 {
120120
if 5 == 2 {
121121
return 1;
122122
}
123123
2
124124
}
125125

126-
// Test that we do not change the tail expr or return in a (unrelated) closure.
127126
let f = || {
128127
if 5 == 2 {
129128
return 1;
130129
}
131130
2
132131
};
133132

134-
// However the following return statement and tail expression should be changed.
135133
if f() == 5 {
136134
return std::future::ready(3);
137135
}
@@ -140,3 +138,24 @@ mod issue17179 {
140138
}
141139
}
142140
}
141+
142+
mod issue17162 {
143+
trait AsyncTraitWithSelf {
144+
async fn do_something(&self) -> u32;
145+
}
146+
147+
impl AsyncTraitWithSelf for ! {
148+
async fn do_something(&self) -> u32 {
149+
unreachable!()
150+
}
151+
}
152+
153+
// so this should lint, cause no self parameter, can be called via <! as
154+
// HasAsyncMethod>::do_something()
155+
impl crate::HasAsyncMethod for ! {
156+
fn do_something() -> impl Future<Output = u32> {
157+
//~^ unused_async_trait_impl
158+
std::future::ready(1)
159+
}
160+
}
161+
}

tests/ui/unused_async_trait_impl.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::unused_async_trait_impl)]
2+
#![feature(never_type)]
23

34
trait HasAsyncMethod {
45
async fn do_something() -> u32;
@@ -115,23 +116,20 @@ mod issue17179 {
115116
async fn do_something() -> u32 {
116117
//~^ unused_async_trait_impl
117118

118-
// Test that local functions are not touched by the suggestion.
119119
fn local_func() -> u32 {
120120
if 5 == 2 {
121121
return 1;
122122
}
123123
2
124124
}
125125

126-
// Test that we do not change the tail expr or return in a (unrelated) closure.
127126
let f = || {
128127
if 5 == 2 {
129128
return 1;
130129
}
131130
2
132131
};
133132

134-
// However the following return statement and tail expression should be changed.
135133
if f() == 5 {
136134
return 3;
137135
}
@@ -140,3 +138,24 @@ mod issue17179 {
140138
}
141139
}
142140
}
141+
142+
mod issue17162 {
143+
trait AsyncTraitWithSelf {
144+
async fn do_something(&self) -> u32;
145+
}
146+
147+
impl AsyncTraitWithSelf for ! {
148+
async fn do_something(&self) -> u32 {
149+
unreachable!()
150+
}
151+
}
152+
153+
// so this should lint, cause no self parameter, can be called via <! as
154+
// HasAsyncMethod>::do_something()
155+
impl crate::HasAsyncMethod for ! {
156+
async fn do_something() -> u32 {
157+
//~^ unused_async_trait_impl
158+
1
159+
}
160+
}
161+
}

tests/ui/unused_async_trait_impl.stderr

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: unused `async` for async trait impl function with no `.await` statements
2-
--> tests/ui/unused_async_trait_impl.rs:16:9
2+
--> tests/ui/unused_async_trait_impl.rs:17:9
33
|
44
LL | / async fn do_something() -> u32 {
55
LL | |
@@ -18,7 +18,7 @@ LL ~ std::future::ready(1)
1818
|
1919

2020
error: unused `async` for async trait impl function with no `.await` statements
21-
--> tests/ui/unused_async_trait_impl.rs:40:9
21+
--> tests/ui/unused_async_trait_impl.rs:41:9
2222
|
2323
LL | / async fn do_something() -> u32 {
2424
LL | |
@@ -40,7 +40,7 @@ LL ~ std::future::ready(x)
4040
|
4141

4242
error: unused `async` for async trait impl function with no `.await` statements
43-
--> tests/ui/unused_async_trait_impl.rs:63:9
43+
--> tests/ui/unused_async_trait_impl.rs:64:9
4444
|
4545
LL | / async fn do_something() -> u32 {
4646
LL | |
@@ -57,7 +57,7 @@ LL ~ std::future::ready(5)
5757
|
5858

5959
error: unused `async` for async trait impl function with no `.await` statements
60-
--> tests/ui/unused_async_trait_impl.rs:97:9
60+
--> tests/ui/unused_async_trait_impl.rs:98:9
6161
|
6262
LL | / async fn do_something() -> vec_ty!(u32) {
6363
LL | |
@@ -74,7 +74,7 @@ LL ~ std::future::ready(Vec::new())
7474
|
7575

7676
error: unused `async` for async trait impl function with no `.await` statements
77-
--> tests/ui/unused_async_trait_impl.rs:104:9
77+
--> tests/ui/unused_async_trait_impl.rs:105:9
7878
|
7979
LL | / async fn do_something() -> Vec<u32> {
8080
LL | |
@@ -91,9 +91,12 @@ LL ~ std::future::ready(vec![])
9191
|
9292

9393
error: unused `async` for async trait impl function with no `.await` statements
94-
--> tests/ui/unused_async_trait_impl.rs:115:9
94+
--> tests/ui/unused_async_trait_impl.rs:116:9
9595
|
9696
LL | / async fn do_something() -> u32 {
97+
LL | |
98+
LL | |
99+
LL | | fn local_func() -> u32 {
97100
... |
98101
LL | | 5
99102
LL | | }
@@ -112,5 +115,22 @@ LL |
112115
LL ~ std::future::ready(5)
113116
|
114117

115-
error: aborting due to 6 previous errors
118+
error: unused `async` for async trait impl function with no `.await` statements
119+
--> tests/ui/unused_async_trait_impl.rs:156:9
120+
|
121+
LL | / async fn do_something() -> u32 {
122+
LL | |
123+
LL | | 1
124+
LL | | }
125+
| |_________^
126+
|
127+
= note: `std::future::ready` creates a `Future` which returns the value immediately when `poll`ed
128+
help: consider removing the `async` from this function and returning `impl Future<Output = u32>` instead
129+
|
130+
LL ~ fn do_something() -> impl Future<Output = u32> {
131+
LL |
132+
LL ~ std::future::ready(1)
133+
|
134+
135+
error: aborting due to 7 previous errors
116136

0 commit comments

Comments
 (0)