Move capture checking into resolve.rs
Drops capture.rs. The new algorithm also checks for captures function arguments and obj fields.
This commit is contained in:
parent
89490e416b
commit
58ec5d1654
@ -7,7 +7,6 @@ import front::eval;
|
||||
import front::ast;
|
||||
import middle::trans;
|
||||
import middle::resolve;
|
||||
import middle::capture;
|
||||
import middle::ty;
|
||||
import middle::typeck;
|
||||
import middle::typestate_check;
|
||||
@ -94,8 +93,6 @@ fn compile_input(session::session sess,
|
||||
bind creader::read_crates(sess, crate));
|
||||
auto def_map = time(time_passes, "resolution",
|
||||
bind resolve::resolve_crate(sess, crate));
|
||||
time[()](time_passes, "capture checking",
|
||||
bind capture::check_for_captures(sess, crate, def_map));
|
||||
|
||||
auto ty_cx = ty::mk_ctxt(sess, def_map);
|
||||
auto typeck_result =
|
||||
|
@ -46,7 +46,6 @@ tag def {
|
||||
def_const(def_id);
|
||||
def_arg(def_id);
|
||||
def_local(def_id);
|
||||
def_upvar(def_id);
|
||||
def_variant(def_id /* tag */, def_id /* variant */);
|
||||
def_ty(def_id);
|
||||
def_ty_arg(uint);
|
||||
@ -74,7 +73,6 @@ fn def_id_of_def(def d) -> def_id {
|
||||
case (def_const(?id)) { ret id; }
|
||||
case (def_arg(?id)) { ret id; }
|
||||
case (def_local(?id)) { ret id; }
|
||||
case (def_upvar(?id)) { ret id; }
|
||||
case (def_variant(_, ?id)) { ret id; }
|
||||
case (def_ty(?id)) { ret id; }
|
||||
case (def_ty_arg(_)) { fail; }
|
||||
|
@ -1,119 +0,0 @@
|
||||
import driver::session;
|
||||
import front::ast;
|
||||
import std::map::hashmap;
|
||||
import std::option;
|
||||
import std::option::some;
|
||||
import std::option::none;
|
||||
import std::_int;
|
||||
import std::_vec;
|
||||
import util::common;
|
||||
import resolve::def_map;
|
||||
|
||||
type fn_id_of_local = std::map::hashmap[ast::def_id, ast::def_id];
|
||||
type env = rec(mutable vec[ast::def_id] current_context, // fn or obj
|
||||
def_map def_map,
|
||||
fn_id_of_local idmap,
|
||||
session::session sess);
|
||||
|
||||
fn current_context(&env e) -> ast::def_id {
|
||||
ret e.current_context.(_vec::len(e.current_context) - 1u);
|
||||
}
|
||||
|
||||
fn enter_item(@env e, &@ast::item i) {
|
||||
alt (i.node) {
|
||||
case (ast::item_fn(?name, _, _, ?id, _)) {
|
||||
_vec::push(e.current_context, id);
|
||||
}
|
||||
case (ast::item_obj(?name, _, _, ?ids, _)) {
|
||||
_vec::push(e.current_context, ids.ty);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
fn leave_item(@env e, &@ast::item i) {
|
||||
alt (i.node) {
|
||||
case (ast::item_fn(?name, _, _, ?id, _)) {
|
||||
_vec::pop(e.current_context);
|
||||
}
|
||||
case (ast::item_obj(_, _, _, ?ids, _)) {
|
||||
_vec::pop(e.current_context);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_expr(@env e, &@ast::expr x) {
|
||||
alt (x.node) {
|
||||
case (ast::expr_for(?d, _, _, _)) {
|
||||
alt (d.node) {
|
||||
case (ast::decl_local(?local)) {
|
||||
e.idmap.insert(local.id, current_context(*e));
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
case (ast::expr_for_each(?d, _, _, _)) {
|
||||
alt (d.node) {
|
||||
case (ast::decl_local(?local)) {
|
||||
e.idmap.insert(local.id, current_context(*e));
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
case (ast::expr_path(?pt, ?ann)) {
|
||||
auto local_id;
|
||||
alt (e.def_map.get(ast::ann_tag(ann))) {
|
||||
case (ast::def_local(?id)) { local_id = id; }
|
||||
case (_) { ret; }
|
||||
}
|
||||
auto df = ast::def_id_of_def(e.def_map.get(ast::ann_tag(ann)));
|
||||
auto def_context = e.idmap.get(df);
|
||||
|
||||
if (current_context(*e) != def_context) {
|
||||
e.sess.span_err(x.span,
|
||||
"attempted dynamic environment-capture");
|
||||
}
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_block(@env e, &ast::block b) {
|
||||
for (@ast::stmt st in b.node.stmts) {
|
||||
alt (st.node) {
|
||||
case (ast::stmt_decl(?d,_)) {
|
||||
alt (d.node) {
|
||||
case (ast::decl_local(?loc)) {
|
||||
e.idmap.insert(loc.id, current_context(*e));
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_captures(session::session sess, @ast::crate crate, def_map dm) {
|
||||
let vec[ast::def_id] curctx = vec();
|
||||
auto env = @rec(mutable current_context = curctx,
|
||||
def_map = dm,
|
||||
idmap = common::new_def_hash[ast::def_id](),
|
||||
sess = sess);
|
||||
auto visitor = rec(visit_item_pre = bind enter_item(env, _),
|
||||
visit_item_post = bind leave_item(env, _),
|
||||
visit_block_pre = bind walk_block(env, _),
|
||||
visit_expr_pre = bind walk_expr(env, _)
|
||||
with walk::default_visitor());
|
||||
walk::walk_crate(visitor, *crate);
|
||||
}
|
||||
|
||||
// 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:
|
@ -317,8 +317,8 @@ fn resolve_import(&env e, &@ast::view_item it, &list[scope] sc) {
|
||||
|
||||
if (n_idents == 1u) {
|
||||
register(e, defid, it.span, end_id,
|
||||
lookup_in_scope(e, sc, end_id, ns_value),
|
||||
lookup_in_scope(e, sc, end_id, ns_type));
|
||||
lookup_in_scope(e, sc, it.span, end_id, ns_value),
|
||||
lookup_in_scope(e, sc, it.span, end_id, ns_type));
|
||||
} else {
|
||||
auto dcur = lookup_in_scope_strict(e, sc, it.span, ids.(0), ns_value);
|
||||
auto i = 1u;
|
||||
@ -394,7 +394,7 @@ fn lookup_path_strict(&env e, &list[scope] sc, &span sp, vec[ident] idents,
|
||||
|
||||
fn lookup_in_scope_strict(&env e, list[scope] sc, &span sp, ident id,
|
||||
namespace ns) -> def {
|
||||
alt (lookup_in_scope(e, sc, id, ns)) {
|
||||
alt (lookup_in_scope(e, sc, sp, id, ns)) {
|
||||
case (none[def]) {
|
||||
unresolved(e, sp, id, ns_name(ns));
|
||||
fail;
|
||||
@ -405,7 +405,35 @@ fn lookup_in_scope_strict(&env e, list[scope] sc, &span sp, ident id,
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_in_scope(&env e, list[scope] sc, ident id, namespace ns)
|
||||
fn scope_is_fn(&scope sc) -> bool {
|
||||
ret alt (sc) {
|
||||
case (scope_item(?it)) {
|
||||
alt (it.node) {
|
||||
case (ast::item_fn(_, _, _, _, _)) { true }
|
||||
case (_) { false }
|
||||
}
|
||||
}
|
||||
case (scope_native_item(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
}
|
||||
|
||||
fn def_is_local(&def d) -> bool {
|
||||
ret alt (d) {
|
||||
case (ast::def_arg(_)) { true }
|
||||
case (ast::def_local(_)) { true }
|
||||
case (ast::def_binding(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
}
|
||||
fn def_is_obj_field(&def d) -> bool {
|
||||
ret alt (d) {
|
||||
case (ast::def_obj_field(_)) { true }
|
||||
case (_) { false }
|
||||
};
|
||||
}
|
||||
|
||||
fn lookup_in_scope(&env e, list[scope] sc, &span sp, ident id, namespace ns)
|
||||
-> option::t[def] {
|
||||
fn in_scope(&env e, ident id, &scope s, namespace ns)
|
||||
-> option::t[def] {
|
||||
@ -441,7 +469,6 @@ fn lookup_in_scope(&env e, list[scope] sc, ident id, namespace ns)
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
case (scope_native_item(?it)) {
|
||||
alt (it.node) {
|
||||
case (ast::native_item_fn(_, _, ?decl, ?ty_params, _, _)){
|
||||
@ -449,7 +476,6 @@ fn lookup_in_scope(&env e, list[scope] sc, ident id, namespace ns)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (scope_loop(?d)) {
|
||||
if (ns == ns_value) {
|
||||
alt (d.node) {
|
||||
@ -461,11 +487,9 @@ fn lookup_in_scope(&env e, list[scope] sc, ident id, namespace ns)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (scope_block(?b)) {
|
||||
ret lookup_in_block(id, b.node, ns);
|
||||
}
|
||||
|
||||
case (scope_arm(?a)) {
|
||||
if (ns == ns_value) {
|
||||
ret lookup_in_pat(id, *a.pat);
|
||||
@ -475,16 +499,30 @@ fn lookup_in_scope(&env e, list[scope] sc, ident id, namespace ns)
|
||||
ret none[def];
|
||||
}
|
||||
|
||||
auto left_fn = false;
|
||||
// Used to determine whether obj fields are in scope
|
||||
auto left_fn_level2 = false;
|
||||
while (true) {
|
||||
alt (sc) {
|
||||
case (nil[scope]) {
|
||||
ret none[def];
|
||||
}
|
||||
case (cons[scope](?hd, ?tl)) {
|
||||
alt (in_scope(e, id, hd, ns)) {
|
||||
case (some[def](?x)) { ret some(x); }
|
||||
case (_) { sc = *tl; }
|
||||
auto fnd = in_scope(e, id, hd, ns);
|
||||
if (fnd != none[def]) {
|
||||
auto df = option::get(fnd);
|
||||
if ((left_fn && def_is_local(df)) ||
|
||||
(left_fn_level2 && def_is_obj_field(df))) {
|
||||
e.sess.span_err(sp, "attempted dynamic " +
|
||||
"environment-capture");
|
||||
}
|
||||
ret fnd;
|
||||
}
|
||||
if (left_fn) { left_fn_level2 = true; }
|
||||
if (ns == ns_value && !left_fn) {
|
||||
left_fn = scope_is_fn(hd);
|
||||
}
|
||||
sc = *tl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -841,7 +879,6 @@ fn check_def_by_ns(def d, namespace ns) -> bool {
|
||||
case (ast::def_const(?id)) { ns == ns_value }
|
||||
case (ast::def_arg(?id)) { ns == ns_value }
|
||||
case (ast::def_local(?id)) { ns == ns_value }
|
||||
case (ast::def_upvar(?id)) { ns == ns_value }
|
||||
case (ast::def_variant(_, ?id)) { ns == ns_value }
|
||||
case (ast::def_ty(?id)) { ns == ns_type }
|
||||
case (ast::def_binding(?id)) { ns == ns_type }
|
||||
|
@ -3807,9 +3807,6 @@ fn collect_upvars(&@block_ctxt cx, &ast::block bloc,
|
||||
case (ast::def_local(?did)) {
|
||||
_vec::push[ast::def_id](e.refs, did);
|
||||
}
|
||||
case (ast::def_upvar(?did)) {
|
||||
_vec::push[ast::def_id](e.refs, did);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ mod middle {
|
||||
mod walk;
|
||||
mod metadata;
|
||||
mod resolve;
|
||||
mod capture;
|
||||
mod typeck;
|
||||
mod typestate_check;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
// xfail-stage0
|
||||
// xfail-stage1
|
||||
// xfail-stage2
|
||||
// error-pattern: attempted dynamic environment-capture
|
||||
fn foo() {
|
||||
let int x;
|
||||
|
11
src/test/compile-fail/bad-env-capture2.rs
Normal file
11
src/test/compile-fail/bad-env-capture2.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// xfail-stage0
|
||||
// xfail-stage1
|
||||
// error-pattern: attempted dynamic environment-capture
|
||||
fn foo(int x) {
|
||||
fn bar() {
|
||||
log x;
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
foo(2);
|
||||
}
|
14
src/test/compile-fail/bad-env-capture3.rs
Normal file
14
src/test/compile-fail/bad-env-capture3.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// xfail-stage0
|
||||
// xfail-stage1
|
||||
// error-pattern: attempted dynamic environment-capture
|
||||
obj foo(int x) {
|
||||
fn mth() {
|
||||
fn bar() {
|
||||
log x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo(2);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user