1
1
2
2
import syntax:: { ast, ast_util} ;
3
3
import ast:: { ident, fn_ident, node_id, def_id} ;
4
- import mut:: { expr_root, mut_field, inner_mut } ;
4
+ import mut:: { expr_root, mut_field, deref , field , index , unbox } ;
5
5
import syntax:: codemap:: span;
6
6
import syntax:: visit;
7
7
import visit:: vt;
@@ -21,7 +21,7 @@ type restrict =
21
21
span: span,
22
22
local_id: uint,
23
23
bindings: [ node_id] ,
24
- unsafe_ty : option :: t< ty:: t> ,
24
+ unsafe_tys : [ ty:: t] ,
25
25
depends_on: [ uint] ,
26
26
mutable ok: valid,
27
27
mutable given_up: bool} ;
@@ -192,21 +192,17 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr], sc: scope) ->
192
192
}
193
193
}
194
194
let root_var = path_def_id ( cx, root. ex ) ;
195
- let unsafe_t =
196
- alt inner_mut ( root. ds ) { some ( t) { some ( t) } _ { none } } ;
197
- restricts +=
198
- [
199
- // FIXME kludge
200
- @{ root_var: root_var,
201
- node_id: arg_t. mode == ast:: by_mut_ref ? 0 : arg. id ,
202
- ty: arg_t. ty ,
203
- span: arg. span ,
204
- local_id: cx. next_local ,
205
- bindings: [ arg. id ] ,
206
- unsafe_ty: unsafe_t,
207
- depends_on : deps( sc, root_var) ,
208
- mutable ok: valid,
209
- mutable given_up: arg_t. mode == ast:: by_move} ] ;
195
+ restricts += [ @{ root_var: root_var,
196
+ // FIXME kludge
197
+ node_id: arg_t. mode == ast:: by_mut_ref ? 0 : arg. id ,
198
+ ty: arg_t. ty ,
199
+ span: arg. span ,
200
+ local_id: cx. next_local ,
201
+ bindings: [ arg. id ] ,
202
+ unsafe_tys: inner_mut ( root. ds ) ,
203
+ depends_on : deps( sc, root_var) ,
204
+ mutable ok: valid,
205
+ mutable given_up: arg_t. mode == ast:: by_move} ] ;
210
206
i += 1 u;
211
207
}
212
208
let f_may_close =
@@ -217,7 +213,7 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr], sc: scope) ->
217
213
if f_may_close {
218
214
let i = 0 u;
219
215
for r in restricts {
220
- if !option :: is_none ( r. unsafe_ty ) && cant_copy ( cx, r) {
216
+ if vec :: len ( r. unsafe_tys ) > 0 u && cant_copy ( cx, r) {
221
217
cx. tcx . sess . span_err ( f. span ,
222
218
#fmt[ "function may alias with argument \
223
219
%u, which is not immutably rooted",
@@ -228,8 +224,7 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr], sc: scope) ->
228
224
}
229
225
let j = 0 u;
230
226
for r in restricts {
231
- alt r. unsafe_ty {
232
- some ( ty) {
227
+ for ty in r. unsafe_tys {
233
228
let i = 0 u;
234
229
for arg_t: ty:: arg in arg_ts {
235
230
let mut_alias = arg_t. mode == ast:: by_mut_ref;
@@ -244,8 +239,6 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr], sc: scope) ->
244
239
}
245
240
i += 1 u;
246
241
}
247
- }
248
- _ { }
249
242
}
250
243
j += 1 u;
251
244
}
@@ -279,24 +272,42 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
279
272
v. visit_expr ( input, sc, v) ;
280
273
let root = expr_root ( cx. tcx , input, true ) ;
281
274
for a: ast:: arm in arms {
282
- let dnums = ast_util:: pat_binding_ids ( a. pats [ 0 ] ) ;
283
- let new_sc = sc;
284
- if vec:: len ( dnums) > 0 u {
285
- let root_var = path_def_id ( cx, root. ex ) ;
286
- // FIXME need to use separate restrict for each binding
287
- new_sc = @( * sc + [ @{ root_var: root_var,
288
- node_id: 0 ,
289
- ty: ty:: mk_int ( cx. tcx ) ,
290
- span: a. pats [ 0 ] . span ,
291
- local_id: cx. next_local ,
292
- bindings: dnums,
293
- unsafe_ty: inner_mut ( root. ds ) ,
294
- depends_on : deps( sc, root_var) ,
295
- mutable ok: valid,
296
- mutable given_up: false} ] ) ;
275
+ // FIXME handle other | patterns
276
+ let new_sc = * sc;
277
+ let root_var = path_def_id ( cx, root. ex ) ;
278
+ let pat_id_map = ast_util:: pat_id_map ( a. pats [ 0 ] ) ;
279
+ type info = { id : node_id , mutable unsafe: [ ty:: t ] , span : span } ;
280
+ let binding_info: [ info ] = [ ] ;
281
+ for pat in a. pats {
282
+ for proot in * pattern_roots ( cx. tcx , root. ds , pat) {
283
+ let canon_id = pat_id_map. get ( proot. name ) ;
284
+ // FIXME I wanted to use a block, but that hit a
285
+ // typestate bug.
286
+ fn match ( x : info , canon : node_id ) -> bool { x. id == canon }
287
+ alt vec:: find ( bind match( _, canon_id) , binding_info) {
288
+ some ( s) { s. unsafe += inner_mut ( proot. ds ) ; }
289
+ none. {
290
+ binding_info += [ { id: canon_id,
291
+ mutable unsafe: inner_mut ( proot. ds ) ,
292
+ span: proot. span } ] ;
293
+ }
294
+ }
295
+ }
296
+ }
297
+ for info in binding_info {
298
+ new_sc += [ @{ root_var: root_var,
299
+ node_id: info. id ,
300
+ ty: ty:: node_id_to_type ( cx. tcx , info. id ) ,
301
+ span: info. span ,
302
+ local_id: cx. next_local ,
303
+ bindings: [ info. id ] ,
304
+ unsafe_tys: info. unsafe ,
305
+ depends_on : deps( sc, root_var) ,
306
+ mutable ok: valid,
307
+ mutable given_up: false} ] ;
297
308
}
298
309
register_locals ( cx, a. pats [ 0 ] ) ;
299
- visit:: visit_arm ( a, new_sc, v) ;
310
+ visit:: visit_arm ( a, @ new_sc, v) ;
300
311
}
301
312
}
302
313
@@ -323,7 +334,7 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
323
334
let elt_t;
324
335
alt ty:: struct ( cx. tcx , seq_t) {
325
336
ty:: ty_vec ( mt) {
326
- if mt. mut != ast:: imm { unsafe = some ( seq_t) ; }
337
+ if mt. mut != ast:: imm { unsafe = [ seq_t] ; }
327
338
elt_t = mt. ty ;
328
339
}
329
340
ty:: ty_str. { elt_t = ty:: mk_mach ( cx. tcx , ast:: ty_u8) ; }
@@ -337,7 +348,7 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
337
348
span: local. node . pat . span ,
338
349
local_id: cx. next_local ,
339
350
bindings: ast_util:: pat_binding_ids ( local. node . pat ) ,
340
- unsafe_ty : unsafe ,
351
+ unsafe_tys : unsafe ,
341
352
depends_on: deps ( sc, root_var) ,
342
353
mutable ok: valid,
343
354
mutable given_up: false } ;
@@ -354,16 +365,12 @@ fn check_var(cx: ctx, ex: @ast::expr, p: ast::path, id: ast::node_id,
354
365
alt cx. local_map . find ( my_defnum) { some ( local ( id) ) { id } _ { 0 u } } ;
355
366
let var_t = ty:: expr_ty ( cx. tcx , ex) ;
356
367
for r: restrict in * sc {
357
-
358
368
// excludes variables introduced since the alias was made
359
369
if my_local_id < r. local_id {
360
- alt r. unsafe_ty {
361
- some ( ty) {
370
+ for ty in r. unsafe_tys {
362
371
if ty_can_unsafely_include ( cx, ty, var_t, assign) {
363
372
r. ok = val_taken ( ex. span , p) ;
364
373
}
365
- }
366
- _ { }
367
374
}
368
375
} else if vec:: member ( my_defnum, r. bindings ) {
369
376
test_scope ( cx, sc, r, p) ;
@@ -546,6 +553,49 @@ fn copy_is_expensive(tcx: ty::ctxt, ty: ty::t) -> bool {
546
553
ret score_ty( tcx, ty) > 8 u;
547
554
}
548
555
556
+ type pattern_root = { id : node_id , name : ident, ds : @[ deref ] , span : span } ;
557
+
558
+ fn pattern_roots ( tcx : ty:: ctxt , base : @[ deref ] , pat : @ast:: pat )
559
+ -> @[ pattern_root ] {
560
+ fn walk ( tcx : ty:: ctxt , base : [ deref ] , pat : @ast:: pat ,
561
+ & set: [ pattern_root ] ) {
562
+ alt pat. node {
563
+ ast:: pat_wild. | ast:: pat_lit ( _) { }
564
+ ast:: pat_bind ( nm) {
565
+ set += [ { id: pat. id , name: nm, ds: @base, span: pat. span } ] ;
566
+ }
567
+ ast:: pat_tag ( _, ps) | ast:: pat_tup ( ps) {
568
+ let base = base + [ @{ mut: false , kind: field,
569
+ outer_t: ty:: node_id_to_type ( tcx, pat. id ) } ] ;
570
+ for p in ps { walk ( tcx, base, p, set) ; }
571
+ }
572
+ ast:: pat_rec ( fs, _) {
573
+ let ty = ty:: node_id_to_type ( tcx, pat. id ) ;
574
+ for f in fs {
575
+ let mut = ty:: get_field ( tcx, ty, f. ident ) . mt . mut != ast:: imm;
576
+ let base = base + [ @{ mut: mut , kind: field, outer_t: ty} ] ;
577
+ walk ( tcx, base, f. pat , set) ;
578
+ }
579
+ }
580
+ ast:: pat_box ( p) {
581
+ let ty = ty:: node_id_to_type ( tcx, pat. id ) ;
582
+ let mut = alt ty:: struct( tcx, ty) {
583
+ ty:: ty_box ( mt) { mt. mut != ast:: imm }
584
+ } ;
585
+ walk ( tcx, base + [ @{ mut: mut , kind: unbox, outer_t: ty} ] , p, set) ;
586
+ }
587
+ }
588
+ }
589
+ let set = [ ] ;
590
+ walk ( tcx, * base, pat, set) ;
591
+ ret @set;
592
+ }
593
+
594
+ fn inner_mut ( ds : @[ deref ] ) -> [ ty:: t ] {
595
+ for d: deref in * ds { if d. mut { ret [ d. outer_t ] ; } }
596
+ ret [ ] ;
597
+ }
598
+
549
599
// Local Variables:
550
600
// mode: rust
551
601
// fill-column: 78;
0 commit comments