2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-06 15:22:13 +02:00
|
|
|
import front::ast;
|
|
|
|
import front::ast::ident;
|
2011-06-19 22:41:21 +02:00
|
|
|
import front::ast::node_id;
|
|
|
|
import front::ast::def_id;
|
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 util::common::span;
|
|
|
|
import visit::vt;
|
2011-06-06 15:22:13 +02:00
|
|
|
import std::vec;
|
|
|
|
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 11:19:50 -07:00
|
|
|
|
2011-06-15 12:17:37 +02:00
|
|
|
// 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).
|
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-06-19 22:41:21 +02:00
|
|
|
@rec(vec[node_id] root_vars,
|
|
|
|
node_id block_defnum,
|
|
|
|
vec[node_id] bindings,
|
2011-06-15 11:19:50 -07:00
|
|
|
vec[ty::t] tys,
|
|
|
|
vec[uint] depends_on,
|
|
|
|
mutable valid ok);
|
2011-06-06 15:22:13 +02:00
|
|
|
|
2011-06-15 14:59:51 +02:00
|
|
|
type scope = vec[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-06-19 22:41:21 +02:00
|
|
|
type ctx = rec(@ty::ctxt tcx,
|
|
|
|
std::map::hashmap[node_id, local_info] local_map);
|
2011-06-06 15:22:13 +02:00
|
|
|
|
2011-06-15 15:14:30 -07:00
|
|
|
fn check_crate(@ty::ctxt tcx, &@ast::crate crate) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto cx =
|
|
|
|
@rec(tcx=tcx,
|
2011-06-16 16:55:46 -07:00
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// Stores information about object fields and function
|
|
|
|
// arguments that's otherwise not easily available.
|
|
|
|
local_map=util::common::new_int_hash());
|
|
|
|
auto v =
|
2011-06-19 22:41:21 +02:00
|
|
|
@rec(visit_fn=bind visit_fn(cx, _, _, _, _, _, _, _),
|
2011-06-15 11:19:50 -07:00
|
|
|
visit_item=bind visit_item(cx, _, _, _),
|
|
|
|
visit_expr=bind visit_expr(cx, _, _, _)
|
|
|
|
with *visit::default_visitor[scope]());
|
2011-06-15 14:59:51 +02:00
|
|
|
visit::visit_crate(*crate, [], visit::vtor(v));
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 14:59:51 +02:00
|
|
|
fn visit_fn(@ctx cx, &ast::_fn f, &vec[ast::ty_param] tp, &span sp,
|
2011-06-19 22:41:21 +02:00
|
|
|
&ident name, ast::node_id id, &scope sc, &vt[scope] 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
|
|
|
visit::visit_fn_decl(f.decl, sc, v);
|
2011-06-15 14:59:51 +02:00
|
|
|
for (ast::arg 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-06-15 14:59:51 +02:00
|
|
|
vt(v).visit_block(f.body, [], v);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 14:59:51 +02:00
|
|
|
fn visit_item(@ctx cx, &@ast::item i, &scope sc, &vt[scope] v) {
|
|
|
|
alt (i.node) {
|
2011-06-16 11:53:06 +02:00
|
|
|
case (ast::item_obj(?o, _, _)) {
|
2011-06-15 14:59:51 +02:00
|
|
|
for (ast::obj_field f in o.fields) {
|
2011-06-19 22:41:21 +02:00
|
|
|
cx.local_map.insert(f.id, objfield(f.mut));
|
2011-06-15 14:59:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2011-06-15 14:59:51 +02:00
|
|
|
}
|
|
|
|
visit::visit_item(i, sc, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_expr(@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) {
|
2011-06-15 21:01:28 +02:00
|
|
|
auto handled = true;
|
2011-06-06 15:22:13 +02:00
|
|
|
alt (ex.node) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_call(?f, ?args)) {
|
2011-06-15 21:01:28 +02:00
|
|
|
check_call(*cx, f, args, sc);
|
|
|
|
handled = false;
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_be(?cl)) {
|
2011-06-15 21:01:28 +02:00
|
|
|
check_tail_call(*cx, cl);
|
|
|
|
visit::visit_expr(cl, sc, v);
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_alt(?input, ?arms)) {
|
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
|
|
|
check_alt(*cx, input, arms, sc, v);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_put(?val)) {
|
2011-06-06 15:22:13 +02:00
|
|
|
alt (val) {
|
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
|
|
|
case (some(?ex)) {
|
|
|
|
auto root = expr_root(*cx, ex, false);
|
2011-06-15 11:03:23 +02:00
|
|
|
if (mut_field(root.ds)) {
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(ex.span,
|
2011-06-16 16:55:46 -07:00
|
|
|
"result of put must be" +
|
|
|
|
" immutably rooted");
|
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_expr(cx, ex, sc, v);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
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-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_for_each(?decl, ?call, ?block)) {
|
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
|
|
|
check_for_each(*cx, decl, call, block, sc, v);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_for(?decl, ?seq, ?block)) {
|
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
|
|
|
check_for(*cx, decl, seq, block, sc, v);
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_path(?pt)) {
|
|
|
|
check_var(*cx, ex, pt, ex.id, false, sc);
|
2011-06-15 21:01:28 +02:00
|
|
|
handled = 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-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_move(?dest, ?src)) {
|
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
|
|
|
check_assign(cx, dest, src, sc, v);
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_assign(?dest, ?src)) {
|
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
|
|
|
check_assign(cx, dest, src, sc, v);
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_assign_op(_, ?dest, ?src)) {
|
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
|
|
|
check_assign(cx, dest, src, sc, v);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-15 21:01:28 +02:00
|
|
|
case (_) { handled = false; }
|
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
|
|
|
if (!handled) { visit::visit_expr(ex, sc, v); }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc) ->
|
2011-06-19 22:41:21 +02:00
|
|
|
rec(vec[node_id] root_vars, vec[ty::t] unsafe_ts) {
|
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
|
|
|
auto fty = ty::expr_ty(*cx.tcx, f);
|
2011-06-15 21:01:28 +02:00
|
|
|
auto arg_ts = fty_args(cx, fty);
|
2011-06-19 22:41:21 +02:00
|
|
|
let vec[node_id] roots = [];
|
|
|
|
let vec[tup(uint, node_id)] mut_roots = [];
|
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
|
|
|
let vec[ty::t] unsafe_ts = [];
|
|
|
|
let vec[uint] unsafe_t_offsets = [];
|
2011-06-10 16:38:13 +02:00
|
|
|
auto i = 0u;
|
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
|
|
|
for (ty::arg arg_t in arg_ts) {
|
|
|
|
if (arg_t.mode != ty::mo_val) {
|
2011-06-10 16:38:13 +02:00
|
|
|
auto arg = args.(i);
|
|
|
|
auto root = expr_root(cx, arg, false);
|
|
|
|
if (arg_t.mode == ty::mo_alias(true)) {
|
|
|
|
alt (path_def_id(cx, arg)) {
|
|
|
|
case (some(?did)) {
|
|
|
|
vec::push(mut_roots, tup(i, did._1));
|
|
|
|
}
|
|
|
|
case (_) {
|
2011-06-15 11:03:23 +02:00
|
|
|
if (!mut_field(root.ds)) {
|
2011-06-16 16:55:46 -07:00
|
|
|
auto m =
|
|
|
|
"passing a temporary value or \
|
2011-06-15 11:19:50 -07:00
|
|
|
immutable field by mutable alias";
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(arg.span, m);
|
2011-06-10 16:38: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
|
|
|
alt (path_def_id(cx, root.ex)) {
|
|
|
|
case (some(?did)) { vec::push(roots, did._1); }
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
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:03:23 +02:00
|
|
|
alt (inner_mut(root.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
|
|
|
case (some(?t)) {
|
|
|
|
vec::push(unsafe_ts, t);
|
|
|
|
vec::push(unsafe_t_offsets, i);
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
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
|
|
|
}
|
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
|
|
|
if (vec::len(unsafe_ts) > 0u) {
|
|
|
|
alt (f.node) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_path(_)) {
|
|
|
|
if (def_is_local(cx.tcx.def_map.get(f.id), true)) {
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(f.span,
|
2011-06-16 16:55:46 -07:00
|
|
|
#fmt("function may alias with \
|
|
|
|
argument %u, which is not immutably rooted",
|
|
|
|
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-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
auto j = 0u;
|
|
|
|
for (ty::t unsafe in unsafe_ts) {
|
|
|
|
auto offset = unsafe_t_offsets.(j);
|
|
|
|
j += 1u;
|
|
|
|
auto i = 0u;
|
|
|
|
for (ty::arg arg_t in arg_ts) {
|
2011-06-10 16:38:13 +02:00
|
|
|
auto mut_alias = arg_t.mode == ty::mo_alias(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
|
|
|
if (i != offset &&
|
2011-06-15 11:19:50 -07:00
|
|
|
ty_can_unsafely_include(cx, unsafe, arg_t.ty, mut_alias))
|
|
|
|
{
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(args.(i).span,
|
2011-06-15 11:19:50 -07:00
|
|
|
#fmt("argument %u may alias with \
|
|
|
|
argument %u, which is not immutably rooted",
|
|
|
|
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-06-19 22:41:21 +02:00
|
|
|
for (tup(uint, node_id) root in mut_roots) {
|
2011-06-10 16:38:13 +02:00
|
|
|
auto mut_alias_to_root = vec::count(root._1, roots) > 1u;
|
2011-06-15 14:59:51 +02:00
|
|
|
for (restrict r in sc) {
|
2011-06-10 16:38:13 +02:00
|
|
|
if (vec::member(root._1, r.root_vars)) {
|
|
|
|
mut_alias_to_root = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mut_alias_to_root) {
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(args.(root._0).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-06-15 11:19:50 -07:00
|
|
|
ret rec(root_vars=roots, unsafe_ts=unsafe_ts);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 21:01:28 +02:00
|
|
|
fn check_tail_call(&ctx cx, &@ast::expr call) {
|
|
|
|
auto args;
|
2011-06-16 16:55:46 -07:00
|
|
|
auto f =
|
|
|
|
alt (call.node) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_call(?f, ?args_)) { args = args_; f }
|
2011-06-16 16:55:46 -07:00
|
|
|
};
|
2011-06-15 21:01:28 +02:00
|
|
|
auto i = 0u;
|
|
|
|
for (ty::arg arg_t in fty_args(cx, ty::expr_ty(*cx.tcx, f))) {
|
|
|
|
if (arg_t.mode != ty::mo_val) {
|
|
|
|
auto mut_a = arg_t.mode == ty::mo_alias(true);
|
|
|
|
auto ok = true;
|
|
|
|
alt (args.(i).node) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_path(_)) {
|
|
|
|
auto def = cx.tcx.def_map.get(args.(i).id);
|
2011-06-15 21:01:28 +02:00
|
|
|
auto dnum = ast::def_id_of_def(def)._1;
|
|
|
|
alt (cx.local_map.find(dnum)) {
|
|
|
|
case (some(arg(ast::alias(?mut)))) {
|
|
|
|
if (mut_a && !mut) {
|
2011-06-20 10:44:38 +02:00
|
|
|
cx.tcx.sess.span_fatal(args.(i).span,
|
2011-06-16 16:55:46 -07:00
|
|
|
"passing an immutable \
|
2011-06-15 21:01:28 +02:00
|
|
|
alias by mutable alias");
|
|
|
|
}
|
|
|
|
}
|
2011-06-16 16:55:46 -07:00
|
|
|
case (_) { ok = !def_is_local(def, false); }
|
2011-06-15 21:01:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (_) { ok = false; }
|
|
|
|
}
|
|
|
|
if (!ok) {
|
2011-06-20 10:44:38 +02:00
|
|
|
cx.tcx.sess.span_fatal(args.(i).span,
|
2011-06-16 16:55:46 -07:00
|
|
|
"can not pass a local value by \
|
|
|
|
alias to a tail call");
|
2011-06-15 21:01:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-16 16:55:46 -07:00
|
|
|
fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, &scope sc,
|
|
|
|
&vt[scope] 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
|
|
|
visit::visit_expr(input, sc, v);
|
|
|
|
auto root = expr_root(cx, input, true);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto roots =
|
|
|
|
alt (path_def_id(cx, root.ex)) {
|
|
|
|
case (some(?did)) { [did._1] }
|
|
|
|
case (_) { [] }
|
|
|
|
};
|
|
|
|
let vec[ty::t] forbidden_tp =
|
|
|
|
alt (inner_mut(root.ds)) { case (some(?t)) { [t] } case (_) { [] } };
|
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
|
|
|
for (ast::arm a in arms) {
|
|
|
|
auto dnums = arm_defnums(a);
|
|
|
|
auto new_sc = sc;
|
|
|
|
if (vec::len(dnums) > 0u) {
|
2011-06-15 11:19:50 -07:00
|
|
|
new_sc =
|
|
|
|
sc +
|
|
|
|
[@rec(root_vars=roots,
|
|
|
|
block_defnum=dnums.(0),
|
|
|
|
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-06-19 22:41:21 +02:00
|
|
|
fn arm_defnums(&ast::arm arm) -> vec[node_id] {
|
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
|
|
|
auto dnums = [];
|
2011-06-19 22:41:21 +02:00
|
|
|
fn walk_pat(&mutable vec[node_id] found, &@ast::pat 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
|
|
|
alt (p.node) {
|
2011-06-19 22:41:21 +02:00
|
|
|
case (ast::pat_bind(_, ?id)) { vec::push(found, id); }
|
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
|
|
|
case (ast::pat_tag(_, ?children, _)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
for (@ast::pat child in children) { walk_pat(found, child); }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
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
|
|
|
walk_pat(dnums, arm.pat);
|
|
|
|
ret dnums;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-06-13 17:04:15 -07:00
|
|
|
fn check_for_each(&ctx cx, &@ast::local local, &@ast::expr call,
|
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
|
|
|
&ast::block block, &scope sc, &vt[scope] v) {
|
|
|
|
visit::visit_expr(call, sc, v);
|
|
|
|
alt (call.node) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_call(?f, ?args)) {
|
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
|
|
|
auto data = check_call(cx, f, args, sc);
|
2011-06-19 22:41:21 +02:00
|
|
|
auto defnum = local.node.id;
|
2011-06-15 11:19:50 -07:00
|
|
|
auto new_sc =
|
|
|
|
@rec(root_vars=data.root_vars,
|
|
|
|
block_defnum=defnum,
|
|
|
|
bindings=[defnum],
|
|
|
|
tys=data.unsafe_ts,
|
|
|
|
depends_on=deps(sc, data.root_vars),
|
|
|
|
mutable ok=valid);
|
2011-06-15 14:59:51 +02:00
|
|
|
visit::visit_block(block, 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-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-06-15 11:19:50 -07:00
|
|
|
fn check_for(&ctx cx, &@ast::local local, &@ast::expr seq, &ast::block block,
|
|
|
|
&scope sc, &vt[scope] 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
|
|
|
visit::visit_expr(seq, sc, v);
|
2011-06-19 22:41:21 +02:00
|
|
|
auto defnum = local.node.id;
|
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
|
|
|
auto root = expr_root(cx, seq, false);
|
2011-06-15 11:19:50 -07:00
|
|
|
auto root_def =
|
|
|
|
alt (path_def_id(cx, root.ex)) {
|
|
|
|
case (some(?did)) { [did._1] }
|
|
|
|
case (_) { [] }
|
|
|
|
};
|
|
|
|
auto unsafe =
|
|
|
|
alt (inner_mut(root.ds)) { case (some(?t)) { [t] } case (_) { [] } };
|
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
|
|
|
// If this is a mutable vector, don't allow it to be touched.
|
2011-06-15 11:19:50 -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
|
|
|
auto seq_t = ty::expr_ty(*cx.tcx, seq);
|
|
|
|
alt (ty::struct(*cx.tcx, seq_t)) {
|
|
|
|
case (ty::ty_vec(?mt)) {
|
|
|
|
if (mt.mut != ast::imm) { unsafe = [seq_t]; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-20 16:52:43 -07:00
|
|
|
case (ty::ty_str) { /* no-op */ }
|
|
|
|
case (ty::ty_ivec(?mt)) {
|
|
|
|
if (mt.mut != ast::imm) { unsafe = [seq_t]; }
|
|
|
|
}
|
|
|
|
case (ty::ty_istr) { /* no-op */ }
|
2011-06-21 10:59:05 -04:00
|
|
|
case (_) {
|
|
|
|
cx.tcx.sess.span_unimpl(seq.span, "unknown seq type " +
|
|
|
|
pretty::ppaux::ty_to_str(*cx.tcx, seq_t));
|
|
|
|
}
|
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
|
|
|
auto new_sc =
|
|
|
|
@rec(root_vars=root_def,
|
|
|
|
block_defnum=defnum,
|
|
|
|
bindings=[defnum],
|
|
|
|
tys=unsafe,
|
|
|
|
depends_on=deps(sc, root_def),
|
|
|
|
mutable ok=valid);
|
2011-06-15 14:59:51 +02:00
|
|
|
visit::visit_block(block, 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-06-19 22:41:21 +02:00
|
|
|
fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::node_id id,
|
|
|
|
bool assign, &scope sc) {
|
|
|
|
auto def = cx.tcx.def_map.get(id);
|
2011-06-15 21:01:28 +02:00
|
|
|
if (!def_is_local(def, true)) { ret; }
|
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
|
|
|
auto my_defnum = ast::def_id_of_def(def)._1;
|
|
|
|
auto var_t = ty::expr_ty(*cx.tcx, ex);
|
2011-06-15 14:59:51 +02:00
|
|
|
for (restrict r in sc) {
|
2011-06-15 11:19:50 -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
|
|
|
|
if (my_defnum < r.block_defnum) {
|
|
|
|
for (ty::t t in r.tys) {
|
|
|
|
if (ty_can_unsafely_include(cx, t, var_t, assign)) {
|
|
|
|
r.ok = val_taken(ex.span, p);
|
|
|
|
}
|
|
|
|
}
|
2011-06-09 14:19:13 +02:00
|
|
|
} else if (vec::member(my_defnum, r.bindings)) {
|
|
|
|
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-06-15 11:19:50 -07:00
|
|
|
|
2011-06-15 12:17:37 +02:00
|
|
|
// FIXME does not catch assigning to immutable object fields yet
|
2011-06-15 11:19:50 -07:00
|
|
|
fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src, &scope sc,
|
|
|
|
&vt[scope] 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
|
|
|
visit_expr(cx, src, sc, v);
|
|
|
|
alt (dest.node) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_path(?p)) {
|
|
|
|
auto dnum = ast::def_id_of_def(cx.tcx.def_map.get(dest.id))._1;
|
2011-06-15 14:59:51 +02:00
|
|
|
if (is_immutable_alias(cx, sc, dnum)) {
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(dest.span,
|
2011-06-15 11:19:50 -07:00
|
|
|
"assigning to immutable alias");
|
2011-06-15 14:59:51 +02:00
|
|
|
} else if (is_immutable_objfield(cx, dnum)) {
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(dest.span,
|
2011-06-15 11:19:50 -07:00
|
|
|
"assigning to immutable obj field");
|
2011-06-10 12:03:50 +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
|
|
|
auto var_t = ty::expr_ty(*cx.tcx, dest);
|
2011-06-15 14:59:51 +02:00
|
|
|
for (restrict r in sc) {
|
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
|
|
|
if (vec::member(dnum, r.root_vars)) {
|
|
|
|
r.ok = overwritten(dest.span, p);
|
|
|
|
}
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
check_var(*cx, dest, p, dest.id, true, sc);
|
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
|
|
|
}
|
|
|
|
case (_) {
|
2011-06-15 12:17:37 +02:00
|
|
|
auto root = expr_root(*cx, dest, false);
|
|
|
|
if (vec::len(root.ds) == 0u) {
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(dest.span, "assignment to non-lvalue");
|
2011-06-15 12:17:37 +02:00
|
|
|
} else if (!root.ds.(0).mut) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto name =
|
|
|
|
alt (root.ds.(0).kind) {
|
|
|
|
case (unbox) { "box" }
|
|
|
|
case (field) { "field" }
|
|
|
|
case (index) { "vec content" }
|
|
|
|
};
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(dest.span,
|
2011-06-15 11:19:50 -07:00
|
|
|
"assignment to immutable " + name);
|
2011-06-15 12:17:37 +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
|
|
|
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-06-19 22:41:21 +02:00
|
|
|
fn is_immutable_alias(&@ctx cx, &scope sc, node_id dnum) -> bool {
|
2011-06-15 14:59:51 +02:00
|
|
|
alt (cx.local_map.find(dnum)) {
|
|
|
|
case (some(arg(ast::alias(false)))) { ret true; }
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { }
|
2011-06-10 16:38:13 +02:00
|
|
|
}
|
2011-06-15 14:59:51 +02:00
|
|
|
for (restrict r in sc) {
|
2011-06-10 16:38:13 +02:00
|
|
|
if (vec::member(dnum, r.bindings)) { ret true; }
|
|
|
|
}
|
|
|
|
ret false;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-06-19 22:41:21 +02:00
|
|
|
fn is_immutable_objfield(&@ctx cx, node_id dnum) -> 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-06-09 14:19:13 +02:00
|
|
|
fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) {
|
|
|
|
auto prob = r.ok;
|
|
|
|
for (uint dep in r.depends_on) {
|
|
|
|
if (prob != valid) { break; }
|
2011-06-15 14:59:51 +02:00
|
|
|
prob = sc.(dep).ok;
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
|
|
|
if (prob != valid) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto msg =
|
|
|
|
alt (prob) {
|
|
|
|
case (overwritten(?sp, ?wpt)) {
|
|
|
|
tup(sp, "overwriting " + ast::path_name(wpt))
|
|
|
|
}
|
|
|
|
case (val_taken(?sp, ?vpt)) {
|
|
|
|
tup(sp, "taking the value of " + ast::path_name(vpt))
|
|
|
|
}
|
|
|
|
};
|
2011-06-18 22:41:20 -07:00
|
|
|
cx.tcx.sess.span_fatal(msg._0,
|
2011-06-15 11:19:50 -07:00
|
|
|
msg._1 + " will invalidate alias " +
|
|
|
|
ast::path_name(p) + ", which is still used");
|
2011-06-09 14:19:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-19 22:41:21 +02:00
|
|
|
fn deps(&scope sc, vec[node_id] roots) -> vec[uint] {
|
2011-06-09 14:19:13 +02:00
|
|
|
auto i = 0u;
|
|
|
|
auto result = [];
|
2011-06-15 14:59:51 +02:00
|
|
|
for (restrict r in sc) {
|
2011-06-19 22:41:21 +02:00
|
|
|
for (node_id dn in roots) {
|
2011-06-15 11:19:50 -07:00
|
|
|
if (vec::member(dn, r.bindings)) { vec::push(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-06-15 11:03:23 +02:00
|
|
|
type deref = rec(bool mut, deref_t kind, ty::t outer_t);
|
|
|
|
|
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-06-15 11:19:50 -07:00
|
|
|
fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
|
|
|
|
rec(@ast::expr ex, vec[deref] ds) {
|
|
|
|
fn maybe_auto_unbox(&ctx cx, &ty::t t) ->
|
|
|
|
rec(ty::t t, option::t[deref] d) {
|
2011-06-15 11:03:23 +02:00
|
|
|
alt (ty::struct(*cx.tcx, t)) {
|
|
|
|
case (ty::ty_box(?mt)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
ret rec(t=mt.ty,
|
|
|
|
d=some(rec(mut=mt.mut != ast::imm,
|
|
|
|
kind=unbox,
|
|
|
|
outer_t=t)));
|
2011-06-15 11:03:23 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (_) { ret rec(t=t, d=none); }
|
2011-06-15 11:03:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fn maybe_push_auto_unbox(&option::t[deref] d, &mutable vec[deref] ds) {
|
2011-06-15 11:19:50 -07:00
|
|
|
alt (d) { case (some(?d)) { vec::push(ds, d); } case (none) { } }
|
2011-06-15 11:03:23 +02:00
|
|
|
}
|
|
|
|
let vec[deref] ds = [];
|
2011-06-06 15:22:13 +02:00
|
|
|
while (true) {
|
2011-06-15 11:19:50 -07:00
|
|
|
alt ({ ex.node }) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_field(?base, ?ident)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto auto_unbox =
|
|
|
|
maybe_auto_unbox(cx, ty::expr_ty(*cx.tcx, base));
|
2011-06-15 11:03:23 +02:00
|
|
|
auto mut = 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
|
|
|
alt (ty::struct(*cx.tcx, auto_unbox.t)) {
|
2011-06-06 15:22:13 +02:00
|
|
|
case (ty::ty_tup(?fields)) {
|
|
|
|
auto fnm = ty::field_num(cx.tcx.sess, ex.span, ident);
|
2011-06-15 11:03:23 +02:00
|
|
|
mut = fields.(fnm).mut != ast::imm;
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
case (ty::ty_rec(?fields)) {
|
|
|
|
for (ty::field fld in fields) {
|
|
|
|
if (str::eq(ident, fld.ident)) {
|
2011-06-15 11:03:23 +02:00
|
|
|
mut = fld.mt.mut != ast::imm;
|
2011-06-06 15:22:13 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (ty::ty_obj(_)) { }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::push(ds, rec(mut=mut, kind=field, outer_t=auto_unbox.t));
|
2011-06-15 11:03:23 +02:00
|
|
|
maybe_push_auto_unbox(auto_unbox.d, ds);
|
2011-06-06 15:22:13 +02:00
|
|
|
ex = base;
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_index(?base, _)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
auto auto_unbox =
|
|
|
|
maybe_auto_unbox(cx, ty::expr_ty(*cx.tcx, base));
|
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
|
|
|
alt (ty::struct(*cx.tcx, auto_unbox.t)) {
|
2011-06-06 15:22:13 +02:00
|
|
|
case (ty::ty_vec(?mt)) {
|
2011-06-15 11:19:50 -07:00
|
|
|
vec::push(ds,
|
|
|
|
rec(mut=mt.mut != ast::imm,
|
|
|
|
kind=index,
|
|
|
|
outer_t=auto_unbox.t));
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-17 19:02:30 -07:00
|
|
|
case (ty::ty_ivec(?mt)) {
|
|
|
|
vec::push(ds,
|
|
|
|
rec(mut=mt.mut != ast::imm,
|
|
|
|
kind=index,
|
|
|
|
outer_t=auto_unbox.t));
|
|
|
|
}
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-15 11:03:23 +02:00
|
|
|
maybe_push_auto_unbox(auto_unbox.d, ds);
|
2011-06-06 15:22:13 +02:00
|
|
|
ex = base;
|
|
|
|
}
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_unary(?op, ?base)) {
|
2011-06-06 15:22:13 +02:00
|
|
|
if (op == ast::deref) {
|
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
|
|
|
auto base_t = ty::expr_ty(*cx.tcx, base);
|
|
|
|
alt (ty::struct(*cx.tcx, base_t)) {
|
2011-06-06 15:22:13 +02:00
|
|
|
case (ty::ty_box(?mt)) {
|
2011-06-28 16:38:14 +02:00
|
|
|
vec::push(ds, rec(mut=mt.mut != ast::imm,
|
|
|
|
kind=unbox,
|
|
|
|
outer_t=base_t));
|
|
|
|
}
|
|
|
|
case (ty::ty_res(_, ?inner)) {
|
|
|
|
vec::push(ds, rec(mut=false,
|
|
|
|
kind=unbox,
|
|
|
|
outer_t=base_t));
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ex = base;
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { break; }
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
case (_) { break; }
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
if (autoderef) {
|
2011-06-15 11:03:23 +02:00
|
|
|
auto auto_unbox = maybe_auto_unbox(cx, ty::expr_ty(*cx.tcx, ex));
|
|
|
|
maybe_push_auto_unbox(auto_unbox.d, 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-06-15 11:03:23 +02:00
|
|
|
ret rec(ex=ex, ds=ds);
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:03:23 +02:00
|
|
|
fn mut_field(&vec[deref] ds) -> bool {
|
2011-06-15 11:19:50 -07:00
|
|
|
for (deref d in ds) { if (d.mut) { ret true; } }
|
2011-06-15 11:03:23 +02:00
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn inner_mut(&vec[deref] ds) -> option::t[ty::t] {
|
2011-06-15 11:19:50 -07:00
|
|
|
for (deref d 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
|
|
|
}
|
|
|
|
|
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
|
|
|
fn path_def_id(&ctx cx, &@ast::expr ex) -> option::t[ast::def_id] {
|
|
|
|
alt (ex.node) {
|
2011-06-21 22:16:40 +02:00
|
|
|
case (ast::expr_path(_)) {
|
|
|
|
ret some(ast::def_id_of_def(cx.tcx.def_map.get(ex.id)));
|
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
|
|
|
case (_) { 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-06-15 11:19:50 -07:00
|
|
|
fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut) ->
|
|
|
|
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
|
|
|
fn get_mut(bool cur, &ty::mt mt) -> bool {
|
|
|
|
ret cur || mt.mut != ast::imm;
|
|
|
|
}
|
|
|
|
fn helper(&ty::ctxt tcx, ty::t needle, ty::t haystack, bool mut) -> bool {
|
|
|
|
if (needle == haystack) { ret true; }
|
|
|
|
alt (ty::struct(tcx, haystack)) {
|
|
|
|
case (ty::ty_tag(_, ?ts)) {
|
|
|
|
for (ty::t t in ts) {
|
|
|
|
if (helper(tcx, needle, t, mut)) { ret true; }
|
|
|
|
}
|
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
case (ty::ty_box(?mt)) {
|
|
|
|
ret helper(tcx, needle, mt.ty, get_mut(mut, mt));
|
|
|
|
}
|
|
|
|
case (ty::ty_vec(?mt)) {
|
|
|
|
ret helper(tcx, needle, mt.ty, get_mut(mut, mt));
|
|
|
|
}
|
|
|
|
case (ty::ty_ptr(?mt)) {
|
|
|
|
ret helper(tcx, needle, mt.ty, get_mut(mut, mt));
|
|
|
|
}
|
|
|
|
case (ty::ty_tup(?mts)) {
|
|
|
|
for (ty::mt mt in mts) {
|
|
|
|
if (helper(tcx, needle, mt.ty, get_mut(mut, mt))) {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
case (ty::ty_rec(?fields)) {
|
|
|
|
for (ty::field f in fields) {
|
|
|
|
if (helper(tcx, needle, f.mt.ty, get_mut(mut, f.mt))) {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret false;
|
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
case (
|
|
|
|
// These may contain anything.
|
|
|
|
ty::ty_fn(_, _, _, _, _)) {
|
|
|
|
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
|
|
|
case (ty::ty_obj(_)) { ret true; }
|
2011-06-15 11:19:50 -07:00
|
|
|
case (
|
|
|
|
// 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.
|
|
|
|
ty::ty_param(_)) {
|
|
|
|
ret 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
|
|
|
case (_) { ret false; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret helper(*cx.tcx, needle, haystack, mut);
|
|
|
|
}
|
|
|
|
|
2011-06-15 21:01:28 +02:00
|
|
|
fn def_is_local(&ast::def d, bool objfields_count) -> 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 alt (d) {
|
2011-06-16 16:55:46 -07:00
|
|
|
case (ast::def_local(_)) { true }
|
|
|
|
case (ast::def_arg(_)) { true }
|
|
|
|
case (ast::def_obj_field(_)) { objfields_count }
|
|
|
|
case (ast::def_binding(_)) { true }
|
|
|
|
case (_) { false }
|
|
|
|
};
|
2011-06-06 15:22:13 +02:00
|
|
|
}
|
2011-06-15 21:01:28 +02:00
|
|
|
|
|
|
|
fn fty_args(&ctx cx, ty::t fty) -> vec[ty::arg] {
|
|
|
|
ret alt (ty::struct(*cx.tcx, fty)) {
|
2011-06-16 16:55:46 -07:00
|
|
|
case (ty::ty_fn(_, ?args, _, _, _)) { args }
|
|
|
|
case (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:
|