Extend alias analysis to check assignments

This is a somewhat odd place to put these checks, but the data tracked
by that pass, and the available functions, make it trivial to do such
a check there.
This commit is contained in:
Marijn Haverbeke 2011-06-15 12:17:37 +02:00
parent 5fb518abc9
commit 0ddade3d7a
4 changed files with 26 additions and 11 deletions

View File

@ -10,6 +10,14 @@ import std::option::some;
import std::option::none;
import std::option::is_none;
// This is not an alias-analyser (though it would merit from becoming one, or
// at getting input from one, to be more precise). It is a pass that checks
// whether aliases are used in a safe way. Beyond that, though it doesn't have
// a lot to do with aliases, it also checks whether assignments are valid
// (using an lval, which is actually mutable), since it already has all the
// information needed to do that (and the typechecker, which would be a
// logical place for such a check, doesn't).
tag valid {
valid;
overwritten(span, ast::path);
@ -318,6 +326,7 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign,
}
}
// FIXME does not catch assigning to immutable object fields yet
fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
&scope sc, &vt[scope] v) {
visit_expr(cx, src, sc, v);
@ -339,6 +348,18 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src,
check_var(*cx, dest, p, ann, true, sc);
}
case (_) {
auto root = expr_root(*cx, dest, false);
if (vec::len(root.ds) == 0u) {
cx.tcx.sess.span_err(dest.span, "assignment to non-lvalue");
} else if (!root.ds.(0).mut) {
auto name = alt (root.ds.(0).kind) {
case (unbox) { "box" }
case (field) { "field" }
case (index) { "vec content" }
};
cx.tcx.sess.span_err
(dest.span, "assignment to immutable " + name);
}
visit_expr(cx, dest, sc, v);
}
}
@ -391,7 +412,7 @@ fn deps(&scope sc, vec[def_num] roots) -> vec[uint] {
tag deref_t {
unbox;
field(ident);
field;
index;
}
type deref = rec(bool mut, deref_t kind, ty::t outer_t);
@ -446,7 +467,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
case (ty::ty_obj(_)) {}
}
vec::push(ds, rec(mut=mut,
kind=field(ident),
kind=field,
outer_t=auto_unbox.t));
maybe_push_auto_unbox(auto_unbox.d, ds);
ex = base;

View File

@ -1,5 +1,3 @@
// xfail-stage0
// xfail-stage1
// error-pattern:assigning to immutable alias
fn f(&int i) {

View File

@ -1,9 +1,7 @@
// xfail-stage0
// xfail-stage1
// xfail-stage2
// -*- rust -*-
// error-pattern: writing to immutable type
// error-pattern:assignment to immutable field
type point = rec(int x, int y, int z);

View File

@ -1,8 +1,6 @@
// xfail-stage0
// xfail-stage1
// xfail-stage2
// error-pattern: writing to immutable type
// error-pattern:assignment to immutable vec content
fn main() {
let vec[int] v = [1, 2, 3];
v.(1) = 4;
}
}