@@ -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:: CoroutineSource :: 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,57 @@ impl<'hir> LoweringContext<'_, 'hir> {
661669 } ) )
662670 }
663671
672+ /// Lower a `gen` construct to a generator that implements `Iterator`.
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+ gen_kind : hir:: CoroutineSource ,
688+ body : impl FnOnce ( & mut Self ) -> hir:: Expr < ' hir > ,
689+ ) -> hir:: ExprKind < ' hir > {
690+ let output = hir:: FnRetTy :: DefaultReturn ( self . lower_span ( span) ) ;
691+
692+ // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
693+ let fn_decl = self . arena . alloc ( hir:: FnDecl {
694+ inputs : & [ ] ,
695+ output,
696+ c_variadic : false ,
697+ implicit_self : hir:: ImplicitSelfKind :: None ,
698+ lifetime_elision_allowed : false ,
699+ } ) ;
700+
701+ let body = self . lower_body ( move |this| {
702+ this. coroutine_kind = Some ( hir:: CoroutineKind :: Gen ( gen_kind) ) ;
703+
704+ let res = body ( this) ;
705+ ( & [ ] , res)
706+ } ) ;
707+
708+ // `static |()| -> () { body }`:
709+ hir:: ExprKind :: Closure ( self . arena . alloc ( hir:: Closure {
710+ def_id : self . local_def_id ( closure_node_id) ,
711+ binder : hir:: ClosureBinder :: Default ,
712+ capture_clause,
713+ bound_generic_params : & [ ] ,
714+ fn_decl,
715+ body,
716+ fn_decl_span : self . lower_span ( span) ,
717+ fn_arg_span : None ,
718+ movability : Some ( Movability :: Movable ) ,
719+ constness : hir:: Constness :: NotConst ,
720+ } ) )
721+ }
722+
664723 /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
665724 /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
666725 pub ( super ) fn maybe_forward_track_caller (
@@ -712,7 +771,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
712771 let full_span = expr. span . to ( await_kw_span) ;
713772 match self . coroutine_kind {
714773 Some ( hir:: CoroutineKind :: Async ( _) ) => { }
715- Some ( hir:: CoroutineKind :: Coroutine ) | None => {
774+ Some ( hir:: CoroutineKind :: Coroutine ) | Some ( hir :: CoroutineKind :: Gen ( _ ) ) | None => {
716775 self . tcx . sess . emit_err ( AwaitOnlyInAsyncFnAndBlocks {
717776 await_kw_span,
718777 item_span : self . current_item ,
@@ -936,8 +995,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
936995 }
937996 Some ( movability)
938997 }
939- Some ( hir:: CoroutineKind :: Async ( _) ) => {
940- panic ! ( "non-`async` closure body turned `async` during lowering" ) ;
998+ Some ( hir:: CoroutineKind :: Gen ( _ ) ) | Some ( hir :: CoroutineKind :: Async ( _) ) => {
999+ panic ! ( "non-`async`/`gen` closure body turned `async`/`gen ` during lowering" ) ;
9411000 }
9421001 None => {
9431002 if movability == Movability :: Static {
@@ -1445,11 +1504,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
14451504
14461505 fn lower_expr_yield ( & mut self , span : Span , opt_expr : Option < & Expr > ) -> hir:: ExprKind < ' hir > {
14471506 match self . coroutine_kind {
1448- Some ( hir:: CoroutineKind :: Coroutine ) => { }
1507+ Some ( hir:: CoroutineKind :: Gen ( _ ) ) => { }
14491508 Some ( hir:: CoroutineKind :: Async ( _) ) => {
14501509 self . tcx . sess . emit_err ( AsyncCoroutinesNotSupported { span } ) ;
14511510 }
1452- None => self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine ) ,
1511+ Some ( hir:: CoroutineKind :: Coroutine ) | None => {
1512+ if !self . tcx . features ( ) . coroutines {
1513+ rustc_session:: parse:: feature_err (
1514+ & self . tcx . sess . parse_sess ,
1515+ sym:: coroutines,
1516+ span,
1517+ "yield syntax is experimental" ,
1518+ )
1519+ . emit ( ) ;
1520+ }
1521+ self . coroutine_kind = Some ( hir:: CoroutineKind :: Coroutine )
1522+ }
14531523 }
14541524
14551525 let expr =
0 commit comments