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:
Marijn Haverbeke 2011-05-13 11:57:58 +02:00
parent 89490e416b
commit 58ec5d1654
9 changed files with 74 additions and 141 deletions

View file

@ -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 =

View file

@ -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; }

View file

@ -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:

View file

@ -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 }

View file

@ -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 (_) {}
}
}

View file

@ -17,7 +17,6 @@ mod middle {
mod walk;
mod metadata;
mod resolve;
mod capture;
mod typeck;
mod typestate_check;
}

View file

@ -1,6 +1,5 @@
// xfail-stage0
// xfail-stage1
// xfail-stage2
// error-pattern: attempted dynamic environment-capture
fn foo() {
let int x;

View 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);
}

View 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);
}