1
1
2
2
import syntax:: { ast, ast_util} ;
3
3
import ast:: { ident, fn_ident, node_id, def_id} ;
4
- import mut:: { mut_field, deref, field, index, unbox} ;
5
4
import syntax:: codemap:: span;
6
5
import syntax:: visit;
7
6
import visit:: vt;
@@ -15,11 +14,13 @@ import std::option::{some, none, is_none};
15
14
tag valid { valid; overwritten ( span, ast:: path) ; val_taken ( span, ast:: path) ; }
16
15
tag copied { not_allowed; copied; not_copied; }
17
16
17
+ tag unsafe_ty { contains( ty:: t) ; mut_contains ( ty:: t) ; }
18
+
18
19
type binding = @{ node_id: node_id,
19
20
span: span,
20
21
root_var: option:: t<node_id>,
21
22
local_id: uint,
22
- unsafe_tys: [ ty :: t ] ,
23
+ unsafe_tys: [ unsafe_ty ] ,
23
24
mutable ok: valid,
24
25
mutable copied: copied} ;
25
26
@@ -28,7 +29,7 @@ tag ret_info { by_ref(bool, node_id); other; }
28
29
type scope = { bs : [ binding ] , ret_info : ret_info } ;
29
30
30
31
fn mk_binding ( cx : ctx , id : node_id , span : span , root_var : option:: t < node_id > ,
31
- unsafe : [ ty :: t ] ) -> binding {
32
+ unsafe : [ unsafe_ty ] ) -> binding {
32
33
ret @{ node_id : id, span : span, root_var : root_var,
33
34
local_id : local_id_of_node ( cx, id) ,
34
35
unsafe_tys : unsafe , mutable ok: valid,
@@ -92,7 +93,7 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
92
93
alt val {
93
94
some( ex) {
94
95
let root = expr_root ( * cx, ex, false ) ;
95
- if mut_field ( root. ds ) {
96
+ if ! is_none ( root. mut ) {
96
97
cx. tcx . sess . span_err ( ex. span ,
97
98
"result of put must be" +
98
99
" immutably rooted" ) ;
@@ -185,9 +186,9 @@ fn add_bindings_for_let(cx: ctx, &bs: [binding], loc: @ast::local) {
185
186
cx. tcx . sess . span_err ( loc. span , "a reference binding can't be \
186
187
rooted in a temporary") ;
187
188
}
188
- for proot in * pattern_roots ( cx. tcx , * root. ds , loc. node . pat ) {
189
+ for proot in pattern_roots ( cx. tcx , root. mut , loc. node . pat ) {
189
190
let bnd = mk_binding ( cx, proot. id , proot. span , root_var,
190
- inner_mut ( proot. ds ) ) ;
191
+ unsafe_set ( proot. mut ) ) ;
191
192
// Don't implicitly copy explicit references
192
193
bnd. copied = not_allowed;
193
194
bs += [ bnd] ;
@@ -246,7 +247,7 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
246
247
span: arg. span ,
247
248
root_var: root_var,
248
249
local_id: 0 u,
249
- unsafe_tys: inner_mut ( root. ds ) ,
250
+ unsafe_tys: unsafe_set ( root. mut ) ,
250
251
mutable ok: valid,
251
252
mutable copied: alt arg_t. mode {
252
253
ast:: by_move. { copied }
@@ -276,12 +277,13 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
276
277
}
277
278
let j = 0 u;
278
279
for b in bindings {
279
- for ty in b. unsafe_tys {
280
+ for unsafe in b. unsafe_tys {
280
281
let i = 0 u;
281
282
for arg_t: ty:: arg in arg_ts {
282
283
let mut_alias = arg_t. mode == ast:: by_mut_ref;
283
284
if i != j &&
284
- ty_can_unsafely_include ( cx, ty, arg_t. ty , mut_alias) &&
285
+ ty_can_unsafely_include ( cx, unsafe , arg_t. ty ,
286
+ mut_alias) &&
285
287
cant_copy ( cx, b) {
286
288
cx. tcx . sess . span_err
287
289
( args[ i] . span ,
@@ -323,7 +325,7 @@ fn check_ret_ref(cx: ctx, sc: scope, mut: bool, arg_node_id: node_id,
323
325
expr : @ast:: expr ) {
324
326
let root = expr_root ( cx, expr, false ) ;
325
327
let bad = none;
326
- let mut_field = mut_field ( root. ds ) ;
328
+ let mut_field = ! is_none ( root. mut ) ;
327
329
alt path_def( cx, root. ex ) {
328
330
none. {
329
331
bad = some ( "a temporary" ) ;
@@ -388,18 +390,18 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
388
390
let new_bs = sc. bs ;
389
391
let root_var = path_def_id ( cx, root. ex ) ;
390
392
let pat_id_map = ast_util:: pat_id_map ( a. pats [ 0 ] ) ;
391
- type info = { id : node_id , mutable unsafe: [ ty :: t ] , span : span } ;
393
+ type info = { id : node_id , mutable unsafe: [ unsafe_ty ] , span : span } ;
392
394
let binding_info: [ info ] = [ ] ;
393
395
for pat in a. pats {
394
- for proot in * pattern_roots ( cx. tcx , * root. ds , pat) {
396
+ for proot in pattern_roots ( cx. tcx , root. mut , pat) {
395
397
let canon_id = pat_id_map. get ( proot. name ) ;
396
398
// FIXME I wanted to use a block here, but that hit bug #913
397
399
fn match ( x : info , canon : node_id ) -> bool { x. id == canon }
398
400
alt vec:: find ( bind match( _, canon_id) , binding_info) {
399
- some ( s) { s. unsafe += inner_mut ( proot. ds ) ; }
401
+ some ( s) { s. unsafe += unsafe_set ( proot. mut ) ; }
400
402
none. {
401
403
binding_info += [ { id: canon_id,
402
- mutable unsafe: inner_mut ( proot. ds ) ,
404
+ mutable unsafe: unsafe_set ( proot. mut ) ,
403
405
span: proot. span } ] ;
404
406
}
405
407
}
@@ -419,9 +421,9 @@ fn check_for_each(cx: ctx, local: @ast::local, call: @ast::expr,
419
421
alt call. node {
420
422
ast:: expr_call ( f, args) {
421
423
let new_bs = sc. bs + check_call ( cx, f, args) ;
422
- for proot in * pattern_roots ( cx. tcx , [ ] , local. node . pat ) {
424
+ for proot in pattern_roots ( cx. tcx , none , local. node . pat ) {
423
425
new_bs += [ mk_binding ( cx, proot. id , proot. span , none,
424
- inner_mut ( proot. ds ) ) ] ;
426
+ unsafe_set ( proot. mut ) ) ] ;
425
427
}
426
428
visit:: visit_block ( blk, { bs: new_bs with sc} , v) ;
427
429
}
@@ -435,20 +437,20 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
435
437
436
438
// If this is a mutable vector, don't allow it to be touched.
437
439
let seq_t = ty:: expr_ty ( cx. tcx , seq) ;
438
- let ext_ds = * root. ds ;
440
+ let cur_mut = root. mut ;
439
441
alt ty:: struct ( cx. tcx , seq_t) {
440
442
ty:: ty_vec ( mt) {
441
443
if mt. mut != ast:: imm {
442
- ext_ds += [ @ { mut : true , kind : index , outer_t : seq_t} ] ;
444
+ cur_mut = some ( contains ( seq_t) ) ;
443
445
}
444
446
}
445
447
_ { }
446
448
}
447
449
let root_var = path_def_id ( cx, root. ex ) ;
448
450
let new_bs = sc. bs ;
449
- for proot in * pattern_roots ( cx. tcx , ext_ds , local. node . pat ) {
451
+ for proot in pattern_roots ( cx. tcx , cur_mut , local. node . pat ) {
450
452
new_bs += [ mk_binding ( cx, proot. id , proot. span , root_var,
451
- inner_mut ( proot. ds ) ) ] ;
453
+ unsafe_set ( proot. mut ) ) ] ;
452
454
}
453
455
visit:: visit_block ( blk, { bs: new_bs with sc} , v) ;
454
456
}
@@ -463,8 +465,8 @@ fn check_var(cx: ctx, ex: @ast::expr, p: ast::path, id: ast::node_id,
463
465
for b in sc. bs {
464
466
// excludes variables introduced since the alias was made
465
467
if my_local_id < b. local_id {
466
- for ty in b. unsafe_tys {
467
- if ty_can_unsafely_include ( cx, ty , var_t, assign) {
468
+ for unsafe in b. unsafe_tys {
469
+ if ty_can_unsafely_include ( cx, unsafe , var_t, assign) {
468
470
b. ok = val_taken ( ex. span , p) ;
469
471
}
470
472
}
@@ -539,14 +541,17 @@ fn path_def_id(cx: ctx, ex: @ast::expr) -> option::t<ast::node_id> {
539
541
}
540
542
}
541
543
542
- fn ty_can_unsafely_include ( cx : ctx , needle : ty :: t , haystack : ty:: t , mut : bool )
543
- -> bool {
544
+ fn ty_can_unsafely_include ( cx : ctx , needle : unsafe_ty , haystack : ty:: t ,
545
+ mut : bool ) -> bool {
544
546
fn get_mut ( cur : bool , mt : ty:: mt ) -> bool {
545
547
ret cur || mt. mut != ast:: imm;
546
548
}
547
- fn helper ( tcx : ty:: ctxt , needle : ty:: t , haystack : ty:: t , mut : bool ) ->
548
- bool {
549
- if needle == haystack { ret true ; }
549
+ fn helper ( tcx : ty:: ctxt , needle : unsafe_ty , haystack : ty:: t , mut : bool )
550
+ -> bool {
551
+ if alt needle {
552
+ contains ( ty) { ty == haystack }
553
+ mut_contains ( ty) { mut && ty == haystack }
554
+ } { ret true ; }
550
555
alt ty:: struct ( tcx, haystack) {
551
556
ty:: ty_tag ( _, ts) {
552
557
for t: ty:: t in ts {
@@ -570,23 +575,13 @@ fn ty_can_unsafely_include(cx: ctx, needle: ty::t, haystack: ty::t, mut: bool)
570
575
for t in ts { if helper ( tcx, needle, t, mut) { ret true ; } }
571
576
ret false;
572
577
}
573
-
574
-
575
-
576
-
577
-
578
578
// These may contain anything.
579
- ty:: ty_fn ( _, _, _, _, _) {
580
- ret true ;
581
- }
582
- ty:: ty_obj ( _) { ret true ; }
579
+ ty:: ty_fn ( _, _, _, _, _) | ty:: ty_obj ( _) { ret true ; }
583
580
// A type param may include everything, but can only be
584
581
// treated as opaque downstream, and is thus safe unless we
585
582
// saw mutable fields, in which case the whole thing can be
586
583
// overwritten.
587
- ty:: ty_param ( _, _) {
588
- ret mut;
589
- }
584
+ ty:: ty_param ( _, _) { ret mut; }
590
585
_ { ret false; }
591
586
}
592
587
}
@@ -640,49 +635,53 @@ fn copy_is_expensive(tcx: ty::ctxt, ty: ty::t) -> bool {
640
635
ret score_ty( tcx, ty) > 8 u;
641
636
}
642
637
643
- type pattern_root = { id : node_id , name : ident, ds : @[ deref ] , span : span } ;
638
+ type pattern_root = { id : node_id ,
639
+ name : ident,
640
+ mut : option:: t < unsafe_ty > ,
641
+ span : span } ;
644
642
645
- fn pattern_roots ( tcx : ty:: ctxt , base : [ deref ] , pat : @ast:: pat )
646
- -> @ [ pattern_root ] {
647
- fn walk ( tcx : ty:: ctxt , base : [ deref ] , pat : @ast:: pat ,
643
+ fn pattern_roots ( tcx : ty:: ctxt , mut : option :: t < unsafe_ty > , pat : @ast:: pat )
644
+ -> [ pattern_root ] {
645
+ fn walk ( tcx : ty:: ctxt , mut : option :: t < unsafe_ty > , pat : @ast:: pat ,
648
646
& set: [ pattern_root ] ) {
649
647
alt pat. node {
650
648
ast:: pat_wild. | ast:: pat_lit ( _) { }
651
649
ast:: pat_bind ( nm) {
652
- set += [ { id: pat. id , name: nm, ds : @base , span: pat. span } ] ;
650
+ set += [ { id: pat. id , name: nm, mut : mut , span: pat. span } ] ;
653
651
}
654
652
ast:: pat_tag ( _, ps) | ast:: pat_tup ( ps) {
655
- let base = base + [ @{ mut: false , kind: field,
656
- outer_t: ty:: node_id_to_type ( tcx, pat. id ) } ] ;
657
- for p in ps { walk ( tcx, base, p, set) ; }
653
+ for p in ps { walk ( tcx, mut, p, set) ; }
658
654
}
659
655
ast:: pat_rec ( fs, _) {
660
656
let ty = ty:: node_id_to_type ( tcx, pat. id ) ;
661
657
for f in fs {
662
- let mut = ty:: get_field ( tcx, ty, f. ident ) . mt . mut != ast:: imm;
663
- let base = base + [ @{ mut: mut , kind: field, outer_t: ty} ] ;
664
- walk ( tcx, base, f. pat , set) ;
658
+ let m = ty:: get_field ( tcx, ty, f. ident ) . mt . mut != ast:: imm;
659
+ walk ( tcx, m ? some ( contains ( ty) ) : mut , f. pat , set) ;
665
660
}
666
661
}
667
662
ast:: pat_box ( p) {
668
663
let ty = ty:: node_id_to_type ( tcx, pat. id ) ;
669
- let mut = alt ty:: struct( tcx, ty) {
664
+ let m = alt ty:: struct ( tcx, ty) {
670
665
ty:: ty_box ( mt) { mt. mut != ast:: imm }
671
666
} ;
672
- walk ( tcx, base + [ @ { mut : mut , kind : unbox , outer_t : ty } ] , p, set) ;
667
+ walk ( tcx, m ? some ( contains ( ty ) ) : mut , p, set) ;
673
668
}
674
669
}
675
670
}
676
671
let set = [ ] ;
677
- walk ( tcx, base , pat, set) ;
678
- ret @ set;
672
+ walk ( tcx, mut , pat, set) ;
673
+ ret set;
679
674
}
680
675
681
676
// Wraps the expr_root in mut.rs to also handle roots that exist through
682
677
// return-by-reference
683
- fn expr_root ( cx : ctx , ex : @ast:: expr , autoderef : bool ) ->
684
- { ex : @ast:: expr , ds : @ [ deref ] } {
678
+ fn expr_root ( cx : ctx , ex : @ast:: expr , autoderef : bool )
679
+ -> { ex : @ast:: expr , mut : option :: t < unsafe_ty > } {
685
680
let base_root = mut:: expr_root ( cx. tcx , ex, autoderef) ;
681
+ let unsafe = none;
682
+ for d in * base_root. ds {
683
+ if d. mut { unsafe = some ( contains ( d. outer_t ) ) ; break ; }
684
+ }
686
685
if is_none ( path_def_id ( cx, base_root. ex ) ) {
687
686
alt base_root. ex . node {
688
687
ast:: expr_call ( f, args) {
@@ -691,24 +690,24 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool) ->
691
690
ast:: return_ref ( mut, arg_n) {
692
691
let arg = args[ arg_n - 1 u] ;
693
692
let arg_root = expr_root ( cx, arg, false ) ;
694
- ret { ex : arg_root. ex ,
695
- ds : @( * arg_root. ds +
696
- ( mut ? [ @{ mut: true , kind: unbox,
697
- outer_t: ty:: expr_ty ( cx. tcx , arg) } ] : [ ] )
698
- + * base_root. ds ) } ;
693
+ if mut {
694
+ let ret_ty = ty:: expr_ty ( cx. tcx , base_root. ex ) ;
695
+ unsafe = some ( mut_contains ( ret_ty) ) ;
696
+ }
697
+ if !is_none ( arg_root. mut ) { unsafe = arg_root. mut ; }
698
+ ret { ex : arg_root. ex , mut: unsafe } ;
699
699
}
700
700
_ { }
701
701
}
702
702
}
703
703
_ { }
704
704
}
705
705
}
706
- ret base_root;
706
+ ret { ex : base_root. ex , mut : unsafe } ;
707
707
}
708
708
709
- fn inner_mut ( ds : @[ deref ] ) -> [ ty:: t ] {
710
- for d: deref in * ds { if d. mut { ret [ d. outer_t ] ; } }
711
- ret [ ] ;
709
+ fn unsafe_set ( from : option:: t < unsafe_ty > ) -> [ unsafe_ty ] {
710
+ alt from { some( t) { [ t] } _ { [ ] } }
712
711
}
713
712
714
713
// Local Variables:
0 commit comments