Skip to content

Commit aa9f535

Browse files
committed
WIP: Remove ResumeTy from async lowering
Instead of using the stdlib supported `ResumeTy`, which is being converting to a `&mut Context<'_>` during the Generator MIR pass, this will use `&mut Context<'_>` directly in HIR lowering. It pretty much reverts rust-lang#105977 and re-applies an updated version of rust-lang#105250. This still fails the testcase added in rust-lang#106264 however, for reasons I don’t understand.
1 parent df5d535 commit aa9f535

File tree

11 files changed

+92
-209
lines changed

11 files changed

+92
-209
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+48-41
Original file line numberDiff line numberDiff line change
@@ -632,17 +632,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
632632
) -> hir::ExprKind<'hir> {
633633
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
634634

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);
635+
// Resume argument type: `&mut Context<'_>`.
636+
let context_lifetime_ident = Ident::with_dummy_span(kw::UnderscoreLifetime);
637+
let context_lifetime = self.arena.alloc(hir::Lifetime {
638+
hir_id: self.next_id(),
639+
ident: context_lifetime_ident,
640+
res: hir::LifetimeName::Infer,
641+
});
642+
let context_path = hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span));
643+
let context_ty = hir::MutTy {
644+
ty: self.arena.alloc(hir::Ty {
645+
hir_id: self.next_id(),
646+
kind: hir::TyKind::Path(context_path),
647+
span: self.lower_span(span),
648+
}),
649+
mutbl: hir::Mutability::Mut,
650+
};
651+
642652
let input_ty = hir::Ty {
643653
hir_id: self.next_id(),
644-
kind: hir::TyKind::Path(resume_ty),
645-
span: unstable_span,
654+
kind: hir::TyKind::Ref(context_lifetime, context_ty),
655+
span: self.lower_span(span),
646656
};
647657

648658
// The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
@@ -768,17 +778,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
768778
) -> hir::ExprKind<'hir> {
769779
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
770780

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);
781+
// Resume argument type: `&mut Context<'_>`.
782+
let context_lifetime_ident = Ident::with_dummy_span(kw::UnderscoreLifetime);
783+
let context_lifetime = self.arena.alloc(hir::Lifetime {
784+
hir_id: self.next_id(),
785+
ident: context_lifetime_ident,
786+
res: hir::LifetimeName::Infer,
787+
});
788+
let context_path = hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span));
789+
let context_ty = hir::MutTy {
790+
ty: self.arena.alloc(hir::Ty {
791+
hir_id: self.next_id(),
792+
kind: hir::TyKind::Path(context_path),
793+
span: self.lower_span(span),
794+
}),
795+
mutbl: hir::Mutability::Mut,
796+
};
797+
778798
let input_ty = hir::Ty {
779799
hir_id: self.next_id(),
780-
kind: hir::TyKind::Path(resume_ty),
781-
span: unstable_span,
800+
kind: hir::TyKind::Ref(context_lifetime, context_ty),
801+
span: self.lower_span(span),
782802
};
783803

784804
// The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
@@ -871,7 +891,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
871891
/// mut __awaitee => loop {
872892
/// match unsafe { ::std::future::Future::poll(
873893
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
874-
/// ::std::future::get_context(task_context),
894+
/// task_context,
875895
/// ) } {
876896
/// ::std::task::Poll::Ready(result) => break result,
877897
/// ::std::task::Poll::Pending => {}
@@ -912,29 +932,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
912932
FutureKind::AsyncIterator => Some(self.allow_for_await.clone()),
913933
};
914934
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
915-
let gen_future_span = self.mark_span_with_reason(
916-
DesugaringKind::Await,
917-
full_span,
918-
Some(self.allow_gen_future.clone()),
919-
);
920935
let expr_hir_id = expr.hir_id;
921936

922937
// Note that the name of this binding must not be changed to something else because
923938
// debuggers and debugger extensions expect it to be called `__awaitee`. They use
924939
// this name to identify what is being awaited by a suspended async functions.
925940
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
926-
let (awaitee_pat, awaitee_pat_hid) = self.pat_ident_binding_mode(
927-
gen_future_span,
928-
awaitee_ident,
929-
hir::BindingAnnotation::MUT,
930-
);
941+
let (awaitee_pat, awaitee_pat_hid) =
942+
self.pat_ident_binding_mode(full_span, awaitee_ident, hir::BindingAnnotation::MUT);
931943

932944
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
933945

934946
// unsafe {
935947
// ::std::future::Future::poll(
936948
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
937-
// ::std::future::get_context(task_context),
949+
// task_context,
938950
// )
939951
// }
940952
let poll_expr = {
@@ -952,21 +964,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
952964
hir::LangItem::PinNewUnchecked,
953965
arena_vec![self; ref_mut_awaitee],
954966
);
955-
let get_context = self.expr_call_lang_item_fn_mut(
956-
gen_future_span,
957-
hir::LangItem::GetContext,
958-
arena_vec![self; task_context],
959-
);
960967
let call = match await_kind {
961968
FutureKind::Future => self.expr_call_lang_item_fn(
962969
span,
963970
hir::LangItem::FuturePoll,
964-
arena_vec![self; new_unchecked, get_context],
971+
arena_vec![self; new_unchecked, task_context],
965972
),
966973
FutureKind::AsyncIterator => self.expr_call_lang_item_fn(
967974
span,
968975
hir::LangItem::AsyncIteratorPollNext,
969-
arena_vec![self; new_unchecked, get_context],
976+
arena_vec![self; new_unchecked, task_context],
970977
),
971978
};
972979
self.arena.alloc(self.expr_unsafe(call))
@@ -977,14 +984,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
977984
let loop_hir_id = self.lower_node_id(loop_node_id);
978985
let ready_arm = {
979986
let x_ident = Ident::with_dummy_span(sym::result);
980-
let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
981-
let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
982-
let ready_field = self.single_pat_field(gen_future_span, x_pat);
987+
let (x_pat, x_pat_hid) = self.pat_ident(full_span, x_ident);
988+
let x_expr = self.expr_ident(full_span, x_ident, x_pat_hid);
989+
let ready_field = self.single_pat_field(full_span, x_pat);
983990
let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
984991
let break_x = self.with_loop_scope(loop_node_id, move |this| {
985992
let expr_break =
986993
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
987-
this.arena.alloc(this.expr(gen_future_span, expr_break))
994+
this.arena.alloc(this.expr(full_span, expr_break))
988995
});
989996
self.arm(ready_pat, break_x)
990997
};

compiler/rustc_hir/src/lang_items.rs

-5
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,6 @@ language_item_table! {
299299
AsyncGenPending, sym::AsyncGenPending, async_gen_pending, Target::AssocConst, GenericRequirement::Exact(1);
300300
AsyncGenFinished, sym::AsyncGenFinished, async_gen_finished, Target::AssocConst, GenericRequirement::Exact(1);
301301

302-
// FIXME(swatinem): the following lang items are used for async lowering and
303-
// should become obsolete eventually.
304-
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
305-
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
306-
307302
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
308303
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
309304

compiler/rustc_mir_transform/src/coroutine.rs

+3-118
Original file line numberDiff line numberDiff line change
@@ -616,112 +616,14 @@ fn replace_local<'tcx>(
616616
new_local
617617
}
618618

619-
/// Transforms the `body` of the coroutine applying the following transforms:
620-
///
621-
/// - Eliminates all the `get_context` calls that async lowering created.
622-
/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`).
623-
///
624-
/// The `Local`s that have their types replaced are:
625-
/// - The `resume` argument itself.
626-
/// - The argument to `get_context`.
627-
/// - The yielded value of a `yield`.
628-
///
629-
/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the
630-
/// `get_context` function is being used to convert that back to a `&mut Context<'_>`.
631-
///
632-
/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection,
633-
/// but rather directly use `&mut Context<'_>`, however that would currently
634-
/// lead to higher-kinded lifetime errors.
635-
/// See <https://github.com/rust-lang/rust/issues/105501>.
636-
///
637-
/// The async lowering step and the type / lifetime inference / checking are
638-
/// still using the `ResumeTy` indirection for the time being, and that indirection
639-
/// is removed here. After this transform, the coroutine body only knows about `&mut Context<'_>`.
640-
fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
641-
let context_mut_ref = Ty::new_task_context(tcx);
642-
643-
// replace the type of the `resume` argument
644-
replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref);
645-
646-
let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
647-
648-
for bb in START_BLOCK..body.basic_blocks.next_index() {
649-
let bb_data = &body[bb];
650-
if bb_data.is_cleanup {
651-
continue;
652-
}
653-
654-
match &bb_data.terminator().kind {
655-
TerminatorKind::Call { func, .. } => {
656-
let func_ty = func.ty(body, tcx);
657-
if let ty::FnDef(def_id, _) = *func_ty.kind() {
658-
if def_id == get_context_def_id {
659-
let local = eliminate_get_context_call(&mut body[bb]);
660-
replace_resume_ty_local(tcx, body, local, context_mut_ref);
661-
}
662-
} else {
663-
continue;
664-
}
665-
}
666-
TerminatorKind::Yield { resume_arg, .. } => {
667-
replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref);
668-
}
669-
_ => {}
670-
}
671-
}
672-
}
673-
674-
fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
675-
let terminator = bb_data.terminator.take().unwrap();
676-
if let TerminatorKind::Call { mut args, destination, target, .. } = terminator.kind {
677-
let arg = args.pop().unwrap();
678-
let local = arg.place().unwrap().local;
679-
680-
let arg = Rvalue::Use(arg);
681-
let assign = Statement {
682-
source_info: terminator.source_info,
683-
kind: StatementKind::Assign(Box::new((destination, arg))),
684-
};
685-
bb_data.statements.push(assign);
686-
bb_data.terminator = Some(Terminator {
687-
source_info: terminator.source_info,
688-
kind: TerminatorKind::Goto { target: target.unwrap() },
689-
});
690-
local
691-
} else {
692-
bug!();
693-
}
694-
}
695-
696-
#[cfg_attr(not(debug_assertions), allow(unused))]
697-
fn replace_resume_ty_local<'tcx>(
698-
tcx: TyCtxt<'tcx>,
699-
body: &mut Body<'tcx>,
700-
local: Local,
701-
context_mut_ref: Ty<'tcx>,
702-
) {
703-
let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref);
704-
// We have to replace the `ResumeTy` that is used for type and borrow checking
705-
// with `&mut Context<'_>` in MIR.
706-
#[cfg(debug_assertions)]
707-
{
708-
if let ty::Adt(resume_ty_adt, _) = local_ty.kind() {
709-
let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
710-
assert_eq!(*resume_ty_adt, expected_adt);
711-
} else {
712-
panic!("expected `ResumeTy`, found `{:?}`", local_ty);
713-
};
714-
}
715-
}
716-
717619
/// Transforms the `body` of the coroutine applying the following transform:
718620
///
719621
/// - Remove the `resume` argument.
720622
///
721623
/// Ideally the async lowering would not add the `resume` argument.
722624
///
723625
/// The async lowering step and the type / lifetime inference / checking are
724-
/// still using the `resume` argument for the time being. After this transform,
626+
/// still using the `resume` argument for the time being. After this transform
725627
/// the coroutine body doesn't have the `resume` argument.
726628
fn transform_gen_context<'tcx>(_tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
727629
// This leaves the local representing the `resume` argument in place,
@@ -1613,14 +1515,6 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
16131515
}
16141516
};
16151517

1616-
let is_async_kind = matches!(
1617-
body.coroutine_kind(),
1618-
Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _))
1619-
);
1620-
let is_async_gen_kind = matches!(
1621-
body.coroutine_kind(),
1622-
Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _))
1623-
);
16241518
let is_gen_kind = matches!(
16251519
body.coroutine_kind(),
16261520
Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _))
@@ -1657,22 +1551,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
16571551
// RETURN_PLACE then is a fresh unused local with type ret_ty.
16581552
let old_ret_local = replace_local(RETURN_PLACE, new_ret_ty, body, tcx);
16591553

1660-
// Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
1661-
if is_async_kind || is_async_gen_kind {
1662-
transform_async_context(tcx, body);
1663-
}
1664-
16651554
// We also replace the resume argument and insert an `Assign`.
16661555
// This is needed because the resume argument `_2` might be live across a `yield`, in which
16671556
// case there is no `Assign` to it that the transform can turn into a store to the coroutine
16681557
// state. After the yield the slot in the coroutine state would then be uninitialized.
16691558
let resume_local = Local::new(2);
1670-
let resume_ty = if is_async_kind {
1671-
Ty::new_task_context(tcx)
1672-
} else {
1673-
body.local_decls[resume_local].ty
1674-
};
1675-
let old_resume_local = replace_local(resume_local, resume_ty, body, tcx);
1559+
let old_resume_local =
1560+
replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
16761561

16771562
// When first entering the coroutine, move the resume argument into its old local
16781563
// (which is now a generator interior).

compiler/rustc_span/src/symbol.rs

-2
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,6 @@ symbols! {
291291
Relaxed,
292292
Release,
293293
Result,
294-
ResumeTy,
295294
Return,
296295
Right,
297296
Rust,
@@ -833,7 +832,6 @@ symbols! {
833832
generic_const_exprs,
834833
generic_const_items,
835834
generic_param_attrs,
836-
get_context,
837835
global_allocator,
838836
global_asm,
839837
globs,

compiler/rustc_ty_utils/src/abi.rs

+2-30
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,7 @@ fn fn_sig_for_fn_abi<'tcx>(
140140
let poll_args = tcx.mk_args(&[sig.return_ty.into()]);
141141
let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_args);
142142

143-
// We have to replace the `ResumeTy` that is used for type and borrow checking
144-
// with `&mut Context<'_>` which is used in codegen.
145-
#[cfg(debug_assertions)]
146-
{
147-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
148-
let expected_adt =
149-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
150-
assert_eq!(*resume_ty_adt, expected_adt);
151-
} else {
152-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
153-
};
154-
}
155-
let context_mut_ref = Ty::new_task_context(tcx);
156-
157-
(Some(context_mut_ref), ret_ty)
143+
(Some(sig.resume_ty), ret_ty)
158144
}
159145
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
160146
// The signature should be `Iterator::next(_) -> Option<Yield>`
@@ -176,21 +162,7 @@ fn fn_sig_for_fn_abi<'tcx>(
176162
// Yield type is already `Poll<Option<yield_ty>>`
177163
let ret_ty = sig.yield_ty;
178164

179-
// We have to replace the `ResumeTy` that is used for type and borrow checking
180-
// with `&mut Context<'_>` which is used in codegen.
181-
#[cfg(debug_assertions)]
182-
{
183-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
184-
let expected_adt =
185-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
186-
assert_eq!(*resume_ty_adt, expected_adt);
187-
} else {
188-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
189-
};
190-
}
191-
let context_mut_ref = Ty::new_task_context(tcx);
192-
193-
(Some(context_mut_ref), ret_ty)
165+
(Some(sig.resume_ty), ret_ty)
194166
}
195167
hir::CoroutineKind::Coroutine(_) => {
196168
// The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`

0 commit comments

Comments
 (0)