@@ -33,6 +33,8 @@ struct InteriorVisitor<'a, 'tcx> {
3333 prev_unresolved_span : Option < Span > ,
3434 linted_values : HirIdSet ,
3535 drop_ranges : DropRanges ,
36+ task_context_hir_id : Option < HirId > ,
37+ in_lowered_await : bool ,
3638}
3739
3840impl < ' a , ' tcx > InteriorVisitor < ' a , ' tcx > {
@@ -53,7 +55,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
5355 ty, hir_id, scope, expr, source_span, self . expr_count,
5456 ) ;
5557
56- let live_across_yield = scope
58+ let mut live_across_yield = scope
5759 . map ( |s| {
5860 self . region_scope_tree . yield_in_scope ( s) . and_then ( |yield_data| {
5961 // If we are recording an expression that is the last yield
@@ -92,6 +94,34 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
9294 Some ( YieldData { span : DUMMY_SP , expr_and_pat_count : 0 , source : self . kind . into ( ) } )
9395 } ) ;
9496
97+ // If this is the `&mut Context<'_>` async resume argument, or we are
98+ // just visiting a `_task_context = yield ()` expression from async
99+ // lowering, we do *not* consider this type to be live across yields.
100+ if Some ( hir_id) == self . task_context_hir_id || self . in_lowered_await {
101+ #[ cfg( debug_assertions) ]
102+ {
103+ // As `record` is being invoked for multiple parts / types of the
104+ // lowered `.await`, the `ty` has to either be the `()` going *into*
105+ // the `yield`, or a `&mut Context<'_>` coming *out* of it.
106+ let tcx = self . fcx . tcx ;
107+ if ty == tcx. types . unit {
108+ // all good
109+ } else if let ty:: Ref ( _, adt, hir:: Mutability :: Mut ) = ty. kind ( ) && let ty:: Adt ( adt, _) = adt. kind ( )
110+ {
111+ let context_def_id = tcx. lang_items ( ) . context ( ) ;
112+ assert_eq ! (
113+ Some ( adt. did( ) ) ,
114+ context_def_id,
115+ "expected `&mut Context<'_>, found `{:?}` instead`" ,
116+ ty
117+ ) ;
118+ } else {
119+ panic ! ( "expected `()` or `&mut Context<'_>`, found `{:?}` instead" , ty) ;
120+ }
121+ }
122+ live_across_yield = None ;
123+ }
124+
95125 if let Some ( yield_data) = live_across_yield {
96126 debug ! (
97127 "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}" ,
@@ -183,6 +213,17 @@ pub fn resolve_interior<'a, 'tcx>(
183213 kind : hir:: GeneratorKind ,
184214) {
185215 let body = fcx. tcx . hir ( ) . body ( body_id) ;
216+
217+ // In case we are in an async block, this is the Param/Pat HirId of the
218+ // `&mut Context<'_>` resume type. We can use this to explicitly prevent it
219+ // from being considered as `live_across_yield`, which it is not, but the
220+ // simple scope-based analysis can't tell.
221+ let task_context_hir_id = if matches ! ( kind, hir:: GeneratorKind :: Async ( _) ) {
222+ Some ( body. params [ 0 ] . pat . hir_id )
223+ } else {
224+ None
225+ } ;
226+
186227 let typeck_results = fcx. inh . typeck_results . borrow ( ) ;
187228 let mut visitor = InteriorVisitor {
188229 fcx,
@@ -194,6 +235,8 @@ pub fn resolve_interior<'a, 'tcx>(
194235 prev_unresolved_span : None ,
195236 linted_values : <_ >:: default ( ) ,
196237 drop_ranges : drop_ranges:: compute_drop_ranges ( fcx, def_id, body) ,
238+ task_context_hir_id,
239+ in_lowered_await : false ,
197240 } ;
198241 intravisit:: walk_body ( & mut visitor, body) ;
199242
@@ -426,6 +469,22 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
426469 }
427470 _ => intravisit:: walk_expr ( self , expr) ,
428471 } ,
472+ ExprKind :: Assign ( _, rhs, _) => {
473+ // An `.await` expression will be lowered to `_task_context = yield ()`.
474+ // In that case, other forms of `yield` are considered errors in lowering.
475+ if self . task_context_hir_id . is_some ( )
476+ && matches ! ( rhs. kind, hir:: ExprKind :: Yield ( ..) )
477+ {
478+ assert ! ( !self . in_lowered_await) ;
479+ self . in_lowered_await = true ;
480+ }
481+ // We are still walking the whole expression including its types.
482+ // First, we need to keep `expr_count` in sync as it is asserted
483+ // at the very end, and to keep all the other computations in
484+ // place just in case they are causing other side effects.
485+ intravisit:: walk_expr ( self , expr) ;
486+ self . in_lowered_await = false ;
487+ }
429488 _ => intravisit:: walk_expr ( self , expr) ,
430489 }
431490
0 commit comments