Skip to content

Commit e92f4f1

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 #105977 and re-applies an updated version of #105250. This still fails the testcase added in #106264 however, for reasons I don’t understand.
1 parent c7224e3 commit e92f4f1

File tree

6 files changed

+38
-167
lines changed

6 files changed

+38
-167
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+28-25
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_hir::def::Res;
1616
use rustc_hir::definitions::DefPathData;
1717
use rustc_session::errors::report_lit_error;
1818
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
19-
use rustc_span::symbol::{sym, Ident, Symbol};
19+
use rustc_span::symbol::{kw, sym, Ident, Symbol};
2020
use rustc_span::DUMMY_SP;
2121
use thin_vec::{thin_vec, ThinVec};
2222

@@ -603,14 +603,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
603603
) -> hir::ExprKind<'hir> {
604604
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
605605

606-
// Resume argument type: `ResumeTy`
607-
let unstable_span =
608-
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
609-
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span, None);
606+
// Resume argument type: `&mut Context<'_>`.
607+
let context_lifetime_ident = Ident::with_dummy_span(kw::UnderscoreLifetime);
608+
let context_lifetime = self.arena.alloc(hir::Lifetime {
609+
hir_id: self.next_id(),
610+
ident: context_lifetime_ident,
611+
res: hir::LifetimeName::Infer,
612+
});
613+
let context_path =
614+
hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span), None);
615+
let context_ty = hir::MutTy {
616+
ty: self.arena.alloc(hir::Ty {
617+
hir_id: self.next_id(),
618+
kind: hir::TyKind::Path(context_path),
619+
span: self.lower_span(span),
620+
}),
621+
mutbl: hir::Mutability::Mut,
622+
};
623+
610624
let input_ty = hir::Ty {
611625
hir_id: self.next_id(),
612-
kind: hir::TyKind::Path(resume_ty),
613-
span: unstable_span,
626+
kind: hir::TyKind::Ref(context_lifetime, context_ty),
627+
span: self.lower_span(span),
614628
};
615629

616630
// The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
@@ -693,7 +707,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
693707
/// mut __awaitee => loop {
694708
/// match unsafe { ::std::future::Future::poll(
695709
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
696-
/// ::std::future::get_context(task_context),
710+
/// task_context,
697711
/// ) } {
698712
/// ::std::task::Poll::Ready(result) => break result,
699713
/// ::std::task::Poll::Pending => {}
@@ -714,11 +728,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
714728
}
715729
}
716730
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
717-
let gen_future_span = self.mark_span_with_reason(
718-
DesugaringKind::Await,
719-
full_span,
720-
self.allow_gen_future.clone(),
721-
);
722731
let expr = self.lower_expr_mut(expr);
723732
let expr_hir_id = expr.hir_id;
724733

@@ -734,7 +743,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
734743
// unsafe {
735744
// ::std::future::Future::poll(
736745
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
737-
// ::std::future::get_context(task_context),
746+
// task_context,
738747
// )
739748
// }
740749
let poll_expr = {
@@ -752,16 +761,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
752761
arena_vec![self; ref_mut_awaitee],
753762
Some(expr_hir_id),
754763
);
755-
let get_context = self.expr_call_lang_item_fn_mut(
756-
gen_future_span,
757-
hir::LangItem::GetContext,
758-
arena_vec![self; task_context],
759-
Some(expr_hir_id),
760-
);
761764
let call = self.expr_call_lang_item_fn(
762765
span,
763766
hir::LangItem::FuturePoll,
764-
arena_vec![self; new_unchecked, get_context],
767+
arena_vec![self; new_unchecked, task_context],
765768
Some(expr_hir_id),
766769
);
767770
self.arena.alloc(self.expr_unsafe(call))
@@ -772,9 +775,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
772775
let loop_hir_id = self.lower_node_id(loop_node_id);
773776
let ready_arm = {
774777
let x_ident = Ident::with_dummy_span(sym::result);
775-
let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
776-
let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
777-
let ready_field = self.single_pat_field(gen_future_span, x_pat);
778+
let (x_pat, x_pat_hid) = self.pat_ident(full_span, x_ident);
779+
let x_expr = self.expr_ident(full_span, x_ident, x_pat_hid);
780+
let ready_field = self.single_pat_field(full_span, x_pat);
778781
let ready_pat = self.pat_lang_item_variant(
779782
span,
780783
hir::LangItem::PollReady,
@@ -784,7 +787,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
784787
let break_x = self.with_loop_scope(loop_node_id, move |this| {
785788
let expr_break =
786789
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
787-
this.arena.alloc(this.expr(gen_future_span, expr_break))
790+
this.arena.alloc(this.expr(full_span, expr_break))
788791
});
789792
self.arm(ready_pat, break_x)
790793
};

compiler/rustc_hir/src/lang_items.rs

-5
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,6 @@ language_item_table! {
294294
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
295295
PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;
296296

297-
// FIXME(swatinem): the following lang items are used for async lowering and
298-
// should become obsolete eventually.
299-
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
300-
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
301-
302297
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
303298
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
304299

compiler/rustc_mir_transform/src/generator.rs

+2-109
Original file line numberDiff line numberDiff line change
@@ -465,104 +465,6 @@ fn replace_local<'tcx>(
465465
new_local
466466
}
467467

468-
/// Transforms the `body` of the generator applying the following transforms:
469-
///
470-
/// - Eliminates all the `get_context` calls that async lowering created.
471-
/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`).
472-
///
473-
/// The `Local`s that have their types replaced are:
474-
/// - The `resume` argument itself.
475-
/// - The argument to `get_context`.
476-
/// - The yielded value of a `yield`.
477-
///
478-
/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the
479-
/// `get_context` function is being used to convert that back to a `&mut Context<'_>`.
480-
///
481-
/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection,
482-
/// but rather directly use `&mut Context<'_>`, however that would currently
483-
/// lead to higher-kinded lifetime errors.
484-
/// See <https://github.com/rust-lang/rust/issues/105501>.
485-
///
486-
/// The async lowering step and the type / lifetime inference / checking are
487-
/// still using the `ResumeTy` indirection for the time being, and that indirection
488-
/// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`.
489-
fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
490-
let context_mut_ref = Ty::new_task_context(tcx);
491-
492-
// replace the type of the `resume` argument
493-
replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref);
494-
495-
let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
496-
497-
for bb in START_BLOCK..body.basic_blocks.next_index() {
498-
let bb_data = &body[bb];
499-
if bb_data.is_cleanup {
500-
continue;
501-
}
502-
503-
match &bb_data.terminator().kind {
504-
TerminatorKind::Call { func, .. } => {
505-
let func_ty = func.ty(body, tcx);
506-
if let ty::FnDef(def_id, _) = *func_ty.kind() {
507-
if def_id == get_context_def_id {
508-
let local = eliminate_get_context_call(&mut body[bb]);
509-
replace_resume_ty_local(tcx, body, local, context_mut_ref);
510-
}
511-
} else {
512-
continue;
513-
}
514-
}
515-
TerminatorKind::Yield { resume_arg, .. } => {
516-
replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref);
517-
}
518-
_ => {}
519-
}
520-
}
521-
}
522-
523-
fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
524-
let terminator = bb_data.terminator.take().unwrap();
525-
if let TerminatorKind::Call { mut args, destination, target, .. } = terminator.kind {
526-
let arg = args.pop().unwrap();
527-
let local = arg.place().unwrap().local;
528-
529-
let arg = Rvalue::Use(arg);
530-
let assign = Statement {
531-
source_info: terminator.source_info,
532-
kind: StatementKind::Assign(Box::new((destination, arg))),
533-
};
534-
bb_data.statements.push(assign);
535-
bb_data.terminator = Some(Terminator {
536-
source_info: terminator.source_info,
537-
kind: TerminatorKind::Goto { target: target.unwrap() },
538-
});
539-
local
540-
} else {
541-
bug!();
542-
}
543-
}
544-
545-
#[cfg_attr(not(debug_assertions), allow(unused))]
546-
fn replace_resume_ty_local<'tcx>(
547-
tcx: TyCtxt<'tcx>,
548-
body: &mut Body<'tcx>,
549-
local: Local,
550-
context_mut_ref: Ty<'tcx>,
551-
) {
552-
let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref);
553-
// We have to replace the `ResumeTy` that is used for type and borrow checking
554-
// with `&mut Context<'_>` in MIR.
555-
#[cfg(debug_assertions)]
556-
{
557-
if let ty::Adt(resume_ty_adt, _) = local_ty.kind() {
558-
let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
559-
assert_eq!(*resume_ty_adt, expected_adt);
560-
} else {
561-
panic!("expected `ResumeTy`, found `{:?}`", local_ty);
562-
};
563-
}
564-
}
565-
566468
struct LivenessInfo {
567469
/// Which locals are live across any suspension point.
568470
saved_locals: GeneratorSavedLocals,
@@ -1458,22 +1360,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
14581360
// RETURN_PLACE then is a fresh unused local with type ret_ty.
14591361
let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx);
14601362

1461-
// Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
1462-
if is_async_kind {
1463-
transform_async_context(tcx, body);
1464-
}
1465-
14661363
// We also replace the resume argument and insert an `Assign`.
14671364
// This is needed because the resume argument `_2` might be live across a `yield`, in which
14681365
// case there is no `Assign` to it that the transform can turn into a store to the generator
14691366
// state. After the yield the slot in the generator state would then be uninitialized.
14701367
let resume_local = Local::new(2);
1471-
let resume_ty = if is_async_kind {
1472-
Ty::new_task_context(tcx)
1473-
} else {
1474-
body.local_decls[resume_local].ty
1475-
};
1476-
let new_resume_local = replace_local(resume_local, resume_ty, body, tcx);
1368+
let new_resume_local =
1369+
replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
14771370

14781371
// When first entering the generator, move the resume argument into its new local.
14791372
let source_info = SourceInfo::outermost(body.span);

compiler/rustc_span/src/symbol.rs

-2
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,6 @@ symbols! {
271271
Relaxed,
272272
Release,
273273
Result,
274-
ResumeTy,
275274
Return,
276275
Right,
277276
Rust,
@@ -801,7 +800,6 @@ symbols! {
801800
generic_const_exprs,
802801
generic_const_items,
803802
generic_param_attrs,
804-
get_context,
805803
global_allocator,
806804
global_asm,
807805
globs,

compiler/rustc_ty_utils/src/abi.rs

+6-24
Original file line numberDiff line numberDiff line change
@@ -120,41 +120,23 @@ fn fn_sig_for_fn_abi<'tcx>(
120120
// `Generator::resume(...) -> GeneratorState` function in case we
121121
// have an ordinary generator, or the `Future::poll(...) -> Poll`
122122
// function in case this is a special generator backing an async construct.
123-
let (resume_ty, ret_ty) = if tcx.generator_is_async(did) {
124-
// The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>`
123+
let ret_ty = if tcx.generator_is_async(did) {
124+
// The signature should be `Future::poll(..) -> Poll<Output>`
125125
let poll_did = tcx.require_lang_item(LangItem::Poll, None);
126126
let poll_adt_ref = tcx.adt_def(poll_did);
127127
let poll_args = tcx.mk_args(&[sig.return_ty.into()]);
128-
let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_args);
129-
130-
// We have to replace the `ResumeTy` that is used for type and borrow checking
131-
// with `&mut Context<'_>` which is used in codegen.
132-
#[cfg(debug_assertions)]
133-
{
134-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
135-
let expected_adt =
136-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
137-
assert_eq!(*resume_ty_adt, expected_adt);
138-
} else {
139-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
140-
};
141-
}
142-
let context_mut_ref = Ty::new_task_context(tcx);
143-
144-
(context_mut_ref, ret_ty)
128+
Ty::new_adt(tcx, poll_adt_ref, poll_args)
145129
} else {
146-
// The signature should be `Generator::resume(_, Resume) -> GeneratorState<Yield, Return>`
130+
// The signature should be `Generator::resume(..) -> GeneratorState<Yield, Return>`
147131
let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
148132
let state_adt_ref = tcx.adt_def(state_did);
149133
let state_args = tcx.mk_args(&[sig.yield_ty.into(), sig.return_ty.into()]);
150-
let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_args);
151-
152-
(sig.resume_ty, ret_ty)
134+
Ty::new_adt(tcx, state_adt_ref, state_args)
153135
};
154136

155137
ty::Binder::bind_with_vars(
156138
tcx.mk_fn_sig(
157-
[env_ty, resume_ty],
139+
[env_ty, sig.resume_ty],
158140
ret_ty,
159141
false,
160142
hir::Unsafety::Normal,

library/core/src/future/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub use poll_fn::{poll_fn, PollFn};
4444
/// non-Send/Sync as well, and we don't want that.
4545
///
4646
/// It also simplifies the HIR lowering of `.await`.
47-
#[lang = "ResumeTy"]
47+
#[cfg_attr(bootstrap, lang = "ResumeTy")]
4848
#[doc(hidden)]
4949
#[unstable(feature = "gen_future", issue = "50547")]
5050
#[derive(Debug, Copy, Clone)]
@@ -56,7 +56,7 @@ unsafe impl Send for ResumeTy {}
5656
#[unstable(feature = "gen_future", issue = "50547")]
5757
unsafe impl Sync for ResumeTy {}
5858

59-
#[lang = "get_context"]
59+
#[cfg_attr(bootstrap, lang = "get_context")]
6060
#[doc(hidden)]
6161
#[unstable(feature = "gen_future", issue = "50547")]
6262
#[must_use]

0 commit comments

Comments
 (0)