@@ -211,6 +211,9 @@ struct TransformVisitor<'tcx> {
211211 old_yield_ty : Ty < ' tcx > ,
212212
213213 old_ret_ty : Ty < ' tcx > ,
214+
215+ /// The rvalue that should be assigned to yield `resume_arg` place.
216+ resume_rvalue : Rvalue < ' tcx > ,
214217}
215218
216219impl < ' tcx > TransformVisitor < ' tcx > {
@@ -533,100 +536,6 @@ fn replace_local<'tcx>(
533536 new_local
534537}
535538
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-
630539/// Transforms the `body` of the coroutine applying the following transform:
631540///
632541/// - Remove the `resume` argument.
@@ -1342,12 +1251,11 @@ fn create_cases<'tcx>(
13421251
13431252 if operation == Operation :: Resume {
13441253 // Move the resume argument to the destination place of the `Yield` terminator
1345- let resume_arg = CTX_ARG ;
13461254 statements. push ( Statement :: new (
13471255 source_info,
13481256 StatementKind :: Assign ( Box :: new ( (
13491257 point. resume_arg ,
1350- Rvalue :: Use ( Operand :: Move ( resume_arg . into ( ) ) ) ,
1258+ transform . resume_rvalue . clone ( ) ,
13511259 ) ) ) ,
13521260 ) ) ;
13531261 }
@@ -1504,12 +1412,8 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15041412 ) && has_expandable_async_drops ( tcx, body, coroutine_ty) ;
15051413
15061414 // Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
1507- if matches ! (
1508- coroutine_kind,
1509- CoroutineKind :: Desugared ( CoroutineDesugaring :: Async | CoroutineDesugaring :: AsyncGen , _)
1510- ) {
1511- let context_mut_ref = transform_async_context ( tcx, body) ;
1512- expand_async_drops ( tcx, body, context_mut_ref, coroutine_kind, coroutine_ty) ;
1415+ if has_async_drops {
1416+ expand_async_drops ( tcx, body, coroutine_kind, coroutine_ty) ;
15131417
15141418 if let Some ( dumper) = MirDumper :: new ( tcx, "coroutine_async_drop_expand" , body) {
15151419 dumper. dump_mir ( body) ;
@@ -1522,22 +1426,27 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15221426 // This is needed because the resume argument `_2` might be live across a `yield`, in which
15231427 // case there is no `Assign` to it that the transform can turn into a store to the coroutine
15241428 // state. After the yield the slot in the coroutine state would then be uninitialized.
1525- let resume_local = CTX_ARG ;
1526- let resume_ty = body. local_decls [ resume_local] . ty ;
1527- let old_resume_local = replace_local ( resume_local, resume_ty, body, tcx) ;
1429+ let resume_ty = body. local_decls [ CTX_ARG ] . ty ;
1430+ let old_resume_local = replace_local ( CTX_ARG , resume_ty, body, tcx) ;
15281431
15291432 // When first entering the coroutine, move the resume argument into its old local
15301433 // (which is now a generator interior).
15311434 let source_info = SourceInfo :: outermost ( body. span ) ;
1532- let stmts = & mut body. basic_blocks_mut ( ) [ START_BLOCK ] . statements ;
1435+ let stmts = & mut body. basic_blocks . as_mut ( ) [ START_BLOCK ] . statements ;
1436+ let resume_rvalue = if matches ! (
1437+ coroutine_kind,
1438+ CoroutineKind :: Desugared ( CoroutineDesugaring :: Async | CoroutineDesugaring :: AsyncGen , _)
1439+ ) {
1440+ body. local_decls [ CTX_ARG ] . ty = Ty :: new_task_context ( tcx) ;
1441+ Rvalue :: WrapUnsafeBinder ( Operand :: Move ( CTX_ARG . into ( ) ) , resume_ty)
1442+ } else {
1443+ Rvalue :: Use ( Operand :: Move ( CTX_ARG . into ( ) ) )
1444+ } ;
15331445 stmts. insert (
15341446 0 ,
15351447 Statement :: new (
15361448 source_info,
1537- StatementKind :: Assign ( Box :: new ( (
1538- old_resume_local. into ( ) ,
1539- Rvalue :: Use ( Operand :: Move ( resume_local. into ( ) ) ) ,
1540- ) ) ) ,
1449+ StatementKind :: Assign ( Box :: new ( ( old_resume_local. into ( ) , resume_rvalue. clone ( ) ) ) ) ,
15411450 ) ,
15421451 ) ;
15431452
@@ -1580,6 +1489,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15801489 discr_ty,
15811490 old_ret_ty,
15821491 old_yield_ty,
1492+ resume_rvalue,
15831493 } ;
15841494 transform. visit_body ( body) ;
15851495
0 commit comments