@@ -325,6 +325,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
325325 hir:: CoroutineSource :: Block ,
326326 |this| this. with_new_scopes ( e. span , |this| this. lower_block_expr ( block) ) ,
327327 ) ,
328+ ExprKind :: Gen ( capture_clause, block, GenBlockKind :: AsyncGen ) => self
329+ . make_async_gen_expr (
330+ * capture_clause,
331+ e. id ,
332+ None ,
333+ e. span ,
334+ hir:: CoroutineSource :: Block ,
335+ |this| this. with_new_scopes ( e. span , |this| this. lower_block_expr ( block) ) ,
336+ ) ,
328337 ExprKind :: Yield ( opt_expr) => self . lower_expr_yield ( e. span , opt_expr. as_deref ( ) ) ,
329338 ExprKind :: Err => hir:: ExprKind :: Err (
330339 self . tcx . sess . delay_span_bug ( e. span , "lowered ExprKind::Err" ) ,
@@ -726,6 +735,84 @@ impl<'hir> LoweringContext<'_, 'hir> {
726735 } ) )
727736 }
728737
738+ /// Lower a `async gen` construct to a generator that implements `AsyncIterator`.
739+ ///
740+ /// This results in:
741+ ///
742+ /// ```text
743+ /// static move? |_task_context| -> () {
744+ /// <body>
745+ /// }
746+ /// ```
747+ pub ( super ) fn make_async_gen_expr (
748+ & mut self ,
749+ capture_clause : CaptureBy ,
750+ closure_node_id : NodeId ,
751+ _yield_ty : Option < hir:: FnRetTy < ' hir > > ,
752+ span : Span ,
753+ async_coroutine_source : hir:: CoroutineSource ,
754+ body : impl FnOnce ( & mut Self ) -> hir:: Expr < ' hir > ,
755+ ) -> hir:: ExprKind < ' hir > {
756+ let output = hir:: FnRetTy :: DefaultReturn ( self . lower_span ( span) ) ;
757+
758+ // Resume argument type: `ResumeTy`
759+ let unstable_span =
760+ self . mark_span_with_reason ( DesugaringKind :: Async , span, self . allow_gen_future . clone ( ) ) ;
761+ let resume_ty = hir:: QPath :: LangItem ( hir:: LangItem :: ResumeTy , unstable_span) ;
762+ let input_ty = hir:: Ty {
763+ hir_id : self . next_id ( ) ,
764+ kind : hir:: TyKind :: Path ( resume_ty) ,
765+ span : unstable_span,
766+ } ;
767+
768+ // The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
769+ let fn_decl = self . arena . alloc ( hir:: FnDecl {
770+ inputs : arena_vec ! [ self ; input_ty] ,
771+ output,
772+ c_variadic : false ,
773+ implicit_self : hir:: ImplicitSelfKind :: None ,
774+ lifetime_elision_allowed : false ,
775+ } ) ;
776+
777+ // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
778+ let ( pat, task_context_hid) = self . pat_ident_binding_mode (
779+ span,
780+ Ident :: with_dummy_span ( sym:: _task_context) ,
781+ hir:: BindingAnnotation :: MUT ,
782+ ) ;
783+ let param = hir:: Param {
784+ hir_id : self . next_id ( ) ,
785+ pat,
786+ ty_span : self . lower_span ( span) ,
787+ span : self . lower_span ( span) ,
788+ } ;
789+ let params = arena_vec ! [ self ; param] ;
790+
791+ let body = self . lower_body ( move |this| {
792+ this. coroutine_kind = Some ( hir:: CoroutineKind :: AsyncGen ( async_coroutine_source) ) ;
793+
794+ let old_ctx = this. task_context ;
795+ this. task_context = Some ( task_context_hid) ;
796+ let res = body ( this) ;
797+ this. task_context = old_ctx;
798+ ( params, res)
799+ } ) ;
800+
801+ // `static |_task_context| -> <ret_ty> { body }`:
802+ hir:: ExprKind :: Closure ( self . arena . alloc ( hir:: Closure {
803+ def_id : self . local_def_id ( closure_node_id) ,
804+ binder : hir:: ClosureBinder :: Default ,
805+ capture_clause,
806+ bound_generic_params : & [ ] ,
807+ fn_decl,
808+ body,
809+ fn_decl_span : self . lower_span ( span) ,
810+ fn_arg_span : None ,
811+ movability : Some ( hir:: Movability :: Static ) ,
812+ constness : hir:: Constness :: NotConst ,
813+ } ) )
814+ }
815+
729816 /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
730817 /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
731818 pub ( super ) fn maybe_forward_track_caller (
@@ -775,15 +862,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
775862 /// ```
776863 fn lower_expr_await ( & mut self , await_kw_span : Span , expr : & Expr ) -> hir:: ExprKind < ' hir > {
777864 let full_span = expr. span . to ( await_kw_span) ;
778- match self . coroutine_kind {
779- Some ( hir:: CoroutineKind :: Async ( _) ) => { }
865+
866+ let is_async_gen = match self . coroutine_kind {
867+ Some ( hir:: CoroutineKind :: Async ( _) ) => false ,
868+ Some ( hir:: CoroutineKind :: AsyncGen ( _) ) => true ,
780869 Some ( hir:: CoroutineKind :: Coroutine ) | Some ( hir:: CoroutineKind :: Gen ( _) ) | None => {
781870 return hir:: ExprKind :: Err ( self . tcx . sess . emit_err ( AwaitOnlyInAsyncFnAndBlocks {
782871 await_kw_span,
783872 item_span : self . current_item ,
784873 } ) ) ;
785874 }
786- }
875+ } ;
876+
787877 let span = self . mark_span_with_reason ( DesugaringKind :: Await , await_kw_span, None ) ;
788878 let gen_future_span = self . mark_span_with_reason (
789879 DesugaringKind :: Await ,
@@ -872,12 +962,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
872962 self . stmt_expr ( span, match_expr)
873963 } ;
874964
875- // task_context = yield ();
965+ // Depending on `async` of `async gen`:
966+ // async - task_context = yield ();
967+ // async gen - task_context = yield async_gen_pending();
876968 let yield_stmt = {
877- let unit = self . expr_unit ( span) ;
969+ let yielded = if is_async_gen {
970+ self . expr_call_lang_item_fn ( span, hir:: LangItem :: AsyncGenPending , & [ ] )
971+ } else {
972+ self . expr_unit ( span)
973+ } ;
974+
878975 let yield_expr = self . expr (
879976 span,
880- hir:: ExprKind :: Yield ( unit , hir:: YieldSource :: Await { expr : Some ( expr_hir_id) } ) ,
977+ hir:: ExprKind :: Yield ( yielded , hir:: YieldSource :: Await { expr : Some ( expr_hir_id) } ) ,
881978 ) ;
882979 let yield_expr = self . arena . alloc ( yield_expr) ;
883980
@@ -987,7 +1084,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
9871084 }
9881085 Some ( movability)
9891086 }
990- Some ( hir:: CoroutineKind :: Gen ( _) ) | Some ( hir:: CoroutineKind :: Async ( _) ) => {
1087+ Some (
1088+ hir:: CoroutineKind :: Gen ( _)
1089+ | hir:: CoroutineKind :: Async ( _)
1090+ | hir:: CoroutineKind :: AsyncGen ( _) ,
1091+ ) => {
9911092 panic ! ( "non-`async`/`gen` closure body turned `async`/`gen` during lowering" ) ;
9921093 }
9931094 None => {
@@ -1494,8 +1595,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
14941595 }
14951596
14961597 fn lower_expr_yield ( & mut self , span : Span , opt_expr : Option < & Expr > ) -> hir:: ExprKind < ' hir > {
1497- match self . coroutine_kind {
1498- Some ( hir:: CoroutineKind :: Gen ( _) ) => { }
1598+ let is_async_gen = match self . coroutine_kind {
1599+ Some ( hir:: CoroutineKind :: Gen ( _) ) => false ,
1600+ Some ( hir:: CoroutineKind :: AsyncGen ( _) ) => true ,
14991601 Some ( hir:: CoroutineKind :: Async ( _) ) => {
15001602 return hir:: ExprKind :: Err (
15011603 self . tcx . sess . emit_err ( AsyncCoroutinesNotSupported { span } ) ,
@@ -1511,14 +1613,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
15111613 )
15121614 . emit ( ) ;
15131615 }
1514- self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine )
1616+ self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine ) ;
1617+ false
15151618 }
1516- }
1619+ } ;
15171620
1518- let expr =
1621+ let mut yielded =
15191622 opt_expr. as_ref ( ) . map ( |x| self . lower_expr ( x) ) . unwrap_or_else ( || self . expr_unit ( span) ) ;
15201623
1521- hir:: ExprKind :: Yield ( expr, hir:: YieldSource :: Yield )
1624+ if is_async_gen {
1625+ // yield async_gen_ready($expr);
1626+ yielded = self . expr_call_lang_item_fn (
1627+ span,
1628+ hir:: LangItem :: AsyncGenReady ,
1629+ std:: slice:: from_ref ( yielded) ,
1630+ ) ;
1631+ }
1632+
1633+ hir:: ExprKind :: Yield ( yielded, hir:: YieldSource :: Yield )
15221634 }
15231635
15241636 /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
0 commit comments