Skip to content

Commit 304d235

Browse files
committed
WIP: Remove ResumeTy from async lowering
This changes from the stdlib supported `ResumeTy`, and converting that to a `&mut Context<'_>` to directly use `&mut Context<'_>` in lowering. It pretty much reverts #105977 and re-applies an updated version of #105250. The PR is currently failing as it depends on `-Zdrop-tracking-mir` becoming the default, so that the compiler does not falsly believe the context is being held across await points,which would make async blocks `!Send` and `!UnwindSafe`. However it also still fails the testcase added in #106264 for reasons I don’t understand.
1 parent 3b63948 commit 304d235

File tree

7 files changed

+38
-170
lines changed

7 files changed

+38
-170
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;
2222

@@ -599,14 +599,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
599599
) -> hir::ExprKind<'hir> {
600600
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
601601

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

612626
// The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
@@ -710,7 +724,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
710724
/// mut __awaitee => loop {
711725
/// match unsafe { ::std::future::Future::poll(
712726
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
713-
/// ::std::future::get_context(task_context),
727+
/// task_context,
714728
/// ) } {
715729
/// ::std::task::Poll::Ready(result) => break result,
716730
/// ::std::task::Poll::Pending => {}
@@ -731,11 +745,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
731745
}
732746
}
733747
let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
734-
let gen_future_span = self.mark_span_with_reason(
735-
DesugaringKind::Await,
736-
full_span,
737-
self.allow_gen_future.clone(),
738-
);
739748
let expr = self.lower_expr_mut(expr);
740749
let expr_hir_id = expr.hir_id;
741750

@@ -751,7 +760,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
751760
// unsafe {
752761
// ::std::future::Future::poll(
753762
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
754-
// ::std::future::get_context(task_context),
763+
// task_context,
755764
// )
756765
// }
757766
let poll_expr = {
@@ -769,16 +778,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
769778
arena_vec![self; ref_mut_awaitee],
770779
Some(expr_hir_id),
771780
);
772-
let get_context = self.expr_call_lang_item_fn_mut(
773-
gen_future_span,
774-
hir::LangItem::GetContext,
775-
arena_vec![self; task_context],
776-
Some(expr_hir_id),
777-
);
778781
let call = self.expr_call_lang_item_fn(
779782
span,
780783
hir::LangItem::FuturePoll,
781-
arena_vec![self; new_unchecked, get_context],
784+
arena_vec![self; new_unchecked, task_context],
782785
Some(expr_hir_id),
783786
);
784787
self.arena.alloc(self.expr_unsafe(call))
@@ -789,9 +792,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
789792
let loop_hir_id = self.lower_node_id(loop_node_id);
790793
let ready_arm = {
791794
let x_ident = Ident::with_dummy_span(sym::result);
792-
let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
793-
let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
794-
let ready_field = self.single_pat_field(gen_future_span, x_pat);
795+
let (x_pat, x_pat_hid) = self.pat_ident(full_span, x_ident);
796+
let x_expr = self.expr_ident(full_span, x_ident, x_pat_hid);
797+
let ready_field = self.single_pat_field(full_span, x_pat);
795798
let ready_pat = self.pat_lang_item_variant(
796799
span,
797800
hir::LangItem::PollReady,
@@ -801,7 +804,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
801804
let break_x = self.with_loop_scope(loop_node_id, move |this| {
802805
let expr_break =
803806
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
804-
this.arena.alloc(this.expr(gen_future_span, expr_break))
807+
this.arena.alloc(this.expr(full_span, expr_break))
805808
});
806809
self.arm(ready_pat, break_x)
807810
};

compiler/rustc_hir/src/lang_items.rs

-2
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,7 @@ language_item_table! {
295295

296296
// FIXME(swatinem): the following lang items are used for async lowering and
297297
// should become obsolete eventually.
298-
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
299298
IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None;
300-
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
301299

302300
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
303301
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;

compiler/rustc_middle/src/ty/context.rs

-9
Original file line numberDiff line numberDiff line change
@@ -1813,15 +1813,6 @@ impl<'tcx> TyCtxt<'tcx> {
18131813
self.mk_ty(GeneratorWitness(types))
18141814
}
18151815

1816-
/// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
1817-
pub fn mk_task_context(self) -> Ty<'tcx> {
1818-
let context_did = self.require_lang_item(LangItem::Context, None);
1819-
let context_adt_ref = self.adt_def(context_did);
1820-
let context_substs = self.intern_substs(&[self.lifetimes.re_erased.into()]);
1821-
let context_ty = self.mk_adt(context_adt_ref, context_substs);
1822-
self.mk_mut_ref(self.lifetimes.re_erased, context_ty)
1823-
}
1824-
18251816
#[inline]
18261817
pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
18271818
self.mk_ty(GeneratorWitnessMIR(id, substs))

compiler/rustc_mir_transform/src/generator.rs

+2-106
Original file line numberDiff line numberDiff line change
@@ -464,104 +464,6 @@ fn replace_local<'tcx>(
464464
new_local
465465
}
466466

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

1474-
// Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
1475-
if is_async_kind {
1476-
transform_async_context(tcx, body);
1477-
}
1478-
14791376
// We also replace the resume argument and insert an `Assign`.
14801377
// This is needed because the resume argument `_2` might be live across a `yield`, in which
14811378
// case there is no `Assign` to it that the transform can turn into a store to the generator
14821379
// state. After the yield the slot in the generator state would then be uninitialized.
14831380
let resume_local = Local::new(2);
1484-
let resume_ty =
1485-
if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty };
1486-
let new_resume_local = replace_local(resume_local, resume_ty, body, tcx);
1381+
let new_resume_local =
1382+
replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
14871383

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

compiler/rustc_span/src/symbol.rs

-2
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@ symbols! {
266266
Relaxed,
267267
Release,
268268
Result,
269-
ResumeTy,
270269
Return,
271270
Right,
272271
Rust,
@@ -765,7 +764,6 @@ symbols! {
765764
generic_associated_types_extended,
766765
generic_const_exprs,
767766
generic_param_attrs,
768-
get_context,
769767
global_allocator,
770768
global_asm,
771769
globs,

compiler/rustc_ty_utils/src/abi.rs

+6-24
Original file line numberDiff line numberDiff line change
@@ -108,41 +108,23 @@ fn fn_sig_for_fn_abi<'tcx>(
108108
// `Generator::resume(...) -> GeneratorState` function in case we
109109
// have an ordinary generator, or the `Future::poll(...) -> Poll`
110110
// function in case this is a special generator backing an async construct.
111-
let (resume_ty, ret_ty) = if tcx.generator_is_async(did) {
112-
// The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>`
111+
let ret_ty = if tcx.generator_is_async(did) {
112+
// The signature should be `Future::poll(..) -> Poll<Output>`
113113
let poll_did = tcx.require_lang_item(LangItem::Poll, None);
114114
let poll_adt_ref = tcx.adt_def(poll_did);
115115
let poll_substs = tcx.intern_substs(&[sig.return_ty.into()]);
116-
let ret_ty = tcx.mk_adt(poll_adt_ref, poll_substs);
117-
118-
// We have to replace the `ResumeTy` that is used for type and borrow checking
119-
// with `&mut Context<'_>` which is used in codegen.
120-
#[cfg(debug_assertions)]
121-
{
122-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
123-
let expected_adt =
124-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
125-
assert_eq!(*resume_ty_adt, expected_adt);
126-
} else {
127-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
128-
};
129-
}
130-
let context_mut_ref = tcx.mk_task_context();
131-
132-
(context_mut_ref, ret_ty)
116+
tcx.mk_adt(poll_adt_ref, poll_substs)
133117
} else {
134-
// The signature should be `Generator::resume(_, Resume) -> GeneratorState<Yield, Return>`
118+
// The signature should be `Generator::resume(..) -> GeneratorState<Yield, Return>`
135119
let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
136120
let state_adt_ref = tcx.adt_def(state_did);
137121
let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
138-
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
139-
140-
(sig.resume_ty, ret_ty)
122+
tcx.mk_adt(state_adt_ref, state_substs)
141123
};
142124

143125
ty::Binder::bind_with_vars(
144126
tcx.mk_fn_sig(
145-
[env_ty, resume_ty].iter(),
127+
[env_ty, sig.resume_ty].iter(),
146128
&ret_ty,
147129
false,
148130
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)