@@ -183,7 +183,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
183183 self . arena . alloc_from_iter ( arms. iter ( ) . map ( |x| self . lower_arm ( x) ) ) ,
184184 hir:: MatchSource :: Normal ,
185185 ) ,
186- ExprKind :: Async ( capture_clause, block) => self . make_async_expr (
186+ ExprKind :: Gen ( capture_clause, block, GenBlockKind :: Async ) => self . make_async_expr (
187187 * capture_clause,
188188 e. id ,
189189 None ,
@@ -317,6 +317,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
317317 rest,
318318 )
319319 }
320+ ExprKind :: Gen ( capture_clause, block, GenBlockKind :: Gen ) => self . make_gen_expr (
321+ * capture_clause,
322+ e. id ,
323+ None ,
324+ e. span ,
325+ hir:: AsyncGeneratorKind :: Block ,
326+ |this| this. with_new_scopes ( |this| this. lower_block_expr ( block) ) ,
327+ ) ,
320328 ExprKind :: Yield ( opt_expr) => self . lower_expr_yield ( e. span , opt_expr. as_deref ( ) ) ,
321329 ExprKind :: Err => hir:: ExprKind :: Err (
322330 self . tcx . sess . delay_span_bug ( e. span , "lowered ExprKind::Err" ) ,
@@ -661,6 +669,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
661669 } ) )
662670 }
663671
672+ /// Lower a `gen` construct to a generator that implements `Future`.
673+ ///
674+ /// This results in:
675+ ///
676+ /// ```text
677+ /// static move? |()| -> () {
678+ /// <body>
679+ /// }
680+ /// ```
681+ pub ( super ) fn make_gen_expr (
682+ & mut self ,
683+ capture_clause : CaptureBy ,
684+ closure_node_id : NodeId ,
685+ yield_ty : Option < hir:: FnRetTy < ' hir > > ,
686+ span : Span ,
687+ // We re-use the async enum, because we have the same cases.
688+ // FIXME(oli-obk): rename the enum.
689+ gen_kind : hir:: AsyncGeneratorKind ,
690+ body : impl FnOnce ( & mut Self ) -> hir:: Expr < ' hir > ,
691+ ) -> hir:: ExprKind < ' hir > {
692+ let output = yield_ty. unwrap_or_else ( || hir:: FnRetTy :: DefaultReturn ( self . lower_span ( span) ) ) ;
693+
694+ // Resume argument type: `ResumeTy`
695+ let unstable_span =
696+ self . mark_span_with_reason ( DesugaringKind :: Async , span, self . allow_gen_future . clone ( ) ) ;
697+ let resume_ty = hir:: QPath :: LangItem ( hir:: LangItem :: ResumeTy , unstable_span, None ) ;
698+ let input_ty = hir:: Ty {
699+ hir_id : self . next_id ( ) ,
700+ kind : hir:: TyKind :: Path ( resume_ty) ,
701+ span : unstable_span,
702+ } ;
703+
704+ // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
705+ let fn_decl = self . arena . alloc ( hir:: FnDecl {
706+ inputs : arena_vec ! [ self ; input_ty] ,
707+ output,
708+ c_variadic : false ,
709+ implicit_self : hir:: ImplicitSelfKind :: None ,
710+ lifetime_elision_allowed : false ,
711+ } ) ;
712+
713+ // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
714+ let ( pat, task_context_hid) = self . pat_ident_binding_mode (
715+ span,
716+ Ident :: with_dummy_span ( sym:: _task_context) ,
717+ hir:: BindingAnnotation :: MUT ,
718+ ) ;
719+ let param = hir:: Param {
720+ hir_id : self . next_id ( ) ,
721+ pat,
722+ ty_span : self . lower_span ( span) ,
723+ span : self . lower_span ( span) ,
724+ } ;
725+ let params = arena_vec ! [ self ; param] ;
726+
727+ let body = self . lower_body ( move |this| {
728+ this. generator_kind = Some ( hir:: GeneratorKind :: Iter ( gen_kind) ) ;
729+
730+ let old_ctx = this. task_context ;
731+ this. task_context = Some ( task_context_hid) ;
732+ let res = body ( this) ;
733+ this. task_context = old_ctx;
734+ ( params, res)
735+ } ) ;
736+
737+ // `static |_task_context| -> <ret_ty> { body }`:
738+ hir:: ExprKind :: Closure ( self . arena . alloc ( hir:: Closure {
739+ def_id : self . local_def_id ( closure_node_id) ,
740+ binder : hir:: ClosureBinder :: Default ,
741+ capture_clause,
742+ bound_generic_params : & [ ] ,
743+ fn_decl,
744+ body,
745+ fn_decl_span : self . lower_span ( span) ,
746+ fn_arg_span : None ,
747+ movability : Some ( hir:: Movability :: Static ) ,
748+ constness : hir:: Constness :: NotConst ,
749+ } ) )
750+ }
751+
664752 /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
665753 /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
666754 pub ( super ) fn maybe_forward_track_caller (
0 commit comments