about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-05-13 11:57:58 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-05-13 12:44:05 +0200
commit58ec5d1654f367d7f3459ebee2b5f4c89e0f3aa1 (patch)
tree803ad4b840000f5af60041d6c565f210f12bf7a1
parent89490e416b9eff7d22cbea235475db1cba581ff6 (diff)
downloadrust-58ec5d1654f367d7f3459ebee2b5f4c89e0f3aa1.tar.gz
rust-58ec5d1654f367d7f3459ebee2b5f4c89e0f3aa1.zip
Move capture checking into resolve.rs
Drops capture.rs. The new algorithm also checks for captures function
arguments and obj fields.
-rw-r--r--src/comp/driver/rustc.rs3
-rw-r--r--src/comp/front/ast.rs2
-rw-r--r--src/comp/middle/capture.rs119
-rw-r--r--src/comp/middle/resolve.rs61
-rw-r--r--src/comp/middle/trans.rs3
-rw-r--r--src/comp/rustc.rc1
-rw-r--r--src/test/compile-fail/bad-env-capture.rs1
-rw-r--r--src/test/compile-fail/bad-env-capture2.rs11
-rw-r--r--src/test/compile-fail/bad-env-capture3.rs14
9 files changed, 74 insertions, 141 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index ad89ac9cad2..6592c23ad10 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -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 =
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index c107e7c8f03..5e5185bf7ee 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -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; }
diff --git a/src/comp/middle/capture.rs b/src/comp/middle/capture.rs
deleted file mode 100644
index 7124554a7c4..00000000000
--- a/src/comp/middle/capture.rs
+++ /dev/null
@@ -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:
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index ce7a2376e5e..11837033b6c 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -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 }
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 78a7a16aca8..d822be174bb 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -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 (_) {}
                 }
             }
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index 0d011eeee68..ca5534b315c 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -17,7 +17,6 @@ mod middle {
     mod walk;
     mod metadata;
     mod resolve;
-    mod capture;
     mod typeck;
     mod typestate_check;
 }
diff --git a/src/test/compile-fail/bad-env-capture.rs b/src/test/compile-fail/bad-env-capture.rs
index 55fa7473661..fa1e1d08acf 100644
--- a/src/test/compile-fail/bad-env-capture.rs
+++ b/src/test/compile-fail/bad-env-capture.rs
@@ -1,6 +1,5 @@
 // xfail-stage0
 // xfail-stage1
-// xfail-stage2
 // error-pattern: attempted dynamic environment-capture
 fn foo() {
   let int x;
diff --git a/src/test/compile-fail/bad-env-capture2.rs b/src/test/compile-fail/bad-env-capture2.rs
new file mode 100644
index 00000000000..ccec3310495
--- /dev/null
+++ b/src/test/compile-fail/bad-env-capture2.rs
@@ -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);
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/bad-env-capture3.rs b/src/test/compile-fail/bad-env-capture3.rs
new file mode 100644
index 00000000000..77f7881d14a
--- /dev/null
+++ b/src/test/compile-fail/bad-env-capture3.rs
@@ -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);
+}