95
95
use dvec:: DVec ;
96
96
use std:: map:: HashMap ;
97
97
use syntax:: { visit, ast_util} ;
98
- use syntax:: print:: pprust:: { expr_to_str} ;
98
+ use syntax:: print:: pprust:: { expr_to_str, block_to_str } ;
99
99
use visit:: vt;
100
- use syntax:: codemap:: span;
100
+ use syntax:: codemap:: { span, span_to_str } ;
101
101
use syntax:: ast:: * ;
102
102
use io:: WriterUtil ;
103
103
use capture:: { cap_move, cap_drop, cap_copy, cap_ref} ;
@@ -167,6 +167,16 @@ impl LiveNodeKind : cmp::Eq {
167
167
pure fn ne ( other : & LiveNodeKind ) -> bool { !self . eq ( other) }
168
168
}
169
169
170
+ fn live_node_kind_to_str ( lnk : LiveNodeKind , cx : ty:: ctxt ) -> ~str {
171
+ let cm = cx. sess . codemap ;
172
+ match lnk {
173
+ FreeVarNode ( s) => fmt ! ( "Free var node [%s]" , span_to_str( s, cm) ) ,
174
+ ExprNode ( s) => fmt ! ( "Expr node [%s]" , span_to_str( s, cm) ) ,
175
+ VarDefNode ( s) => fmt ! ( "Var def node [%s]" , span_to_str( s, cm) ) ,
176
+ ExitNode => ~"Exit node"
177
+ }
178
+ }
179
+
170
180
fn check_crate ( tcx : ty:: ctxt ,
171
181
method_map : typeck:: method_map ,
172
182
crate : @crate ) -> last_use_map {
@@ -277,8 +287,8 @@ fn IrMaps(tcx: ty::ctxt, method_map: typeck::method_map,
277
287
tcx : tcx,
278
288
method_map : method_map,
279
289
last_use_map : last_use_map,
280
- num_live_nodes : 0 u ,
281
- num_vars : 0 u ,
290
+ num_live_nodes : 0 ,
291
+ num_vars : 0 ,
282
292
live_node_map : HashMap ( ) ,
283
293
variable_map : HashMap ( ) ,
284
294
capture_map : HashMap ( ) ,
@@ -291,9 +301,10 @@ impl IrMaps {
291
301
fn add_live_node ( lnk : LiveNodeKind ) -> LiveNode {
292
302
let ln = LiveNode ( self . num_live_nodes ) ;
293
303
self . lnks . push ( lnk) ;
294
- self . num_live_nodes += 1 u ;
304
+ self . num_live_nodes += 1 ;
295
305
296
- debug ! ( "%s is of kind %?" , ln. to_str( ) , lnk) ;
306
+ debug ! ( "%s is of kind %s" , ln. to_str( ) ,
307
+ live_node_kind_to_str( lnk, self . tcx) ) ;
297
308
298
309
ln
299
310
}
@@ -308,7 +319,7 @@ impl IrMaps {
308
319
fn add_variable ( vk : VarKind ) -> Variable {
309
320
let v = Variable ( self . num_vars ) ;
310
321
self . var_kinds . push ( vk) ;
311
- self . num_vars += 1 u ;
322
+ self . num_vars += 1 ;
312
323
313
324
match vk {
314
325
Local ( LocalInfo { id : node_id, _} ) |
@@ -491,6 +502,10 @@ fn visit_expr(expr: @expr, &&self: @IrMaps, vt: vt<@IrMaps>) {
491
502
}
492
503
expr_fn( _, _, _, cap_clause) |
493
504
expr_fn_block( _, _, cap_clause) => {
505
+ // Interesting control flow (for loops can contain labeled
506
+ // breaks or continues)
507
+ self . add_live_node_for_node( expr. id, ExprNode ( expr. span) ) ;
508
+
494
509
// Make a live_node for each captured variable, with the span
495
510
// being the location that the variable is used. This results
496
511
// in better error messages than just pointing at the closure
@@ -571,14 +586,22 @@ const ACC_READ: uint = 1u;
571
586
const ACC_WRITE : uint = 2 u;
572
587
const ACC_USE : uint = 4 u;
573
588
589
+ type LiveNodeMap = HashMap <node_id, LiveNode >;
590
+
574
591
struct Liveness {
575
592
tcx : ty:: ctxt,
576
593
ir : @IrMaps ,
577
594
s : Specials ,
578
595
successors : ~[ mut LiveNode ] ,
579
596
users : ~[ mut users] ,
580
- mut break_ln : LiveNode ,
581
- mut cont_ln : LiveNode ,
597
+ // The list of node IDs for the nested loop scopes
598
+ // we're in.
599
+ mut loop_scope: @DVec < node_id > ,
600
+ // mappings from loop node ID to LiveNode
601
+ // ("break" label should map to loop node ID,
602
+ // it probably doesn't now)
603
+ break_ln : LiveNodeMap ,
604
+ cont_ln : LiveNodeMap
582
605
}
583
606
584
607
fn Liveness ( ir: @IrMaps , specials: Specials ) -> Liveness {
@@ -594,8 +617,9 @@ fn Liveness(ir: @IrMaps, specials: Specials) -> Liveness {
594
617
vec:: to_mut(
595
618
vec:: from_elem( ir. num_live_nodes * ir. num_vars,
596
619
invalid_users( ) ) ) ,
597
- break_ln : invalid_node( ) ,
598
- cont_ln : invalid_node( )
620
+ loop_scope: @DVec ( ) ,
621
+ break_ln: HashMap ( ) ,
622
+ cont_ln: HashMap ( )
599
623
}
600
624
}
601
625
@@ -691,6 +715,9 @@ impl Liveness {
691
715
if reader. is_valid( ) { Some ( ( * self . ir) . lnk( reader) ) } else { None }
692
716
}
693
717
718
+ /*
719
+ Is this variable live on entry to any of its successor nodes?
720
+ */
694
721
fn live_on_exit( ln: LiveNode , var: Variable )
695
722
-> Option < LiveNodeKind > {
696
723
@@ -717,8 +744,8 @@ impl Liveness {
717
744
}
718
745
719
746
fn indices( ln: LiveNode , op: fn ( uint) ) {
720
- let node_base_idx = self . idx( ln, Variable ( 0 u ) ) ;
721
- for uint:: range( 0 u , self . ir. num_vars) |var_idx| {
747
+ let node_base_idx = self . idx( ln, Variable ( 0 ) ) ;
748
+ for uint:: range( 0 , self . ir. num_vars) |var_idx| {
722
749
op( node_base_idx + var_idx)
723
750
}
724
751
}
@@ -735,8 +762,8 @@ impl Liveness {
735
762
fn write_vars( wr: io:: Writer ,
736
763
ln: LiveNode ,
737
764
test: fn ( uint) -> LiveNode ) {
738
- let node_base_idx = self . idx( ln, Variable ( 0 u ) ) ;
739
- for uint:: range( 0 u , self . ir. num_vars) |var_idx| {
765
+ let node_base_idx = self . idx( ln, Variable ( 0 ) ) ;
766
+ for uint:: range( 0 , self . ir. num_vars) |var_idx| {
740
767
let idx = node_base_idx + var_idx;
741
768
if test( idx) . is_valid( ) {
742
769
wr. write_str( ~" ");
@@ -745,6 +772,28 @@ impl Liveness {
745
772
}
746
773
}
747
774
775
+ fn find_loop_scope(opt_label: Option<ident>, id: node_id, sp: span)
776
+ -> node_id {
777
+ match opt_label {
778
+ Some(_) => // Refers to a labeled loop. Use the results of resolve
779
+ // to find with one
780
+ match self.tcx.def_map.find(id) {
781
+ Some(def_label(loop_id)) => loop_id,
782
+ _ => self.tcx.sess.span_bug(sp, ~"Label on break /loop \
783
+ doesn' t refer to a loop " )
784
+ } ,
785
+ None =>
786
+ // Vanilla 'break' or 'loop', so use the enclosing
787
+ // loop scope
788
+ if self . loop_scope. len( ) == 0 {
789
+ self . tcx. sess. span_bug( sp, ~"break outside loop") ;
790
+ }
791
+ else {
792
+ self . loop_scope. last( )
793
+ }
794
+ }
795
+ }
796
+
748
797
fn ln_str( ln: LiveNode ) -> ~str {
749
798
do io:: with_str_writer |wr| {
750
799
wr. write_str( ~"[ ln( ");
@@ -833,18 +882,18 @@ impl Liveness {
833
882
let idx = self . idx( ln, var) ;
834
883
let user = & mut self . users[ idx] ;
835
884
836
- if ( acc & ACC_WRITE ) != 0 u {
885
+ if ( acc & ACC_WRITE ) != 0 {
837
886
user. reader = invalid_node( ) ;
838
887
user. writer = ln;
839
888
}
840
889
841
890
// Important: if we both read/write, must do read second
842
891
// or else the write will override.
843
- if ( acc & ACC_READ ) != 0 u {
892
+ if ( acc & ACC_READ ) != 0 {
844
893
user. reader = ln;
845
894
}
846
895
847
- if ( acc & ACC_USE ) != 0 u {
896
+ if ( acc & ACC_USE ) != 0 {
848
897
self . users[ idx] . used = true;
849
898
}
850
899
@@ -858,10 +907,13 @@ impl Liveness {
858
907
// if there is a `break` or `again` at the top level, then it's
859
908
// effectively a return---this only occurs in `for` loops,
860
909
// where the body is really a closure.
910
+
911
+ debug!( "compute: using id for block, %s", block_to_str( body,
912
+ self . tcx. sess. intr( ) ) ) ;
913
+
861
914
let entry_ln: LiveNode =
862
- self . with_loop_nodes( self . s. exit_ln, self . s. exit_ln, || {
863
- self . propagate_through_fn_block( decl, body)
864
- } ) ;
915
+ self . with_loop_nodes( body. node. id, self . s. exit_ln, self . s. exit_ln,
916
+ || { self . propagate_through_fn_block( decl, body) } ) ;
865
917
866
918
// hack to skip the loop unless debug! is enabled:
867
919
debug ! ( "^^ liveness computation results for body %d (entry=%s)" ,
@@ -972,6 +1024,9 @@ impl Liveness {
972
1024
}
973
1025
974
1026
fn propagate_through_expr( expr: @expr, succ: LiveNode ) -> LiveNode {
1027
+ debug!( "propagate_through_expr: %s",
1028
+ expr_to_str( expr, self . tcx. sess. intr( ) ) ) ;
1029
+
975
1030
match expr. node {
976
1031
// Interesting cases with control flow or which gen/kill
977
1032
@@ -983,16 +1038,27 @@ impl Liveness {
983
1038
self . propagate_through_expr( e, succ)
984
1039
}
985
1040
986
- expr_fn( * ) | expr_fn_block( * ) => {
987
- // the construction of a closure itself is not important,
988
- // but we have to consider the closed over variables.
989
- let caps = ( * self . ir) . captures( expr) ;
990
- do ( * caps) . foldr( succ) |cap, succ| {
991
- self . init_from_succ( cap. ln, succ) ;
992
- let var = self . variable( cap. var_nid, expr. span) ;
993
- self . acc( cap. ln, var, ACC_READ | ACC_USE ) ;
994
- cap. ln
995
- }
1041
+ expr_fn( _, _, blk, _) | expr_fn_block( _, blk, _) => {
1042
+ debug!( "%s is an expr_fn or expr_fn_block",
1043
+ expr_to_str( expr, self . tcx. sess. intr( ) ) ) ;
1044
+
1045
+ /*
1046
+ The next-node for a break is the successor of the entire
1047
+ loop. The next-node for a continue is the top of this loop.
1048
+ */
1049
+ self . with_loop_nodes( blk. node. id, succ,
1050
+ self . live_node( expr. id, expr. span) , || {
1051
+
1052
+ // the construction of a closure itself is not important,
1053
+ // but we have to consider the closed over variables.
1054
+ let caps = ( * self . ir) . captures( expr) ;
1055
+ do ( * caps) . foldr( succ) |cap, succ| {
1056
+ self . init_from_succ( cap. ln, succ) ;
1057
+ let var = self . variable( cap. var_nid, expr. span) ;
1058
+ self . acc( cap. ln, var, ACC_READ | ACC_USE ) ;
1059
+ cap. ln
1060
+ }
1061
+ } )
996
1062
}
997
1063
998
1064
expr_if( cond, then, els) => {
@@ -1021,6 +1087,8 @@ impl Liveness {
1021
1087
self . propagate_through_loop( expr, Some ( cond) , blk, succ)
1022
1088
}
1023
1089
1090
+ // Note that labels have been resolved, so we don't need to look
1091
+ // at the label ident
1024
1092
expr_loop( blk, _) => {
1025
1093
self . propagate_through_loop( expr, None , blk, succ)
1026
1094
}
@@ -1062,29 +1130,31 @@ impl Liveness {
1062
1130
}
1063
1131
1064
1132
expr_break( opt_label) => {
1065
- if !self . break_ln. is_valid( ) {
1066
- self . tcx. sess. span_bug(
1067
- expr. span, ~"break with invalid break_ln") ;
1068
- }
1133
+ // Find which label this break jumps to
1134
+ let sc = self . find_loop_scope( opt_label, expr. id, expr. span) ;
1069
1135
1070
- if opt_label. is_some( ) {
1071
- self . tcx. sess. span_unimpl( expr. span, ~"labeled break ");
1072
- }
1136
+ // Now that we know the label we're going to,
1137
+ // look it up in the break loop nodes table
1073
1138
1074
- self.break_ln
1139
+ match self . break_ln. find( sc) {
1140
+ Some ( b) => b,
1141
+ None => self . tcx. sess. span_bug( expr. span,
1142
+ ~"Break to unknown label")
1143
+ }
1075
1144
}
1076
1145
1077
1146
expr_again( opt_label) => {
1078
- if !self.cont_ln.is_valid() {
1079
- self.tcx.sess.span_bug(
1080
- expr.span, ~" cont with invalid cont_ln") ;
1081
- }
1147
+ // Find which label this expr continues to to
1148
+ let sc = self . find_loop_scope( opt_label, expr. id, expr. span) ;
1082
1149
1083
- if opt_label. is_some ( ) {
1084
- self . tcx . sess . span_unimpl ( expr. span , ~"labeled again") ;
1085
- }
1150
+ // Now that we know the label we're going to,
1151
+ // look it up in the continue loop nodes table
1086
1152
1087
- self . cont_ln
1153
+ match self . cont_ln. find( sc) {
1154
+ Some ( b) => b,
1155
+ None => self . tcx. sess. span_bug( expr. span,
1156
+ ~"Loop to unknown label")
1157
+ }
1088
1158
}
1089
1159
1090
1160
expr_move( l, r) | expr_assign( l, r) => {
@@ -1314,6 +1384,7 @@ impl Liveness {
1314
1384
1315
1385
*/
1316
1386
1387
+
1317
1388
// first iteration:
1318
1389
let mut first_merge = true;
1319
1390
let ln = self . live_node( expr. id, expr. span) ;
@@ -1325,32 +1396,37 @@ impl Liveness {
1325
1396
self . merge_from_succ( ln, succ, first_merge) ;
1326
1397
first_merge = false;
1327
1398
}
1399
+ debug!( "propagate_through_loop: using id for loop body %d %s",
1400
+ expr. id, block_to_str( body, self . tcx. sess. intr( ) ) ) ;
1401
+
1328
1402
let cond_ln = self . propagate_through_opt_expr( cond, ln) ;
1329
- let body_ln = self . with_loop_nodes ( succ, ln, || {
1403
+ let body_ln = self . with_loop_nodes( expr . id , succ, ln, || {
1330
1404
self . propagate_through_block( body, cond_ln)
1331
1405
} ) ;
1332
1406
1333
1407
// repeat until fixed point is reached:
1334
1408
while self . merge_from_succ( ln, body_ln, first_merge) {
1335
1409
first_merge = false;
1336
1410
assert cond_ln == self . propagate_through_opt_expr( cond, ln) ;
1337
- assert body_ln == self . with_loop_nodes ( succ, ln, || {
1411
+ assert body_ln == self . with_loop_nodes( expr. id, succ, ln,
1412
+ || {
1338
1413
self . propagate_through_block( body, cond_ln)
1339
1414
} ) ;
1340
1415
}
1341
1416
1342
1417
cond_ln
1343
1418
}
1344
1419
1345
- fn with_loop_nodes<R >( break_ln: LiveNode ,
1420
+ fn with_loop_nodes<R >( loop_node_id: node_id,
1421
+ break_ln: LiveNode ,
1346
1422
cont_ln: LiveNode ,
1347
1423
f: fn ( ) -> R ) -> R {
1348
- let bl = self . break_ln , cl = self . cont_ln ;
1349
- self . break_ln = break_ln ;
1350
- self . cont_ln = cont_ln ;
1351
- let r <- f ( ) ;
1352
- self . break_ln = bl ;
1353
- self . cont_ln = cl ;
1424
+ debug! ( "with_loop_nodes : %d %u" , loop_node_id , * break_ln ) ;
1425
+ self . loop_scope . push ( loop_node_id ) ;
1426
+ self . break_ln . insert ( loop_node_id , break_ln ) ;
1427
+ self . cont_ln . insert ( loop_node_id , cont_ln ) ;
1428
+ let r = f ( ) ;
1429
+ self . loop_scope . pop ( ) ;
1354
1430
move r
1355
1431
}
1356
1432
}
@@ -1526,6 +1602,10 @@ impl @Liveness {
1526
1602
}
1527
1603
}
1528
1604
1605
+ /*
1606
+ Checks whether <var> is live on entry to any of the successors of <ln>.
1607
+ If it is, report an error.
1608
+ */
1529
1609
fn check_move_from_var ( span : span , ln : LiveNode , var : Variable ) {
1530
1610
debug ! ( "check_move_from_var(%s, %s)" ,
1531
1611
ln. to_str( ) , var. to_str( ) ) ;
0 commit comments