Skip to content

Commit e270344

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 645bc60 commit e270344

File tree

14 files changed

+76
-199
lines changed

14 files changed

+76
-199
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+29-28
Original file line numberDiff line numberDiff line change
@@ -627,17 +627,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
627627
// whereas a generator does not.
628628
let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
629629
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
630-
// Resume argument type: `ResumeTy`
631-
let unstable_span = self.mark_span_with_reason(
632-
DesugaringKind::Async,
633-
self.lower_span(span),
634-
Some(self.allow_gen_future.clone()),
635-
);
636-
let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
630+
// Resume argument type: `&mut Context<'_>`.
631+
let context_lifetime_ident = Ident::with_dummy_span(kw::UnderscoreLifetime);
632+
let context_lifetime = self.arena.alloc(hir::Lifetime {
633+
hir_id: self.next_id(),
634+
ident: context_lifetime_ident,
635+
res: hir::LifetimeName::Infer,
636+
});
637+
let context_path =
638+
hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span));
639+
let context_ty = hir::MutTy {
640+
ty: self.arena.alloc(hir::Ty {
641+
hir_id: self.next_id(),
642+
kind: hir::TyKind::Path(context_path),
643+
span: self.lower_span(span),
644+
}),
645+
mutbl: hir::Mutability::Mut,
646+
};
647+
637648
let input_ty = hir::Ty {
638649
hir_id: self.next_id(),
639-
kind: hir::TyKind::Path(resume_ty),
640-
span: unstable_span,
650+
kind: hir::TyKind::Ref(context_lifetime, context_ty),
651+
span: self.lower_span(span),
641652
};
642653
let inputs = arena_vec![self; input_ty];
643654

@@ -737,7 +748,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
737748
/// mut __awaitee => loop {
738749
/// match unsafe { ::std::future::Future::poll(
739750
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
740-
/// ::std::future::get_context(task_context),
751+
/// task_context,
741752
/// ) } {
742753
/// ::std::task::Poll::Ready(result) => break result,
743754
/// ::std::task::Poll::Pending => {}
@@ -796,26 +807,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
796807
FutureKind::AsyncIterator => Some(self.allow_for_await.clone()),
797808
};
798809
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
799-
let gen_future_span = self.mark_span_with_reason(
800-
DesugaringKind::Await,
801-
full_span,
802-
Some(self.allow_gen_future.clone()),
803-
);
804810
let expr_hir_id = expr.hir_id;
805811

806812
// Note that the name of this binding must not be changed to something else because
807813
// debuggers and debugger extensions expect it to be called `__awaitee`. They use
808814
// this name to identify what is being awaited by a suspended async functions.
809815
let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
810816
let (awaitee_pat, awaitee_pat_hid) =
811-
self.pat_ident_binding_mode(gen_future_span, awaitee_ident, hir::BindingMode::MUT);
817+
self.pat_ident_binding_mode(full_span, awaitee_ident, hir::BindingMode::MUT);
812818

813819
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
814820

815821
// unsafe {
816822
// ::std::future::Future::poll(
817823
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
818-
// ::std::future::get_context(task_context),
824+
// task_context,
819825
// )
820826
// }
821827
let poll_expr = {
@@ -833,21 +839,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
833839
hir::LangItem::PinNewUnchecked,
834840
arena_vec![self; ref_mut_awaitee],
835841
);
836-
let get_context = self.expr_call_lang_item_fn_mut(
837-
gen_future_span,
838-
hir::LangItem::GetContext,
839-
arena_vec![self; task_context],
840-
);
841842
let call = match await_kind {
842843
FutureKind::Future => self.expr_call_lang_item_fn(
843844
span,
844845
hir::LangItem::FuturePoll,
845-
arena_vec![self; new_unchecked, get_context],
846+
arena_vec![self; new_unchecked, task_context],
846847
),
847848
FutureKind::AsyncIterator => self.expr_call_lang_item_fn(
848849
span,
849850
hir::LangItem::AsyncIteratorPollNext,
850-
arena_vec![self; new_unchecked, get_context],
851+
arena_vec![self; new_unchecked, task_context],
851852
),
852853
};
853854
self.arena.alloc(self.expr_unsafe(call))
@@ -858,14 +859,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
858859
let loop_hir_id = self.lower_node_id(loop_node_id);
859860
let ready_arm = {
860861
let x_ident = Ident::with_dummy_span(sym::result);
861-
let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
862-
let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
863-
let ready_field = self.single_pat_field(gen_future_span, x_pat);
862+
let (x_pat, x_pat_hid) = self.pat_ident(full_span, x_ident);
863+
let x_expr = self.expr_ident(full_span, x_ident, x_pat_hid);
864+
let ready_field = self.single_pat_field(full_span, x_pat);
864865
let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
865866
let break_x = self.with_loop_scope(loop_node_id, move |this| {
866867
let expr_break =
867868
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
868-
this.arena.alloc(this.expr(gen_future_span, expr_break))
869+
this.arena.alloc(this.expr(full_span, expr_break))
869870
});
870871
self.arm(ready_pat, break_x)
871872
};

compiler/rustc_hir/src/lang_items.rs

-5
Original file line numberDiff line numberDiff line change
@@ -348,11 +348,6 @@ language_item_table! {
348348
AsyncGenPending, sym::AsyncGenPending, async_gen_pending, Target::AssocConst, GenericRequirement::Exact(1);
349349
AsyncGenFinished, sym::AsyncGenFinished, async_gen_finished, Target::AssocConst, GenericRequirement::Exact(1);
350350

351-
// FIXME(swatinem): the following lang items are used for async lowering and
352-
// should become obsolete eventually.
353-
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
354-
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
355-
356351
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
357352
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
358353

compiler/rustc_middle/src/ty/sty.rs

-9
Original file line numberDiff line numberDiff line change
@@ -1831,15 +1831,6 @@ impl<'tcx> Ty<'tcx> {
18311831
let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None);
18321832
Ty::new_generic_adt(tcx, def_id, ty)
18331833
}
1834-
1835-
/// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
1836-
pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
1837-
let context_did = tcx.require_lang_item(LangItem::Context, None);
1838-
let context_adt_ref = tcx.adt_def(context_did);
1839-
let context_args = tcx.mk_args(&[tcx.lifetimes.re_erased.into()]);
1840-
let context_ty = Ty::new_adt(tcx, context_adt_ref, context_args);
1841-
Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, context_ty)
1842-
}
18431834
}
18441835

18451836
impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {

compiler/rustc_mir_transform/src/coroutine.rs

+1-107
Original file line numberDiff line numberDiff line change
@@ -619,112 +619,14 @@ fn replace_local<'tcx>(
619619
new_local
620620
}
621621

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

1688-
// Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
1689-
if matches!(
1690-
coroutine_kind,
1691-
CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _)
1692-
) {
1693-
transform_async_context(tcx, body);
1694-
}
1695-
16961590
// We also replace the resume argument and insert an `Assign`.
16971591
// This is needed because the resume argument `_2` might be live across a `yield`, in which
16981592
// case there is no `Assign` to it that the transform can turn into a store to the coroutine

compiler/rustc_span/src/symbol.rs

-2
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,6 @@ symbols! {
286286
Relaxed,
287287
Release,
288288
Result,
289-
ResumeTy,
290289
Return,
291290
Right,
292291
Rust,
@@ -924,7 +923,6 @@ symbols! {
924923
generic_const_exprs,
925924
generic_const_items,
926925
generic_param_attrs,
927-
get_context,
928926
global_alloc_ty,
929927
global_allocator,
930928
global_asm,

compiler/rustc_ty_utils/src/abi.rs

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

235-
// We have to replace the `ResumeTy` that is used for type and borrow checking
236-
// with `&mut Context<'_>` which is used in codegen.
237-
#[cfg(debug_assertions)]
238-
{
239-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
240-
let expected_adt =
241-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
242-
assert_eq!(*resume_ty_adt, expected_adt);
243-
} else {
244-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
245-
};
246-
}
247-
let context_mut_ref = Ty::new_task_context(tcx);
248-
249-
(Some(context_mut_ref), ret_ty)
235+
(Some(sig.resume_ty), ret_ty)
250236
}
251237
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
252238
// The signature should be `Iterator::next(_) -> Option<Yield>`
@@ -268,21 +254,7 @@ fn fn_sig_for_fn_abi<'tcx>(
268254
// Yield type is already `Poll<Option<yield_ty>>`
269255
let ret_ty = sig.yield_ty;
270256

271-
// We have to replace the `ResumeTy` that is used for type and borrow checking
272-
// with `&mut Context<'_>` which is used in codegen.
273-
#[cfg(debug_assertions)]
274-
{
275-
if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
276-
let expected_adt =
277-
tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
278-
assert_eq!(*resume_ty_adt, expected_adt);
279-
} else {
280-
panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
281-
};
282-
}
283-
let context_mut_ref = Ty::new_task_context(tcx);
284-
285-
(Some(context_mut_ref), ret_ty)
257+
(Some(sig.resume_ty), ret_ty)
286258
}
287259
hir::CoroutineKind::Coroutine(_) => {
288260
// The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`

library/core/src/future/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub use async_drop::{async_drop, async_drop_in_place, AsyncDrop, AsyncDropInPlac
4848
/// non-Send/Sync as well, and we don't want that.
4949
///
5050
/// It also simplifies the HIR lowering of `.await`.
51-
#[lang = "ResumeTy"]
51+
#[cfg_attr(bootstrap, lang = "ResumeTy")]
5252
#[doc(hidden)]
5353
#[unstable(feature = "gen_future", issue = "50547")]
5454
#[derive(Debug, Copy, Clone)]
@@ -60,7 +60,7 @@ unsafe impl Send for ResumeTy {}
6060
#[unstable(feature = "gen_future", issue = "50547")]
6161
unsafe impl Sync for ResumeTy {}
6262

63-
#[lang = "get_context"]
63+
#[cfg_attr(bootstrap, lang = "get_context")]
6464
#[doc(hidden)]
6565
#[unstable(feature = "gen_future", issue = "50547")]
6666
#[must_use]

tests/ui/async-await/issue-69446-fnmut-capture.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ LL | | });
1414
|
1515
= note: `FnMut` closures only have access to their captured variables while they are executing...
1616
= note: ...therefore, they cannot allow references to captured variables to escape
17+
= note: requirement occurs because of a mutable reference to `Context<'_>`
18+
= note: mutable references are invariant over their type parameter
19+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
1720

1821
error: aborting due to 1 previous error
1922

+2-2
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() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: unreachable expression
2+
--> $DIR/unreachable-lint.rs:5:5
3+
|
4+
LL | endless().await;
5+
| ^^^^^^^^^^^^^^^
6+
| |
7+
| unreachable expression
8+
| any code following this expression is unreachable
9+
|
10+
note: the lint level is defined here
11+
--> $DIR/unreachable-lint.rs:2:9
12+
|
13+
LL | #![deny(unreachable_code)]
14+
| ^^^^^^^^^^^^^^^^
15+
16+
error: aborting due to 1 previous error
17+

0 commit comments

Comments
 (0)