Skip to content

Commit f7376a0

Browse files
Deal with additional wrapping of async closure body in clippy
1 parent 5a45dbe commit f7376a0

File tree

3 files changed

+82
-42
lines changed

3 files changed

+82
-42
lines changed

clippy_lints/src/async_yields_async.rs

+60-38
Original file line numberDiff line numberDiff line change
@@ -45,50 +45,72 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
4545

4646
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
4747
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
48-
// For functions, with explicitly defined types, don't warn.
49-
// XXXkhuey maybe we should?
50-
if let ExprKind::Closure(Closure {
51-
kind:
52-
ClosureKind::Coroutine(CoroutineKind::Desugared(
53-
CoroutineDesugaring::Async,
54-
CoroutineSource::Block | CoroutineSource::Closure,
55-
)),
48+
let ExprKind::Closure(Closure {
49+
kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, kind)),
5650
body: body_id,
5751
..
5852
}) = expr.kind
59-
{
60-
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
61-
let typeck_results = cx.tcx.typeck_body(*body_id);
62-
let body = cx.tcx.hir().body(*body_id);
63-
let expr_ty = typeck_results.expr_ty(body.value);
53+
else {
54+
return;
55+
};
6456

65-
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
66-
let return_expr_span = match &body.value.kind {
67-
// XXXkhuey there has to be a better way.
68-
ExprKind::Block(block, _) => block.expr.map(|e| e.span),
69-
ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
70-
_ => None,
71-
};
72-
if let Some(return_expr_span) = return_expr_span {
73-
span_lint_hir_and_then(
74-
cx,
75-
ASYNC_YIELDS_ASYNC,
76-
body.value.hir_id,
57+
let body_expr = match kind {
58+
CoroutineSource::Fn => {
59+
// For functions, with explicitly defined types, don't warn.
60+
// XXXkhuey maybe we should?
61+
return;
62+
},
63+
CoroutineSource::Block => cx.tcx.hir().body(*body_id).value,
64+
CoroutineSource::Closure => {
65+
// Like `async fn`, async closures are wrapped in an additional block
66+
// to move all of the closure's arguments into the future.
67+
68+
let async_closure_body = cx.tcx.hir().body(*body_id).value;
69+
let ExprKind::Block(block, _) = async_closure_body.kind else {
70+
return;
71+
};
72+
let Some(block_expr) = block.expr else {
73+
return;
74+
};
75+
let ExprKind::DropTemps(body_expr) = block_expr.kind else {
76+
return;
77+
};
78+
body_expr
79+
},
80+
};
81+
82+
let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() else {
83+
return;
84+
};
85+
86+
let typeck_results = cx.tcx.typeck_body(*body_id);
87+
let expr_ty = typeck_results.expr_ty(body_expr);
88+
89+
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
90+
let return_expr_span = match &body_expr.kind {
91+
// XXXkhuey there has to be a better way.
92+
ExprKind::Block(block, _) => block.expr.map(|e| e.span),
93+
ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
94+
_ => None,
95+
};
96+
if let Some(return_expr_span) = return_expr_span {
97+
span_lint_hir_and_then(
98+
cx,
99+
ASYNC_YIELDS_ASYNC,
100+
body_expr.hir_id,
101+
return_expr_span,
102+
"an async construct yields a type which is itself awaitable",
103+
|db| {
104+
db.span_label(body_expr.span, "outer async construct");
105+
db.span_label(return_expr_span, "awaitable value not awaited");
106+
db.span_suggestion(
77107
return_expr_span,
78-
"an async construct yields a type which is itself awaitable",
79-
|db| {
80-
db.span_label(body.value.span, "outer async construct");
81-
db.span_label(return_expr_span, "awaitable value not awaited");
82-
db.span_suggestion(
83-
return_expr_span,
84-
"consider awaiting this value",
85-
format!("{}.await", snippet(cx, return_expr_span, "..")),
86-
Applicability::MaybeIncorrect,
87-
);
88-
},
108+
"consider awaiting this value",
109+
format!("{}.await", snippet(cx, return_expr_span, "..")),
110+
Applicability::MaybeIncorrect,
89111
);
90-
}
91-
}
112+
},
113+
);
92114
}
93115
}
94116
}

clippy_lints/src/redundant_closure_call.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use clippy_utils::sugg::Sugg;
55
use rustc_errors::Applicability;
66
use rustc_hir as hir;
77
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
8-
use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
8+
use rustc_hir::{
9+
intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node,
10+
};
911
use rustc_lint::{LateContext, LateLintPass};
1012
use rustc_middle::hir::nested_filter;
1113
use rustc_middle::lint::in_external_macro;
@@ -166,10 +168,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
166168
if coroutine_kind.is_async()
167169
&& let hir::ExprKind::Closure(closure) = body.kind
168170
{
169-
let async_closure_body = cx.tcx.hir().body(closure.body);
171+
// Like `async fn`, async closures are wrapped in an additional block
172+
// to move all of the closure's arguments into the future.
173+
174+
let async_closure_body = cx.tcx.hir().body(closure.body).value;
175+
let ExprKind::Block(block, _) = async_closure_body.kind else {
176+
return;
177+
};
178+
let Some(block_expr) = block.expr else {
179+
return;
180+
};
181+
let ExprKind::DropTemps(body_expr) = block_expr.kind else {
182+
return;
183+
};
170184

171185
// `async x` is a syntax error, so it becomes `async { x }`
172-
if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) {
186+
if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) {
173187
hint = hint.blockify();
174188
}
175189

tests/ui/author/blocks.stdout

+5-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_
4848
&& expr2 = &cx.tcx.hir().body(body_id1).value
4949
&& let ExprKind::Block(block, None) = expr2.kind
5050
&& block.stmts.is_empty()
51-
&& block.expr.is_none()
51+
&& let Some(trailing_expr) = block.expr
52+
&& let ExprKind::DropTemps(expr3) = trailing_expr.kind
53+
&& let ExprKind::Block(block1, None) = expr3.kind
54+
&& block1.stmts.is_empty()
55+
&& block1.expr.is_none()
5256
{
5357
// report your lint here
5458
}

0 commit comments

Comments
 (0)