@@ -104,10 +104,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
104
104
use rustc_hir:: intravisit:: { FnKind , Visitor , walk_expr} ;
105
105
use rustc_hir:: {
106
106
self as hir, Arm , BindingMode , Block , BlockCheckMode , Body , ByRef , Closure , ConstArgKind , ConstContext ,
107
- Destination , Expr , ExprField , ExprKind , FnDecl , FnRetTy , GenericArg , GenericArgs , HirId , Impl , ImplItem ,
108
- ImplItemKind , ImplItemRef , Item , ItemKind , LangItem , LetStmt , MatchSource , Mutability , Node , OwnerId , OwnerNode ,
109
- Param , Pat , PatExpr , PatExprKind , PatKind , Path , PathSegment , PrimTy , QPath , Stmt , StmtKind , TraitFn , TraitItem ,
110
- TraitItemKind , TraitItemRef , TraitRef , TyKind , UnOp , def,
107
+ CoroutineDesugaring , CoroutineKind , Destination , Expr , ExprField , ExprKind , FnDecl , FnRetTy , GenericArg ,
108
+ GenericArgs , HirId , Impl , ImplItem , ImplItemKind , ImplItemRef , Item , ItemKind , LangItem , LetStmt , MatchSource ,
109
+ Mutability , Node , OwnerId , OwnerNode , Param , Pat , PatExpr , PatExprKind , PatKind , Path , PathSegment , PrimTy , QPath ,
110
+ Stmt , StmtKind , TraitFn , TraitItem , TraitItemKind , TraitItemRef , TraitRef , TyKind , UnOp , def,
111
111
} ;
112
112
use rustc_lexer:: { TokenKind , tokenize} ;
113
113
use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
@@ -124,6 +124,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind};
124
124
use rustc_span:: source_map:: SourceMap ;
125
125
use rustc_span:: symbol:: { Ident , Symbol , kw} ;
126
126
use rustc_span:: { InnerSpan , Span , sym} ;
127
+ use source:: walk_span_to_context;
127
128
use visitors:: { Visitable , for_each_unconsumed_temporary} ;
128
129
129
130
use crate :: consts:: { ConstEvalCtxt , Constant , mir_to_const} ;
@@ -2131,25 +2132,34 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
2131
2132
}
2132
2133
}
2133
2134
2134
- /// Peels away all the compiler generated code surrounding the body of an async function,
2135
- pub fn get_async_fn_body < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & Body < ' _ > ) -> Option < & ' tcx Expr < ' tcx > > {
2136
- if let ExprKind :: Closure ( & Closure { body, .. } ) = body. value . kind
2135
+ /// Peels away all the compiler generated code surrounding the body of an async closure.
2136
+ pub fn get_async_closure_expr < ' tcx > ( tcx : TyCtxt < ' tcx > , expr : & Expr < ' _ > ) -> Option < & ' tcx Expr < ' tcx > > {
2137
+ if let ExprKind :: Closure ( & Closure {
2138
+ body,
2139
+ kind : hir:: ClosureKind :: Coroutine ( CoroutineKind :: Desugared ( CoroutineDesugaring :: Async , _) ) ,
2140
+ ..
2141
+ } ) = expr. kind
2137
2142
&& let ExprKind :: Block (
2138
2143
Block {
2139
- stmts : [ ] ,
2140
2144
expr :
2141
2145
Some ( Expr {
2142
- kind : ExprKind :: DropTemps ( expr ) ,
2146
+ kind : ExprKind :: DropTemps ( inner_expr ) ,
2143
2147
..
2144
2148
} ) ,
2145
2149
..
2146
2150
} ,
2147
2151
_,
2148
2152
) = tcx. hir_body ( body) . value . kind
2149
2153
{
2150
- return Some ( expr) ;
2154
+ Some ( inner_expr)
2155
+ } else {
2156
+ None
2151
2157
}
2152
- None
2158
+ }
2159
+
2160
+ /// Peels away all the compiler generated code surrounding the body of an async function,
2161
+ pub fn get_async_fn_body < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & Body < ' _ > ) -> Option < & ' tcx Expr < ' tcx > > {
2162
+ get_async_closure_expr ( tcx, body. value )
2153
2163
}
2154
2164
2155
2165
// check if expr is calling method or function with #[must_use] attribute
@@ -3716,3 +3726,20 @@ pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir::
3716
3726
}
3717
3727
hir_ty
3718
3728
}
3729
+
3730
+ /// If `expr` is a desugared `.await`, return the original expression if it does not come from a
3731
+ /// macro expansion.
3732
+ pub fn desugar_await < ' tcx > ( expr : & ' tcx Expr < ' _ > ) -> Option < & ' tcx Expr < ' tcx > > {
3733
+ if let ExprKind :: Match ( match_value, _, MatchSource :: AwaitDesugar ) = expr. kind
3734
+ && let ExprKind :: Call ( _, [ into_future_arg] ) = match_value. kind
3735
+ && let ctxt = expr. span . ctxt ( )
3736
+ && for_each_expr_without_closures ( into_future_arg, |e| {
3737
+ walk_span_to_context ( e. span , ctxt) . map_or ( ControlFlow :: Break ( ( ) ) , |_| ControlFlow :: Continue ( ( ) ) )
3738
+ } )
3739
+ . is_none ( )
3740
+ {
3741
+ Some ( into_future_arg)
3742
+ } else {
3743
+ None
3744
+ }
3745
+ }
0 commit comments