about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-08-14 19:20:56 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-08-15 16:20:34 -0700
commitbdb206f2855cc6f7d3d79379633f7429b7327fec (patch)
tree05764770b6b2729780bb1289d3c2db55d1cc55c5 /src/rustc
parentd54db12155257787797cd9c7eaf06a215ff516e5 (diff)
rustc: Parse labeled loop, break, and again
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/astencode.rs1
-rw-r--r--src/rustc/middle/borrowck/gather_loans.rs2
-rw-r--r--src/rustc/middle/check_loop.rs6
-rw-r--r--src/rustc/middle/liveness.rs18
-rw-r--r--src/rustc/middle/mem_categorization.rs7
-rw-r--r--src/rustc/middle/resolve3.rs61
-rw-r--r--src/rustc/middle/trans/base.rs12
-rw-r--r--src/rustc/middle/trans/type_use.rs4
-rw-r--r--src/rustc/middle/typeck/check.rs9
-rw-r--r--src/rustc/util/common.rs4
10 files changed, 91 insertions, 33 deletions
diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs
index d1ccc72ac00..0f9f4db36e7 100644
--- a/src/rustc/middle/astencode.rs
+++ b/src/rustc/middle/astencode.rs
@@ -374,6 +374,7 @@ impl ast::def: tr {
           ast::def_typaram_binder(nid) => {
             ast::def_typaram_binder(xcx.tr_id(nid))
           }
+          ast::def_label(nid) => ast::def_label(xcx.tr_id(nid))
         }
     }
 }
diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs
index 3541ddad626..83dc54e5f86 100644
--- a/src/rustc/middle/borrowck/gather_loans.rs
+++ b/src/rustc/middle/borrowck/gather_loans.rs
@@ -227,7 +227,7 @@ fn req_loans_in_expr(ex: @ast::expr,
       }
 
       // see explanation attached to the `root_ub` field:
-      ast::expr_loop(body) => {
+      ast::expr_loop(body, _) => {
         self.root_ub = body.node.id;
         visit::visit_expr(ex, self, vt);
       }
diff --git a/src/rustc/middle/check_loop.rs b/src/rustc/middle/check_loop.rs
index a105ce68529..1fef670c0ba 100644
--- a/src/rustc/middle/check_loop.rs
+++ b/src/rustc/middle/check_loop.rs
@@ -15,7 +15,7 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
                 v.visit_expr(e, cx, v);
                 v.visit_block(b, {in_loop: true with cx}, v);
               }
-              expr_loop(b) => {
+              expr_loop(b, _) => {
                 v.visit_block(b, {in_loop: true with cx}, v);
               }
               expr_fn(_, _, _, _) => {
@@ -29,12 +29,12 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
                                                                       e)));
                 v.visit_block(b, {in_loop: true, can_ret: blk}, v);
               }
-              expr_break => {
+              expr_break(_) => {
                 if !cx.in_loop {
                     tcx.sess.span_err(e.span, ~"`break` outside of loop");
                 }
               }
-              expr_again => {
+              expr_again(_) => {
                 if !cx.in_loop {
                     tcx.sess.span_err(e.span, ~"`again` outside of loop");
                 }
diff --git a/src/rustc/middle/liveness.rs b/src/rustc/middle/liveness.rs
index f8983f2bebb..c89095423c6 100644
--- a/src/rustc/middle/liveness.rs
+++ b/src/rustc/middle/liveness.rs
@@ -469,7 +469,7 @@ fn visit_expr(expr: @expr, &&self: @ir_maps, vt: vt<@ir_maps>) {
       expr_assert(*) | expr_addr_of(*) | expr_copy(*) |
       expr_loop_body(*) | expr_do_body(*) | expr_cast(*) |
       expr_unary(*) | expr_fail(*) |
-      expr_break | expr_again | expr_lit(_) | expr_ret(*) |
+      expr_break(_) | expr_again(_) | expr_lit(_) | expr_ret(*) |
       expr_block(*) | expr_move(*) | expr_unary_move(*) | expr_assign(*) |
       expr_swap(*) | expr_assign_op(*) | expr_mac(*) | expr_struct(*) |
       expr_repeat(*) => {
@@ -962,7 +962,7 @@ class liveness {
             self.propagate_through_loop(expr, some(cond), blk, succ)
           }
 
-          expr_loop(blk) => {
+          expr_loop(blk, _) => {
             self.propagate_through_loop(expr, none, blk, succ)
           }
 
@@ -1000,21 +1000,29 @@ class liveness {
             self.propagate_through_opt_expr(o_e, self.s.exit_ln)
           }
 
-          expr_break => {
+          expr_break(opt_label) => {
             if !self.break_ln.is_valid() {
                 self.tcx.sess.span_bug(
                     expr.span, ~"break with invalid break_ln");
             }
 
+            if opt_label.is_some() {
+                self.tcx.sess.span_unimpl(expr.span, ~"labeled break");
+            }
+
             self.break_ln
           }
 
-          expr_again => {
+          expr_again(opt_label) => {
             if !self.cont_ln.is_valid() {
                 self.tcx.sess.span_bug(
                     expr.span, ~"cont with invalid cont_ln");
             }
 
+            if opt_label.is_some() {
+                self.tcx.sess.span_unimpl(expr.span, ~"labeled again");
+            }
+
             self.cont_ln
           }
 
@@ -1457,7 +1465,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
       expr_assert(*) | expr_copy(*) |
       expr_loop_body(*) | expr_do_body(*) |
       expr_cast(*) | expr_unary(*) | expr_fail(*) |
-      expr_ret(*) | expr_break | expr_again | expr_lit(_) |
+      expr_ret(*) | expr_break(*) | expr_again(*) | expr_lit(_) |
       expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) |
       expr_struct(*) | expr_repeat(*) => {
         visit::visit_expr(expr, self, vt);
diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs
index b509880ab5f..5ffc36f4160 100644
--- a/src/rustc/middle/mem_categorization.rs
+++ b/src/rustc/middle/mem_categorization.rs
@@ -317,8 +317,8 @@ impl &mem_categorization_ctxt {
           ast::expr_if(*) | ast::expr_log(*) |
           ast::expr_binary(*) | ast::expr_while(*) |
           ast::expr_block(*) | ast::expr_loop(*) | ast::expr_match(*) |
-          ast::expr_lit(*) | ast::expr_break | ast::expr_mac(*) |
-          ast::expr_again | ast::expr_rec(*) | ast::expr_struct(*) |
+          ast::expr_lit(*) | ast::expr_break(*) | ast::expr_mac(*) |
+          ast::expr_again(*) | ast::expr_rec(*) | ast::expr_struct(*) |
           ast::expr_unary_move(*) | ast::expr_repeat(*) => {
             return self.cat_rvalue(expr, expr_ty);
           }
@@ -335,7 +335,8 @@ impl &mem_categorization_ctxt {
           ast::def_use(_) | ast::def_variant(*) |
           ast::def_ty(_) | ast::def_prim_ty(_) |
           ast::def_ty_param(*) | ast::def_class(*) |
-          ast::def_typaram_binder(*) | ast::def_region(_) => {
+          ast::def_typaram_binder(*) | ast::def_region(_) |
+          ast::def_label(_) => {
             @{id:id, span:span,
               cat:cat_special(sk_static_item), lp:none,
               mutbl:m_imm, ty:expr_ty}
diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs
index a06e6ea1dba..0262efca156 100644
--- a/src/rustc/middle/resolve3.rs
+++ b/src/rustc/middle/resolve3.rs
@@ -14,7 +14,7 @@ import syntax::ast::{bound_trait, binding_mode,
                      capture_clause, class_ctor, class_dtor};
 import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
 import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn};
-import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod};
+import syntax::ast::{def_foreign_mod, def_id, def_label, def_local, def_mod};
 import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
 import syntax::ast::{def_typaram_binder, def_static_method};
 import syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op};
@@ -22,9 +22,10 @@ import syntax::ast::{expr_binary, expr_cast, expr_field, expr_fn};
 import syntax::ast::{expr_fn_block, expr_index, expr_path};
 import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
 import syntax::ast::{def_upvar, def_use, def_variant, div, eq};
-import syntax::ast::{enum_variant_kind, expr, expr_assign_op, expr_binary};
-import syntax::ast::{expr_cast, expr_field, expr_fn, expr_fn_block};
-import syntax::ast::{expr_index, expr_path, expr_struct, expr_unary, fn_decl};
+import syntax::ast::{enum_variant_kind, expr, expr_again, expr_assign_op};
+import syntax::ast::{expr_binary, expr_break, expr_cast, expr_field, expr_fn};
+import syntax::ast::{expr_fn_block, expr_index, expr_loop};
+import syntax::ast::{expr_path, expr_struct, expr_unary, fn_decl};
 import syntax::ast::{foreign_item, foreign_item_fn, ge, gt, ident, trait_ref};
 import syntax::ast::{impure_fn, instance_var, item, item_class, item_const};
 import syntax::ast::{item_enum, item_fn, item_mac, item_foreign_mod};
@@ -310,10 +311,7 @@ fn atom_hashmap<V:copy>() -> hashmap<Atom,V> {
     hashmap::<Atom,V>(uint::hash, uint::eq)
 }
 
-/**
- * One local scope. In Rust, local scopes can only contain value bindings.
- * Therefore, we don't have to worry about the other namespaces here.
- */
+/// One local scope.
 class Rib {
     let bindings: hashmap<Atom,def_like>;
     let kind: RibKind;
@@ -676,12 +674,14 @@ class Resolver {
 
     // The current set of local scopes, for values.
     // XXX: Reuse ribs to avoid allocation.
-
     let value_ribs: @DVec<@Rib>;
 
     // The current set of local scopes, for types.
     let type_ribs: @DVec<@Rib>;
 
+    // The current set of local scopes, for labels.
+    let label_ribs: @DVec<@Rib>;
+
     // Whether the current context is an X-ray context. An X-ray context is
     // allowed to access private names of any module.
     let mut xray_context: XrayFlag;
@@ -728,6 +728,7 @@ class Resolver {
         self.current_module = (*self.graph_root).get_module();
         self.value_ribs = @dvec();
         self.type_ribs = @dvec();
+        self.label_ribs = @dvec();
 
         self.xray_context = NoXray;
         self.current_trait_refs = none;
@@ -1486,7 +1487,7 @@ class Resolver {
           def_self(*) | def_arg(*) | def_local(*) |
           def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
           def_use(*) | def_upvar(*) | def_region(*) |
-          def_typaram_binder(*) => {
+          def_typaram_binder(*) | def_label(*) => {
             fail fmt!("didn't expect `%?`", def);
           }
         }
@@ -3305,12 +3306,18 @@ class Resolver {
                 (*self.type_ribs).pop();
             }
 
-            NoTypeParameters =>{
+            NoTypeParameters => {
                 // Nothing to do.
             }
         }
     }
 
+    fn with_label_rib(f: fn()) {
+        (*self.label_ribs).push(@Rib(NormalRibKind));
+        f();
+        (*self.label_ribs).pop();
+    }
+
     fn resolve_function(rib_kind: RibKind,
                         optional_declaration: option<@fn_decl>,
                         type_parameters: TypeParameters,
@@ -3348,6 +3355,10 @@ class Resolver {
         let function_value_rib = @Rib(rib_kind);
         (*self.value_ribs).push(function_value_rib);
 
+        // Create a label rib for the function.
+        let function_label_rib = @Rib(rib_kind);
+        (*self.label_ribs).push(function_label_rib);
+
         // If this function has type parameters, add them now.
         do self.with_type_parameter_rib(type_parameters) {
             // Resolve the type parameters.
@@ -3400,6 +3411,7 @@ class Resolver {
             debug!{"(resolving function) leaving function"};
         }
 
+        (*self.label_ribs).pop();
         (*self.value_ribs).pop();
     }
 
@@ -4428,6 +4440,33 @@ class Resolver {
                 visit_expr(expr, (), visitor);
             }
 
+            expr_loop(_, some(label)) => {
+                do self.with_label_rib {
+                    let atom = self.atom_table.intern(label);
+                    let def_like = dl_def(def_label(expr.id));
+                    self.label_ribs.last().bindings.insert(atom, def_like);
+
+                    visit_expr(expr, (), visitor);
+                }
+            }
+
+            expr_break(some(label)) | expr_again(some(label)) => {
+                let atom = self.atom_table.intern(label);
+                match self.search_ribs(self.label_ribs, atom, expr.span,
+                                       DontAllowCapturingSelf) {
+                    none =>
+                        self.session.span_err(expr.span,
+                                              fmt!("use of undeclared label \
+                                                   `%s`", *label)),
+                    some(dl_def(def @ def_label(id))) =>
+                        self.record_def(expr.id, def),
+                    some(_) =>
+                        self.session.span_bug(expr.span,
+                                              ~"label wasn't mapped to a \
+                                                label def!")
+                }
+            }
+
             _ => {
                 visit_expr(expr, (), visitor);
             }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 2734fa85ae6..487435f2ef2 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -3852,12 +3852,18 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
           }
 
           // These return nothing
-          ast::expr_break => {
+          ast::expr_break(label_opt) => {
             assert dest == ignore;
+            if label_opt.is_some() {
+                bcx.tcx().sess.span_unimpl(e.span, ~"labeled break");
+            }
             return trans_break(bcx);
           }
-          ast::expr_again => {
+          ast::expr_again(label_opt) => {
             assert dest == ignore;
+            if label_opt.is_some() {
+                bcx.tcx().sess.span_unimpl(e.span, ~"labeled again");
+            }
             return trans_cont(bcx);
           }
           ast::expr_ret(ex) => {
@@ -3880,7 +3886,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
             assert dest == ignore;
             return trans_while(bcx, cond, body);
           }
-          ast::expr_loop(body) => {
+          ast::expr_loop(body, _) => {
             assert dest == ignore;
             return trans_loop(bcx, body);
           }
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index 880c6c546f2..a53d9b3a3ba 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -253,10 +253,10 @@ fn mark_for_expr(cx: ctx, e: @expr) {
         })
       }
       expr_match(_, _, _) | expr_block(_) | expr_if(_, _, _) |
-      expr_while(_, _) | expr_fail(_) | expr_break | expr_again |
+      expr_while(_, _) | expr_fail(_) | expr_break(_) | expr_again(_) |
       expr_unary(_, _) | expr_lit(_) | expr_assert(_) |
       expr_mac(_) | expr_addr_of(_, _) |
-      expr_ret(_) | expr_loop(_) |
+      expr_ret(_) | expr_loop(_, _) |
       expr_loop_body(_) | expr_do_body(_) => ()
     }
 }
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 3bc4e578c74..64ebcd5fbbb 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -1466,8 +1466,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         }
         fcx.write_bot(id);
       }
-      ast::expr_break => { fcx.write_bot(id); bot = true; }
-      ast::expr_again => { fcx.write_bot(id); bot = true; }
+      ast::expr_break(_) => { fcx.write_bot(id); bot = true; }
+      ast::expr_again(_) => { fcx.write_bot(id); bot = true; }
       ast::expr_ret(expr_opt) => {
         bot = true;
         let ret_ty = match fcx.indirect_ret_ty {
@@ -1518,7 +1518,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         check_block_no_value(fcx, body);
         fcx.write_ty(id, ty::mk_nil(tcx));
       }
-      ast::expr_loop(body) => {
+      ast::expr_loop(body, _) => {
         check_block_no_value(fcx, body);
         fcx.write_ty(id, ty::mk_nil(tcx));
         bot = !may_break(body);
@@ -2296,6 +2296,9 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
         fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type \
                                           parameter");
       }
+      ast::def_label(*) => {
+        fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found label");
+      }
     }
 }
 
diff --git a/src/rustc/util/common.rs b/src/rustc/util/common.rs
index 906f3b7bdb3..b4195d0c04c 100644
--- a/src/rustc/util/common.rs
+++ b/src/rustc/util/common.rs
@@ -59,7 +59,7 @@ fn loop_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
 fn has_nonlocal_exits(b: ast::blk) -> bool {
     do loop_query(b) |e| {
         match e {
-          ast::expr_break | ast::expr_again => true,
+          ast::expr_break(_) | ast::expr_again(_) => true,
           _ => false
         }
     }
@@ -68,7 +68,7 @@ fn has_nonlocal_exits(b: ast::blk) -> bool {
 fn may_break(b: ast::blk) -> bool {
     do loop_query(b) |e| {
         match e {
-          ast::expr_break => true,
+          ast::expr_break(_) => true,
           _ => false
         }
     }