1
1
//! This calculates the types which has storage which lives across a suspension point in a
2
2
//! generator from the perspective of typeck. The actual types used at runtime
3
- //! is calculated in `rustc_const_eval ::transform::generator` and may be a subset of the
3
+ //! is calculated in `rustc_mir ::transform::generator` and may be a subset of the
4
4
//! types computed here.
5
5
6
+ // use crate::expr_use_visitor::{self, ExprUseVisitor};
7
+
8
+ use crate :: expr_use_visitor:: { self , ExprUseVisitor } ;
9
+
10
+ use super :: generator_liveness:: Liveness ;
6
11
use super :: FnCtxt ;
7
- use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
12
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
8
13
use rustc_hir as hir;
9
14
use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
10
15
use rustc_hir:: def_id:: DefId ;
11
16
use rustc_hir:: hir_id:: HirIdSet ;
12
17
use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
13
18
use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
19
+ use rustc_infer:: infer:: RegionVariableOrigin ;
14
20
use rustc_middle:: middle:: region:: { self , YieldData } ;
15
- use rustc_middle:: ty:: { self , Ty } ;
21
+ use rustc_middle:: ty:: { self , BorrowKind , Ty , TypeckResults } ;
22
+ use rustc_passes:: liveness:: { self , IrMaps , Variable } ;
16
23
use rustc_span:: Span ;
17
24
use smallvec:: SmallVec ;
18
25
19
- struct InteriorVisitor < ' a , ' tcx > {
26
+ struct InteriorVisitor < ' a , ' atcx , ' tcx > {
20
27
fcx : & ' a FnCtxt < ' a , ' tcx > ,
21
28
types : FxIndexSet < ty:: GeneratorInteriorTypeCause < ' tcx > > ,
22
29
region_scope_tree : & ' tcx region:: ScopeTree ,
@@ -30,9 +37,11 @@ struct InteriorVisitor<'a, 'tcx> {
30
37
/// that they may succeed the said yield point in the post-order.
31
38
guard_bindings : SmallVec < [ SmallVec < [ HirId ; 4 ] > ; 1 ] > ,
32
39
guard_bindings_set : HirIdSet ,
40
+ liveness : Liveness < ' a , ' atcx , ' tcx > ,
41
+ live_across_yield : FxIndexSet < Variable > ,
33
42
}
34
43
35
- impl < ' a , ' tcx > InteriorVisitor < ' a , ' tcx > {
44
+ impl < ' a , ' atcx , ' tcx > InteriorVisitor < ' a , ' atcx , ' tcx > {
36
45
fn record (
37
46
& mut self ,
38
47
ty : Ty < ' tcx > ,
@@ -154,24 +163,72 @@ pub fn resolve_interior<'a, 'tcx>(
154
163
kind : hir:: GeneratorKind ,
155
164
) {
156
165
let body = fcx. tcx . hir ( ) . body ( body_id) ;
157
- let mut visitor = InteriorVisitor {
158
- fcx,
159
- types : FxIndexSet :: default ( ) ,
160
- region_scope_tree : fcx. tcx . region_scope_tree ( def_id) ,
161
- expr_count : 0 ,
162
- kind,
163
- prev_unresolved_span : None ,
164
- guard_bindings : <_ >:: default ( ) ,
165
- guard_bindings_set : <_ >:: default ( ) ,
166
- } ;
167
- intravisit:: walk_body ( & mut visitor, body) ;
168
-
169
- // Check that we visited the same amount of expressions and the RegionResolutionVisitor
170
- let region_expr_count = visitor. region_scope_tree . body_expr_count ( body_id) . unwrap ( ) ;
171
- assert_eq ! ( region_expr_count, visitor. expr_count) ;
166
+ let types = {
167
+ let mut ir_maps = IrMaps :: new ( fcx. tcx ) ;
168
+ // FIXME: use this to inform capture information
169
+ let typeck_results = fcx. inh . typeck_results . borrow ( ) ;
170
+ let liveness = compute_body_liveness ( & fcx, & mut ir_maps, body_id, & typeck_results) ;
171
+ let mut visitor = InteriorVisitor {
172
+ fcx,
173
+ types : FxIndexSet :: default ( ) ,
174
+ region_scope_tree : fcx. tcx . region_scope_tree ( def_id) ,
175
+ expr_count : 0 ,
176
+ kind,
177
+ prev_unresolved_span : None ,
178
+ guard_bindings : <_ >:: default ( ) ,
179
+ guard_bindings_set : <_ >:: default ( ) ,
180
+ liveness : liveness. liveness ,
181
+ live_across_yield : FxIndexSet :: default ( ) ,
182
+ } ;
183
+ intravisit:: walk_body ( & mut visitor, body) ;
184
+
185
+ // Check that we visited the same amount of expressions and the RegionResolutionVisitor
186
+ let region_expr_count = visitor. region_scope_tree . body_expr_count ( body_id) . unwrap ( ) ;
187
+ assert_eq ! ( region_expr_count, visitor. expr_count) ;
188
+
189
+ // The types are already kept in insertion order.
190
+ // let types = visitor.types;
191
+ let borrows = liveness. borrows ;
192
+ let mut types = visitor
193
+ . live_across_yield
194
+ . iter ( )
195
+ . map ( |v| {
196
+ let var_hir_id = visitor. liveness . ir . variable_hir_id ( * v) ;
197
+ let ty = visitor. fcx . inh . typeck_results . borrow ( ) . node_type ( var_hir_id) ;
198
+
199
+ // fixup type if it is borrowed
200
+ let ty = if let Some ( bk) = borrows. get ( & var_hir_id) {
201
+ // FIXME: this is almost certainly the wrong origin to use here.
202
+ let origin = RegionVariableOrigin :: AddrOfRegion ( fcx. tcx . hir ( ) . span ( var_hir_id) ) ;
203
+ let region = fcx. infcx . next_region_var ( origin) ;
204
+ match bk {
205
+ BorrowKind :: ImmBorrow | BorrowKind :: UniqueImmBorrow => {
206
+ visitor. fcx . tcx . mk_imm_ref ( region, ty)
207
+ }
208
+ BorrowKind :: MutBorrow => visitor. fcx . tcx . mk_mut_ref ( region, ty) ,
209
+ }
210
+ } else {
211
+ ty
212
+ } ;
213
+
214
+ ty:: GeneratorInteriorTypeCause {
215
+ ty,
216
+ span : fcx. tcx . hir ( ) . span ( var_hir_id) ,
217
+ scope_span : None ,
218
+ yield_span : fcx. tcx . hir ( ) . span ( var_hir_id) , // FIXME: this should be the yield span instead
219
+ expr : None ,
220
+ }
221
+ } )
222
+ . collect :: < FxIndexSet < _ > > ( ) ;
172
223
173
- // The types are already kept in insertion order.
174
- let types = visitor. types ;
224
+ // Now add in any temporaries that implement Drop
225
+ for ty in visitor. types . drain ( ..) {
226
+ if ty. ty . has_significant_drop ( fcx. tcx , fcx. param_env ) {
227
+ types. insert ( ty) ;
228
+ }
229
+ }
230
+ types
231
+ } ;
175
232
176
233
// The types in the generator interior contain lifetimes local to the generator itself,
177
234
// which should not be exposed outside of the generator. Therefore, we replace these
@@ -224,7 +281,7 @@ pub fn resolve_interior<'a, 'tcx>(
224
281
fcx. tcx . mk_generator_witness ( ty:: Binder :: bind_with_vars ( type_list, bound_vars. clone ( ) ) ) ;
225
282
226
283
// Store the generator types and spans into the typeck results for this generator.
227
- visitor . fcx . inh . typeck_results . borrow_mut ( ) . generator_interior_types =
284
+ fcx. inh . typeck_results . borrow_mut ( ) . generator_interior_types =
228
285
ty:: Binder :: bind_with_vars ( type_causes, bound_vars) ;
229
286
230
287
debug ! (
@@ -242,7 +299,7 @@ pub fn resolve_interior<'a, 'tcx>(
242
299
// This visitor has to have the same visit_expr calls as RegionResolutionVisitor in
243
300
// librustc_middle/middle/region.rs since `expr_count` is compared against the results
244
301
// there.
245
- impl < ' a , ' tcx > Visitor < ' tcx > for InteriorVisitor < ' a , ' tcx > {
302
+ impl < ' a , ' atcx , ' tcx > Visitor < ' tcx > for InteriorVisitor < ' a , ' atcx , ' tcx > {
246
303
type Map = intravisit:: ErasedMap < ' tcx > ;
247
304
248
305
fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
@@ -332,6 +389,30 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
332
389
_ => { }
333
390
}
334
391
}
392
+ ExprKind :: Yield ( ..) => {
393
+ let live_node = self . liveness . live_node ( expr. hir_id , expr. span ) ;
394
+
395
+ debug ! ( "***Dumping variable liveness information***" ) ;
396
+ for ( _, & var) in self . liveness . ir . variable_map . iter ( ) {
397
+ if self . liveness . live_on_entry ( live_node, var) {
398
+ debug ! (
399
+ " Variable {:?}: {:?} (ty={:?}) is live on entry at {:?}" ,
400
+ var,
401
+ self . liveness. ir. variable_name( var) ,
402
+ self . fcx
403
+ . typeck_results
404
+ . borrow( )
405
+ . node_type( self . liveness. ir. variable_hir_id( var) ) ,
406
+ expr. span
407
+ ) ;
408
+
409
+ self . live_across_yield . insert ( var) ;
410
+ }
411
+ }
412
+ debug ! ( "***Done dumping variable liveness information***" ) ;
413
+
414
+ intravisit:: walk_expr ( self , expr) ;
415
+ }
335
416
_ => intravisit:: walk_expr ( self , expr) ,
336
417
}
337
418
@@ -409,3 +490,119 @@ impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
409
490
}
410
491
}
411
492
}
493
+
494
+ struct GeneratorLiveness < ' a , ' atcx , ' tcx > {
495
+ liveness : Liveness < ' a , ' atcx , ' tcx > ,
496
+ borrows : FxIndexMap < HirId , BorrowKind > ,
497
+ }
498
+
499
+ // Expose liveness computation to other passes that might need it.
500
+ fn compute_body_liveness (
501
+ fcx : & FnCtxt < ' a , ' tcx > ,
502
+ maps : & ' a mut IrMaps < ' tcx > ,
503
+ body_id : hir:: BodyId ,
504
+ typeck_results : & ' atcx TypeckResults < ' tcx > ,
505
+ ) -> GeneratorLiveness < ' a , ' atcx , ' tcx >
506
+ where
507
+ ' atcx : ' a ,
508
+ {
509
+ let body = fcx. tcx . hir ( ) . body ( body_id) ;
510
+ let body_owner = fcx. tcx . hir ( ) . body_owner ( body_id) ;
511
+ let body_owner_local_def_id = fcx. tcx . hir ( ) . local_def_id ( body_owner) ;
512
+
513
+ if let Some ( captures) =
514
+ typeck_results. closure_min_captures . get ( & body_owner_local_def_id. to_def_id ( ) )
515
+ {
516
+ for & var_hir_id in captures. keys ( ) {
517
+ let var_name = fcx. tcx . hir ( ) . name ( var_hir_id) ;
518
+ maps. add_variable ( liveness:: VarKind :: Upvar ( var_hir_id, var_name) ) ;
519
+ }
520
+ }
521
+
522
+ let mut borrows = <_ >:: default ( ) ;
523
+
524
+ // gather up the various local variables, significant expressions,
525
+ // and so forth:
526
+ intravisit:: walk_body ( maps, body) ;
527
+ ExprUseVisitor :: new (
528
+ & mut ExprUseDelegate {
529
+ hir : & fcx. tcx . hir ( ) ,
530
+ _maps : maps,
531
+ typeck_results : & fcx. typeck_results . borrow ( ) ,
532
+ borrows : & mut borrows,
533
+ } ,
534
+ & fcx. infcx ,
535
+ body_owner_local_def_id,
536
+ fcx. param_env ,
537
+ typeck_results,
538
+ )
539
+ . consume_body ( body) ;
540
+
541
+ // compute liveness
542
+ let mut lsets = Liveness :: new ( maps, body_owner_local_def_id, typeck_results) ;
543
+ lsets. compute ( & body, body_owner) ;
544
+
545
+ GeneratorLiveness { liveness : lsets, borrows }
546
+ }
547
+
548
+ /// We use ExprUseVisitor to gather up all the temporary values whose liveness we need to consider.
549
+ struct ExprUseDelegate < ' a , ' tcx > {
550
+ hir : & ' a rustc_middle:: hir:: map:: Map < ' tcx > ,
551
+ _maps : & ' a mut IrMaps < ' tcx > ,
552
+ typeck_results : & ' a TypeckResults < ' tcx > ,
553
+ borrows : & ' a mut FxIndexMap < HirId , BorrowKind > ,
554
+ }
555
+
556
+ impl < ' a , ' tcx > expr_use_visitor:: Delegate < ' tcx > for ExprUseDelegate < ' a , ' tcx > {
557
+ fn consume (
558
+ & mut self ,
559
+ place_with_id : & rustc_middle:: hir:: place:: PlaceWithHirId < ' tcx > ,
560
+ _diag_expr_id : hir:: HirId ,
561
+ ) {
562
+ debug ! (
563
+ "ExprUseDelegate: consume {} ty={:?}, {:?}" ,
564
+ place_with_id. hir_id,
565
+ self . typeck_results. node_type( place_with_id. hir_id) ,
566
+ self . hir. span( place_with_id. hir_id)
567
+ ) ;
568
+ // self.maps.add_variable(liveness::VarKind::Temporary(place_with_id.hir_id));
569
+ }
570
+
571
+ fn borrow (
572
+ & mut self ,
573
+ place_with_id : & rustc_middle:: hir:: place:: PlaceWithHirId < ' tcx > ,
574
+ _diag_expr_id : hir:: HirId ,
575
+ bk : BorrowKind ,
576
+ ) {
577
+ debug ! (
578
+ "ExprUseDelegate: borrow {} ty={:?}, {:?}" ,
579
+ place_with_id. hir_id,
580
+ self . typeck_results. node_type( place_with_id. hir_id) ,
581
+ self . hir. span( place_with_id. hir_id)
582
+ ) ;
583
+ self . borrows . insert ( place_with_id. hir_id , bk) ;
584
+ // self.maps.add_variable(liveness::VarKind::Temporary(place_with_id.hir_id));
585
+ }
586
+
587
+ fn mutate (
588
+ & mut self ,
589
+ assignee_place : & rustc_middle:: hir:: place:: PlaceWithHirId < ' tcx > ,
590
+ _diag_expr_id : hir:: HirId ,
591
+ ) {
592
+ debug ! (
593
+ "ExprUseDelegate: mutate {} ty={:?}, {:?}" ,
594
+ assignee_place. hir_id,
595
+ self . typeck_results. node_type( assignee_place. hir_id) ,
596
+ self . hir. span( assignee_place. hir_id)
597
+ ) ;
598
+ // self.maps.add_variable(liveness::VarKind::Temporary(assignee_place.hir_id));
599
+ }
600
+
601
+ fn fake_read (
602
+ & mut self ,
603
+ _place : rustc_middle:: hir:: place:: Place < ' tcx > ,
604
+ _cause : rustc_middle:: mir:: FakeReadCause ,
605
+ _diag_expr_id : hir:: HirId ,
606
+ ) {
607
+ }
608
+ }
0 commit comments