Skip to content

Commit 5e957c0

Browse files
committed
implicit_return: do not suggest adding return into desugared code
Blocks created by desugaring will not contain an explicit `return`. Do not suggest to add it when the user has no control over the desugared code.
1 parent 1e5237f commit 5e957c0

File tree

5 files changed

+106
-15
lines changed

5 files changed

+106
-15
lines changed

clippy_lints/src/implicit_return.rs

Lines changed: 3 additions & 1 deletion
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::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
33
use clippy_utils::visitors::for_each_expr_without_closures;
4-
use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro};
4+
use clippy_utils::{get_async_closure_expr, get_async_fn_body, is_async_fn, is_from_proc_macro};
55
use core::ops::ControlFlow;
66
use rustc_errors::Applicability;
77
use rustc_hir::intravisit::FnKind;
@@ -241,6 +241,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
241241
Some(e) => e,
242242
None => return,
243243
}
244+
} else if let Some(expr) = get_async_closure_expr(cx.tcx, body.value) {
245+
expr
244246
} else {
245247
body.value
246248
};

clippy_utils/src/lib.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
106106
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
107107
use rustc_hir::{
108108
self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
109-
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItem,
110-
ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
111-
Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem,
112-
TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def,
109+
CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl,
110+
ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId,
111+
OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn,
112+
TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def,
113113
};
114114
use rustc_lexer::{TokenKind, tokenize};
115115
use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -2136,28 +2136,35 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
21362136
}
21372137
}
21382138

2139-
/// Peels away all the compiler generated code surrounding the body of an async function,
2140-
pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
2141-
if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind {
2142-
if let ExprKind::Block(
2139+
/// Peels away all the compiler generated code surrounding the body of an async closure.
2140+
pub fn get_async_closure_expr<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
2141+
if let ExprKind::Closure(&Closure {
2142+
body,
2143+
kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(..)),
2144+
..
2145+
}) = expr.kind
2146+
&& let ExprKind::Block(
21432147
Block {
2144-
stmts: [],
21452148
expr:
21462149
Some(Expr {
2147-
kind: ExprKind::DropTemps(expr),
2150+
kind: ExprKind::DropTemps(inner_expr),
21482151
..
21492152
}),
21502153
..
21512154
},
21522155
_,
21532156
) = tcx.hir_body(body).value.kind
2154-
{
2155-
return Some(expr);
2156-
}
2157+
{
2158+
return Some(inner_expr);
21572159
}
21582160
None
21592161
}
21602162

2163+
/// Peels away all the compiler generated code surrounding the body of an async function.
2164+
pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
2165+
get_async_closure_expr(tcx, body.value)
2166+
}
2167+
21612168
// check if expr is calling method or function with #[must_use] attribute
21622169
pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
21632170
let did = match expr.kind {

tests/ui/implicit_return.fixed

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,22 @@ with_span!(
165165
x
166166
}
167167
);
168+
169+
fn desugared_closure_14446() {
170+
let _ = async || return 0;
171+
//~^ implicit_return
172+
#[rustfmt::skip]
173+
let _ = async || -> i32 { return 0 };
174+
//~^ implicit_return
175+
let _ = async |a: i32| return a;
176+
//~^ implicit_return
177+
#[rustfmt::skip]
178+
let _ = async |a: i32| { return a };
179+
//~^ implicit_return
180+
181+
let _ = async || return 0;
182+
let _ = async || -> i32 { return 0 };
183+
let _ = async |a: i32| return a;
184+
#[rustfmt::skip]
185+
let _ = async |a: i32| { return a };
186+
}

tests/ui/implicit_return.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,22 @@ with_span!(
165165
x
166166
}
167167
);
168+
169+
fn desugared_closure_14446() {
170+
let _ = async || 0;
171+
//~^ implicit_return
172+
#[rustfmt::skip]
173+
let _ = async || -> i32 { 0 };
174+
//~^ implicit_return
175+
let _ = async |a: i32| a;
176+
//~^ implicit_return
177+
#[rustfmt::skip]
178+
let _ = async |a: i32| { a };
179+
//~^ implicit_return
180+
181+
let _ = async || return 0;
182+
let _ = async || -> i32 { return 0 };
183+
let _ = async |a: i32| return a;
184+
#[rustfmt::skip]
185+
let _ = async |a: i32| { return a };
186+
}

tests/ui/implicit_return.stderr

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,5 +183,49 @@ help: add `return` as shown
183183
LL | return true
184184
| ++++++
185185

186-
error: aborting due to 16 previous errors
186+
error: missing `return` statement
187+
--> tests/ui/implicit_return.rs:170:22
188+
|
189+
LL | let _ = async || 0;
190+
| ^
191+
|
192+
help: add `return` as shown
193+
|
194+
LL | let _ = async || return 0;
195+
| ++++++
196+
197+
error: missing `return` statement
198+
--> tests/ui/implicit_return.rs:173:31
199+
|
200+
LL | let _ = async || -> i32 { 0 };
201+
| ^
202+
|
203+
help: add `return` as shown
204+
|
205+
LL | let _ = async || -> i32 { return 0 };
206+
| ++++++
207+
208+
error: missing `return` statement
209+
--> tests/ui/implicit_return.rs:175:28
210+
|
211+
LL | let _ = async |a: i32| a;
212+
| ^
213+
|
214+
help: add `return` as shown
215+
|
216+
LL | let _ = async |a: i32| return a;
217+
| ++++++
218+
219+
error: missing `return` statement
220+
--> tests/ui/implicit_return.rs:178:30
221+
|
222+
LL | let _ = async |a: i32| { a };
223+
| ^
224+
|
225+
help: add `return` as shown
226+
|
227+
LL | let _ = async |a: i32| { return a };
228+
| ++++++
229+
230+
error: aborting due to 20 previous errors
187231

0 commit comments

Comments
 (0)