Skip to content

Commit 9ba3fe5

Browse files
committed
Clean up handling of restriction contexts in alias analysis
1 parent 91f05fb commit 9ba3fe5

File tree

1 file changed

+94
-93
lines changed

1 file changed

+94
-93
lines changed

src/comp/middle/alias.rs

+94-93
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ import std::option::is_none;
2727
tag valid { valid; overwritten(span, ast::path); val_taken(span, ast::path); }
2828

2929
type restrict =
30-
@{root_vars: [node_id],
30+
@{root_var: option::t<node_id>,
3131
local_id: uint,
3232
bindings: [node_id],
33-
tys: [ty::t],
33+
unsafe_ty: option::t<ty::t>,
3434
depends_on: [uint],
3535
mutable ok: valid};
3636

@@ -86,12 +86,11 @@ fn visit_fn(cx: &@ctx, f: &ast::_fn, _tp: &[ast::ty_param], _sp: &span,
8686
for each nid in freevars::get_freevar_defs(cx.tcx, id).keys() {
8787
dnums += [nid];
8888
};
89-
@[
90-
// I'm not sure if there is anything sensical to put here
91-
@{root_vars: [],
89+
// I'm not sure if there is anything sensical to put here
90+
@[@{root_var: none,
9291
local_id: cx.next_local,
9392
bindings: dnums,
94-
tys: [],
93+
unsafe_ty: none,
9594
depends_on: [],
9695
mutable ok: valid}]
9796
}
@@ -195,14 +194,12 @@ fn visit_decl(cx: &@ctx, d: &@ast::decl, sc: &scope, v: &vt<scope>) {
195194
}
196195
}
197196

198-
fn check_call(cx: &ctx, f: &@ast::expr, args: &[@ast::expr], sc: &scope) ->
199-
{root_vars: [node_id], unsafe_ts: [ty::t]} {
197+
fn check_call(cx: &ctx, f: &@ast::expr, args: &[@ast::expr], sc: &scope)
198+
-> [restrict] {
200199
let fty = ty::expr_ty(cx.tcx, f);
201200
let arg_ts = fty_args(cx, fty);
202-
let roots: [node_id] = [];
203201
let mut_roots: [{arg: uint, node: node_id}] = [];
204-
let unsafe_ts: [ty::t] = [];
205-
let unsafe_t_offsets: [uint] = [];
202+
let restricts = [];
206203
let i = 0u;
207204
for arg_t: ty::arg in arg_ts {
208205
if arg_t.mode != ty::mo_val {
@@ -242,70 +239,83 @@ fn check_call(cx: &ctx, f: &@ast::expr, args: &[@ast::expr], sc: &scope) ->
242239
}
243240
}
244241
}
245-
alt path_def_id(cx, root.ex) {
246-
some(did) { roots += [did.node]; }
247-
_ { }
248-
}
249-
alt inner_mut(root.ds) {
250-
some(t) { unsafe_ts += [t]; unsafe_t_offsets += [i]; }
251-
_ { }
252-
}
242+
let root_var = path_def_id(cx, root.ex);
243+
let unsafe_t = alt inner_mut(root.ds) {
244+
some(t) { some(t) }
245+
_ { none }
246+
};
247+
restricts += [@{root_var: root_var,
248+
local_id: cx.next_local,
249+
bindings: [arg.id],
250+
unsafe_ty: unsafe_t,
251+
depends_on: deps(sc, root_var),
252+
mutable ok: valid}];
253253
}
254254
i += 1u;
255255
}
256-
if vec::len(unsafe_ts) > 0u {
257-
alt f.node {
258-
ast::expr_path(_) {
259-
if def_is_local(cx.tcx.def_map.get(f.id), true) {
256+
let f_may_close = alt f.node {
257+
ast::expr_path(_) { def_is_local(cx.tcx.def_map.get(f.id), true) }
258+
_ { false } // FIXME should be true!
259+
};
260+
if f_may_close {
261+
let i = 0u;
262+
for r in restricts {
263+
if !option::is_none(r.unsafe_ty) {
260264
cx.tcx.sess.span_err(f.span,
261-
#ifmt["function may alias with \
262-
argument %u, which is not immutably rooted",
263-
unsafe_t_offsets[0]]);
265+
#ifmt["function may alias with argument \
266+
%u, which is not immutably rooted",
267+
i]);
264268
}
265-
}
266-
_ { }
269+
i += 1u;
267270
}
268271
}
269272
let j = 0u;
270-
for unsafe: ty::t in unsafe_ts {
271-
let offset = unsafe_t_offsets[j];
272-
j += 1u;
273-
let i = 0u;
274-
for arg_t: ty::arg in arg_ts {
275-
let mut_alias = arg_t.mode == ty::mo_alias(true);
276-
if i != offset &&
277-
ty_can_unsafely_include(cx, unsafe, arg_t.ty, mut_alias) {
278-
cx.tcx.sess.span_err(args[i].span,
279-
#ifmt["argument %u may alias with \
280-
argument %u, which is not immutably rooted",
281-
i, offset]);
273+
for @{unsafe_ty, _} in restricts {
274+
alt unsafe_ty {
275+
some(ty) {
276+
let i = 0u;
277+
for arg_t: ty::arg in arg_ts {
278+
let mut_alias = arg_t.mode == ty::mo_alias(true);
279+
if i != j &&
280+
ty_can_unsafely_include(cx, ty, arg_t.ty, mut_alias) {
281+
cx.tcx.sess.span_err(args[i].span,
282+
#ifmt["argument %u may alias with argument %u, \
283+
which is not immutably rooted", i, j]);
284+
}
285+
i += 1u;
282286
}
283-
i += 1u;
287+
}
288+
_ {}
284289
}
290+
j += 1u;
285291
}
286292
// Ensure we're not passing a root by mutable alias.
287293

288-
for root: {arg: uint, node: node_id} in mut_roots {
294+
for {node, arg} in mut_roots {
289295
let mut_alias_to_root = false;
290296
let mut_alias_to_root_count = 0u;
291-
for r: node_id in roots {
292-
if root.node == r {
293-
mut_alias_to_root_count += 1u;
294-
if mut_alias_to_root_count > 1u {
295-
mut_alias_to_root = true;
296-
break;
297+
for @{root_var, _} in restricts {
298+
alt root_var {
299+
some(root) {
300+
if node == root {
301+
mut_alias_to_root_count += 1u;
302+
if mut_alias_to_root_count > 1u {
303+
mut_alias_to_root = true;
304+
break;
305+
}
297306
}
307+
}
308+
none. {}
298309
}
299310
}
300311

301-
302312
if mut_alias_to_root {
303-
cx.tcx.sess.span_err(args[root.arg].span,
304-
~"passing a mutable alias to a \
305-
variable that roots another alias");
313+
cx.tcx.sess.span_err(args[arg].span,
314+
~"passing a mutable alias to a variable \
315+
that roots another alias");
306316
}
307317
}
308-
ret {root_vars: roots, unsafe_ts: unsafe_ts};
318+
ret restricts;
309319
}
310320

311321
fn check_tail_call(cx: &ctx, call: &@ast::expr) {
@@ -347,19 +357,16 @@ fn check_alt(cx: &ctx, input: &@ast::expr, arms: &[ast::arm], sc: &scope,
347357
v: &vt<scope>) {
348358
v.visit_expr(input, sc, v);
349359
let root = expr_root(cx, input, true);
350-
let roots =
351-
alt path_def_id(cx, root.ex) { some(did) { [did.node] } _ { [] } };
352-
let forbidden_tp: [ty::t] =
353-
alt inner_mut(root.ds) { some(t) { [t] } _ { [] } };
354360
for a: ast::arm in arms {
355361
let dnums = ast_util::pat_binding_ids(a.pats[0]);
356362
let new_sc = sc;
357363
if vec::len(dnums) > 0u {
358-
new_sc = @(*sc + [@{root_vars: roots,
364+
let root_var = path_def_id(cx, root.ex);
365+
new_sc = @(*sc + [@{root_var: root_var,
359366
local_id: cx.next_local,
360367
bindings: dnums,
361-
tys: forbidden_tp,
362-
depends_on: deps(sc, roots),
368+
unsafe_ty: inner_mut(root.ds),
369+
depends_on: deps(sc, root_var),
363370
mutable ok: valid}]);
364371
}
365372
register_locals(cx, a.pats[0]);
@@ -372,17 +379,9 @@ fn check_for_each(cx: &ctx, local: &@ast::local, call: &@ast::expr,
372379
v.visit_expr(call, sc, v);
373380
alt call.node {
374381
ast::expr_call(f, args) {
375-
let data = check_call(cx, f, args, sc);
376-
let bindings = ast_util::pat_binding_ids(local.node.pat);
377-
let new_sc =
378-
@{root_vars: data.root_vars,
379-
local_id: cx.next_local,
380-
bindings: bindings,
381-
tys: data.unsafe_ts,
382-
depends_on: deps(sc, data.root_vars),
383-
mutable ok: valid};
382+
let restricts = check_call(cx, f, args, sc);
384383
register_locals(cx, local.node.pat);
385-
visit::visit_block(blk, @(*sc + [new_sc]), v);
384+
visit::visit_block(blk, @(*sc + restricts), v);
386385
}
387386
}
388387
}
@@ -391,29 +390,25 @@ fn check_for(cx: &ctx, local: &@ast::local, seq: &@ast::expr, blk: &ast::blk,
391390
sc: &scope, v: &vt<scope>) {
392391
v.visit_expr(seq, sc, v);
393392
let root = expr_root(cx, seq, false);
394-
let root_def =
395-
alt path_def_id(cx, root.ex) { some(did) { [did.node] } _ { [] } };
396-
let unsafe = alt inner_mut(root.ds) { some(t) { [t] } _ { [] } };
393+
let unsafe = inner_mut(root.ds);
397394

398395
// If this is a mutable vector, don't allow it to be touched.
399396
let seq_t = ty::expr_ty(cx.tcx, seq);
400397
alt ty::struct(cx.tcx, seq_t) {
401-
ty::ty_vec(mt) { if mt.mut != ast::imm { unsafe = [seq_t]; } }
398+
ty::ty_vec(mt) { if mt.mut != ast::imm { unsafe = some(seq_t); } }
402399
ty::ty_str. | ty::ty_istr. {/* no-op */ }
403400
_ {
404-
cx.tcx.sess.span_unimpl(
405-
seq.span,
406-
~"unknown seq type " +
407-
util::ppaux::ty_to_str(cx.tcx, seq_t));
401+
cx.tcx.sess.span_unimpl(seq.span, ~"unknown seq type " +
402+
util::ppaux::ty_to_str(cx.tcx, seq_t));
408403
}
409404
}
410-
let bindings = ast_util::pat_binding_ids(local.node.pat);
405+
let root_var = path_def_id(cx, root.ex);
411406
let new_sc =
412-
@{root_vars: root_def,
407+
@{root_var: root_var,
413408
local_id: cx.next_local,
414-
bindings: bindings,
415-
tys: unsafe,
416-
depends_on: deps(sc, root_def),
409+
bindings: ast_util::pat_binding_ids(local.node.pat),
410+
unsafe_ty: unsafe,
411+
depends_on: deps(sc, root_var),
417412
mutable ok: valid};
418413
register_locals(cx, local.node.pat);
419414
visit::visit_block(blk, @(*sc + [new_sc]), v);
@@ -432,10 +427,13 @@ fn check_var(cx: &ctx, ex: &@ast::expr, p: &ast::path, id: ast::node_id,
432427
for r: restrict in *sc {
433428
// excludes variables introduced since the alias was made
434429
if my_local_id < r.local_id {
435-
for t: ty::t in r.tys {
436-
if ty_can_unsafely_include(cx, t, var_t, assign) {
430+
alt r.unsafe_ty {
431+
some(ty) {
432+
if ty_can_unsafely_include(cx, ty, var_t, assign) {
437433
r.ok = val_taken(ex.span, p);
438434
}
435+
}
436+
_ {}
439437
}
440438
} else if vec::member(my_defnum, r.bindings) {
441439
test_scope(cx, sc, r, p);
@@ -455,7 +453,7 @@ fn check_lval(cx: &@ctx, dest: &@ast::expr, sc: &scope, v: &vt<scope>) {
455453
~"assigning to immutable obj field");
456454
}
457455
for r: restrict in *sc {
458-
if vec::member(dnum, r.root_vars) {
456+
if r.root_var == some(dnum) {
459457
r.ok = overwritten(dest.span, p);
460458
}
461459
}
@@ -548,14 +546,17 @@ fn test_scope(cx: &ctx, sc: &scope, r: &restrict, p: &ast::path) {
548546
}
549547
}
550548

551-
fn deps(sc: &scope, roots: &[node_id]) -> [uint] {
552-
let i = 0u;
549+
fn deps(sc: &scope, root: &option::t<node_id>) -> [uint] {
553550
let result = [];
554-
for r: restrict in *sc {
555-
for dn: node_id in roots {
551+
alt root {
552+
some(dn) {
553+
let i = 0u;
554+
for r: restrict in *sc {
556555
if vec::member(dn, r.bindings) { result += [i]; }
556+
i += 1u;
557557
}
558-
i += 1u;
558+
}
559+
_ {}
559560
}
560561
ret result;
561562
}
@@ -678,10 +679,10 @@ fn path_def(cx: &ctx, ex: &@ast::expr) -> option::t<ast::def> {
678679
}
679680
}
680681

681-
fn path_def_id(cx: &ctx, ex: &@ast::expr) -> option::t<ast::def_id> {
682+
fn path_def_id(cx: &ctx, ex: &@ast::expr) -> option::t<ast::node_id> {
682683
alt ex.node {
683684
ast::expr_path(_) {
684-
ret some(ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)));
685+
ret some(ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)).node);
685686
}
686687
_ { ret none; }
687688
}

0 commit comments

Comments
 (0)