Skip to content

Commit 91859ed

Browse files
committed
Auto merge of rust-lang#119258 - compiler-errors:closure-kind, r=eholk
Make closures carry their own ClosureKind Right now, we use the "`movability`" field of `hir::Closure` to distinguish a closure and a coroutine. This is paired together with the `CoroutineKind`, which is located not in the `hir::Closure`, but the `hir::Body`. This is strange and redundant. This PR introduces `ClosureKind` with two variants -- `Closure` and `Coroutine`, which is put into `hir::Closure`. The `CoroutineKind` is thus removed from `hir::Body`, and `Option<Movability>` no longer needs to be a stand-in for "is this a closure or a coroutine". r? eholk
2 parents 620a1e4 + e0097f5 commit 91859ed

14 files changed

+119
-73
lines changed

clippy_lints/src/async_yields_async.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
22
use clippy_utils::source::snippet;
33
use clippy_utils::ty::implements_trait;
44
use rustc_errors::Applicability;
5-
use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, CoroutineDesugaring, ExprKind, QPath};
5+
use rustc_hir::{
6+
Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath,
7+
};
68
use rustc_lint::{LateContext, LateLintPass};
79
use rustc_session::declare_lint_pass;
810

@@ -44,15 +46,22 @@ declare_clippy_lint! {
4446
declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
4547

4648
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
47-
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
49+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
4850
// For functions, with explicitly defined types, don't warn.
4951
// XXXkhuey maybe we should?
50-
if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block | CoroutineSource::Closure)) = body.coroutine_kind {
52+
if let ExprKind::Closure(Closure {
53+
kind:
54+
ClosureKind::Coroutine(CoroutineKind::Desugared(
55+
CoroutineDesugaring::Async,
56+
CoroutineSource::Block | CoroutineSource::Closure,
57+
)),
58+
body: body_id,
59+
..
60+
}) = expr.kind
61+
{
5162
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
52-
let body_id = BodyId {
53-
hir_id: body.value.hir_id,
54-
};
55-
let typeck_results = cx.tcx.typeck_body(body_id);
63+
let typeck_results = cx.tcx.typeck_body(*body_id);
64+
let body = cx.tcx.hir().body(*body_id);
5665
let expr_ty = typeck_results.expr_ty(body.value);
5766

5867
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {

clippy_lints/src/await_holding_invalid.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use clippy_config::types::DisallowedPath;
22
use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::{match_def_path, paths};
44
use rustc_data_structures::fx::FxHashMap;
5+
use rustc_hir as hir;
56
use rustc_hir::def_id::DefId;
6-
use rustc_hir::{Body, CoroutineKind, CoroutineDesugaring};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_middle::mir::CoroutineLayout;
99
use rustc_session::impl_lint_pass;
@@ -183,8 +183,8 @@ impl AwaitHolding {
183183
}
184184
}
185185

186-
impl LateLintPass<'_> for AwaitHolding {
187-
fn check_crate(&mut self, cx: &LateContext<'_>) {
186+
impl<'tcx> LateLintPass<'tcx> for AwaitHolding {
187+
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
188188
for conf in &self.conf_invalid_types {
189189
let segs: Vec<_> = conf.path().split("::").collect();
190190
for id in clippy_utils::def_path_def_ids(cx, &segs) {
@@ -193,10 +193,14 @@ impl LateLintPass<'_> for AwaitHolding {
193193
}
194194
}
195195

196-
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
197-
if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = body.coroutine_kind {
198-
let def_id = cx.tcx.hir().body_owner_def_id(body.id());
199-
if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) {
196+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
197+
if let hir::ExprKind::Closure(hir::Closure {
198+
kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)),
199+
def_id,
200+
..
201+
}) = expr.kind
202+
{
203+
if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) {
200204
self.check_interior_types(cx, coroutine_layout);
201205
}
202206
}

clippy_lints/src/manual_async_fn.rs

+21-11
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
33
use rustc_errors::Applicability;
44
use rustc_hir::intravisit::FnKind;
55
use rustc_hir::{
6-
Block, Body, Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
7-
ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
6+
Block, Body, Closure, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy,
7+
GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind,
8+
TypeBindingKind, ClosureKind,
89
};
910
use rustc_lint::{LateContext, LateLintPass};
1011
use rustc_session::declare_lint_pass;
@@ -171,16 +172,25 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
171172
.all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
172173
}
173174

174-
fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
175-
if let Some(block_expr) = block.expr
176-
&& let Expr {
177-
kind: ExprKind::Closure(&Closure { body, .. }),
178-
..
179-
} = block_expr
180-
&& let closure_body = cx.tcx.hir().body(body)
181-
&& closure_body.coroutine_kind == Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))
175+
fn desugared_async_block<'tcx>(
176+
cx: &LateContext<'tcx>,
177+
block: &'tcx Block<'tcx>,
178+
) -> Option<&'tcx Body<'tcx>> {
179+
if let Some(Expr {
180+
kind:
181+
ExprKind::Closure(&Closure {
182+
kind:
183+
ClosureKind::Coroutine(CoroutineKind::Desugared(
184+
CoroutineDesugaring::Async,
185+
CoroutineSource::Block,
186+
)),
187+
body,
188+
..
189+
}),
190+
..
191+
}) = block.expr
182192
{
183-
return Some(closure_body);
193+
return Some(cx.tcx.hir().body(body));
184194
}
185195

186196
None

clippy_lints/src/methods/iter_kv_map.rs

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ pub(super) fn check<'tcx>(
3232
&& let Body {
3333
params: [p],
3434
value: body_expr,
35-
coroutine_kind: _,
3635
} = cx.tcx.hir().body(c.body)
3736
&& let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind
3837
&& let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {

clippy_lints/src/needless_question_mark.rs

+15-17
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use clippy_utils::path_res;
33
use clippy_utils::source::snippet;
44
use rustc_errors::Applicability;
55
use rustc_hir::def::{DefKind, Res};
6-
use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, LangItem, MatchSource, QPath};
6+
use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_session::declare_lint_pass;
99

@@ -86,22 +86,20 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
8686
}
8787

8888
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
89-
if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) = body.coroutine_kind {
90-
if let ExprKind::Block(
91-
Block {
92-
expr:
93-
Some(Expr {
94-
kind: ExprKind::DropTemps(async_body),
95-
..
96-
}),
97-
..
98-
},
99-
_,
100-
) = body.value.kind
101-
{
102-
if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind {
103-
check(cx, expr);
104-
}
89+
if let ExprKind::Block(
90+
Block {
91+
expr:
92+
Some(Expr {
93+
kind: ExprKind::DropTemps(async_body),
94+
..
95+
}),
96+
..
97+
},
98+
_,
99+
) = body.value.kind
100+
{
101+
if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind {
102+
check(cx, expr.peel_blocks());
105103
}
106104
} else {
107105
check(cx, body.value.peel_blocks());

clippy_lints/src/redundant_async_block.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
55
use clippy_utils::source::{snippet, walk_span_to_context};
66
use clippy_utils::visitors::for_each_expr;
77
use rustc_errors::Applicability;
8-
use rustc_hir::{Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource};
8+
use rustc_hir::{Closure, ClosureKind, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::lint::in_external_macro;
1111
use rustc_middle::ty::UpvarCapture;
@@ -69,9 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
6969
/// If `expr` is a desugared `async` block, return the original expression if it does not capture
7070
/// any variable by ref.
7171
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
72-
if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind
72+
if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind
7373
&& let body = cx.tcx.hir().body(*body)
74-
&& matches!(body.coroutine_kind, Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)))
74+
&& matches!(kind, ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)))
7575
{
7676
cx.typeck_results()
7777
.closure_min_captures

clippy_lints/src/redundant_closure_call.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ 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, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node};
8+
use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node, ClosureKind};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::hir::nested_filter;
1111
use rustc_middle::lint::in_external_macro;
@@ -63,11 +63,10 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor {
6363
/// Checks if the body is owned by an async closure.
6464
/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression
6565
/// }`.
66-
fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool {
66+
fn is_async_closure(body: &hir::Body<'_>) -> bool {
6767
if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
68-
&& let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body)
6968
// checks whether it is `async || whatever_expression`
70-
&& let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind
69+
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind
7170
{
7271
true
7372
} else {
@@ -103,7 +102,7 @@ fn find_innermost_closure<'tcx>(
103102
data = Some((
104103
body.value,
105104
closure.fn_decl,
106-
if is_async_closure(cx, body) {
105+
if is_async_closure(body) {
107106
ty::Asyncness::Yes
108107
} else {
109108
ty::Asyncness::No

clippy_lints/src/unused_async.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_hir_and_then;
22
use clippy_utils::is_def_id_trait_method;
33
use rustc_hir::def::DefKind;
4-
use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
4+
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
55
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
66
use rustc_lint::{LateContext, LateLintPass};
77
use rustc_middle::hir::nested_filter;
@@ -78,32 +78,32 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
7878
self.await_in_async_block = Some(ex.span);
7979
}
8080
}
81-
walk_expr(self, ex);
82-
}
83-
84-
fn nested_visit_map(&mut self) -> Self::Map {
85-
self.cx.tcx.hir()
86-
}
8781

88-
fn visit_body(&mut self, b: &'tcx Body<'tcx>) {
8982
let is_async_block = matches!(
90-
b.coroutine_kind,
91-
Some(rustc_hir::CoroutineKind::Desugared(
92-
rustc_hir::CoroutineDesugaring::Async,
93-
_
94-
))
83+
ex.kind,
84+
ExprKind::Closure(rustc_hir::Closure {
85+
kind: rustc_hir::ClosureKind::Coroutine(rustc_hir::CoroutineKind::Desugared(
86+
rustc_hir::CoroutineDesugaring::Async,
87+
_
88+
)),
89+
..
90+
})
9591
);
9692

9793
if is_async_block {
9894
self.async_depth += 1;
9995
}
10096

101-
walk_body(self, b);
97+
walk_expr(self, ex);
10298

10399
if is_async_block {
104100
self.async_depth -= 1;
105101
}
106102
}
103+
104+
fn nested_visit_map(&mut self) -> Self::Map {
105+
self.cx.tcx.hir()
106+
}
107107
}
108108

109109
impl<'tcx> LateLintPass<'tcx> for UnusedAsync {

clippy_lints/src/utils/author.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use rustc_ast::LitIntType;
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_hir as hir;
99
use rustc_hir::{
10-
ArrayLen, BindingAnnotation, CaptureBy, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
10+
ArrayLen, BindingAnnotation, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit,
11+
PatKind, QPath, StmtKind, TyKind,
1112
};
1213
use rustc_lint::{LateContext, LateLintPass, LintContext};
1314
use rustc_session::declare_lint_pass;
@@ -476,23 +477,35 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
476477
capture_clause,
477478
fn_decl,
478479
body: body_id,
479-
movability,
480+
kind,
480481
..
481482
}) => {
482483
let capture_clause = match capture_clause {
483484
CaptureBy::Value { .. } => "Value { .. }",
484485
CaptureBy::Ref => "Ref",
485486
};
486487

487-
let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
488+
let closure_kind = match kind {
489+
ClosureKind::Closure => "ClosureKind::Closure".to_string(),
490+
ClosureKind::Coroutine(coroutine_kind) => match coroutine_kind {
491+
CoroutineKind::Desugared(desugaring, source) => format!(
492+
"ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::{desugaring:?}, CoroutineSource::{source:?}))"
493+
),
494+
CoroutineKind::Coroutine(movability) => {
495+
format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})")
496+
},
497+
},
498+
};
488499

489500
let ret_ty = match fn_decl.output {
490501
FnRetTy::DefaultReturn(_) => "FnRetTy::DefaultReturn(_)",
491502
FnRetTy::Return(_) => "FnRetTy::Return(_ty)",
492503
};
493504

494505
bind!(self, fn_decl, body_id);
495-
kind!("Closure(CaptureBy::{capture_clause}, {fn_decl}, {body_id}, _, {movability})");
506+
kind!(
507+
"Closure {{ capture_clause: CaptureBy::{capture_clause}, fn_decl: {fn_decl}, body: {body_id}, closure_kind: {closure_kind}, .. }}"
508+
);
496509
chain!(self, "let {ret_ty} = {fn_decl}.output");
497510
self.body(body_id);
498511
},

tests/ui/author/blocks.stdout

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind
4040
{
4141
// report your lint here
4242
}
43-
if let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl, body_id, _, None) = expr.kind
43+
if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = expr.kind
4444
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
4545
&& expr1 = &cx.tcx.hir().body(body_id).value
46-
&& let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
46+
&& let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind
4747
&& let FnRetTy::DefaultReturn(_) = fn_decl1.output
4848
&& expr2 = &cx.tcx.hir().body(body_id1).value
4949
&& let ExprKind::Block(block, None) = expr2.kind

tests/ui/author/macro_in_closure.stdout

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
if let StmtKind::Local(local) = stmt.kind
22
&& let Some(init) = local.init
3-
&& let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind
3+
&& let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = init.kind
44
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
55
&& expr = &cx.tcx.hir().body(body_id).value
66
&& let ExprKind::Block(block, None) = expr.kind

tests/ui/needless_question_mark.fixed

+4
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
135135
async fn async_result_bad(s: TR) -> Result<usize, bool> {
136136
s.magic
137137
}
138+
139+
async fn async_wrapped<T>(a: Option<T>) -> Option<T> {
140+
{ a }
141+
}

tests/ui/needless_question_mark.rs

+4
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
135135
async fn async_result_bad(s: TR) -> Result<usize, bool> {
136136
Ok(s.magic?)
137137
}
138+
139+
async fn async_wrapped<T>(a: Option<T>) -> Option<T> {
140+
{ Some(a?) }
141+
}

tests/ui/needless_question_mark.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,11 @@ error: question mark operator is useless here
9090
LL | Ok(s.magic?)
9191
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
9292

93-
error: aborting due to 14 previous errors
93+
error: question mark operator is useless here
94+
--> $DIR/needless_question_mark.rs:140:7
95+
|
96+
LL | { Some(a?) }
97+
| ^^^^^^^^ help: try removing question mark and `Some()`: `a`
98+
99+
error: aborting due to 15 previous errors
94100

0 commit comments

Comments
 (0)