Skip to content

Commit 3401ea6

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 a153133 commit 3401ea6

File tree

13 files changed

+77
-216
lines changed

13 files changed

+77
-216
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_middle::span_bug;
1212
use rustc_middle::ty::TyCtxt;
1313
use rustc_session::errors::report_lit_error;
1414
use rustc_span::source_map::{Spanned, respan};
15-
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
15+
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
1616
use thin_vec::{ThinVec, thin_vec};
1717
use visit::{Visitor, walk_expr};
1818

@@ -718,18 +718,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
718718
// whereas a generator does not.
719719
let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
720720
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
721-
// Resume argument type: `ResumeTy`
722-
let unstable_span = self.mark_span_with_reason(
723-
DesugaringKind::Async,
724-
self.lower_span(span),
725-
Some(Arc::clone(&self.allow_gen_future)),
726-
);
727-
let resume_ty =
728-
self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);
721+
// Resume argument type: `&mut Context<'_>`.
722+
let context_lifetime_ident = Ident::with_dummy_span(kw::UnderscoreLifetime);
723+
let context_lifetime = self.arena.alloc(hir::Lifetime {
724+
hir_id: self.next_id(),
725+
ident: context_lifetime_ident,
726+
kind: hir::LifetimeKind::Infer,
727+
source: hir::LifetimeSource::Other,
728+
syntax: hir::LifetimeSyntax::Implicit,
729+
});
730+
let context_path =
731+
hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span));
732+
let context_ty = hir::MutTy {
733+
ty: self.arena.alloc(hir::Ty {
734+
hir_id: self.next_id(),
735+
kind: hir::TyKind::Path(context_path),
736+
span: self.lower_span(span),
737+
}),
738+
mutbl: hir::Mutability::Mut,
739+
};
740+
729741
let input_ty = hir::Ty {
730742
hir_id: self.next_id(),
731-
kind: hir::TyKind::Path(resume_ty),
732-
span: unstable_span,
743+
kind: hir::TyKind::Ref(context_lifetime, context_ty),
744+
span: self.lower_span(span),
733745
};
734746
let inputs = arena_vec![self; input_ty];
735747

@@ -830,7 +842,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
830842
/// mut __awaitee => loop {
831843
/// match unsafe { ::std::future::Future::poll(
832844
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
833-
/// ::std::future::get_context(task_context),
845+
/// task_context,
834846
/// ) } {
835847
/// ::std::task::Poll::Ready(result) => break result,
836848
/// ::std::task::Poll::Pending => {}
@@ -889,26 +901,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
889901
FutureKind::AsyncIterator => Some(Arc::clone(&self.allow_for_await)),
890902
};
891903
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
892-
let gen_future_span = self.mark_span_with_reason(
893-
DesugaringKind::Await,
894-
full_span,
895-
Some(Arc::clone(&self.allow_gen_future)),
896-
);
897904
let expr_hir_id = expr.hir_id;
898905

899906
// Note that the name of this binding must not be changed to something else because
900907
// debuggers and debugger extensions expect it to be called `__awaitee`. They use
901908
// this name to identify what is being awaited by a suspended async functions.
902909
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
903910
let (awaitee_pat, awaitee_pat_hid) =
904-
self.pat_ident_binding_mode(gen_future_span, awaitee_ident, hir::BindingMode::MUT);
911+
self.pat_ident_binding_mode(full_span, awaitee_ident, hir::BindingMode::MUT);
905912

906913
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
907914

908915
// unsafe {
909916
// ::std::future::Future::poll(
910917
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
911-
// ::std::future::get_context(task_context),
918+
// task_context,
912919
// )
913920
// }
914921
let poll_expr = {
@@ -926,21 +933,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
926933
hir::LangItem::PinNewUnchecked,
927934
arena_vec![self; ref_mut_awaitee],
928935
);
929-
let get_context = self.expr_call_lang_item_fn_mut(
930-
gen_future_span,
931-
hir::LangItem::GetContext,
932-
arena_vec![self; task_context],
933-
);
934936
let call = match await_kind {
935937
FutureKind::Future => self.expr_call_lang_item_fn(
936938
span,
937939
hir::LangItem::FuturePoll,
938-
arena_vec![self; new_unchecked, get_context],
940+
arena_vec![self; new_unchecked, task_context],
939941
),
940942
FutureKind::AsyncIterator => self.expr_call_lang_item_fn(
941943
span,
942944
hir::LangItem::AsyncIteratorPollNext,
943-
arena_vec![self; new_unchecked, get_context],
945+
arena_vec![self; new_unchecked, task_context],
944946
),
945947
};
946948
self.arena.alloc(self.expr_unsafe(call))
@@ -951,14 +953,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
951953
let loop_hir_id = self.lower_node_id(loop_node_id);
952954
let ready_arm = {
953955
let x_ident = Ident::with_dummy_span(sym::result);
954-
let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
955-
let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
956-
let ready_field = self.single_pat_field(gen_future_span, x_pat);
956+
let (x_pat, x_pat_hid) = self.pat_ident(full_span, x_ident);
957+
let x_expr = self.expr_ident(full_span, x_ident, x_pat_hid);
958+
let ready_field = self.single_pat_field(full_span, x_pat);
957959
let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
958960
let break_x = self.with_loop_scope(loop_hir_id, move |this| {
959961
let expr_break =
960962
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
961-
this.arena.alloc(this.expr(gen_future_span, expr_break))
963+
this.arena.alloc(this.expr(full_span, expr_break))
962964
});
963965
self.arm(ready_pat, break_x)
964966
};

compiler/rustc_hir/src/lang_items.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,6 @@ language_item_table! {
379379
AsyncGenPending, sym::AsyncGenPending, async_gen_pending, Target::AssocConst, GenericRequirement::Exact(1);
380380
AsyncGenFinished, sym::AsyncGenFinished, async_gen_finished, Target::AssocConst, GenericRequirement::Exact(1);
381381

382-
// FIXME(swatinem): the following lang items are used for async lowering and
383-
// should become obsolete eventually.
384-
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
385-
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
386-
387382
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
388383
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
389384

compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -533,108 +533,14 @@ fn replace_local<'tcx>(
533533
new_local
534534
}
535535

536-
/// Transforms the `body` of the coroutine applying the following transforms:
537-
///
538-
/// - Eliminates all the `get_context` calls that async lowering created.
539-
/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`).
540-
///
541-
/// The `Local`s that have their types replaced are:
542-
/// - The `resume` argument itself.
543-
/// - The argument to `get_context`.
544-
/// - The yielded value of a `yield`.
545-
///
546-
/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the
547-
/// `get_context` function is being used to convert that back to a `&mut Context<'_>`.
548-
///
549-
/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection,
550-
/// but rather directly use `&mut Context<'_>`, however that would currently
551-
/// lead to higher-kinded lifetime errors.
552-
/// See <https://github.com/rust-lang/rust/issues/105501>.
553-
///
554-
/// The async lowering step and the type / lifetime inference / checking are
555-
/// still using the `ResumeTy` indirection for the time being, and that indirection
556-
/// is removed here. After this transform, the coroutine body only knows about `&mut Context<'_>`.
557-
fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ty<'tcx> {
558-
let context_mut_ref = Ty::new_task_context(tcx);
559-
560-
// replace the type of the `resume` argument
561-
replace_resume_ty_local(tcx, body, CTX_ARG, context_mut_ref);
562-
563-
let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, body.span);
564-
565-
for bb in body.basic_blocks.indices() {
566-
let bb_data = &body[bb];
567-
if bb_data.is_cleanup {
568-
continue;
569-
}
570-
571-
match &bb_data.terminator().kind {
572-
TerminatorKind::Call { func, .. } => {
573-
let func_ty = func.ty(body, tcx);
574-
if let ty::FnDef(def_id, _) = *func_ty.kind()
575-
&& def_id == get_context_def_id
576-
{
577-
let local = eliminate_get_context_call(&mut body[bb]);
578-
replace_resume_ty_local(tcx, body, local, context_mut_ref);
579-
}
580-
}
581-
TerminatorKind::Yield { resume_arg, .. } => {
582-
replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref);
583-
}
584-
_ => {}
585-
}
586-
}
587-
context_mut_ref
588-
}
589-
590-
fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
591-
let terminator = bb_data.terminator.take().unwrap();
592-
let TerminatorKind::Call { args, destination, target, .. } = terminator.kind else {
593-
bug!();
594-
};
595-
let [arg] = *Box::try_from(args).unwrap();
596-
let local = arg.node.place().unwrap().local;
597-
598-
let arg = Rvalue::Use(arg.node);
599-
let assign =
600-
Statement::new(terminator.source_info, StatementKind::Assign(Box::new((destination, arg))));
601-
bb_data.statements.push(assign);
602-
bb_data.terminator = Some(Terminator {
603-
source_info: terminator.source_info,
604-
kind: TerminatorKind::Goto { target: target.unwrap() },
605-
});
606-
local
607-
}
608-
609-
#[cfg_attr(not(debug_assertions), allow(unused))]
610-
fn replace_resume_ty_local<'tcx>(
611-
tcx: TyCtxt<'tcx>,
612-
body: &mut Body<'tcx>,
613-
local: Local,
614-
context_mut_ref: Ty<'tcx>,
615-
) {
616-
let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref);
617-
// We have to replace the `ResumeTy` that is used for type and borrow checking
618-
// with `&mut Context<'_>` in MIR.
619-
#[cfg(debug_assertions)]
620-
{
621-
if let ty::Adt(resume_ty_adt, _) = local_ty.kind() {
622-
let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, body.span));
623-
assert_eq!(*resume_ty_adt, expected_adt);
624-
} else {
625-
panic!("expected `ResumeTy`, found `{:?}`", local_ty);
626-
};
627-
}
628-
}
629-
630536
/// Transforms the `body` of the coroutine applying the following transform:
631537
///
632538
/// - Remove the `resume` argument.
633539
///
634540
/// Ideally the async lowering would not add the `resume` argument.
635541
///
636542
/// The async lowering step and the type / lifetime inference / checking are
637-
/// still using the `resume` argument for the time being. After this transform,
543+
/// still using the `resume` argument for the time being. After this transform
638544
/// the coroutine body doesn't have the `resume` argument.
639545
fn transform_gen_context<'tcx>(body: &mut Body<'tcx>) {
640546
// This leaves the local representing the `resume` argument in place,
@@ -1504,7 +1410,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15041410
coroutine_kind,
15051411
CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _)
15061412
) {
1507-
let context_mut_ref = transform_async_context(tcx, body);
1413+
let context_mut_ref = Ty::new_task_context(tcx);
15081414
expand_async_drops(tcx, body, context_mut_ref, coroutine_kind, coroutine_ty);
15091415
dump_mir(tcx, false, "coroutine_async_drop_expand", &0, body, |_, _| Ok(()));
15101416
} else {

compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,10 @@ pub(super) fn build_async_drop_shim<'tcx>(
6464
let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env);
6565
let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env);
6666

67-
let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
68-
let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty());
67+
let context_mut_ref = Ty::new_task_context(tcx);
6968

7069
let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
71-
[ty, resume_ty],
70+
[ty, context_mut_ref],
7271
tcx.types.unit,
7372
false,
7473
Safety::Safe,

compiler/rustc_span/src/symbol.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,6 @@ symbols! {
336336
Relaxed,
337337
Release,
338338
Result,
339-
ResumeTy,
340339
Return,
341340
Reverse,
342341
Right,
@@ -1107,7 +1106,6 @@ symbols! {
11071106
generic_const_parameter_types,
11081107
generic_param_attrs,
11091108
generic_pattern_types,
1110-
get_context,
11111109
global_alloc_ty,
11121110
global_allocator,
11131111
global_asm,

compiler/rustc_ty_utils/src/abi.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -155,21 +155,7 @@ fn fn_sig_for_fn_abi<'tcx>(
155155
let poll_args = tcx.mk_args(&[sig.return_ty.into()]);
156156
let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_args);
157157

158-
// We have to replace the `ResumeTy` that is used for type and borrow checking
159-
// with `&mut Context<'_>` which is used in codegen.
160-
#[cfg(debug_assertions)]
161-
{
162-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
163-
let expected_adt =
164-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
165-
assert_eq!(*resume_ty_adt, expected_adt);
166-
} else {
167-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
168-
};
169-
}
170-
let context_mut_ref = Ty::new_task_context(tcx);
171-
172-
(Some(context_mut_ref), ret_ty)
158+
(Some(sig.resume_ty), ret_ty)
173159
}
174160
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
175161
// The signature should be `Iterator::next(_) -> Option<Yield>`
@@ -191,21 +177,7 @@ fn fn_sig_for_fn_abi<'tcx>(
191177
// Yield type is already `Poll<Option<yield_ty>>`
192178
let ret_ty = sig.yield_ty;
193179

194-
// We have to replace the `ResumeTy` that is used for type and borrow checking
195-
// with `&mut Context<'_>` which is used in codegen.
196-
#[cfg(debug_assertions)]
197-
{
198-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
199-
let expected_adt =
200-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
201-
assert_eq!(*resume_ty_adt, expected_adt);
202-
} else {
203-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
204-
};
205-
}
206-
let context_mut_ref = Ty::new_task_context(tcx);
207-
208-
(Some(context_mut_ref), ret_ty)
180+
(Some(sig.resume_ty), ret_ty)
209181
}
210182
hir::CoroutineKind::Coroutine(_) => {
211183
// The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`

library/core/src/future/mod.rs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
//! [`await`]: ../../std/keyword.await.html
1010
//! [async book]: https://rust-lang.github.io/async-book/
1111
12-
use crate::ptr::NonNull;
13-
use crate::task::Context;
14-
1512
mod async_drop;
1613
mod future;
1714
mod into_future;
@@ -35,34 +32,3 @@ pub use ready::{Ready, ready};
3532
pub use self::future::Future;
3633
#[unstable(feature = "future_join", issue = "91642")]
3734
pub use self::join::join;
38-
39-
/// This type is needed because:
40-
///
41-
/// a) Coroutines cannot implement `for<'a, 'b> Coroutine<&'a mut Context<'b>>`, so we need to pass
42-
/// a raw pointer (see <https://github.com/rust-lang/rust/issues/68923>).
43-
/// b) Raw pointers and `NonNull` aren't `Send` or `Sync`, so that would make every single future
44-
/// non-Send/Sync as well, and we don't want that.
45-
///
46-
/// It also simplifies the HIR lowering of `.await`.
47-
#[lang = "ResumeTy"]
48-
#[doc(hidden)]
49-
#[unstable(feature = "gen_future", issue = "none")]
50-
#[derive(Debug, Copy, Clone)]
51-
pub struct ResumeTy(NonNull<Context<'static>>);
52-
53-
#[unstable(feature = "gen_future", issue = "none")]
54-
unsafe impl Send for ResumeTy {}
55-
56-
#[unstable(feature = "gen_future", issue = "none")]
57-
unsafe impl Sync for ResumeTy {}
58-
59-
#[lang = "get_context"]
60-
#[doc(hidden)]
61-
#[unstable(feature = "gen_future", issue = "none")]
62-
#[must_use]
63-
#[inline]
64-
pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
65-
// SAFETY: the caller must guarantee that `cx.0` is a valid pointer
66-
// that fulfills all the requirements for a mutable reference.
67-
unsafe { &mut *cx.0.as_ptr().cast() }
68-
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
//@ check-pass
21
//@ edition:2018
32
#![deny(unreachable_code)]
43

54
async fn foo() {
65
endless().await;
6+
//~^ ERROR unreachable expression
77
}
88

99
async fn endless() -> ! {
1010
loop {}
1111
}
1212

13-
fn main() { }
13+
fn main() {}

0 commit comments

Comments
 (0)