@@ -24,15 +24,26 @@ import std::list;
24
24
// (by `break` or conditionals), and for handling loops.
25
25
26
26
// Marks expr_paths that are last uses.
27
- type last_uses = std:: map:: hashmap < node_id , ( ) > ;
27
+ enum is_last_use {
28
+ is_last_use,
29
+ has_last_use,
30
+ closes_over( [ node_id ] ) ,
31
+ }
32
+ type last_uses = std:: map:: hashmap < node_id , is_last_use > ;
28
33
29
34
enum seen { unset, seen( node_id ) , }
30
35
enum block_type { func, loop, }
31
36
32
- type set = [ { def : node_id , exprs : list < node_id > } ] ;
37
+ enum use { var_use( node_id ) , close_over( node_id ) , }
38
+ type set = [ { def : node_id , uses : list < use > } ] ;
33
39
type bl = @{ type : block_type , mutable second: bool , mutable exits: [ set ] } ;
34
40
35
- type ctx = { last_uses : std:: map:: hashmap < node_id , bool > ,
41
+ enum use_id { path( node_id ) , close( node_id , node_id ) }
42
+ fn hash_use_id ( id : use_id ) -> uint {
43
+ ( alt id { path( i) { i } close ( i, j) { ( i << 10 ) + j } } ) as uint
44
+ }
45
+
46
+ type ctx = { last_uses : std:: map:: hashmap < use_id , bool > ,
36
47
def_map : resolve:: def_map ,
37
48
ref_map : alias:: ref_map ,
38
49
tcx : ty:: ctxt ,
@@ -43,9 +54,10 @@ type ctx = {last_uses: std::map::hashmap<node_id, bool>,
43
54
fn find_last_uses ( c : @crate , def_map : resolve:: def_map ,
44
55
ref_map : alias:: ref_map , tcx : ty:: ctxt ) -> last_uses {
45
56
let v = visit:: mk_vt ( @{ visit_expr: visit_expr,
57
+ visit_stmt: visit_stmt,
46
58
visit_fn: visit_fn
47
59
with * visit:: default_visitor ( ) } ) ;
48
- let cx = { last_uses: std:: map:: new_int_hash ( ) ,
60
+ let cx = { last_uses: std:: map:: mk_hashmap ( hash_use_id , { |a , b| a == b } ) ,
49
61
def_map: def_map,
50
62
ref_map: ref_map,
51
63
tcx: tcx,
@@ -54,22 +66,26 @@ fn find_last_uses(c: @crate, def_map: resolve::def_map,
54
66
visit:: visit_crate ( * c, cx, v) ;
55
67
let mini_table = std:: map:: new_int_hash ( ) ;
56
68
cx. last_uses . items { |key, val|
57
- if val {
58
- mini_table. insert ( key, ( ) ) ;
59
- let def_node = ast_util:: def_id_of_def ( def_map. get ( key) ) . node ;
60
- mini_table. insert ( def_node, ( ) ) ;
69
+ if !val { ret; }
70
+ alt key {
71
+ path( id) {
72
+ mini_table. insert ( id, is_last_use) ;
73
+ let def_node = ast_util:: def_id_of_def ( def_map. get ( id) ) . node ;
74
+ mini_table. insert ( def_node, has_last_use) ;
75
+ }
76
+ close ( fn_id, local_id) {
77
+ mini_table. insert ( local_id, has_last_use) ;
78
+ let known = alt check mini_table. find ( fn_id) {
79
+ some ( closes_over ( ids) ) { ids }
80
+ none { [ ] }
81
+ } ;
82
+ mini_table. insert ( fn_id, closes_over ( known + [ local_id] ) ) ;
83
+ }
61
84
}
62
85
}
63
86
ret mini_table;
64
87
}
65
88
66
- fn ex_is_blockish ( cx : ctx , id : node_id ) -> bool {
67
- alt ty:: get ( ty:: node_id_to_type ( cx. tcx , id) ) . struct {
68
- ty:: ty_fn ( { proto: p, _} ) if is_blockish ( p) { true }
69
- _ { false }
70
- }
71
- }
72
-
73
89
fn visit_expr ( ex : @expr, cx : ctx , v : visit:: vt < ctx > ) {
74
90
alt ex. node {
75
91
expr_ret ( oexpr) {
@@ -107,15 +123,17 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
107
123
cx. current = join_branches ( [ cur, cx. current ] ) ;
108
124
}
109
125
expr_path ( _) {
110
- let my_def = ast_util:: def_id_of_def ( cx. def_map . get ( ex. id ) ) . node ;
111
- alt cx. ref_map . find ( my_def) {
112
- option:: some ( root_id) { clear_in_current ( cx, root_id, false ) ; }
126
+ let my_def = cx. def_map . get ( ex. id ) ;
127
+ let my_def_id = ast_util:: def_id_of_def ( my_def) . node ;
128
+ alt cx. ref_map . find ( my_def_id) {
129
+ option:: some ( root_id) {
130
+ clear_in_current ( cx, root_id, false ) ;
131
+ }
113
132
_ {
114
- alt clear_if_path( cx, ex, v, false ) {
115
- option:: some ( my_def) {
116
- cx. current += [ { def: my_def, exprs: cons ( ex. id , @nil) } ] ;
117
- }
118
- _ { }
133
+ option : : may ( def_is_owned_local ( cx, my_def) ) { |nid|
134
+ clear_in_current ( cx, nid, false ) ;
135
+ cx. current += [ { def: nid,
136
+ uses: cons ( var_use ( ex. id ) , @nil) } ] ;
119
137
}
120
138
}
121
139
}
@@ -138,7 +156,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
138
156
// then they are ignored, otherwise they will show up
139
157
// as freevars in the body.
140
158
vec:: iter ( cap_clause. moves ) { |ci|
141
- clear_def_if_path ( cx, cx. def_map . get ( ci. id ) , true ) ;
159
+ clear_def_if_local ( cx, cx. def_map . get ( ci. id ) , false ) ;
142
160
}
143
161
visit:: visit_expr ( ex, cx, v) ;
144
162
}
@@ -148,10 +166,8 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
148
166
let arg_ts = ty:: ty_fn_args ( ty:: expr_ty ( cx. tcx , f) ) ;
149
167
for arg in args {
150
168
alt arg. node {
151
- expr_fn ( p, _, _, _) if is_blockish ( p) {
152
- fns += [ arg] ;
153
- }
154
- expr_fn_block ( _, _) if ex_is_blockish ( cx, arg. id ) {
169
+ expr_fn ( _, _, _, _) | expr_fn_block ( _, _)
170
+ if is_blockish ( ty:: ty_fn_proto ( arg_ts[ i] . ty ) ) {
155
171
fns += [ arg] ;
156
172
}
157
173
_ {
@@ -169,6 +185,26 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
169
185
}
170
186
}
171
187
188
+ fn visit_stmt ( s : @stmt, cx : ctx , v : visit:: vt < ctx > ) {
189
+ alt s. node {
190
+ stmt_decl ( @{ node: decl_local ( ls) , _} , _) {
191
+ shadow_in_current ( cx, { |id|
192
+ for local in ls {
193
+ let found = false ;
194
+ pat_util:: pat_bindings ( cx. tcx . def_map , local. node . pat ,
195
+ { |pid, _a, _b|
196
+ if pid == id { found = true ; }
197
+ } ) ;
198
+ if found { ret true ; }
199
+ }
200
+ false
201
+ } ) ;
202
+ }
203
+ _ { }
204
+ }
205
+ visit:: visit_stmt ( s, cx, v) ;
206
+ }
207
+
172
208
fn visit_fn ( fk : visit:: fn_kind , decl : fn_decl , body : blk ,
173
209
sp : span , id : node_id ,
174
210
cx : ctx , v : visit:: vt < ctx > ) {
@@ -177,42 +213,48 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
177
213
alt proto {
178
214
proto_any | proto_block {
179
215
visit_block( func, cx, { ||
216
+ shadow_in_current ( cx, { |id|
217
+ for arg in decl. inputs { if arg. id == id { ret true ; } }
218
+ false
219
+ } ) ;
180
220
visit:: visit_fn ( fk, decl, body, sp, id, cx, v) ;
181
221
} ) ;
182
222
}
183
223
proto_box | proto_uniq | proto_bare {
184
224
alt cx. tcx . freevars . find ( id) {
185
225
some ( vars) {
186
226
for v in * vars {
187
- clear_in_current ( cx, ast_util:: def_id_of_def ( v. def ) . node ,
188
- false ) ;
227
+ option:: may ( def_is_owned_local ( cx, v. def ) ) { |nid|
228
+ clear_in_current ( cx, nid, false ) ;
229
+ cx. current += [ { def: nid,
230
+ uses: cons ( close_over ( id) , @nil) } ] ;
231
+ }
189
232
}
190
233
}
191
234
_ { }
192
235
}
193
- let old = nil;
194
- cx. blocks <-> old;
236
+ let old_cur = [ ] , old_blocks = nil;
237
+ cx. blocks <-> old_blocks;
238
+ cx. current <-> old_cur;
195
239
visit:: visit_fn ( fk, decl, body, sp, id, cx, v) ;
196
- cx. blocks <-> old ;
240
+ cx. blocks <-> old_blocks ;
197
241
leave_fn ( cx) ;
242
+ cx. current <-> old_cur;
198
243
}
199
244
}
200
245
}
201
246
202
247
fn visit_block ( tp : block_type , cx : ctx , visit : fn ( ) ) {
203
248
let local = @{ type : tp, mutable second: false , mutable exits : [ ] } ;
204
249
cx. blocks = cons ( local, @cx. blocks ) ;
205
- let start_current = cx. current ;
206
250
visit ( ) ;
207
251
local. second = true ;
208
252
local. exits = [ ] ;
209
- cx. current = start_current;
210
253
visit ( ) ;
211
254
let cx_blocks = cx. blocks ;
212
255
cx. blocks = tail ( cx_blocks) ;
213
- let branches = if tp == func { local. exits + [ cx. current ] }
214
- else { local. exits } ;
215
- cx. current = join_branches ( branches) ;
256
+ local. exits += [ cx. current ] ;
257
+ cx. current = join_branches ( local. exits ) ;
216
258
}
217
259
218
260
fn add_block_exit ( cx : ctx , tp : block_type ) -> bool {
@@ -240,82 +282,92 @@ fn join_branches(branches: [set]) -> set {
240
282
let found: set = [ ] , i = 0 u, l = vec:: len ( branches) ;
241
283
for set in branches {
242
284
i += 1 u;
243
- for { def, exprs } in set {
285
+ for { def, uses } in set {
244
286
if !vec:: any ( found, { |v| v. def == def} ) {
245
- let j = i, nne = exprs ;
287
+ let j = i, nne = uses ;
246
288
while j < l {
247
- for { def: d2, exprs } in branches[ j] {
289
+ for { def: d2, uses } in branches[ j] {
248
290
if d2 == def {
249
- list:: iter ( exprs ) { |e|
291
+ list:: iter ( uses ) { |e|
250
292
if !list:: has ( nne, e) { nne = cons ( e, @nne) ; }
251
293
}
252
294
}
253
295
}
254
296
j += 1 u;
255
297
}
256
- found += [ { def: def, exprs : nne} ] ;
298
+ found += [ { def: def, uses : nne} ] ;
257
299
}
258
300
}
259
301
}
260
302
ret found;
261
303
}
262
304
263
305
fn leave_fn ( cx : ctx ) {
264
- for { def, exprs} in cx. current {
265
- list:: iter ( exprs) { |ex_id|
266
- if !cx. last_uses . contains_key ( ex_id) {
267
- cx. last_uses . insert ( ex_id, true ) ;
306
+ for { def, uses} in cx. current {
307
+ list:: iter ( uses) { |use|
308
+ let key = alt use {
309
+ var_use( pth_id) { path ( pth_id) }
310
+ close_over ( fn_id) { close ( fn_id, def) }
311
+ } ;
312
+ if !cx. last_uses . contains_key ( key) {
313
+ cx. last_uses . insert ( key, true ) ;
268
314
}
269
315
}
270
316
}
271
317
}
272
318
319
+ fn shadow_in_current ( cx : ctx , p : fn ( node_id ) -> bool ) {
320
+ let out = [ ] ;
321
+ cx. current <-> out;
322
+ for e in out { if !p ( e. def ) { cx. current += [ e] ; } }
323
+ }
324
+
273
325
fn clear_in_current ( cx : ctx , my_def : node_id , to : bool ) {
274
- for { def, exprs } in cx. current {
326
+ for { def, uses } in cx. current {
275
327
if def == my_def {
276
- list:: iter ( exprs) { |expr|
277
- if !to || !cx. last_uses . contains_key ( expr) {
278
- cx. last_uses . insert ( expr, to) ;
328
+ list:: iter ( uses) { |use|
329
+ let key = alt use {
330
+ var_use( pth_id) { path ( pth_id) }
331
+ close_over ( fn_id) { close ( fn_id, def) }
332
+ } ;
333
+ if !to || !cx. last_uses . contains_key ( key) {
334
+ cx. last_uses . insert ( key, to) ;
279
335
}
280
336
}
281
- cx. current = vec:: filter ( copy cx. current ,
282
- { |x| x. def != my_def} ) ;
337
+ cx. current = vec:: filter ( copy cx. current , { |x| x. def != my_def} ) ;
283
338
break ;
284
339
}
285
340
}
286
341
}
287
342
288
- fn clear_def_if_path ( cx : ctx , d : def , to : bool )
289
- -> option < node_id > {
343
+ fn def_is_owned_local ( cx : ctx , d : def ) -> option < node_id > {
290
344
alt d {
291
- def_local( nid) {
292
- clear_in_current ( cx, nid, to) ;
293
- some ( nid)
294
- }
295
- def_arg ( nid, m) {
345
+ def_local( id) { some ( id) }
346
+ def_arg ( id, m) {
296
347
alt ty:: resolved_mode ( cx. tcx , m) {
297
- by_copy | by_move {
298
- clear_in_current( cx, nid, to) ;
299
- some ( nid)
300
- }
301
- by_ref | by_val | by_mutbl_ref {
302
- none
303
- }
348
+ by_copy | by_move { some( id) }
349
+ by_ref | by_val | by_mutbl_ref { none }
304
350
}
305
351
}
306
- _ {
307
- none
352
+ def_upvar ( _, d, fn_id) {
353
+ if is_blockish ( ty:: ty_fn_proto ( ty:: node_id_to_type ( cx. tcx , fn_id) ) ) {
354
+ def_is_owned_local ( cx, * d)
355
+ } else { none }
308
356
}
357
+ _ { none }
309
358
}
310
359
}
311
360
312
- fn clear_if_path ( cx : ctx , ex: @expr, v : visit:: vt < ctx > , to : bool )
313
- -> option < node_id > {
361
+ fn clear_def_if_local ( cx : ctx , d : def , to : bool ) {
362
+ alt def_is_owned_local ( cx, d) {
363
+ some ( nid) { clear_in_current ( cx, nid, to) ; }
364
+ _ { }
365
+ }
366
+ }
367
+
368
+ fn clear_if_path ( cx : ctx , ex: @expr, v : visit:: vt < ctx > , to : bool ) {
314
369
alt ex. node {
315
- expr_path ( _) {
316
- ret clear_def_if_path ( cx, cx. def_map . get ( ex. id ) , to) ;
317
- }
370
+ expr_path ( _) { clear_def_if_local ( cx, cx. def_map . get ( ex. id ) , to) ; }
318
371
_ { v. visit_expr ( ex, cx, v) ; }
319
372
}
320
- ret option:: none;
321
373
}
0 commit comments