@@ -183,14 +183,6 @@ 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::Gen(capture_clause, block, GenBlockKind::Async) => self.make_async_expr(
187
- *capture_clause,
188
- e.id,
189
- None,
190
- e.span,
191
- hir::CoroutineSource::Block,
192
- |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
193
- ),
194
186
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
195
187
ExprKind::Closure(box Closure {
196
188
binder,
@@ -226,6 +218,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
226
218
*fn_arg_span,
227
219
),
228
220
},
221
+ ExprKind::Gen(capture_clause, block, genblock_kind) => {
222
+ let desugaring_kind = match genblock_kind {
223
+ GenBlockKind::Async => hir::CoroutineDesugaring::Async,
224
+ GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,
225
+ GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,
226
+ };
227
+ self.make_desugared_coroutine_expr(
228
+ *capture_clause,
229
+ e.id,
230
+ None,
231
+ e.span,
232
+ desugaring_kind,
233
+ hir::CoroutineSource::Block,
234
+ |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
235
+ )
236
+ }
229
237
ExprKind::Block(blk, opt_label) => {
230
238
let opt_label = self.lower_label(*opt_label);
231
239
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
@@ -313,23 +321,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
313
321
rest,
314
322
)
315
323
}
316
- ExprKind::Gen(capture_clause, block, GenBlockKind::Gen) => self.make_gen_expr(
317
- *capture_clause,
318
- e.id,
319
- None,
320
- e.span,
321
- hir::CoroutineSource::Block,
322
- |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
323
- ),
324
- ExprKind::Gen(capture_clause, block, GenBlockKind::AsyncGen) => self
325
- .make_async_gen_expr(
326
- *capture_clause,
327
- e.id,
328
- None,
329
- e.span,
330
- hir::CoroutineSource::Block,
331
- |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
332
- ),
333
324
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
334
325
ExprKind::Err => {
335
326
hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
@@ -612,213 +603,91 @@ impl<'hir> LoweringContext<'_, 'hir> {
612
603
hir::Arm { hir_id, pat, guard, body, span }
613
604
}
614
605
615
- /// Lower an `async` construct to a coroutine that implements `Future` .
606
+ /// Lower/desugar a coroutine construct .
616
607
///
617
- /// This results in:
618
- ///
619
- /// ```text
620
- /// static move? |_task_context| -> <ret_ty> {
621
- /// <body>
622
- /// }
623
- /// ```
624
- pub(super) fn make_async_expr(
625
- &mut self,
626
- capture_clause: CaptureBy,
627
- closure_node_id: NodeId,
628
- ret_ty: Option<hir::FnRetTy<'hir>>,
629
- span: Span,
630
- async_coroutine_source: hir::CoroutineSource,
631
- body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
632
- ) -> hir::ExprKind<'hir> {
633
- let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
634
-
635
- // Resume argument type: `ResumeTy`
636
- let unstable_span = self.mark_span_with_reason(
637
- DesugaringKind::Async,
638
- self.lower_span(span),
639
- Some(self.allow_gen_future.clone()),
640
- );
641
- let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
642
- let input_ty = hir::Ty {
643
- hir_id: self.next_id(),
644
- kind: hir::TyKind::Path(resume_ty),
645
- span: unstable_span,
646
- };
647
-
648
- // The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
649
- let fn_decl = self.arena.alloc(hir::FnDecl {
650
- inputs: arena_vec![self; input_ty],
651
- output,
652
- c_variadic: false,
653
- implicit_self: hir::ImplicitSelfKind::None,
654
- lifetime_elision_allowed: false,
655
- });
656
-
657
- // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
658
- let (pat, task_context_hid) = self.pat_ident_binding_mode(
659
- span,
660
- Ident::with_dummy_span(sym::_task_context),
661
- hir::BindingAnnotation::MUT,
662
- );
663
- let param = hir::Param {
664
- hir_id: self.next_id(),
665
- pat,
666
- ty_span: self.lower_span(span),
667
- span: self.lower_span(span),
668
- };
669
- let params = arena_vec![self; param];
670
-
671
- let coroutine_kind =
672
- hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, async_coroutine_source);
673
- let body = self.lower_body(move |this| {
674
- this.coroutine_kind = Some(coroutine_kind);
675
-
676
- let old_ctx = this.task_context;
677
- this.task_context = Some(task_context_hid);
678
- let res = body(this);
679
- this.task_context = old_ctx;
680
- (params, res)
681
- });
682
-
683
- // `static |_task_context| -> <ret_ty> { body }`:
684
- hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
685
- def_id: self.local_def_id(closure_node_id),
686
- binder: hir::ClosureBinder::Default,
687
- capture_clause,
688
- bound_generic_params: &[],
689
- fn_decl,
690
- body,
691
- fn_decl_span: self.lower_span(span),
692
- fn_arg_span: None,
693
- kind: hir::ClosureKind::Coroutine(coroutine_kind),
694
- constness: hir::Constness::NotConst,
695
- }))
696
- }
697
-
698
- /// Lower a `gen` construct to a generator that implements `Iterator`.
608
+ /// In particular, this creates the correct async resume argument and `_task_context`.
699
609
///
700
610
/// This results in:
701
611
///
702
612
/// ```text
703
- /// static move? |() | -> () {
613
+ /// static move? |<_task_context?> | -> <return_ty> {
704
614
/// <body>
705
615
/// }
706
616
/// ```
707
- pub(super) fn make_gen_expr (
617
+ pub(super) fn make_desugared_coroutine_expr (
708
618
&mut self,
709
619
capture_clause: CaptureBy,
710
620
closure_node_id: NodeId,
711
- _yield_ty : Option<hir::FnRetTy<'hir>>,
621
+ return_ty : Option<hir::FnRetTy<'hir>>,
712
622
span: Span,
623
+ desugaring_kind: hir::CoroutineDesugaring,
713
624
coroutine_source: hir::CoroutineSource,
714
625
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
715
626
) -> hir::ExprKind<'hir> {
716
- let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
717
-
718
- // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
719
- let fn_decl = self.arena.alloc(hir::FnDecl {
720
- inputs: &[],
721
- output,
722
- c_variadic: false,
723
- implicit_self: hir::ImplicitSelfKind::None,
724
- lifetime_elision_allowed: false,
725
- });
726
-
727
- let coroutine_kind =
728
- hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, coroutine_source);
729
- let body = self.lower_body(move |this| {
730
- this.coroutine_kind = Some(coroutine_kind);
731
-
732
- let res = body(this);
733
- (&[], res)
734
- });
735
-
736
- // `static |()| -> () { body }`:
737
- hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
738
- def_id: self.local_def_id(closure_node_id),
739
- binder: hir::ClosureBinder::Default,
740
- capture_clause,
741
- bound_generic_params: &[],
742
- fn_decl,
743
- body,
744
- fn_decl_span: self.lower_span(span),
745
- fn_arg_span: None,
746
- kind: hir::ClosureKind::Coroutine(coroutine_kind),
747
- constness: hir::Constness::NotConst,
748
- }))
749
- }
627
+ let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
628
+
629
+ // The `async` desugaring takes a resume argument and maintains a `task_context`,
630
+ // whereas a generator does not.
631
+ let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
632
+ hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
633
+ // Resume argument type: `ResumeTy`
634
+ let unstable_span = self.mark_span_with_reason(
635
+ DesugaringKind::Async,
636
+ self.lower_span(span),
637
+ Some(self.allow_gen_future.clone()),
638
+ );
639
+ let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
640
+ let input_ty = hir::Ty {
641
+ hir_id: self.next_id(),
642
+ kind: hir::TyKind::Path(resume_ty),
643
+ span: unstable_span,
644
+ };
645
+ let inputs = arena_vec![self; input_ty];
750
646
751
- /// Lower a `async gen` construct to a generator that implements `AsyncIterator`.
752
- ///
753
- /// This results in:
754
- ///
755
- /// ```text
756
- /// static move? |_task_context| -> () {
757
- /// <body>
758
- /// }
759
- /// ```
760
- pub(super) fn make_async_gen_expr(
761
- &mut self,
762
- capture_clause: CaptureBy,
763
- closure_node_id: NodeId,
764
- _yield_ty: Option<hir::FnRetTy<'hir>>,
765
- span: Span,
766
- async_coroutine_source: hir::CoroutineSource,
767
- body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
768
- ) -> hir::ExprKind<'hir> {
769
- let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
647
+ // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
648
+ let (pat, task_context_hid) = self.pat_ident_binding_mode(
649
+ span,
650
+ Ident::with_dummy_span(sym::_task_context),
651
+ hir::BindingAnnotation::MUT,
652
+ );
653
+ let param = hir::Param {
654
+ hir_id: self.next_id(),
655
+ pat,
656
+ ty_span: self.lower_span(span),
657
+ span: self.lower_span(span),
658
+ };
659
+ let params = arena_vec![self; param];
770
660
771
- // Resume argument type: `ResumeTy`
772
- let unstable_span = self.mark_span_with_reason(
773
- DesugaringKind::Async,
774
- self.lower_span(span),
775
- Some(self.allow_gen_future.clone()),
776
- );
777
- let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
778
- let input_ty = hir::Ty {
779
- hir_id: self.next_id(),
780
- kind: hir::TyKind::Path(resume_ty),
781
- span: unstable_span,
661
+ (inputs, params, Some(task_context_hid))
662
+ }
663
+ hir::CoroutineDesugaring::Gen => (&[], &[], None),
782
664
};
783
665
784
- // The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
666
+ let output =
667
+ return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
668
+
785
669
let fn_decl = self.arena.alloc(hir::FnDecl {
786
- inputs: arena_vec![self; input_ty] ,
670
+ inputs,
787
671
output,
788
672
c_variadic: false,
789
673
implicit_self: hir::ImplicitSelfKind::None,
790
674
lifetime_elision_allowed: false,
791
675
});
792
676
793
- // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
794
- let (pat, task_context_hid) = self.pat_ident_binding_mode(
795
- span,
796
- Ident::with_dummy_span(sym::_task_context),
797
- hir::BindingAnnotation::MUT,
798
- );
799
- let param = hir::Param {
800
- hir_id: self.next_id(),
801
- pat,
802
- ty_span: self.lower_span(span),
803
- span: self.lower_span(span),
804
- };
805
- let params = arena_vec![self; param];
806
-
807
- let coroutine_kind = hir::CoroutineKind::Desugared(
808
- hir::CoroutineDesugaring::AsyncGen,
809
- async_coroutine_source,
810
- );
811
677
let body = self.lower_body(move |this| {
812
678
this.coroutine_kind = Some(coroutine_kind);
813
679
814
680
let old_ctx = this.task_context;
815
- this.task_context = Some(task_context_hid);
681
+ if task_context.is_some() {
682
+ this.task_context = task_context;
683
+ }
816
684
let res = body(this);
817
685
this.task_context = old_ctx;
686
+
818
687
(params, res)
819
688
});
820
689
821
- // `static |_task_context| -> <ret_ty > { body }`:
690
+ // `static |< _task_context?> | -> <return_ty > { < body> }`:
822
691
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
823
692
def_id: self.local_def_id(closure_node_id),
824
693
binder: hir::ClosureBinder::Default,
@@ -1203,11 +1072,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
1203
1072
None
1204
1073
};
1205
1074
1206
- let async_body = this.make_async_expr (
1075
+ let async_body = this.make_desugared_coroutine_expr (
1207
1076
capture_clause,
1208
1077
inner_closure_id,
1209
1078
async_ret_ty,
1210
1079
body.span,
1080
+ hir::CoroutineDesugaring::Async,
1211
1081
hir::CoroutineSource::Closure,
1212
1082
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
1213
1083
);
0 commit comments