@@ -324,6 +324,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
324324 hir:: CoroutineSource :: Block ,
325325 |this| this. with_new_scopes ( e. span , |this| this. lower_block_expr ( block) ) ,
326326 ) ,
327+ ExprKind :: Gen ( capture_clause, block, GenBlockKind :: AsyncGen ) => self
328+ . make_async_gen_expr (
329+ * capture_clause,
330+ e. id ,
331+ None ,
332+ e. span ,
333+ hir:: CoroutineSource :: Block ,
334+ |this| this. with_new_scopes ( e. span , |this| this. lower_block_expr ( block) ) ,
335+ ) ,
327336 ExprKind :: Yield ( opt_expr) => self . lower_expr_yield ( e. span , opt_expr. as_deref ( ) ) ,
328337 ExprKind :: Err => hir:: ExprKind :: Err (
329338 self . tcx . sess . span_delayed_bug ( e. span , "lowered ExprKind::Err" ) ,
@@ -706,6 +715,87 @@ impl<'hir> LoweringContext<'_, 'hir> {
706715 } ) )
707716 }
708717
718+ /// Lower a `async gen` construct to a generator that implements `AsyncIterator`.
719+ ///
720+ /// This results in:
721+ ///
722+ /// ```text
723+ /// static move? |_task_context| -> () {
724+ /// <body>
725+ /// }
726+ /// ```
727+ pub ( super ) fn make_async_gen_expr (
728+ & mut self ,
729+ capture_clause : CaptureBy ,
730+ closure_node_id : NodeId ,
731+ _yield_ty : Option < hir:: FnRetTy < ' hir > > ,
732+ span : Span ,
733+ async_coroutine_source : hir:: CoroutineSource ,
734+ body : impl FnOnce ( & mut Self ) -> hir:: Expr < ' hir > ,
735+ ) -> hir:: ExprKind < ' hir > {
736+ let output = hir:: FnRetTy :: DefaultReturn ( self . lower_span ( span) ) ;
737+
738+ // Resume argument type: `ResumeTy`
739+ let unstable_span = self . mark_span_with_reason (
740+ DesugaringKind :: Async ,
741+ span,
742+ Some ( self . allow_gen_future . clone ( ) ) ,
743+ ) ;
744+ let resume_ty = hir:: QPath :: LangItem ( hir:: LangItem :: ResumeTy , unstable_span) ;
745+ let input_ty = hir:: Ty {
746+ hir_id : self . next_id ( ) ,
747+ kind : hir:: TyKind :: Path ( resume_ty) ,
748+ span : unstable_span,
749+ } ;
750+
751+ // The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
752+ let fn_decl = self . arena . alloc ( hir:: FnDecl {
753+ inputs : arena_vec ! [ self ; input_ty] ,
754+ output,
755+ c_variadic : false ,
756+ implicit_self : hir:: ImplicitSelfKind :: None ,
757+ lifetime_elision_allowed : false ,
758+ } ) ;
759+
760+ // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
761+ let ( pat, task_context_hid) = self . pat_ident_binding_mode (
762+ span,
763+ Ident :: with_dummy_span ( sym:: _task_context) ,
764+ hir:: BindingAnnotation :: MUT ,
765+ ) ;
766+ let param = hir:: Param {
767+ hir_id : self . next_id ( ) ,
768+ pat,
769+ ty_span : self . lower_span ( span) ,
770+ span : self . lower_span ( span) ,
771+ } ;
772+ let params = arena_vec ! [ self ; param] ;
773+
774+ let body = self . lower_body ( move |this| {
775+ this. coroutine_kind = Some ( hir:: CoroutineKind :: AsyncGen ( async_coroutine_source) ) ;
776+
777+ let old_ctx = this. task_context ;
778+ this. task_context = Some ( task_context_hid) ;
779+ let res = body ( this) ;
780+ this. task_context = old_ctx;
781+ ( params, res)
782+ } ) ;
783+
784+ // `static |_task_context| -> <ret_ty> { body }`:
785+ hir:: ExprKind :: Closure ( self . arena . alloc ( hir:: Closure {
786+ def_id : self . local_def_id ( closure_node_id) ,
787+ binder : hir:: ClosureBinder :: Default ,
788+ capture_clause,
789+ bound_generic_params : & [ ] ,
790+ fn_decl,
791+ body,
792+ fn_decl_span : self . lower_span ( span) ,
793+ fn_arg_span : None ,
794+ movability : Some ( hir:: Movability :: Static ) ,
795+ constness : hir:: Constness :: NotConst ,
796+ } ) )
797+ }
798+
709799 /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
710800 /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
711801 pub ( super ) fn maybe_forward_track_caller (
@@ -755,15 +845,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
755845 /// ```
756846 fn lower_expr_await ( & mut self , await_kw_span : Span , expr : & Expr ) -> hir:: ExprKind < ' hir > {
757847 let full_span = expr. span . to ( await_kw_span) ;
758- match self . coroutine_kind {
759- Some ( hir:: CoroutineKind :: Async ( _) ) => { }
848+
849+ let is_async_gen = match self . coroutine_kind {
850+ Some ( hir:: CoroutineKind :: Async ( _) ) => false ,
851+ Some ( hir:: CoroutineKind :: AsyncGen ( _) ) => true ,
760852 Some ( hir:: CoroutineKind :: Coroutine ) | Some ( hir:: CoroutineKind :: Gen ( _) ) | None => {
761853 return hir:: ExprKind :: Err ( self . tcx . sess . emit_err ( AwaitOnlyInAsyncFnAndBlocks {
762854 await_kw_span,
763855 item_span : self . current_item ,
764856 } ) ) ;
765857 }
766- }
858+ } ;
859+
767860 let span = self . mark_span_with_reason ( DesugaringKind :: Await , await_kw_span, None ) ;
768861 let gen_future_span = self . mark_span_with_reason (
769862 DesugaringKind :: Await ,
@@ -852,12 +945,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
852945 self . stmt_expr ( span, match_expr)
853946 } ;
854947
855- // task_context = yield ();
948+ // Depending on `async` of `async gen`:
949+ // async - task_context = yield ();
950+ // async gen - task_context = yield async_gen_pending();
856951 let yield_stmt = {
857- let unit = self . expr_unit ( span) ;
952+ let yielded = if is_async_gen {
953+ self . expr_call_lang_item_fn ( span, hir:: LangItem :: AsyncGenPending , & [ ] )
954+ } else {
955+ self . expr_unit ( span)
956+ } ;
957+
858958 let yield_expr = self . expr (
859959 span,
860- hir:: ExprKind :: Yield ( unit , hir:: YieldSource :: Await { expr : Some ( expr_hir_id) } ) ,
960+ hir:: ExprKind :: Yield ( yielded , hir:: YieldSource :: Await { expr : Some ( expr_hir_id) } ) ,
861961 ) ;
862962 let yield_expr = self . arena . alloc ( yield_expr) ;
863963
@@ -967,7 +1067,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
9671067 }
9681068 Some ( movability)
9691069 }
970- Some ( hir:: CoroutineKind :: Gen ( _) ) | Some ( hir:: CoroutineKind :: Async ( _) ) => {
1070+ Some (
1071+ hir:: CoroutineKind :: Gen ( _)
1072+ | hir:: CoroutineKind :: Async ( _)
1073+ | hir:: CoroutineKind :: AsyncGen ( _) ,
1074+ ) => {
9711075 panic ! ( "non-`async`/`gen` closure body turned `async`/`gen` during lowering" ) ;
9721076 }
9731077 None => {
@@ -1474,8 +1578,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
14741578 }
14751579
14761580 fn lower_expr_yield ( & mut self , span : Span , opt_expr : Option < & Expr > ) -> hir:: ExprKind < ' hir > {
1477- match self . coroutine_kind {
1478- Some ( hir:: CoroutineKind :: Gen ( _) ) => { }
1581+ let is_async_gen = match self . coroutine_kind {
1582+ Some ( hir:: CoroutineKind :: Gen ( _) ) => false ,
1583+ Some ( hir:: CoroutineKind :: AsyncGen ( _) ) => true ,
14791584 Some ( hir:: CoroutineKind :: Async ( _) ) => {
14801585 return hir:: ExprKind :: Err (
14811586 self . tcx . sess . emit_err ( AsyncCoroutinesNotSupported { span } ) ,
@@ -1491,14 +1596,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
14911596 )
14921597 . emit ( ) ;
14931598 }
1494- self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine )
1599+ self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine ) ;
1600+ false
14951601 }
1496- }
1602+ } ;
14971603
1498- let expr =
1604+ let mut yielded =
14991605 opt_expr. as_ref ( ) . map ( |x| self . lower_expr ( x) ) . unwrap_or_else ( || self . expr_unit ( span) ) ;
15001606
1501- hir:: ExprKind :: Yield ( expr, hir:: YieldSource :: Yield )
1607+ if is_async_gen {
1608+ // yield async_gen_ready($expr);
1609+ yielded = self . expr_call_lang_item_fn (
1610+ span,
1611+ hir:: LangItem :: AsyncGenReady ,
1612+ std:: slice:: from_ref ( yielded) ,
1613+ ) ;
1614+ }
1615+
1616+ hir:: ExprKind :: Yield ( yielded, hir:: YieldSource :: Yield )
15021617 }
15031618
15041619 /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
0 commit comments