summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-03-11 12:05:17 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-03-11 12:05:17 -0700
commite968672ac7b4fe840b2b1561585f7ca7d4fd892d (patch)
tree97170e550a81cde99d9519e7dbaf12ee83eac46b /src
parentd3035a1b205caef6279c91b276e672c54318838c (diff)
rustc: Map local variables to their containing blocks so we know their regions
Diffstat (limited to 'src')
-rw-r--r--src/rustc/driver/driver.rs2
-rw-r--r--src/rustc/middle/region.rs91
2 files changed, 85 insertions, 8 deletions
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs
index ca7028e5e9e..6dacdf49b85 100644
--- a/src/rustc/driver/driver.rs
+++ b/src/rustc/driver/driver.rs
@@ -142,7 +142,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
              bind freevars::annotate_freevars(def_map, crate));
     let region_map =
         time(time_passes, "region resolution",
-             bind middle::region::resolve_crate(sess, crate));
+             bind middle::region::resolve_crate(sess, def_map, crate));
     let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars, region_map);
     let (method_map, dict_map) =
         time(time_passes, "typechecking",
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index 1981377a83e..303ad24513d 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -10,20 +10,36 @@ import std::map;
 import std::map::hashmap;
 
 type region_map = {
+    /* Mapping from a block to its parent block, if there is one. */
     parent_blocks: hashmap<ast::node_id,ast::node_id>,
-    ast_type_to_region: hashmap<ast::node_id,ty::region>
+    /* Mapping from a region type in the AST to its resolved region. */
+    ast_type_to_region: hashmap<ast::node_id,ty::region>,
+    /* Mapping from a local variable to its containing block. */
+    local_blocks: hashmap<ast::node_id,ast::node_id>
 };
 
+/* Represents the type of the most immediate parent node. */
 enum parent {
     pa_item(ast::node_id),
     pa_block(ast::node_id),
+    pa_alt,
     pa_crate
 }
 
 type ctxt = {
     sess: session,
+    def_map: resolve::def_map,
     region_map: @region_map,
     names_in_scope: hashmap<str,ast::def_id>,
+
+    /*
+     * A list of local IDs that will be parented to the next block we traverse.
+     * This is used when resolving `alt` statements. Since we see the pattern
+     * before the associated block, upon seeing a pattern we must parent all the
+     * bindings in that pattern to the next block we see.
+     */
+    mut queued_locals: [ast::node_id],
+
     parent: parent
 };
 
@@ -44,6 +60,12 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
                         pa_block(block_id) {
                             region = ty::re_block(block_id);
                         }
+                        pa_alt {
+                            // FIXME: Need a design decision here.
+                            cx.sess.span_bug(ty.span,
+                                             "what does & in an alt " +
+                                             "resolve to?");
+                        }
                         pa_crate {
                             cx.sess.span_bug(ty.span,
                                              "region type outside item");
@@ -59,7 +81,7 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
                         none {
                             alt cx.parent {
                                 pa_item(_) { /* ok; fall through */ }
-                                pa_block(_) {
+                                pa_block(_) | pa_alt {
                                     cx.sess.span_err(ty.span,
                                                      "unknown region `" +
                                                      ident + "`");
@@ -89,6 +111,12 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
                         pa_block(block_id) {
                             region = ty::re_block(block_id);
                         }
+                        pa_alt {
+                            // FIXME: Need a design decision here.
+                            cx.sess.span_bug(ty.span,
+                                             "what does &self. in an alt " +
+                                             "resolve to?");
+                        }
                         pa_crate {
                             cx.sess.span_bug(ty.span,
                                              "region type outside item");
@@ -108,17 +136,60 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
 
 fn resolve_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
     alt cx.parent {
-        pa_item(_) { /* no-op */ }
+        pa_item(_) | pa_alt { /* no-op */ }
         pa_block(parent_block_id) {
             cx.region_map.parent_blocks.insert(blk.node.id, parent_block_id);
         }
         pa_crate { cx.sess.span_bug(blk.span, "block outside item?!"); }
     }
 
-    let new_cx: ctxt = {parent: pa_block(blk.node.id) with cx};
+    // Resolve queued locals to this block.
+    for local_id in cx.queued_locals {
+        cx.region_map.local_blocks.insert(local_id, blk.node.id);
+    }
+
+    let new_cx: ctxt = {parent: pa_block(blk.node.id),
+                        mut queued_locals: [] with cx};
     visit::visit_block(blk, new_cx, visitor);
 }
 
+fn resolve_arm(arm: ast::arm, cx: ctxt, visitor: visit::vt<ctxt>) {
+    let new_cx: ctxt = {parent: pa_alt,
+                        mut queued_locals: [] with cx};
+    visit::visit_arm(arm, new_cx, visitor);
+}
+
+fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
+    alt pat.node {
+        ast::pat_ident(path, _) {
+            let defn_opt = cx.def_map.find(pat.id);
+            alt defn_opt {
+                some(ast::def_variant(_,_)) {
+                    /* Nothing to do; this names a variant. */
+                }
+                _ {
+                    /*
+                     * This names a local. Enqueue it or bind it to the containing
+                     * block, depending on whether we're in an alt or not.
+                     */
+                    alt cx.parent {
+                        pa_block(block_id) {
+                            cx.region_map.local_blocks.insert(pat.id, block_id);
+                        }
+                        pa_alt {
+                            vec::push(cx.queued_locals, pat.id);
+                        }
+                        _ { cx.sess.span_bug(pat.span, "unexpected parent"); }
+                    }
+                }
+            }
+        }
+        _ { /* no-op */ }
+    }
+
+    visit::visit_pat(pat, cx, visitor);
+}
+
 fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
     // Items create a new outer block scope as far as we're concerned.
     let new_cx: ctxt = {names_in_scope: map::new_str_hash(),
@@ -127,16 +198,22 @@ fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
     visit::visit_item(item, new_cx, visitor);
 }
 
-fn resolve_crate(sess: session, crate: @ast::crate) -> @region_map {
+fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
+        -> @region_map {
     let cx: ctxt = {sess: sess,
+                    def_map: def_map,
                     region_map: @{parent_blocks: map::new_int_hash(),
-                                  ast_type_to_region: map::new_int_hash()},
+                                  ast_type_to_region: map::new_int_hash(),
+                                  local_blocks: map::new_int_hash()},
                     names_in_scope: map::new_str_hash(),
+                    mut queued_locals: [],
                     parent: pa_crate};
     let visitor = visit::mk_vt(@{
         visit_block: resolve_block,
         visit_item: resolve_item,
-        visit_ty: resolve_ty
+        visit_ty: resolve_ty,
+        visit_arm: resolve_arm,
+        visit_pat: resolve_pat
         with *visit::default_visitor()
     });
     visit::visit_crate(*crate, cx, visitor);