@@ -104,10 +104,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
104104use rustc_hir:: intravisit:: { FnKind , Visitor , walk_expr} ;
105105use rustc_hir:: {
106106 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,
111111} ;
112112use rustc_lexer:: { TokenKind , tokenize} ;
113113use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
@@ -124,6 +124,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind};
124124use rustc_span:: source_map:: SourceMap ;
125125use rustc_span:: symbol:: { Ident , Symbol , kw} ;
126126use rustc_span:: { InnerSpan , Span , sym} ;
127+ use source:: walk_span_to_context;
127128use visitors:: { Visitable , for_each_unconsumed_temporary} ;
128129
129130use crate :: consts:: { ConstEvalCtxt , Constant , mir_to_const} ;
@@ -2131,25 +2132,34 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
21312132 }
21322133}
21332134
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
21372142 && let ExprKind :: Block (
21382143 Block {
2139- stmts : [ ] ,
21402144 expr :
21412145 Some ( Expr {
2142- kind : ExprKind :: DropTemps ( expr ) ,
2146+ kind : ExprKind :: DropTemps ( inner_expr ) ,
21432147 ..
21442148 } ) ,
21452149 ..
21462150 } ,
21472151 _,
21482152 ) = tcx. hir_body ( body) . value . kind
21492153 {
2150- return Some ( expr) ;
2154+ Some ( inner_expr)
2155+ } else {
2156+ None
21512157 }
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 )
21532163}
21542164
21552165// 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::
37163726 }
37173727 hir_ty
37183728}
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