about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorRafael Ávila de Espíndola <respindola@mozilla.com>2011-04-11 15:35:01 -0400
committerRafael Ávila de Espíndola <respindola@mozilla.com>2011-04-11 15:35:01 -0400
commitcca6335c26ce3ddacafd3e6079dc56c842856c3c (patch)
tree909b80973fb4aa6b8dd6a486aa6bf207945218dc /src/comp
parent4bd8dcccbc6437a29a684633ddca66508ad940a3 (diff)
downloadrust-cca6335c26ce3ddacafd3e6079dc56c842856c3c.tar.gz
rust-cca6335c26ce3ddacafd3e6079dc56c842856c3c.zip
Implement the "attempted dynamic environment-capture" error in rustc.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/driver/rustc.rs2
-rw-r--r--src/comp/middle/capture.rs118
-rw-r--r--src/comp/rustc.rc1
3 files changed, 121 insertions, 0 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index c2f633685a7..9b2d88e8ffd 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -6,6 +6,7 @@ import front.token;
 import front.eval;
 import middle.trans;
 import middle.resolve;
+import middle.capture;
 import middle.ty;
 import middle.typeck;
 import middle.typestate_check;
@@ -67,6 +68,7 @@ impure fn compile_input(session.session sess,
     if (parse_only) {ret;}
     crate = creader.read_crates(sess, crate, library_search_paths);
     crate = resolve.resolve_crate(sess, crate);
+    capture.check_for_captures(sess, crate);
     auto typeck_result = typeck.check_crate(sess, crate);
     crate = typeck_result._0;
     auto type_cache = typeck_result._1;
diff --git a/src/comp/middle/capture.rs b/src/comp/middle/capture.rs
new file mode 100644
index 00000000000..73c8fef8045
--- /dev/null
+++ b/src/comp/middle/capture.rs
@@ -0,0 +1,118 @@
+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 util.common;
+
+type fn_id_of_local = std.map.hashmap[ast.def_id, ast.def_id];
+type env = rec(option.t[ast.def_id] current_context, // fn or obj
+               fn_id_of_local idmap,
+               session.session sess);
+
+fn update_env_for_item(&env e, @ast.item i) -> env {
+    alt (i.node) {
+        case (ast.item_fn(?name, _, _, ?id, _)) {
+            ret rec(current_context = some(id) with e);
+        }
+        case (ast.item_obj(_, _, _, ?ids, _)) {
+            ret rec(current_context = some(ids.ty) with e);
+        }
+        case (_) {
+            ret e;
+        }
+    }
+}
+
+fn update_env_for_expr(&env e, @ast.expr x) -> env {
+    alt (x.node) {
+        case (ast.expr_for(?d, _, _, _)) {
+            alt (d.node) {
+                case (ast.decl_local(?local)) {
+                    auto curr_context =
+                        option.get[ast.def_id](e.current_context);
+                    e.idmap.insert(local.id, curr_context);
+                }
+                case (_) {
+                }
+            }
+        }
+        case (ast.expr_for_each(?d, _, _, _)) {
+            alt (d.node) {
+                case (ast.decl_local(?local)) {
+                    auto curr_context =
+                        option.get[ast.def_id](e.current_context);
+                    e.idmap.insert(local.id, curr_context);
+                }
+                case (_) {
+                }
+            }
+        }
+        case (_) { }
+    }
+    ret e;
+}
+
+fn update_env_for_block(&env e, &ast.block b) -> env {
+    auto curr_context = option.get[ast.def_id](e.current_context);
+
+    for each (@tup(ast.ident, ast.block_index_entry) it in
+              b.node.index.items()) {
+        alt (it._1) {
+            case (ast.bie_local(?local)) {
+                e.idmap.insert(local.id, curr_context);
+            }
+            case (_) {
+            }
+        }
+    }
+
+    ret e;
+}
+
+fn fold_expr_path(&env e, &ast.span sp, &ast.path p, &option.t[ast.def] d,
+                  ast.ann a) -> @ast.expr {
+    auto local_id;
+    alt (option.get[ast.def](d)) {
+        case (ast.def_local(?id)) {
+            local_id = id;
+        }
+        case (_) {
+            ret @fold.respan[ast.expr_](sp, ast.expr_path(p, d, a));
+        }
+    }
+
+    auto curr_context = option.get[ast.def_id](e.current_context);
+    auto x = ast.def_id_of_def(option.get[ast.def](d));
+    auto def_context = option.get[ast.def_id](e.idmap.find(x));
+
+    if (curr_context != def_context) {
+        e.sess.span_err(sp, "attempted dynamic environment-capture");
+    }
+
+    ret @fold.respan[ast.expr_](sp, ast.expr_path(p, d, a));
+}
+
+fn check_for_captures(session.session sess, @ast.crate crate) {
+    let fold.ast_fold[env] fld = fold.new_identity_fold[env]();
+    fld = @rec( update_env_for_item = bind update_env_for_item(_,_),
+                update_env_for_block = bind update_env_for_block(_,_),
+                update_env_for_expr = bind update_env_for_expr(_,_),
+                fold_expr_path = bind fold_expr_path(_,_,_,_,_)
+                with *fld);
+    auto idmap = common.new_def_hash[ast.def_id]();
+    auto e = rec(current_context = none[ast.def_id], idmap = idmap,
+                 sess = sess);
+    fold.fold_crate[env](e, fld, 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/rustc.rc b/src/comp/rustc.rc
index 981577abc57..8e57ff4d90f 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -18,6 +18,7 @@ mod middle {
     mod fold;
     mod metadata;
     mod resolve;
+    mod capture;
     mod trans;
     mod ty;
     mod typeck;