diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2012-08-14 19:20:56 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2012-08-15 16:20:34 -0700 |
| commit | bdb206f2855cc6f7d3d79379633f7429b7327fec (patch) | |
| tree | 05764770b6b2729780bb1289d3c2db55d1cc55c5 /src/rustc | |
| parent | d54db12155257787797cd9c7eaf06a215ff516e5 (diff) | |
rustc: Parse labeled loop, break, and again
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/middle/astencode.rs | 1 | ||||
| -rw-r--r-- | src/rustc/middle/borrowck/gather_loans.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/check_loop.rs | 6 | ||||
| -rw-r--r-- | src/rustc/middle/liveness.rs | 18 | ||||
| -rw-r--r-- | src/rustc/middle/mem_categorization.rs | 7 | ||||
| -rw-r--r-- | src/rustc/middle/resolve3.rs | 61 | ||||
| -rw-r--r-- | src/rustc/middle/trans/base.rs | 12 | ||||
| -rw-r--r-- | src/rustc/middle/trans/type_use.rs | 4 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check.rs | 9 | ||||
| -rw-r--r-- | src/rustc/util/common.rs | 4 |
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 } } |
