Skip to content

Commit 65ddf90

Browse files
authored
Unrolled build for rust-lang#119375
Rollup merge of rust-lang#119375 - Swatinem:merge-coroutine-lowering, r=compiler-errors Merge Coroutine lowering functions Instead of having separate `make_async/etc_expr` functions, this merges them them into one, reducing code duplication a bit.
2 parents 95613d1 + 2480a0f commit 65ddf90

File tree

2 files changed

+81
-224
lines changed

2 files changed

+81
-224
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+68-198
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,6 @@ 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::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-
),
194186
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
195187
ExprKind::Closure(box Closure {
196188
binder,
@@ -226,6 +218,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
226218
*fn_arg_span,
227219
),
228220
},
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+
}
229237
ExprKind::Block(blk, opt_label) => {
230238
let opt_label = self.lower_label(*opt_label);
231239
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
@@ -313,23 +321,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
313321
rest,
314322
)
315323
}
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-
),
333324
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
334325
ExprKind::Err => {
335326
hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
@@ -612,213 +603,91 @@ impl<'hir> LoweringContext<'_, 'hir> {
612603
hir::Arm { hir_id, pat, guard, body, span }
613604
}
614605

615-
/// Lower an `async` construct to a coroutine that implements `Future`.
606+
/// Lower/desugar a coroutine construct.
616607
///
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`.
699609
///
700610
/// This results in:
701611
///
702612
/// ```text
703-
/// static move? |()| -> () {
613+
/// static move? |<_task_context?>| -> <return_ty> {
704614
/// <body>
705615
/// }
706616
/// ```
707-
pub(super) fn make_gen_expr(
617+
pub(super) fn make_desugared_coroutine_expr(
708618
&mut self,
709619
capture_clause: CaptureBy,
710620
closure_node_id: NodeId,
711-
_yield_ty: Option<hir::FnRetTy<'hir>>,
621+
return_ty: Option<hir::FnRetTy<'hir>>,
712622
span: Span,
623+
desugaring_kind: hir::CoroutineDesugaring,
713624
coroutine_source: hir::CoroutineSource,
714625
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
715626
) -> 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];
750646

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];
770660

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),
782664
};
783665

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+
785669
let fn_decl = self.arena.alloc(hir::FnDecl {
786-
inputs: arena_vec![self; input_ty],
670+
inputs,
787671
output,
788672
c_variadic: false,
789673
implicit_self: hir::ImplicitSelfKind::None,
790674
lifetime_elision_allowed: false,
791675
});
792676

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-
);
811677
let body = self.lower_body(move |this| {
812678
this.coroutine_kind = Some(coroutine_kind);
813679

814680
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+
}
816684
let res = body(this);
817685
this.task_context = old_ctx;
686+
818687
(params, res)
819688
});
820689

821-
// `static |_task_context| -> <ret_ty> { body }`:
690+
// `static |<_task_context?>| -> <return_ty> { <body> }`:
822691
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
823692
def_id: self.local_def_id(closure_node_id),
824693
binder: hir::ClosureBinder::Default,
@@ -1203,11 +1072,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
12031072
None
12041073
};
12051074

1206-
let async_body = this.make_async_expr(
1075+
let async_body = this.make_desugared_coroutine_expr(
12071076
capture_clause,
12081077
inner_closure_id,
12091078
async_ret_ty,
12101079
body.span,
1080+
hir::CoroutineDesugaring::Async,
12111081
hir::CoroutineSource::Closure,
12121082
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
12131083
);

compiler/rustc_ast_lowering/src/item.rs

+13-26
Original file line numberDiff line numberDiff line change
@@ -1209,33 +1209,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
12091209

12101210
this.expr_block(body)
12111211
};
1212-
// FIXME(gen_blocks): Consider unifying the `make_*_expr` functions.
1213-
let coroutine_expr = match coroutine_kind {
1214-
CoroutineKind::Async { .. } => this.make_async_expr(
1215-
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
1216-
closure_id,
1217-
None,
1218-
body.span,
1219-
hir::CoroutineSource::Fn,
1220-
mkbody,
1221-
),
1222-
CoroutineKind::Gen { .. } => this.make_gen_expr(
1223-
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
1224-
closure_id,
1225-
None,
1226-
body.span,
1227-
hir::CoroutineSource::Fn,
1228-
mkbody,
1229-
),
1230-
CoroutineKind::AsyncGen { .. } => this.make_async_gen_expr(
1231-
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
1232-
closure_id,
1233-
None,
1234-
body.span,
1235-
hir::CoroutineSource::Fn,
1236-
mkbody,
1237-
),
1212+
let desugaring_kind = match coroutine_kind {
1213+
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
1214+
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
1215+
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
12381216
};
1217+
let coroutine_expr = this.make_desugared_coroutine_expr(
1218+
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
1219+
closure_id,
1220+
None,
1221+
body.span,
1222+
desugaring_kind,
1223+
hir::CoroutineSource::Fn,
1224+
mkbody,
1225+
);
12391226

12401227
let hir_id = this.lower_node_id(closure_id);
12411228
this.maybe_forward_track_caller(body.span, fn_id, hir_id);

0 commit comments

Comments
 (0)