@@ -325,6 +325,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
325
325
hir:: CoroutineSource :: Block ,
326
326
|this| this. with_new_scopes ( e. span , |this| this. lower_block_expr ( block) ) ,
327
327
) ,
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
+ ) ,
328
337
ExprKind :: Yield ( opt_expr) => self . lower_expr_yield ( e. span , opt_expr. as_deref ( ) ) ,
329
338
ExprKind :: Err => hir:: ExprKind :: Err (
330
339
self . tcx . sess . delay_span_bug ( e. span , "lowered ExprKind::Err" ) ,
@@ -726,6 +735,84 @@ impl<'hir> LoweringContext<'_, 'hir> {
726
735
} ) )
727
736
}
728
737
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
+
729
816
/// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
730
817
/// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
731
818
pub ( super ) fn maybe_forward_track_caller (
@@ -775,15 +862,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
775
862
/// ```
776
863
fn lower_expr_await ( & mut self , await_kw_span : Span , expr : & Expr ) -> hir:: ExprKind < ' hir > {
777
864
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 ,
780
869
Some ( hir:: CoroutineKind :: Coroutine ) | Some ( hir:: CoroutineKind :: Gen ( _) ) | None => {
781
870
return hir:: ExprKind :: Err ( self . tcx . sess . emit_err ( AwaitOnlyInAsyncFnAndBlocks {
782
871
await_kw_span,
783
872
item_span : self . current_item ,
784
873
} ) ) ;
785
874
}
786
- }
875
+ } ;
876
+
787
877
let span = self . mark_span_with_reason ( DesugaringKind :: Await , await_kw_span, None ) ;
788
878
let gen_future_span = self . mark_span_with_reason (
789
879
DesugaringKind :: Await ,
@@ -872,12 +962,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
872
962
self . stmt_expr ( span, match_expr)
873
963
} ;
874
964
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();
876
968
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
+
878
975
let yield_expr = self . expr (
879
976
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) } ) ,
881
978
) ;
882
979
let yield_expr = self . arena . alloc ( yield_expr) ;
883
980
@@ -987,7 +1084,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
987
1084
}
988
1085
Some ( movability)
989
1086
}
990
- Some ( hir:: CoroutineKind :: Gen ( _) ) | Some ( hir:: CoroutineKind :: Async ( _) ) => {
1087
+ Some (
1088
+ hir:: CoroutineKind :: Gen ( _)
1089
+ | hir:: CoroutineKind :: Async ( _)
1090
+ | hir:: CoroutineKind :: AsyncGen ( _) ,
1091
+ ) => {
991
1092
panic ! ( "non-`async`/`gen` closure body turned `async`/`gen` during lowering" ) ;
992
1093
}
993
1094
None => {
@@ -1494,8 +1595,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
1494
1595
}
1495
1596
1496
1597
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 ,
1499
1601
Some ( hir:: CoroutineKind :: Async ( _) ) => {
1500
1602
return hir:: ExprKind :: Err (
1501
1603
self . tcx . sess . emit_err ( AsyncCoroutinesNotSupported { span } ) ,
@@ -1511,14 +1613,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
1511
1613
)
1512
1614
. emit ( ) ;
1513
1615
}
1514
- self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine )
1616
+ self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine ) ;
1617
+ false
1515
1618
}
1516
- }
1619
+ } ;
1517
1620
1518
- let expr =
1621
+ let mut yielded =
1519
1622
opt_expr. as_ref ( ) . map ( |x| self . lower_expr ( x) ) . unwrap_or_else ( || self . expr_unit ( span) ) ;
1520
1623
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 )
1522
1634
}
1523
1635
1524
1636
/// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
0 commit comments