2011-06-15 11:19:50 -07:00
|
|
|
|
2011-07-05 11:48:19 +02:00
|
|
|
import syntax::ast;
|
|
|
|
import ast::ident;
|
|
|
|
import ast::fn_ident;
|
|
|
|
import ast::node_id;
|
|
|
|
import ast::def_id;
|
|
|
|
import syntax::codemap::span;
|
|
|
|
import syntax::visit;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
import visit::vt;
|
2011-08-15 16:38:23 -07:00
|
|
|
import std::vec;
|
2011-06-06 15:22:13 +02:00
|
|
|
import std::str;
|
|
|
|
import std::option;
|
|
|
|
import std::option::some;
|
|
|
|
import std::option::none;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
import std::option::is_none;
|
2011-06-06 15:22:13 +02:00
|
|
|
|
2011-06-15 12:17:37 +02:00
|
|
|
// This is not an alias-analyser (though it would merit from becoming one, or
|
2011-07-07 10:21:14 +02:00
|
|
|
// getting input from one, to be more precise). It is a pass that checks
|
2011-06-15 12:17:37 +02:00
|
|
|
// 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).
|
2011-07-07 10:21:14 +02:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
tag valid { valid; overwritten(span, ast::path); val_taken(span, ast::path); }
|
2011-06-15 12:17:37 +02:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
type restrict =
|
2011-08-04 16:20:09 -07:00
|
|
|
@{root_vars: [node_id],
|
2011-07-27 14:19:39 +02:00
|
|
|
block_defnum: node_id,
|
2011-08-04 16:20:09 -07:00
|
|
|
bindings: [node_id],
|
|
|
|
tys: [ty::t],
|
|
|
|
depends_on: [uint],
|
2011-07-27 14:19:39 +02:00
|
|
|
mutable ok: valid};
|
2011-06-06 15:22:13 +02:00
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
type scope = @[restrict];
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
tag local_info { arg(ast::mode); objfield(ast::mutability); }
|
2011-06-10 12:03:50 +02:00
|
|
|
|
2011-08-19 14:34:45 +02:00
|
|
|
type mut_map = std::map::hashmap<node_id, ()>;
|
|
|
|
type ctx = {tcx: ty::ctxt,
|
|
|
|
local_map: std::map::hashmap<node_id, local_info>,
|
|
|
|
mut_map: mut_map};
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-08-19 14:34:45 +02:00
|
|
|
fn check_crate(tcx: ty::ctxt, crate: &@ast::crate) -> mut_map {
|
2011-07-27 14:48:34 +02:00
|
|
|
// Stores information about object fields and function
|
|
|
|
// arguments that's otherwise not easily available.
|
2011-08-19 14:34:45 +02:00
|
|
|
let cx = @{tcx: tcx,
|
|
|
|
local_map: std::map::new_int_hash(),
|
|
|
|
mut_map: std::map::new_int_hash()};
|
|
|
|
let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _),
|
|
|
|
visit_item: bind visit_item(cx, _, _, _),
|
|
|
|
visit_expr: bind visit_expr(cx, _, _, _),
|
|
|
|
visit_decl: bind visit_decl(cx, _, _, _)
|
|
|
|
with *visit::default_visitor::<scope>()};
|
2011-08-19 15:16:48 -07:00
|
|
|
visit::visit_crate(*crate, @[], visit::mk_vt(v));
|
2011-07-04 21:59:50 +02:00
|
|
|
tcx.sess.abort_if_errors();
|
2011-08-19 14:34:45 +02:00
|
|
|
ret cx.mut_map;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-08-18 10:01:39 +02:00
|
|
|
fn visit_fn(cx: &@ctx, f: &ast::_fn, _tp: &[ast::ty_param], _sp: &span,
|
|
|
|
_name: &fn_ident, id: ast::node_id, sc: &scope, v: &vt<scope>) {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
visit::visit_fn_decl(f.decl, sc, v);
|
2011-08-15 21:54:52 -07:00
|
|
|
for arg_: ast::arg in f.decl.inputs {
|
2011-06-19 22:41:21 +02:00
|
|
|
cx.local_map.insert(arg_.id, arg(arg_.mode));
|
2011-06-10 12:03:50 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
let scope =
|
|
|
|
alt f.proto {
|
|
|
|
|
|
|
|
// Blocks need to obey any restrictions from the enclosing scope.
|
|
|
|
ast::proto_block. {
|
|
|
|
sc
|
|
|
|
}
|
|
|
|
|
|
|
|
// Closures need to prohibit writing to any of the upvars.
|
|
|
|
// This doesn't seem like a particularly clean way to do this.
|
|
|
|
ast::proto_closure. {
|
|
|
|
let dnums = [];
|
|
|
|
for each nid in freevars::get_freevar_defs(cx.tcx, id).keys() {
|
|
|
|
dnums += [nid];
|
|
|
|
};
|
|
|
|
@[
|
|
|
|
// I'm not sure if there is anything sensical to put here
|
|
|
|
@{root_vars: [],
|
|
|
|
block_defnum: 0,
|
|
|
|
bindings: dnums,
|
|
|
|
tys: [],
|
|
|
|
depends_on: [],
|
|
|
|
mutable ok: valid}]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Non capturing functions start out fresh.
|
|
|
|
_ {
|
|
|
|
@[]
|
|
|
|
}
|
|
|
|
};
|
2011-08-04 19:31:47 -07:00
|
|
|
|
|
|
|
v.visit_block(f.body, scope, v);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn visit_item(cx: &@ctx, i: &@ast::item, sc: &scope, v: &vt<scope>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt i.node {
|
|
|
|
ast::item_obj(o, _, _) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for f: ast::obj_field in o.fields {
|
2011-07-27 14:19:39 +02:00
|
|
|
cx.local_map.insert(f.id, objfield(f.mut));
|
2011-06-15 14:59:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { }
|
2011-06-15 14:59:51 +02:00
|
|
|
}
|
|
|
|
visit::visit_item(i, sc, v);
|
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn visit_expr(cx: &@ctx, ex: &@ast::expr, sc: &scope, v: &vt<scope>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
let handled = true;
|
|
|
|
alt ex.node {
|
|
|
|
ast::expr_call(f, args) {
|
|
|
|
check_call(*cx, f, args, sc);
|
|
|
|
handled = false;
|
|
|
|
}
|
|
|
|
ast::expr_be(cl) {
|
|
|
|
check_tail_call(*cx, cl);
|
|
|
|
visit::visit_expr(cl, sc, v);
|
|
|
|
}
|
|
|
|
ast::expr_alt(input, arms) { check_alt(*cx, input, arms, sc, v); }
|
|
|
|
ast::expr_put(val) {
|
|
|
|
alt val {
|
|
|
|
some(ex) {
|
|
|
|
let root = expr_root(*cx, ex, false);
|
|
|
|
if mut_field(root.ds) {
|
|
|
|
cx.tcx.sess.span_err(ex.span,
|
|
|
|
"result of put must be" +
|
|
|
|
" immutably rooted");
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
visit_expr(cx, ex, sc, v);
|
|
|
|
}
|
|
|
|
_ { }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::expr_for_each(decl, call, blk) {
|
|
|
|
check_for_each(*cx, decl, call, blk, sc, v);
|
|
|
|
}
|
|
|
|
ast::expr_for(decl, seq, blk) { check_for(*cx, decl, seq, blk, sc, v); }
|
|
|
|
ast::expr_path(pt) {
|
|
|
|
check_var(*cx, ex, pt, ex.id, false, sc);
|
|
|
|
handled = false;
|
|
|
|
}
|
|
|
|
ast::expr_swap(lhs, rhs) {
|
|
|
|
check_lval(cx, lhs, sc, v);
|
|
|
|
check_lval(cx, rhs, sc, v);
|
|
|
|
handled = false;
|
|
|
|
}
|
|
|
|
ast::expr_move(dest, src) {
|
|
|
|
check_assign(cx, dest, src, sc, v);
|
|
|
|
check_move_rhs(cx, src, sc, v);
|
|
|
|
}
|
|
|
|
ast::expr_assign(dest, src) | ast::expr_assign_op(_, dest, src) {
|
|
|
|
check_assign(cx, dest, src, sc, v);
|
|
|
|
}
|
|
|
|
_ { handled = false; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
if !handled { visit::visit_expr(ex, sc, v); }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn visit_decl(cx: &@ctx, d: &@ast::decl, sc: &scope, v: &vt<scope>) {
|
2011-07-13 10:23:13 +02:00
|
|
|
visit::visit_decl(d, sc, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt d.node {
|
|
|
|
ast::decl_local(locs) {
|
2011-07-28 12:01:45 +02:00
|
|
|
for loc: @ast::local in locs {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt loc.node.init {
|
|
|
|
some(init) {
|
|
|
|
if init.op == ast::init_move {
|
2011-07-22 17:19:06 +02:00
|
|
|
check_move_rhs(cx, init.expr, sc, v);
|
2011-07-13 10:23:13 +02:00
|
|
|
}
|
2011-07-22 17:19:06 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
none. { }
|
2011-07-13 10:23:13 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-22 17:19:06 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
_ { }
|
2011-07-13 10:23:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
fn check_call(cx: &ctx, f: &@ast::expr, args: &[@ast::expr], sc: &scope) ->
|
|
|
|
{root_vars: [node_id], unsafe_ts: [ty::t]} {
|
2011-07-27 14:19:39 +02:00
|
|
|
let fty = ty::expr_ty(cx.tcx, f);
|
|
|
|
let arg_ts = fty_args(cx, fty);
|
2011-08-19 15:16:48 -07:00
|
|
|
let roots: [node_id] = [];
|
|
|
|
let mut_roots: [{arg: uint, node: node_id}] = [];
|
|
|
|
let unsafe_ts: [ty::t] = [];
|
|
|
|
let unsafe_t_offsets: [uint] = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
let i = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for arg_t: ty::arg in arg_ts {
|
2011-07-27 14:19:39 +02:00
|
|
|
if arg_t.mode != ty::mo_val {
|
2011-08-19 15:16:48 -07:00
|
|
|
let arg = args[i];
|
2011-07-27 14:19:39 +02:00
|
|
|
let root = expr_root(cx, arg, false);
|
|
|
|
if arg_t.mode == ty::mo_alias(true) {
|
2011-07-27 17:19:46 +02:00
|
|
|
alt path_def(cx, arg) {
|
|
|
|
some(def) {
|
|
|
|
let dnum = ast::def_id_of_def(def).node;
|
|
|
|
if def_is_local(def, true) {
|
|
|
|
if is_immutable_alias(cx, sc, dnum) {
|
2011-08-19 15:16:48 -07:00
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
arg.span,
|
|
|
|
"passing an immutable alias \
|
|
|
|
by mutable alias");
|
2011-07-27 17:19:46 +02:00
|
|
|
} else if is_immutable_objfield(cx, dnum) {
|
2011-08-19 15:16:48 -07:00
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
arg.span,
|
|
|
|
"passing an immutable object \
|
|
|
|
field by mutable alias");
|
2011-07-27 17:19:46 +02:00
|
|
|
}
|
|
|
|
} else {
|
2011-08-19 15:16:48 -07:00
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
arg.span,
|
|
|
|
"passing a static item by mutable alias");
|
2011-07-27 17:19:46 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
mut_roots += [{arg: i, node: dnum}];
|
2011-07-27 17:19:46 +02:00
|
|
|
}
|
2011-07-14 17:26:10 -07:00
|
|
|
_ {
|
2011-07-27 14:19:39 +02:00
|
|
|
if !mut_field(root.ds) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let m =
|
|
|
|
"passing a temporary value or \
|
2011-06-15 11:19:50 -07:00
|
|
|
immutable field by mutable alias";
|
2011-07-14 17:26:10 -07:00
|
|
|
cx.tcx.sess.span_err(arg.span, m);
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
2011-07-14 17:26:10 -07:00
|
|
|
}
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
alt path_def_id(cx, root.ex) {
|
2011-08-19 15:16:48 -07:00
|
|
|
some(did) { roots += [did.node]; }
|
2011-07-14 17:26:10 -07:00
|
|
|
_ { }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
alt inner_mut(root.ds) {
|
2011-08-19 15:16:48 -07:00
|
|
|
some(t) { unsafe_ts += [t]; unsafe_t_offsets += [i]; }
|
2011-07-14 17:26:10 -07:00
|
|
|
_ { }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 1u;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::len(unsafe_ts) > 0u {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt f.node {
|
|
|
|
ast::expr_path(_) {
|
|
|
|
if def_is_local(cx.tcx.def_map.get(f.id), true) {
|
|
|
|
cx.tcx.sess.span_err(f.span,
|
2011-08-19 15:16:48 -07:00
|
|
|
#fmt["function may alias with \
|
2011-06-16 16:55:46 -07:00
|
|
|
argument %u, which is not immutably rooted",
|
2011-08-19 15:16:48 -07:00
|
|
|
unsafe_t_offsets[0]]);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
let j = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for unsafe: ty::t in unsafe_ts {
|
2011-08-19 15:16:48 -07:00
|
|
|
let offset = unsafe_t_offsets[j];
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
j += 1u;
|
2011-07-27 14:19:39 +02:00
|
|
|
let i = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for arg_t: ty::arg in arg_ts {
|
2011-07-27 14:19:39 +02:00
|
|
|
let mut_alias = arg_t.mode == ty::mo_alias(true);
|
|
|
|
if i != offset &&
|
|
|
|
ty_can_unsafely_include(cx, unsafe, arg_t.ty, mut_alias) {
|
2011-08-19 15:16:48 -07:00
|
|
|
cx.tcx.sess.span_err(args[i].span,
|
|
|
|
#fmt["argument %u may alias with \
|
2011-06-15 11:19:50 -07:00
|
|
|
argument %u, which is not immutably rooted",
|
2011-08-19 15:16:48 -07:00
|
|
|
i, offset]);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
2011-06-10 16:38:13 +02:00
|
|
|
// Ensure we're not passing a root by mutable alias.
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-08-15 21:54:52 -07:00
|
|
|
for root: {arg: uint, node: node_id} in mut_roots {
|
2011-07-27 14:19:39 +02:00
|
|
|
let mut_alias_to_root = false;
|
|
|
|
let mut_alias_to_root_count = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for r: node_id in roots {
|
2011-07-26 14:06:02 +02:00
|
|
|
if root.node == r {
|
2011-07-14 17:26:10 -07:00
|
|
|
mut_alias_to_root_count += 1u;
|
|
|
|
if mut_alias_to_root_count > 1u {
|
|
|
|
mut_alias_to_root = true;
|
|
|
|
break;
|
|
|
|
}
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-14 17:26:10 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
if mut_alias_to_root {
|
2011-08-19 15:16:48 -07:00
|
|
|
cx.tcx.sess.span_err(args[root.arg].span,
|
2011-06-15 11:19:50 -07:00
|
|
|
"passing a mutable alias to a \
|
2011-06-10 16:38:13 +02:00
|
|
|
variable that roots another alias");
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret {root_vars: roots, unsafe_ts: unsafe_ts};
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn check_tail_call(cx: &ctx, call: &@ast::expr) {
|
|
|
|
let args;
|
|
|
|
let f = alt call.node { ast::expr_call(f, args_) { args = args_; f } };
|
|
|
|
let i = 0u;
|
2011-08-15 21:54:52 -07:00
|
|
|
for arg_t: ty::arg in fty_args(cx, ty::expr_ty(cx.tcx, f)) {
|
2011-07-27 14:19:39 +02:00
|
|
|
if arg_t.mode != ty::mo_val {
|
|
|
|
let mut_a = arg_t.mode == ty::mo_alias(true);
|
|
|
|
let ok = true;
|
2011-08-19 15:16:48 -07:00
|
|
|
alt args[i].node {
|
2011-07-27 14:19:39 +02:00
|
|
|
ast::expr_path(_) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let def = cx.tcx.def_map.get(args[i].id);
|
2011-07-27 14:19:39 +02:00
|
|
|
let dnum = ast::def_id_of_def(def).node;
|
|
|
|
alt cx.local_map.find(dnum) {
|
|
|
|
some(arg(ast::alias(mut))) {
|
|
|
|
if mut_a && !mut {
|
2011-08-19 15:16:48 -07:00
|
|
|
cx.tcx.sess.span_err(args[i].span,
|
2011-07-27 14:19:39 +02:00
|
|
|
"passing an immutable \
|
2011-06-15 21:01:28 +02:00
|
|
|
alias by mutable alias");
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { ok = !def_is_local(def, false); }
|
2011-06-15 21:01:28 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { ok = false; }
|
2011-06-15 21:01:28 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
if !ok {
|
2011-08-19 15:16:48 -07:00
|
|
|
cx.tcx.sess.span_err(args[i].span,
|
2011-07-27 14:19:39 +02:00
|
|
|
"can not pass a local value by \
|
2011-06-16 16:55:46 -07:00
|
|
|
alias to a tail call");
|
2011-06-15 21:01:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
fn check_alt(cx: &ctx, input: &@ast::expr, arms: &[ast::arm], sc: &scope,
|
2011-08-12 07:15:18 -07:00
|
|
|
v: &vt<scope>) {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
visit::visit_expr(input, sc, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
let root = expr_root(cx, input, true);
|
|
|
|
let roots =
|
2011-08-19 15:16:48 -07:00
|
|
|
alt path_def_id(cx, root.ex) { some(did) { [did.node] } _ { [] } };
|
2011-08-04 16:20:09 -07:00
|
|
|
let forbidden_tp: [ty::t] =
|
2011-08-19 15:16:48 -07:00
|
|
|
alt inner_mut(root.ds) { some(t) { [t] } _ { [] } };
|
2011-08-15 21:54:52 -07:00
|
|
|
for a: ast::arm in arms {
|
2011-07-27 14:19:39 +02:00
|
|
|
let dnums = arm_defnums(a);
|
|
|
|
let new_sc = sc;
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::len(dnums) > 0u {
|
2011-08-19 15:16:48 -07:00
|
|
|
new_sc =
|
|
|
|
@(*sc +
|
|
|
|
[@{root_vars: roots,
|
|
|
|
block_defnum: dnums[vec::len(dnums) - 1u],
|
|
|
|
bindings: dnums,
|
|
|
|
tys: forbidden_tp,
|
|
|
|
depends_on: deps(sc, roots),
|
|
|
|
mutable ok: valid}]);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
visit::visit_arm(a, new_sc, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
fn arm_defnums(arm: &ast::arm) -> [node_id] {
|
2011-08-19 15:16:48 -07:00
|
|
|
ret ast::pat_binding_ids(arm.pats[0]);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn check_for_each(cx: &ctx, local: &@ast::local, call: &@ast::expr,
|
2011-08-12 07:15:18 -07:00
|
|
|
blk: &ast::blk, sc: &scope, v: &vt<scope>) {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
visit::visit_expr(call, sc, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt call.node {
|
|
|
|
ast::expr_call(f, args) {
|
|
|
|
let data = check_call(cx, f, args, sc);
|
2011-08-03 10:19:36 +02:00
|
|
|
let bindings = ast::pat_binding_ids(local.node.pat);
|
2011-08-19 15:16:48 -07:00
|
|
|
let new_sc =
|
|
|
|
@{root_vars: data.root_vars,
|
|
|
|
block_defnum: bindings[vec::len(bindings) - 1u],
|
|
|
|
bindings: bindings,
|
|
|
|
tys: data.unsafe_ts,
|
|
|
|
depends_on: deps(sc, data.root_vars),
|
|
|
|
mutable ok: valid};
|
|
|
|
visit::visit_block(blk, @(*sc + [new_sc]), v);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn check_for(cx: &ctx, local: &@ast::local, seq: &@ast::expr, blk: &ast::blk,
|
2011-08-12 07:15:18 -07:00
|
|
|
sc: &scope, v: &vt<scope>) {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
visit::visit_expr(seq, sc, v);
|
2011-07-27 14:19:39 +02:00
|
|
|
let root = expr_root(cx, seq, false);
|
|
|
|
let root_def =
|
2011-08-19 15:16:48 -07:00
|
|
|
alt path_def_id(cx, root.ex) { some(did) { [did.node] } _ { [] } };
|
|
|
|
let unsafe = alt inner_mut(root.ds) { some(t) { [t] } _ { [] } };
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-07-13 10:23:13 +02:00
|
|
|
// If this is a mutable vector, don't allow it to be touched.
|
2011-07-27 14:19:39 +02:00
|
|
|
let seq_t = ty::expr_ty(cx.tcx, seq);
|
|
|
|
alt ty::struct(cx.tcx, seq_t) {
|
2011-08-19 15:16:48 -07:00
|
|
|
ty::ty_vec(mt) { if mt.mut != ast::imm { unsafe = [seq_t]; } }
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_str. | ty::ty_istr. {/* no-op */ }
|
|
|
|
_ {
|
|
|
|
cx.tcx.sess.span_unimpl(seq.span,
|
|
|
|
"unknown seq type " +
|
2011-07-21 15:32:31 -07:00
|
|
|
util::ppaux::ty_to_str(cx.tcx, seq_t));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-08-03 10:19:36 +02:00
|
|
|
let bindings = ast::pat_binding_ids(local.node.pat);
|
2011-08-19 15:16:48 -07:00
|
|
|
let new_sc =
|
|
|
|
@{root_vars: root_def,
|
|
|
|
block_defnum: bindings[vec::len(bindings) - 1u],
|
|
|
|
bindings: bindings,
|
|
|
|
tys: unsafe,
|
|
|
|
depends_on: deps(sc, root_def),
|
|
|
|
mutable ok: valid};
|
|
|
|
visit::visit_block(blk, @(*sc + [new_sc]), v);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn check_var(cx: &ctx, ex: &@ast::expr, p: &ast::path, id: ast::node_id,
|
|
|
|
assign: bool, sc: &scope) {
|
|
|
|
let def = cx.tcx.def_map.get(id);
|
|
|
|
if !def_is_local(def, true) { ret; }
|
|
|
|
let my_defnum = ast::def_id_of_def(def).node;
|
|
|
|
let var_t = ty::expr_ty(cx.tcx, ex);
|
2011-08-15 21:54:52 -07:00
|
|
|
for r: restrict in *sc {
|
2011-08-19 15:16:48 -07:00
|
|
|
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
// excludes variables introduced since the alias was made
|
2011-07-28 12:01:45 +02:00
|
|
|
// FIXME This does not work anymore, now that we have macros.
|
2011-07-27 14:19:39 +02:00
|
|
|
if my_defnum < r.block_defnum {
|
2011-07-28 12:01:45 +02:00
|
|
|
for t: ty::t in r.tys {
|
2011-07-27 14:19:39 +02:00
|
|
|
if ty_can_unsafely_include(cx, t, var_t, assign) {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
r.ok = val_taken(ex.span, p);
|
|
|
|
}
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if vec::member(my_defnum, r.bindings) {
|
2011-06-09 14:19:13 +02:00
|
|
|
test_scope(cx, sc, r, p);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn check_lval(cx: &@ctx, dest: &@ast::expr, sc: &scope, v: &vt<scope>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt dest.node {
|
|
|
|
ast::expr_path(p) {
|
|
|
|
let dnum = ast::def_id_of_def(cx.tcx.def_map.get(dest.id)).node;
|
2011-08-19 14:34:45 +02:00
|
|
|
cx.mut_map.insert(dnum, ());
|
2011-07-27 17:19:46 +02:00
|
|
|
if is_immutable_alias(*cx, sc, dnum) {
|
2011-07-27 14:19:39 +02:00
|
|
|
cx.tcx.sess.span_err(dest.span, "assigning to immutable alias");
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if is_immutable_objfield(*cx, dnum) {
|
2011-07-27 14:19:39 +02:00
|
|
|
cx.tcx.sess.span_err(dest.span,
|
|
|
|
"assigning to immutable obj field");
|
|
|
|
}
|
2011-07-27 17:19:46 +02:00
|
|
|
for r: restrict in *sc {
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::member(dnum, r.root_vars) {
|
2011-07-27 14:19:39 +02:00
|
|
|
r.ok = overwritten(dest.span, p);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
let root = expr_root(*cx, dest, false);
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::len(*root.ds) == 0u {
|
2011-07-27 14:19:39 +02:00
|
|
|
cx.tcx.sess.span_err(dest.span, "assignment to non-lvalue");
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if !root.ds[0].mut {
|
2011-07-27 14:19:39 +02:00
|
|
|
let name =
|
2011-08-19 15:16:48 -07:00
|
|
|
alt root.ds[0].kind {
|
2011-07-27 14:19:39 +02:00
|
|
|
unbox. { "box" }
|
|
|
|
field. { "field" }
|
|
|
|
index. { "vec content" }
|
|
|
|
};
|
|
|
|
cx.tcx.sess.span_err(dest.span,
|
|
|
|
"assignment to immutable " + name);
|
|
|
|
}
|
|
|
|
visit_expr(cx, dest, sc, v);
|
|
|
|
}
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn check_move_rhs(cx: &@ctx, src: &@ast::expr, sc: &scope, v: &vt<scope>) {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt src.node {
|
|
|
|
ast::expr_path(p) {
|
|
|
|
alt cx.tcx.def_map.get(src.id) {
|
|
|
|
ast::def_obj_field(_) {
|
|
|
|
cx.tcx.sess.span_err(src.span,
|
|
|
|
"may not move out of an obj field");
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
check_lval(cx, src, sc, v);
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
let root = expr_root(*cx, src, false);
|
|
|
|
|
|
|
|
// Not a path and no-derefs means this is a temporary.
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::len(*root.ds) != 0u {
|
2011-07-27 14:19:39 +02:00
|
|
|
cx.tcx.sess.span_err(src.span, "moving out of a data structure");
|
2011-07-07 10:21:14 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-07-07 10:21:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn check_assign(cx: &@ctx, dest: &@ast::expr, src: &@ast::expr, sc: &scope,
|
2011-08-12 07:15:18 -07:00
|
|
|
v: &vt<scope>) {
|
2011-06-28 17:24:59 -07:00
|
|
|
visit_expr(cx, src, sc, v);
|
|
|
|
check_lval(cx, dest, sc, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-27 17:19:46 +02:00
|
|
|
fn is_immutable_alias(cx: &ctx, sc: &scope, dnum: node_id) -> bool {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt cx.local_map.find(dnum) {
|
|
|
|
some(arg(ast::alias(false))) { ret true; }
|
|
|
|
_ { }
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
for r: restrict in *sc { if vec::member(dnum, r.bindings) { ret true; } }
|
2011-06-10 16:38:13 +02:00
|
|
|
ret false;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-07-27 17:19:46 +02:00
|
|
|
fn is_immutable_objfield(cx: &ctx, dnum: node_id) -> bool {
|
2011-06-15 14:59:51 +02:00
|
|
|
ret cx.local_map.find(dnum) == some(objfield(ast::imm));
|
|
|
|
}
|
2011-06-10 16:38:13 +02:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn test_scope(cx: &ctx, sc: &scope, r: &restrict, p: &ast::path) {
|
|
|
|
let prob = r.ok;
|
2011-08-15 21:54:52 -07:00
|
|
|
for dep: uint in r.depends_on {
|
2011-07-27 14:19:39 +02:00
|
|
|
if prob != valid { break; }
|
2011-08-19 15:16:48 -07:00
|
|
|
prob = sc[dep].ok;
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
if prob != valid {
|
2011-08-19 15:16:48 -07:00
|
|
|
let msg =
|
|
|
|
alt prob {
|
|
|
|
overwritten(sp, wpt) {
|
|
|
|
{span: sp, msg: "overwriting " + ast::path_name(wpt)}
|
|
|
|
}
|
|
|
|
val_taken(sp, vpt) {
|
|
|
|
{span: sp, msg: "taking the value of " + ast::path_name(vpt)}
|
|
|
|
}
|
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
cx.tcx.sess.span_err(msg.span,
|
|
|
|
msg.msg + " will invalidate alias " +
|
|
|
|
ast::path_name(p) + ", which is still used");
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
fn deps(sc: &scope, roots: &[node_id]) -> [uint] {
|
2011-07-27 14:19:39 +02:00
|
|
|
let i = 0u;
|
2011-08-19 15:16:48 -07:00
|
|
|
let result = [];
|
2011-08-15 21:54:52 -07:00
|
|
|
for r: restrict in *sc {
|
|
|
|
for dn: node_id in roots {
|
2011-08-19 15:16:48 -07:00
|
|
|
if vec::member(dn, r.bindings) { result += [i]; }
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
tag deref_t { unbox; field; index; }
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
type deref = @{mut: bool, kind: deref_t, outer_t: ty::t};
|
2011-06-15 11:03:23 +02:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-15 11:03:23 +02:00
|
|
|
// Finds the root (the thing that is dereferenced) for the given expr, and a
|
|
|
|
// vec of dereferences that were used on this root. Note that, in this vec,
|
|
|
|
// the inner derefs come in front, so foo.bar.baz becomes rec(ex=foo,
|
|
|
|
// ds=[field(baz),field(bar)])
|
2011-07-27 14:19:39 +02:00
|
|
|
fn expr_root(cx: &ctx, ex: @ast::expr, autoderef: bool) ->
|
2011-08-04 16:20:09 -07:00
|
|
|
{ex: @ast::expr, ds: @[deref]} {
|
|
|
|
fn maybe_auto_unbox(cx: &ctx, t: ty::t) -> {t: ty::t, ds: [deref]} {
|
2011-08-19 15:16:48 -07:00
|
|
|
let ds = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
while true {
|
|
|
|
alt ty::struct(cx.tcx, t) {
|
|
|
|
ty::ty_box(mt) {
|
2011-08-19 15:16:48 -07:00
|
|
|
ds += [@{mut: mt.mut != ast::imm, kind: unbox, outer_t: t}];
|
2011-07-22 09:29:01 +02:00
|
|
|
t = mt.ty;
|
|
|
|
}
|
2011-08-10 17:23:46 -07:00
|
|
|
ty::ty_uniq(mt) {
|
2011-08-19 15:16:48 -07:00
|
|
|
ds += [@{mut: false, kind: unbox, outer_t: t}];
|
2011-08-10 17:23:46 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_res(_, inner, tps) {
|
2011-08-19 15:16:48 -07:00
|
|
|
ds += [@{mut: false, kind: unbox, outer_t: t}];
|
2011-07-22 09:29:01 +02:00
|
|
|
t = ty::substitute_type_params(cx.tcx, tps, inner);
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_tag(did, tps) {
|
|
|
|
let variants = ty::tag_variants(cx.tcx, did);
|
2011-08-15 16:38:23 -07:00
|
|
|
if vec::len(variants) != 1u ||
|
2011-08-19 15:16:48 -07:00
|
|
|
vec::len(variants[0].args) != 1u {
|
2011-07-22 09:29:01 +02:00
|
|
|
break;
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
ds += [@{mut: false, kind: unbox, outer_t: t}];
|
2011-07-27 14:19:39 +02:00
|
|
|
t =
|
|
|
|
ty::substitute_type_params(cx.tcx, tps,
|
2011-08-19 15:16:48 -07:00
|
|
|
variants[0].args[0]);
|
2011-07-22 09:29:01 +02:00
|
|
|
}
|
|
|
|
_ { break; }
|
2011-06-15 11:03:23 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret {t: t, ds: ds};
|
2011-06-15 11:03:23 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
let ds: [deref] = [];
|
2011-07-27 14:19:39 +02:00
|
|
|
while true {
|
|
|
|
alt { ex.node } {
|
|
|
|
ast::expr_field(base, ident) {
|
|
|
|
let auto_unbox = maybe_auto_unbox(cx, ty::expr_ty(cx.tcx, base));
|
|
|
|
let mut = false;
|
|
|
|
alt ty::struct(cx.tcx, auto_unbox.t) {
|
|
|
|
ty::ty_rec(fields) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for fld: ty::field in fields {
|
2011-07-27 14:19:39 +02:00
|
|
|
if str::eq(ident, fld.ident) {
|
|
|
|
mut = fld.mt.mut != ast::imm;
|
|
|
|
break;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ty::ty_obj(_) { }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
ds += [@{mut: mut, kind: field, outer_t: auto_unbox.t}];
|
2011-07-27 14:19:39 +02:00
|
|
|
ds += auto_unbox.ds;
|
|
|
|
ex = base;
|
|
|
|
}
|
|
|
|
ast::expr_index(base, _) {
|
|
|
|
let auto_unbox = maybe_auto_unbox(cx, ty::expr_ty(cx.tcx, base));
|
|
|
|
alt ty::struct(cx.tcx, auto_unbox.t) {
|
2011-08-18 14:11:06 -07:00
|
|
|
ty::ty_vec(mt) {
|
2011-07-27 14:19:39 +02:00
|
|
|
ds +=
|
2011-08-19 15:16:48 -07:00
|
|
|
[@{mut: mt.mut != ast::imm,
|
|
|
|
kind: index,
|
|
|
|
outer_t: auto_unbox.t}];
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ds += auto_unbox.ds;
|
|
|
|
ex = base;
|
|
|
|
}
|
|
|
|
ast::expr_unary(op, base) {
|
|
|
|
if op == ast::deref {
|
|
|
|
let base_t = ty::expr_ty(cx.tcx, base);
|
|
|
|
let mut = false;
|
|
|
|
alt ty::struct(cx.tcx, base_t) {
|
|
|
|
ty::ty_box(mt) { mut = mt.mut != ast::imm; }
|
2011-08-10 17:23:46 -07:00
|
|
|
ty::ty_uniq(_) { }
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_res(_, _, _) { }
|
|
|
|
ty::ty_tag(_, _) { }
|
|
|
|
ty::ty_ptr(mt) { mut = mt.mut != ast::imm; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
ds += [@{mut: mut, kind: unbox, outer_t: base_t}];
|
2011-06-06 15:22:13 +02:00
|
|
|
ex = base;
|
2011-07-27 14:19:39 +02:00
|
|
|
} else { break; }
|
|
|
|
}
|
|
|
|
_ { break; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
if autoderef {
|
|
|
|
let auto_unbox = maybe_auto_unbox(cx, ty::expr_ty(cx.tcx, ex));
|
2011-07-22 09:29:01 +02:00
|
|
|
ds += auto_unbox.ds;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret {ex: ex, ds: @ds};
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
fn mut_field(ds: &@[deref]) -> bool {
|
2011-08-15 21:54:52 -07:00
|
|
|
for d: deref in *ds { if d.mut { ret true; } }
|
2011-06-15 11:03:23 +02:00
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn inner_mut(ds: &@[deref]) -> option::t<ty::t> {
|
2011-08-15 21:54:52 -07:00
|
|
|
for d: deref in *ds { if d.mut { ret some(d.outer_t); } }
|
2011-06-15 11:03:23 +02:00
|
|
|
ret none;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn path_def(cx: &ctx, ex: &@ast::expr) -> option::t<ast::def> {
|
2011-07-27 17:19:46 +02:00
|
|
|
ret alt ex.node {
|
2011-08-19 15:16:48 -07:00
|
|
|
ast::expr_path(_) { some(cx.tcx.def_map.get(ex.id)) }
|
|
|
|
_ { none }
|
|
|
|
}
|
2011-07-27 17:19:46 +02:00
|
|
|
}
|
|
|
|
|
2011-08-12 07:15:18 -07:00
|
|
|
fn path_def_id(cx: &ctx, ex: &@ast::expr) -> option::t<ast::def_id> {
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ex.node {
|
|
|
|
ast::expr_path(_) {
|
|
|
|
ret some(ast::def_id_of_def(cx.tcx.def_map.get(ex.id)));
|
|
|
|
}
|
|
|
|
_ { ret none; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn ty_can_unsafely_include(cx: &ctx, needle: ty::t, haystack: ty::t,
|
|
|
|
mut: bool) -> bool {
|
|
|
|
fn get_mut(cur: bool, mt: &ty::mt) -> bool {
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
ret cur || mt.mut != ast::imm;
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
fn helper(tcx: &ty::ctxt, needle: ty::t, haystack: ty::t, mut: bool) ->
|
|
|
|
bool {
|
|
|
|
if needle == haystack { ret true; }
|
|
|
|
alt ty::struct(tcx, haystack) {
|
|
|
|
ty::ty_tag(_, ts) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for t: ty::t in ts {
|
2011-07-27 14:19:39 +02:00
|
|
|
if helper(tcx, needle, t, mut) { ret true; }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret false;
|
|
|
|
}
|
2011-08-18 11:46:52 -07:00
|
|
|
ty::ty_box(mt) | ty::ty_ptr(mt) {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret helper(tcx, needle, mt.ty, get_mut(mut, mt));
|
|
|
|
}
|
2011-08-10 17:23:46 -07:00
|
|
|
ty::ty_uniq(t) { ret helper(tcx, needle, t, false); }
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_rec(fields) {
|
2011-08-15 21:54:52 -07:00
|
|
|
for f: ty::field in fields {
|
2011-07-27 14:19:39 +02:00
|
|
|
if helper(tcx, needle, f.mt.ty, get_mut(mut, f.mt)) {
|
|
|
|
ret true;
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret false;
|
|
|
|
}
|
2011-08-15 12:08:05 +02:00
|
|
|
ty::ty_tup(ts) {
|
2011-08-19 15:16:48 -07:00
|
|
|
for t in ts { if helper(tcx, needle, t, mut) { ret true; } }
|
2011-08-15 11:40:26 +02:00
|
|
|
ret false;
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
// These may contain anything.
|
|
|
|
ty::ty_fn(_, _, _, _, _) {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
ty::ty_obj(_) { ret true; }
|
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
// A type param may include everything, but can only be
|
|
|
|
// treated as opaque downstream, and is thus safe unless we
|
|
|
|
// saw mutable fields, in which case the whole thing can be
|
|
|
|
// overwritten.
|
2011-08-19 15:16:48 -07:00
|
|
|
ty::ty_param(_, _) {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret mut;
|
|
|
|
}
|
|
|
|
_ { ret false; }
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-21 15:32:31 -07:00
|
|
|
ret helper(cx.tcx, needle, haystack, mut);
|
A revised, improved alias-checker
The old system tried to ensure that the location an alias pointed at
would retain its type. That turned out to not be strong enough in the
face of aliases to the inside of tags.
The new system instead proves that values pointed to by aliases are
not replaced (or invalidated in some other way) at all. It knows of
two sufficient conditions for this, and tries to prove at least of
them:
A) The alias is 'immutably rooted' in a local, and this local is not
reassigned for the lifetime of the alias. Immutably rooted means
the alias refers to the local itself, or to something reachable
from the local through immutable dereferencing.
B) No value whose type might include the type of the 'inner mutable
element' of the thing the alias refers to (for example, the box in
rec(mutable x = @mutable int)) is from the outer scope is accessed
for the lifetime of the alias. This means for functions, no other
argument types may include the alias's inner mutable type. For alt,
for each, and for, it means the body does not refer to any locals
originating from outside their scope that include this type.
The lifetime of an alias in an alt, for each, or for body is defined
as the range from its definition to its last use, not to the point
where it goes out of scope. This makes working around these
restrictions somewhat less annoying. For example, you can assign to
your alt-ed value you don't refer to any bindings afterwards.
2011-06-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn def_is_local(d: &ast::def, objfields_count: bool) -> bool {
|
|
|
|
ret alt d {
|
|
|
|
ast::def_local(_) | ast::def_arg(_) | ast::def_binding(_) { true }
|
|
|
|
ast::def_obj_field(_) { objfields_count }
|
|
|
|
_ { false }
|
|
|
|
};
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-15 21:01:28 +02:00
|
|
|
|
2011-08-04 16:20:09 -07:00
|
|
|
fn fty_args(cx: &ctx, fty: ty::t) -> [ty::arg] {
|
2011-07-27 14:19:39 +02:00
|
|
|
ret alt ty::struct(cx.tcx, ty::type_autoderef(cx.tcx, fty)) {
|
|
|
|
ty::ty_fn(_, args, _, _, _) | ty::ty_native_fn(_, args, _) { args }
|
|
|
|
};
|
2011-06-15 21:01:28 +02:00
|
|
|
}
|
2011-06-06 15:22:13 +02:00
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
|
|
|
// End:
|