@@ -45,50 +45,72 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
4545
4646impl < ' 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 }
0 commit comments