Skip to content

Commit c7ab88c

Browse files
committed
Implement checking against assignments to immutable obj fields
1 parent b0d46ef commit c7ab88c

File tree

4 files changed

+61
-38
lines changed

4 files changed

+61
-38
lines changed

src/comp/middle/alias.rs

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,53 @@ type restrict = @rec(vec[def_num] root_vars,
3030
vec[ty::t] tys,
3131
vec[uint] depends_on,
3232
mutable valid ok);
33+
type scope = vec[restrict];
3334

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);
3838
}
3939

4040
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);
4243

4344
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, _, _, _),
4652
visit_expr = bind visit_expr(cx, _, _, _)
4753
with *visit::default_visitor[scope]());
48-
visit::visit_crate(*crate, rec(args=[], rs=[]), visit::vtor(v));
54+
visit::visit_crate(*crate, [], visit::vtor(v));
4955
}
5056

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) {
5360
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));
5763
}
58-
vt(v).visit_block(f.body, rec(args=args, rs=[]), v);
64+
vt(v).visit_block(f.body, [], v);
5965
}
6066

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) {
6280
auto handled = false;
6381
alt (ex.node) {
6482
case (ast::expr_call(?f, ?args, _)) {
@@ -193,7 +211,7 @@ fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc)
193211
// Ensure we're not passing a root by mutable alias.
194212
for (tup(uint, def_num) root in mut_roots) {
195213
auto mut_alias_to_root = vec::count(root._1, roots) > 1u;
196-
for (restrict r in sc.rs) {
214+
for (restrict r in sc) {
197215
if (vec::member(root._1, r.root_vars)) {
198216
mut_alias_to_root = true;
199217
}
@@ -225,12 +243,12 @@ fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms,
225243
auto dnums = arm_defnums(a);
226244
auto new_sc = sc;
227245
if (vec::len(dnums) > 0u) {
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)];
234252
}
235253
visit::visit_arm(a, new_sc, v);
236254
}
@@ -269,7 +287,7 @@ fn check_for_each(&ctx cx, &@ast::local local, &@ast::expr call,
269287
tys=data.unsafe_ts,
270288
depends_on=deps(sc, data.root_vars),
271289
mutable ok=valid);
272-
visit::visit_block(block, scope(sc, [new_sc]), v);
290+
visit::visit_block(block, sc + [new_sc], v);
273291
}
274292
}
275293
}
@@ -303,7 +321,7 @@ fn check_for(&ctx cx, &@ast::local local, &@ast::expr seq,
303321
tys=unsafe,
304322
depends_on=deps(sc, root_def),
305323
mutable ok=valid);
306-
visit::visit_block(block, scope(sc, [new_sc]), v);
324+
visit::visit_block(block, sc + [new_sc], v);
307325
}
308326

309327
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,
312330
if (!def_is_local(def)) { ret; }
313331
auto my_defnum = ast::def_id_of_def(def)._1;
314332
auto var_t = ty::expr_ty(*cx.tcx, ex);
315-
for (restrict r in sc.rs) {
333+
for (restrict r in sc) {
316334
// excludes variables introduced since the alias was made
317335
if (my_defnum < r.block_defnum) {
318336
for (ty::t t in r.tys) {
@@ -334,13 +352,16 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
334352
alt (dest.node) {
335353
case (ast::expr_path(?p, ?ann)) {
336354
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)) {
338356
cx.tcx.sess.span_err
339357
(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");
340361
}
341362

342363
auto var_t = ty::expr_ty(*cx.tcx, dest);
343-
for (restrict r in sc.rs) {
364+
for (restrict r in sc) {
344365
if (vec::member(dnum, r.root_vars)) {
345366
r.ok = overwritten(dest.span, p);
346367
}
@@ -365,21 +386,25 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
365386
}
366387
}
367388

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 (_) {}
371393
}
372-
for (restrict r in sc.rs) {
394+
for (restrict r in sc) {
373395
if (vec::member(dnum, r.bindings)) { ret true; }
374396
}
375397
ret false;
376398
}
399+
fn is_immutable_objfield(&@ctx cx, def_num dnum) -> bool {
400+
ret cx.local_map.find(dnum) == some(objfield(ast::imm));
401+
}
377402

378403
fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) {
379404
auto prob = r.ok;
380405
for (uint dep in r.depends_on) {
381406
if (prob != valid) { break; }
382-
prob = sc.rs.(dep).ok;
407+
prob = sc.(dep).ok;
383408
}
384409
if (prob != valid) {
385410
auto msg = alt (prob) {
@@ -399,7 +424,7 @@ fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) {
399424
fn deps(&scope sc, vec[def_num] roots) -> vec[uint] {
400425
auto i = 0u;
401426
auto result = [];
402-
for (restrict r in sc.rs) {
427+
for (restrict r in sc) {
403428
for (def_num dn in roots) {
404429
if (vec::member(dn, r.bindings)) {
405430
vec::push(result, i);

src/comp/middle/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type visitor[E] =
2424
fn(&@view_item v, &E e, &vt[E] v) visit_view_item,
2525
fn(&@native_item i, &E e, &vt[E] v) visit_native_item,
2626
fn(&@item i, &E e, &vt[E] v) visit_item,
27-
fn(&@local l, &E e, &vt[E] v) visit_local,
27+
fn(&@local l, &E e, &vt[E] v) visit_local,
2828
fn(&block b, &E e, &vt[E] v) visit_block,
2929
fn(&@stmt s, &E e, &vt[E] v) visit_stmt,
3030
fn(&arm a, &E e, &vt[E] v) visit_arm,

src/test/compile-fail/writing-to-immutable-obj.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// xfail-stage0
2-
// xfail-stage1
3-
// xfail-stage2
4-
// error-pattern: writing to immutable type
2+
// error-pattern:assigning to immutable obj field
53
obj objy(int x) {
64
fn foo() -> () {
75
x = 5;

src/test/run-pass/vec-append.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn slow_growth() {
3030

3131
fn slow_growth2_helper(str s) { // ref up: s
3232

33-
obj acc(vec[str] v) {
33+
obj acc(mutable vec[str] v) {
3434
fn add(&str s) { v += [s]; }
3535
}
3636

0 commit comments

Comments
 (0)