@@ -183,7 +183,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
183
183
self . arena . alloc_from_iter ( arms. iter ( ) . map ( |x| self . lower_arm ( x) ) ) ,
184
184
hir:: MatchSource :: Normal ,
185
185
) ,
186
- ExprKind :: Async ( capture_clause, block) => self . make_async_expr (
186
+ ExprKind :: Gen ( capture_clause, block, GenBlockKind :: Async ) => self . make_async_expr (
187
187
* capture_clause,
188
188
e. id ,
189
189
None ,
@@ -317,6 +317,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
317
317
rest,
318
318
)
319
319
}
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
+ ) ,
320
328
ExprKind :: Yield ( opt_expr) => self . lower_expr_yield ( e. span , opt_expr. as_deref ( ) ) ,
321
329
ExprKind :: Err => hir:: ExprKind :: Err (
322
330
self . tcx . sess . delay_span_bug ( e. span , "lowered ExprKind::Err" ) ,
@@ -661,6 +669,57 @@ impl<'hir> LoweringContext<'_, 'hir> {
661
669
} ) )
662
670
}
663
671
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
+
664
723
/// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
665
724
/// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
666
725
pub ( super ) fn maybe_forward_track_caller (
@@ -712,7 +771,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
712
771
let full_span = expr. span . to ( await_kw_span) ;
713
772
match self . coroutine_kind {
714
773
Some ( hir:: CoroutineKind :: Async ( _) ) => { }
715
- Some ( hir:: CoroutineKind :: Coroutine ) | None => {
774
+ Some ( hir:: CoroutineKind :: Coroutine ) | Some ( hir :: CoroutineKind :: Gen ( _ ) ) | None => {
716
775
self . tcx . sess . emit_err ( AwaitOnlyInAsyncFnAndBlocks {
717
776
await_kw_span,
718
777
item_span : self . current_item ,
@@ -936,8 +995,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
936
995
}
937
996
Some ( movability)
938
997
}
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" ) ;
941
1000
}
942
1001
None => {
943
1002
if movability == Movability :: Static {
@@ -1445,11 +1504,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
1445
1504
1446
1505
fn lower_expr_yield ( & mut self , span : Span , opt_expr : Option < & Expr > ) -> hir:: ExprKind < ' hir > {
1447
1506
match self . coroutine_kind {
1448
- Some ( hir:: CoroutineKind :: Coroutine ) => { }
1507
+ Some ( hir:: CoroutineKind :: Gen ( _ ) ) => { }
1449
1508
Some ( hir:: CoroutineKind :: Async ( _) ) => {
1450
1509
self . tcx . sess . emit_err ( AsyncCoroutinesNotSupported { span } ) ;
1451
1510
}
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
+ }
1453
1523
}
1454
1524
1455
1525
let expr =
0 commit comments