@@ -30,35 +30,53 @@ type restrict = @rec(vec[def_num] root_vars,
30
30
vec[ ty:: t ] tys ,
31
31
vec[ uint] depends_on ,
32
32
mutable valid ok) ;
33
+ type scope = vec[ restrict ] ;
33
34
34
- type scope = rec ( vec[ tup( def_num, ast:: mode) ] args ,
35
- vec[ restrict] rs ) ;
36
- fn scope ( & scope sc, vec[ restrict] add ) -> scope {
37
- ret rec ( args=sc. args , rs=sc. rs + add) ;
35
+ tag local_info {
36
+ arg( ast:: mode) ;
37
+ objfield ( ast:: mutability) ;
38
38
}
39
39
40
40
type ctx = rec ( @ty:: ctxt tcx,
41
- resolve:: def_map dm) ;
41
+ resolve:: def_map dm,
42
+ std:: map:: hashmap[ def_num, local_info] local_map ) ;
42
43
43
44
fn check_crate ( @ty:: ctxt tcx, resolve:: def_map dm, & @ast:: crate crate) {
44
- auto cx = @rec ( tcx = tcx, dm = dm) ;
45
- auto v = @rec ( visit_fn = visit_fn,
45
+ auto cx = @rec ( tcx = tcx,
46
+ dm = dm,
47
+ // Stores information about object fields and function
48
+ // arguments that's otherwise not easily available.
49
+ local_map = util:: common:: new_int_hash ( ) ) ;
50
+ auto v = @rec ( visit_fn = bind visit_fn ( cx, _, _, _, _, _, _, _, _) ,
51
+ visit_item = bind visit_item ( cx, _, _, _) ,
46
52
visit_expr = bind visit_expr ( cx, _, _, _)
47
53
with * visit:: default_visitor[ scope] ( ) ) ;
48
- visit:: visit_crate ( * crate , rec ( args= [ ] , rs= [ ] ) , visit:: vtor ( v) ) ;
54
+ visit:: visit_crate ( * crate , [ ] , visit:: vtor ( v) ) ;
49
55
}
50
56
51
- fn visit_fn ( & ast:: _fn f, & vec[ ast:: ty_param ] tp , & span sp, & ident name,
52
- & ast:: def_id d_id, & ast:: ann a, & scope sc, & vt[ scope] v ) {
57
+ fn visit_fn ( @ctx cx , & ast:: _fn f, & vec[ ast:: ty_param ] tp , & span sp,
58
+ & ident name, & ast:: def_id d_id, & ast:: ann a, & scope sc,
59
+ & vt[ scope] v ) {
53
60
visit:: visit_fn_decl ( f. decl , sc, v) ;
54
- auto args = [ ] ;
55
- for ( ast:: arg arg in f. decl. inputs) {
56
- vec:: push ( args, tup ( arg. id . _1 , arg. mode ) ) ;
61
+ for ( ast:: arg arg_ in f. decl. inputs) {
62
+ cx. local_map . insert ( arg_. id . _1 , arg ( arg_. mode ) ) ;
57
63
}
58
- vt ( v) . visit_block ( f. body , rec ( args=args , rs= [ ] ) , v) ;
64
+ vt ( v) . visit_block ( f. body , [ ] , v) ;
59
65
}
60
66
61
- fn visit_expr ( & @ctx cx , & @ast:: expr ex, & scope sc, & vt[ scope] v ) {
67
+ fn visit_item ( @ctx cx , & @ast:: item i, & scope sc, & vt[ scope] v ) {
68
+ alt ( i. node ) {
69
+ case ( ast:: item_obj ( _, ?o, _, _, _) ) {
70
+ for ( ast:: obj_field f in o. fields) {
71
+ cx. local_map . insert ( f. id . _1 , objfield ( f. mut ) ) ;
72
+ }
73
+ }
74
+ case ( _) { }
75
+ }
76
+ visit:: visit_item ( i, sc, v) ;
77
+ }
78
+
79
+ fn visit_expr ( @ctx cx , & @ast:: expr ex, & scope sc, & vt[ scope] v ) {
62
80
auto handled = false ;
63
81
alt ( ex. node ) {
64
82
case ( ast:: expr_call ( ?f, ?args, _) ) {
@@ -193,7 +211,7 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
193
211
// Ensure we're not passing a root by mutable alias.
194
212
for ( tup( uint, def_num) root in mut_roots) {
195
213
auto mut_alias_to_root = vec:: count( root. _1, roots) > 1 u;
196
- for ( restrict r in sc. rs ) {
214
+ for ( restrict r in sc) {
197
215
if ( vec:: member( root. _1, r. root_vars) ) {
198
216
mut_alias_to_root = true ;
199
217
}
@@ -225,12 +243,12 @@ fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms,
225
243
auto dnums = arm_defnums( a) ;
226
244
auto new_sc = sc;
227
245
if ( vec:: len( dnums) > 0 u) {
228
- new_sc = scope ( sc , [ @rec( root_vars=roots,
229
- block_defnum=dnums. ( 0 ) ,
230
- bindings=dnums,
231
- tys=forbidden_tp,
232
- depends_on=deps( sc, roots) ,
233
- mutable ok=valid) ] ) ;
246
+ new_sc = sc + [ @rec( root_vars=roots,
247
+ block_defnum=dnums. ( 0 ) ,
248
+ bindings=dnums,
249
+ tys=forbidden_tp,
250
+ depends_on=deps( sc, roots) ,
251
+ mutable ok=valid) ] ;
234
252
}
235
253
visit:: visit_arm( a, new_sc, v) ;
236
254
}
@@ -269,7 +287,7 @@ fn check_for_each(&ctx cx, &@ast::local local, &@ast::expr call,
269
287
tys=data. unsafe_ts,
270
288
depends_on=deps( sc, data. root_vars) ,
271
289
mutable ok=valid) ;
272
- visit:: visit_block( block, scope ( sc , [ new_sc] ) , v) ;
290
+ visit:: visit_block( block, sc + [ new_sc] , v) ;
273
291
}
274
292
}
275
293
}
@@ -303,7 +321,7 @@ fn check_for(&ctx cx, &@ast::local local, &@ast::expr seq,
303
321
tys=unsafe ,
304
322
depends_on=deps( sc, root_def) ,
305
323
mutable ok=valid) ;
306
- visit:: visit_block( block, scope ( sc , [ new_sc] ) , v) ;
324
+ visit:: visit_block( block, sc + [ new_sc] , v) ;
307
325
}
308
326
309
327
fn check_var( & ctx cx, & @ast:: expr ex, & ast:: path p, ast:: ann ann, bool assign,
@@ -312,7 +330,7 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign,
312
330
if ( !def_is_local( def) ) { ret; }
313
331
auto my_defnum = ast:: def_id_of_def( def) . _1;
314
332
auto var_t = ty:: expr_ty( * cx. tcx, ex) ;
315
- for ( restrict r in sc. rs ) {
333
+ for ( restrict r in sc) {
316
334
// excludes variables introduced since the alias was made
317
335
if ( my_defnum < r. block_defnum) {
318
336
for ( ty:: t t in r. tys) {
@@ -334,13 +352,16 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
334
352
alt ( dest. node ) {
335
353
case ( ast:: expr_path ( ?p, ?ann) ) {
336
354
auto dnum = ast:: def_id_of_def ( cx. dm . get ( ann. id ) ) . _1 ;
337
- if ( is_immutable_alias ( sc, dnum) ) {
355
+ if ( is_immutable_alias ( cx , sc, dnum) ) {
338
356
cx. tcx . sess . span_err
339
357
( dest. span , "assigning to immutable alias" ) ;
358
+ } else if ( is_immutable_objfield ( cx, dnum) ) {
359
+ cx. tcx . sess . span_err
360
+ ( dest. span , "assigning to immutable obj field" ) ;
340
361
}
341
362
342
363
auto var_t = ty:: expr_ty ( * cx. tcx , dest) ;
343
- for ( restrict r in sc. rs ) {
364
+ for ( restrict r in sc) {
344
365
if ( vec:: member ( dnum, r. root_vars ) ) {
345
366
r. ok = overwritten ( dest. span , p) ;
346
367
}
@@ -365,21 +386,25 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
365
386
}
366
387
}
367
388
368
- fn is_immutable_alias ( & scope sc, def_num dnum) -> bool {
369
- for ( tup( def_num, ast:: mode) arg in sc. args) {
370
- if ( arg. _0 == dnum && arg. _1 == ast:: alias ( false ) ) { ret true ; }
389
+ fn is_immutable_alias ( & @ctx cx , & scope sc, def_num dnum) -> bool {
390
+ alt ( cx. local_map . find ( dnum) ) {
391
+ case ( some ( arg ( ast:: alias ( false ) ) ) ) { ret true ; }
392
+ case ( _) { }
371
393
}
372
- for ( restrict r in sc. rs ) {
394
+ for ( restrict r in sc) {
373
395
if ( vec:: member ( dnum, r. bindings ) ) { ret true ; }
374
396
}
375
397
ret false;
376
398
}
399
+ fn is_immutable_objfield ( & @ctx cx , def_num dnum) -> bool {
400
+ ret cx. local_map . find ( dnum) == some ( objfield ( ast:: imm) ) ;
401
+ }
377
402
378
403
fn test_scope ( & ctx cx, & scope sc, & restrict r, & ast:: path p) {
379
404
auto prob = r. ok ;
380
405
for ( uint dep in r. depends_on) {
381
406
if ( prob != valid) { break ; }
382
- prob = sc. rs . ( dep) . ok ;
407
+ prob = sc. ( dep) . ok ;
383
408
}
384
409
if ( prob != valid) {
385
410
auto msg = alt ( prob) {
@@ -399,7 +424,7 @@ fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) {
399
424
fn deps ( & scope sc, vec[ def_num] roots ) -> vec[ uint ] {
400
425
auto i = 0 u;
401
426
auto result = [ ] ;
402
- for ( restrict r in sc. rs ) {
427
+ for ( restrict r in sc) {
403
428
for ( def_num dn in roots) {
404
429
if ( vec:: member ( dn, r. bindings ) ) {
405
430
vec:: push ( result, i) ;
0 commit comments