From 321fd80219e024cabb7ee539e701bc6b4a258751 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 9 Mar 2012 16:11:56 -0800 Subject: [PATCH] Add an infinite loop construct Add a loop {} construct for infinite loops, and use it in test cases. See #1906 for details. --- src/libcore/uint.rs | 4 +- src/libstd/uv.rs | 62 +++++----- src/rustc/metadata/astencode_gen.rs | 111 +++++++++++------- src/rustc/middle/last_use.rs | 10 +- src/rustc/middle/trans/base.rs | 17 ++- .../middle/tstate/pre_post_conditions.rs | 13 ++ src/rustc/middle/tstate/states.rs | 18 ++- src/rustc/middle/typeck.rs | 5 +- src/rustc/syntax/ast.rs | 4 + src/rustc/syntax/fold.rs | 5 +- src/rustc/syntax/parse/parser.rs | 21 +++- src/rustc/syntax/print/pprust.rs | 5 + src/rustc/syntax/visit.rs | 1 + src/rustdoc/markdown_writer.rs | 2 +- src/rustdoc/page_pass.rs | 2 +- src/test/bench/shootout-pfib.rs | 2 +- .../bench/task-perf-word-count-generic.rs | 4 +- src/test/bench/task-perf-word-count.rs | 4 +- .../block-must-not-have-result-while.rs | 2 +- src/test/compile-fail/while-bypass.rs | 2 +- .../compile-fail/while-loop-constraints.rs | 8 +- .../while-loop-pred-constraints.rs | 4 +- src/test/run-pass/acyclic-unwind.rs | 2 +- src/test/run-pass/break-value.rs | 2 +- src/test/run-pass/infinite-loops.rs | 2 +- src/test/run-pass/issue-687.rs | 4 +- src/test/run-pass/last-use-corner-cases.rs | 2 +- src/test/run-pass/last-use-in-block.rs | 2 +- src/test/run-pass/preempt.rs | 2 +- src/test/run-pass/send-iloop.rs | 2 +- src/test/run-pass/terminate-in-initializer.rs | 2 +- src/test/run-pass/unreachable-code.rs | 2 +- src/test/run-pass/weird-exprs.rs | 2 +- 33 files changed, 208 insertions(+), 122 deletions(-) diff --git a/src/libcore/uint.rs b/src/libcore/uint.rs index 69981d2e980..776965d350a 100644 --- a/src/libcore/uint.rs +++ b/src/libcore/uint.rs @@ -138,7 +138,7 @@ fn range(lo: uint, hi: uint, it: fn(uint)) { } /* -Function: loop +Function: iterate Iterate over the range [`lo`..`hi`), or stop when requested @@ -153,7 +153,7 @@ Returns: `true` If execution proceeded correctly, `false` if it was interrupted, that is if `it` returned `false` at any point. */ -fn loop(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool { +fn iterate(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool { let mut i = lo; while i < hi { if (!it(i)) { ret false; } diff --git a/src/libstd/uv.rs b/src/libstd/uv.rs index 9991d68b295..6797ad9873d 100644 --- a/src/libstd/uv.rs +++ b/src/libstd/uv.rs @@ -53,11 +53,11 @@ enum uv_loop { #[nolink] native mod rustrt { fn rust_uv_loop_new() -> *ctypes::void; - fn rust_uv_loop_delete(loop: *ctypes::void); + fn rust_uv_loop_delete(lp: *ctypes::void); fn rust_uv_loop_set_data( - loop: *ctypes::void, + lp: *ctypes::void, data: *uv_loop_data); - fn rust_uv_bind_op_cb(loop: *ctypes::void, cb: *u8) + fn rust_uv_bind_op_cb(lp: *ctypes::void, cb: *u8) -> *ctypes::void; fn rust_uv_stop_op_cb(handle: *ctypes::void); fn rust_uv_run(loop_handle: *ctypes::void); @@ -317,37 +317,37 @@ fn loop_new() -> uv_loop unsafe { ret comm::recv(ret_recv_port); } -fn loop_delete(loop: uv_loop) { - let loop_ptr = get_loop_ptr_from_uv_loop(loop); +fn loop_delete(lp: uv_loop) { + let loop_ptr = get_loop_ptr_from_uv_loop(lp); rustrt::rust_uv_loop_delete(loop_ptr); } -fn run(loop: uv_loop) { +fn run(lp: uv_loop) { let end_port = comm::port::(); let end_chan = comm::chan::(end_port); - let loop_chan = get_loop_chan_from_uv_loop(loop); + let loop_chan = get_loop_chan_from_uv_loop(lp); comm::send(loop_chan, msg_run(end_chan)); comm::recv(end_port); } -fn run_in_bg(loop: uv_loop) { - let loop_chan = get_loop_chan_from_uv_loop(loop); +fn run_in_bg(lp: uv_loop) { + let loop_chan = get_loop_chan_from_uv_loop(lp); comm::send(loop_chan, msg_run_in_bg); } fn async_init ( - loop: uv_loop, + lp: uv_loop, async_cb: fn~(uv_handle), after_cb: fn~(uv_handle)) { let msg = msg_async_init(async_cb, after_cb); - let loop_chan = get_loop_chan_from_uv_loop(loop); + let loop_chan = get_loop_chan_from_uv_loop(lp); comm::send(loop_chan, msg); } fn async_send(async: uv_handle) { alt async { - uv_async(id, loop) { - let loop_chan = get_loop_chan_from_uv_loop(loop); + uv_async(id, lp) { + let loop_chan = get_loop_chan_from_uv_loop(lp); comm::send(loop_chan, msg_async_send(id)); } _ { @@ -362,18 +362,18 @@ fn close(h: uv_handle, cb: fn~()) { comm::send(loop_chan, msg_close(h, cb)); } -fn timer_init(loop: uv_loop, after_cb: fn~(uv_handle)) { +fn timer_init(lp: uv_loop, after_cb: fn~(uv_handle)) { let msg = msg_timer_init(after_cb); - let loop_chan = get_loop_chan_from_uv_loop(loop); + let loop_chan = get_loop_chan_from_uv_loop(lp); comm::send(loop_chan, msg); } fn timer_start(the_timer: uv_handle, timeout: u32, repeat:u32, timer_cb: fn~(uv_handle)) { alt the_timer { - uv_timer(id, loop) { + uv_timer(id, lp) { let msg = msg_timer_start(id, timeout, repeat, timer_cb); - let loop_chan = get_loop_chan_from_uv_loop(loop); + let loop_chan = get_loop_chan_from_uv_loop(lp); comm::send(loop_chan, msg); } _ { @@ -385,8 +385,8 @@ fn timer_start(the_timer: uv_handle, timeout: u32, repeat:u32, fn timer_stop(the_timer: uv_handle, after_cb: fn~(uv_handle)) { alt the_timer { - uv_timer(id, loop) { - let loop_chan = get_loop_chan_from_uv_loop(loop); + uv_timer(id, lp) { + let loop_chan = get_loop_chan_from_uv_loop(lp); let msg = msg_timer_stop(id, after_cb); comm::send(loop_chan, msg); } @@ -423,8 +423,8 @@ fn get_loop_chan_from_data(data: *uv_loop_data) fn get_loop_chan_from_handle(handle: uv_handle) -> comm::chan { alt handle { - uv_async(id,loop) | uv_timer(id,loop) { - let loop_chan = get_loop_chan_from_uv_loop(loop); + uv_async(id,lp) | uv_timer(id,lp) { + let loop_chan = get_loop_chan_from_uv_loop(lp); ret loop_chan; } _ { @@ -434,15 +434,15 @@ fn get_loop_chan_from_handle(handle: uv_handle) } } -fn get_loop_ptr_from_uv_loop(loop: uv_loop) -> *ctypes::void { - alt loop { +fn get_loop_ptr_from_uv_loop(lp: uv_loop) -> *ctypes::void { + alt lp { uv_loop_new(loop_chan, loop_ptr) { ret loop_ptr; } } } -fn get_loop_chan_from_uv_loop(loop: uv_loop) -> comm::chan { - alt loop { +fn get_loop_chan_from_uv_loop(lp: uv_loop) -> comm::chan { + alt lp { uv_loop_new(loop_chan, loop_ptr) { ret loop_chan; } @@ -451,7 +451,7 @@ fn get_loop_chan_from_uv_loop(loop: uv_loop) -> comm::chan { fn get_id_from_handle(handle: uv_handle) -> [u8] { alt handle { - uv_async(id,loop) | uv_timer(id,loop) { + uv_async(id,lp) | uv_timer(id,lp) { ret id; } _ { @@ -462,7 +462,7 @@ fn get_id_from_handle(handle: uv_handle) -> [u8] { // crust crust fn process_operation( - loop: *ctypes::void, + lp: *ctypes::void, data: *uv_loop_data) unsafe { let op_port = (*data).operation_port; let loop_chan = get_loop_chan_from_data(data); @@ -472,7 +472,7 @@ crust fn process_operation( op_async_init(id) { let id_ptr = vec::unsafe::to_ptr(id); let async_handle = rustrt::rust_uv_async_init( - loop, + lp, process_async_send, id_ptr); comm::send(loop_chan, uv_async_init( @@ -485,7 +485,7 @@ crust fn process_operation( op_timer_init(id) { let id_ptr = vec::unsafe::to_ptr(id); let timer_handle = rustrt::rust_uv_timer_init( - loop, + lp, process_timer_call, id_ptr); comm::send(loop_chan, uv_timer_init( @@ -515,12 +515,12 @@ crust fn process_operation( fn handle_op_close(handle: uv_handle, handle_ptr: *ctypes::void) { // it's just like im doing C alt handle { - uv_async(id, loop) { + uv_async(id, lp) { let cb = process_close_async; rustrt::rust_uv_close( handle_ptr, cb); } - uv_timer(id, loop) { + uv_timer(id, lp) { let cb = process_close_timer; rustrt::rust_uv_close( handle_ptr, cb); diff --git a/src/rustc/metadata/astencode_gen.rs b/src/rustc/metadata/astencode_gen.rs index f8aa1ee7fa8..8aeefe084dc 100644 --- a/src/rustc/metadata/astencode_gen.rs +++ b/src/rustc/metadata/astencode_gen.rs @@ -2419,6 +2419,7 @@ fn serialize_74(s: S, /*@syntax::ast::local*//*@syntax::ast::expr*/ /*syntax::ast::blk*/ /*syntax::ast::blk*//*@syntax::ast::expr*/ + /*syntax::ast::blk*/ /*@syntax::ast::expr*//*[syntax::ast::arm]*/ /*syntax::ast::alt_mode*/ /*syntax::ast::proto*//*syntax::ast::fn_decl*/ @@ -2683,8 +2684,20 @@ fn serialize_74(s: S, } }) } + syntax::ast::expr_loop(v0) { + s.emit_enum_variant("syntax::ast::expr_loop", 13u, 1u, + {|| + { + s.emit_enum_variant_arg(0u, + {|| + serialize_83(s, + v0) + }) + } + }) + } syntax::ast::expr_alt(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_alt", 13u, 3u, + s.emit_enum_variant("syntax::ast::expr_alt", 14u, 3u, {|| { s.emit_enum_variant_arg(0u, @@ -2706,7 +2719,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_fn(v0, v1, v2, v3) { - s.emit_enum_variant("syntax::ast::expr_fn", 14u, 4u, + s.emit_enum_variant("syntax::ast::expr_fn", 15u, 4u, {|| { s.emit_enum_variant_arg(0u, @@ -2733,7 +2746,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_fn_block(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_fn_block", 15u, + s.emit_enum_variant("syntax::ast::expr_fn_block", 16u, 2u, {|| { @@ -2751,7 +2764,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_block(v0) { - s.emit_enum_variant("syntax::ast::expr_block", 16u, + s.emit_enum_variant("syntax::ast::expr_block", 17u, 1u, {|| { @@ -2764,7 +2777,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_copy(v0) { - s.emit_enum_variant("syntax::ast::expr_copy", 17u, 1u, + s.emit_enum_variant("syntax::ast::expr_copy", 18u, 1u, {|| { s.emit_enum_variant_arg(0u, @@ -2776,7 +2789,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_move(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_move", 18u, 2u, + s.emit_enum_variant("syntax::ast::expr_move", 19u, 2u, {|| { s.emit_enum_variant_arg(0u, @@ -2793,7 +2806,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_assign(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_assign", 19u, + s.emit_enum_variant("syntax::ast::expr_assign", 20u, 2u, {|| { @@ -2811,7 +2824,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_swap(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_swap", 20u, 2u, + s.emit_enum_variant("syntax::ast::expr_swap", 21u, 2u, {|| { s.emit_enum_variant_arg(0u, @@ -2829,7 +2842,7 @@ fn serialize_74(s: S, } syntax::ast::expr_assign_op(v0, v1, v2) { s.emit_enum_variant("syntax::ast::expr_assign_op", - 21u, 3u, + 22u, 3u, {|| { s.emit_enum_variant_arg(0u, @@ -2851,7 +2864,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_field(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_field", 22u, + s.emit_enum_variant("syntax::ast::expr_field", 23u, 3u, {|| { @@ -2874,7 +2887,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_index(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_index", 23u, + s.emit_enum_variant("syntax::ast::expr_index", 24u, 2u, {|| { @@ -2892,7 +2905,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_path(v0) { - s.emit_enum_variant("syntax::ast::expr_path", 24u, 1u, + s.emit_enum_variant("syntax::ast::expr_path", 25u, 1u, {|| { s.emit_enum_variant_arg(0u, @@ -2904,7 +2917,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_addr_of(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_addr_of", 25u, + s.emit_enum_variant("syntax::ast::expr_addr_of", 26u, 2u, {|| { @@ -2922,7 +2935,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_fail(v0) { - s.emit_enum_variant("syntax::ast::expr_fail", 26u, 1u, + s.emit_enum_variant("syntax::ast::expr_fail", 27u, 1u, {|| { s.emit_enum_variant_arg(0u, @@ -2934,15 +2947,15 @@ fn serialize_74(s: S, }) } syntax::ast::expr_break { - s.emit_enum_variant("syntax::ast::expr_break", 27u, + s.emit_enum_variant("syntax::ast::expr_break", 28u, 0u, {|| }) } syntax::ast::expr_cont { - s.emit_enum_variant("syntax::ast::expr_cont", 28u, 0u, + s.emit_enum_variant("syntax::ast::expr_cont", 29u, 0u, {|| }) } syntax::ast::expr_ret(v0) { - s.emit_enum_variant("syntax::ast::expr_ret", 29u, 1u, + s.emit_enum_variant("syntax::ast::expr_ret", 30u, 1u, {|| { s.emit_enum_variant_arg(0u, @@ -2954,7 +2967,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_be(v0) { - s.emit_enum_variant("syntax::ast::expr_be", 30u, 1u, + s.emit_enum_variant("syntax::ast::expr_be", 31u, 1u, {|| { s.emit_enum_variant_arg(0u, @@ -2966,7 +2979,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_log(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_log", 31u, 3u, + s.emit_enum_variant("syntax::ast::expr_log", 32u, 3u, {|| { s.emit_enum_variant_arg(0u, @@ -2988,7 +3001,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_assert(v0) { - s.emit_enum_variant("syntax::ast::expr_assert", 32u, + s.emit_enum_variant("syntax::ast::expr_assert", 33u, 1u, {|| { @@ -3001,7 +3014,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_check(v0, v1) { - s.emit_enum_variant("syntax::ast::expr_check", 33u, + s.emit_enum_variant("syntax::ast::expr_check", 34u, 2u, {|| { @@ -3019,7 +3032,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_if_check(v0, v1, v2) { - s.emit_enum_variant("syntax::ast::expr_if_check", 34u, + s.emit_enum_variant("syntax::ast::expr_if_check", 35u, 3u, {|| { @@ -3042,7 +3055,7 @@ fn serialize_74(s: S, }) } syntax::ast::expr_mac(v0) { - s.emit_enum_variant("syntax::ast::expr_mac", 35u, 1u, + s.emit_enum_variant("syntax::ast::expr_mac", 36u, 1u, {|| { s.emit_enum_variant_arg(0u, @@ -6596,6 +6609,8 @@ fn deserialize_74(s: S) -> /*syntax::ast::blk*//*@syntax::ast::expr*/ + /*syntax::ast::blk*/ + /*@syntax::ast::expr*//*[syntax::ast::arm]*/ /*syntax::ast::alt_mode*/ @@ -6788,6 +6803,12 @@ fn deserialize_74(s: S) -> })) } 13u { + syntax::ast::expr_loop(s.read_enum_variant_arg(0u, + {|| + deserialize_83(s) + })) + } + 14u { syntax::ast::expr_alt(s.read_enum_variant_arg(0u, {|| deserialize_72(s) @@ -6801,7 +6822,7 @@ fn deserialize_74(s: S) -> deserialize_123(s) })) } - 14u { + 15u { syntax::ast::expr_fn(s.read_enum_variant_arg(0u, {|| deserialize_39(s) @@ -6819,7 +6840,7 @@ fn deserialize_74(s: S) -> deserialize_124(s) })) } - 15u { + 16u { syntax::ast::expr_fn_block(s.read_enum_variant_arg(0u, {|| deserialize_40(s) @@ -6829,19 +6850,19 @@ fn deserialize_74(s: S) -> deserialize_83(s) })) } - 16u { + 17u { syntax::ast::expr_block(s.read_enum_variant_arg(0u, {|| deserialize_83(s) })) } - 17u { + 18u { syntax::ast::expr_copy(s.read_enum_variant_arg(0u, {|| deserialize_72(s) })) } - 18u { + 19u { syntax::ast::expr_move(s.read_enum_variant_arg(0u, {|| deserialize_72(s) @@ -6851,7 +6872,7 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 19u { + 20u { syntax::ast::expr_assign(s.read_enum_variant_arg(0u, {|| deserialize_72(s) @@ -6861,7 +6882,7 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 20u { + 21u { syntax::ast::expr_swap(s.read_enum_variant_arg(0u, {|| deserialize_72(s) @@ -6871,7 +6892,7 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 21u { + 22u { syntax::ast::expr_assign_op(s.read_enum_variant_arg(0u, {|| deserialize_81(s) @@ -6885,7 +6906,7 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 22u { + 23u { syntax::ast::expr_field(s.read_enum_variant_arg(0u, {|| deserialize_72(s) @@ -6899,7 +6920,7 @@ fn deserialize_74(s: S) -> deserialize_55(s) })) } - 23u { + 24u { syntax::ast::expr_index(s.read_enum_variant_arg(0u, {|| deserialize_72(s) @@ -6909,13 +6930,13 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 24u { + 25u { syntax::ast::expr_path(s.read_enum_variant_arg(0u, {|| deserialize_51(s) })) } - 25u { + 26u { syntax::ast::expr_addr_of(s.read_enum_variant_arg(0u, {|| deserialize_33(s) @@ -6925,27 +6946,27 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 26u { + 27u { syntax::ast::expr_fail(s.read_enum_variant_arg(0u, {|| deserialize_79(s) })) } - 27u { syntax::ast::expr_break } - 28u { syntax::ast::expr_cont } - 29u { + 28u { syntax::ast::expr_break } + 29u { syntax::ast::expr_cont } + 30u { syntax::ast::expr_ret(s.read_enum_variant_arg(0u, {|| deserialize_79(s) })) } - 30u { + 31u { syntax::ast::expr_be(s.read_enum_variant_arg(0u, {|| deserialize_72(s) })) } - 31u { + 32u { syntax::ast::expr_log(s.read_enum_variant_arg(0u, {|| deserialize_129(s) @@ -6959,13 +6980,13 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 32u { + 33u { syntax::ast::expr_assert(s.read_enum_variant_arg(0u, {|| deserialize_72(s) })) } - 33u { + 34u { syntax::ast::expr_check(s.read_enum_variant_arg(0u, {|| deserialize_130(s) @@ -6975,7 +6996,7 @@ fn deserialize_74(s: S) -> deserialize_72(s) })) } - 34u { + 35u { syntax::ast::expr_if_check(s.read_enum_variant_arg(0u, {|| deserialize_72(s) @@ -6989,7 +7010,7 @@ fn deserialize_74(s: S) -> deserialize_79(s) })) } - 35u { + 36u { syntax::ast::expr_mac(s.read_enum_variant_arg(0u, {|| deserialize_69(s) diff --git a/src/rustc/middle/last_use.rs b/src/rustc/middle/last_use.rs index 854439c8533..fab8cd146d4 100644 --- a/src/rustc/middle/last_use.rs +++ b/src/rustc/middle/last_use.rs @@ -33,7 +33,7 @@ enum is_last_use { type last_uses = std::map::hashmap; enum seen { unset, seen(node_id), } -enum block_type { func, loop, } +enum block_type { func, lp, } enum use { var_use(node_id), close_over(node_id), } type set = [{def: node_id, uses: list}]; @@ -97,13 +97,13 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt) { visit::visit_expr_opt(oexpr, cx, v); leave_fn(cx); } - expr_break { add_block_exit(cx, loop); } - expr_while(_, _) | expr_do_while(_, _) { - visit_block(loop, cx) {|| visit::visit_expr(ex, cx, v);} + expr_break { add_block_exit(cx, lp); } + expr_while(_, _) | expr_do_while(_, _) | expr_loop(_) { + visit_block(lp, cx) {|| visit::visit_expr(ex, cx, v);} } expr_for(_, coll, blk) { v.visit_expr(coll, cx, v); - visit_block(loop, cx) {|| visit::visit_block(blk, cx, v);} + visit_block(lp, cx) {|| visit::visit_block(blk, cx, v);} } expr_alt(input, arms, _) { v.visit_expr(input, cx, v); diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index e6b1fdb4dd0..0a8c0350b40 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2029,6 +2029,17 @@ fn trans_do_while(cx: block, body: ast::blk, cond: @ast::expr) -> ret next_cx; } +fn trans_loop(cx:block, body: ast::blk) -> block { + let next_cx = sub_block(cx, "next"); + let body_cx = + loop_scope_block(cx, cont_self, next_cx, + "infinite loop body", body.span); + let body_end = trans_block(body_cx, body, ignore); + cleanup_and_Br(body_end, body_cx, body_cx.llbb); + Br(cx, body_cx.llbb); + ret next_cx; +} + type generic_info = {item_type: ty::t, static_tis: [option<@tydesc_info>], tydescs: [ValueRef], @@ -3255,6 +3266,10 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block { assert dest == ignore; ret trans_while(bcx, cond, body); } + ast::expr_loop(body) { + assert dest == ignore; + ret trans_loop(bcx, body); + } ast::expr_do_while(body, cond) { assert dest == ignore; ret trans_do_while(bcx, body, cond); @@ -3293,7 +3308,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block { assert dest == ignore; ret trans_assign_op(bcx, e, op, dst, src); } - _ { bcx.tcx().sess.span_bug(e.span, "trans_expr reached\ + _ { bcx.tcx().sess.span_bug(e.span, "trans_expr reached \ fall-through case"); } } diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs index c5c281ed74e..5b6d5cc2911 100644 --- a/src/rustc/middle/tstate/pre_post_conditions.rs +++ b/src/rustc/middle/tstate/pre_post_conditions.rs @@ -446,6 +446,19 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { expr_pp(fcx.ccx, test)]), loop_postcond); } + expr_loop(body) { + find_pre_post_block(fcx, body); + /* Infinite loop: if control passes it, everything is true. */ + let loop_postcond = false_postcond(num_local_vars); + /* Conservative approximation: if the body has any nonlocal exits, + the poststate is blank since we don't know what parts of it + execute. */ + if has_nonlocal_exits(body) { + loop_postcond = empty_poststate(num_local_vars); + } + set_pre_and_post(fcx.ccx, e.id, block_precond(fcx.ccx, body), + loop_postcond); + } expr_for(d, index, body) { find_pre_post_loop(fcx, d, index, body, e.id); } diff --git a/src/rustc/middle/tstate/states.rs b/src/rustc/middle/tstate/states.rs index 31f50881f2c..d85f9731ece 100644 --- a/src/rustc/middle/tstate/states.rs +++ b/src/rustc/middle/tstate/states.rs @@ -354,7 +354,6 @@ fn find_pre_post_state_cap_clause(fcx: fn_ctxt, e_id: node_id, fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { let num_constrs = num_constraints(fcx.enclosing); - alt e.node { expr_vec(elts, _) { ret find_pre_post_state_exprs(fcx, pres, e.id, @@ -489,8 +488,6 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { */ let loop_pres = intersect_states(block_poststate(fcx.ccx, body), pres); - // aux::log_tritv_err(fcx, loop_pres); - // #error("---------------"); let changed = set_prestate_ann(fcx.ccx, e.id, loop_pres) | @@ -545,6 +542,21 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { } ret changed; } + expr_loop(body) { + let loop_pres = + intersect_states(block_poststate(fcx.ccx, body), pres); + let changed = set_prestate_ann(fcx.ccx, e.id, loop_pres) + | find_pre_post_state_block(fcx, loop_pres, body); + /* conservative approximation: if a loop contains a break + or cont, we assume nothing about the poststate */ + /* which is still unsound -- see [Break-unsound] */ + if has_nonlocal_exits(body) { + ret changed | set_poststate_ann(fcx.ccx, e.id, pres); + } else { + ret changed | set_poststate_ann(fcx.ccx, e.id, + block_poststate(fcx.ccx, body)); + } + } expr_for(d, index, body) { ret find_pre_post_state_loop(fcx, pres, d, index, body, e.id); } diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 341c5252639..4bdc6592dd4 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -2323,6 +2323,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, check_block_no_value(fcx, body); write_ty(tcx, id, block_ty(tcx, body)); } + ast::expr_loop(body) { + check_block_no_value(fcx, body); + write_ty(tcx, id, ty::mk_nil(tcx)); + } ast::expr_alt(expr, arms, _) { bot = check_expr(fcx, expr); @@ -2613,7 +2617,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, } } } - _ { tcx.sess.unimpl("expr type in typeck::check_expr"); } } if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); } diff --git a/src/rustc/syntax/ast.rs b/src/rustc/syntax/ast.rs index b98a1374888..fdd40e6e199 100644 --- a/src/rustc/syntax/ast.rs +++ b/src/rustc/syntax/ast.rs @@ -229,6 +229,10 @@ enum expr_ { expr_while(@expr, blk), expr_for(@local, @expr, blk), expr_do_while(blk, @expr), + /* Conditionless loop (can be exited with break, cont, ret, or fail) + Same semantics as while(true) { body }, but typestate knows that the + (implicit) condition is always true. */ + expr_loop(blk), expr_alt(@expr, [arm], alt_mode), expr_fn(proto, fn_decl, blk, @capture_clause), expr_fn_block(fn_decl, blk), diff --git a/src/rustc/syntax/fold.rs b/src/rustc/syntax/fold.rs index 6b461fbc7ec..dbdd8cd9b36 100644 --- a/src/rustc/syntax/fold.rs +++ b/src/rustc/syntax/fold.rs @@ -380,7 +380,7 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ { let fold_mac = bind fold_mac_(_, fld); ret alt e { - expr_vec(exprs, mutt) { + expr_vec(exprs, mutt) { expr_vec(fld.map_exprs(fld.fold_expr, exprs), mutt) } expr_rec(fields, maybe_expr) { @@ -417,6 +417,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ { expr_do_while(blk, expr) { expr_do_while(fld.fold_block(blk), fld.fold_expr(expr)) } + expr_loop(body) { + expr_loop(fld.fold_block(body)) + } expr_alt(expr, arms, mode) { expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm), mode) } diff --git a/src/rustc/syntax/parse/parser.rs b/src/rustc/syntax/parse/parser.rs index 95c7383cb66..53f75d8f7c3 100644 --- a/src/rustc/syntax/parse/parser.rs +++ b/src/rustc/syntax/parse/parser.rs @@ -146,11 +146,11 @@ fn new_parser(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, fn bad_expr_word_table() -> hashmap { let words = new_str_hash(); for word in ["alt", "assert", "be", "break", "check", "claim", - "class", "const", "cont", "copy", "do", "else", "enum", - "export", "fail", "fn", "for", "if", "iface", "impl", - "import", "let", "log", "mod", "mutable", "native", "pure", - "resource", "ret", "trait", "type", "unchecked", "unsafe", - "while", "crust", "mut"] { + "class", "const", "cont", "copy", "crust", "do", "else", + "enum", "export", "fail", "fn", "for", "if", "iface", + "impl", "import", "let", "log", "loop", "mod", "mut", + "mutable", "native", "pure", "resource", "ret", "trait", + "type", "unchecked", "unsafe", "while"] { words.insert(word, ()); } words @@ -839,6 +839,8 @@ fn parse_bottom_expr(p: parser) -> pexpr { ret pexpr(parse_while_expr(p)); } else if eat_word(p, "do") { ret pexpr(parse_do_while_expr(p)); + } else if eat_word(p, "loop") { + ret pexpr(parse_loop_expr(p)); } else if eat_word(p, "alt") { ret pexpr(parse_alt_expr(p)); } else if eat_word(p, "fn") { @@ -1399,6 +1401,13 @@ fn parse_do_while_expr(p: parser) -> @ast::expr { ret mk_expr(p, lo, hi, ast::expr_do_while(body, cond)); } +fn parse_loop_expr(p: parser) -> @ast::expr { + let lo = p.last_span.lo; + let body = parse_block_no_value(p); + let hi = body.span.hi; + ret mk_expr(p, lo, hi, ast::expr_loop(body)); +} + fn parse_alt_expr(p: parser) -> @ast::expr { let lo = p.last_span.lo; let mode = if eat_word(p, "check") { ast::alt_check } @@ -1691,7 +1700,7 @@ fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool { ast::expr_if(_, _, _) | ast::expr_if_check(_, _, _) | ast::expr_alt(_, _, _) | ast::expr_block(_) | ast::expr_do_while(_, _) | ast::expr_while(_, _) - | ast::expr_for(_, _, _) + | ast::expr_loop(_) | ast::expr_for(_, _, _) | ast::expr_call(_, _, true) { false } diff --git a/src/rustc/syntax/print/pprust.rs b/src/rustc/syntax/print/pprust.rs index 2db67a0c97d..ba9c76c748f 100644 --- a/src/rustc/syntax/print/pprust.rs +++ b/src/rustc/syntax/print/pprust.rs @@ -913,6 +913,11 @@ fn print_expr(s: ps, &&expr: @ast::expr) { space(s.s); print_block(s, blk); } + ast::expr_loop(blk) { + head(s, "loop"); + space(s.s); + print_block(s, blk); + } ast::expr_for(decl, expr, blk) { head(s, "for"); print_for_decl(s, decl, expr); diff --git a/src/rustc/syntax/visit.rs b/src/rustc/syntax/visit.rs index 01aaac48f4a..d9060ea2cfd 100644 --- a/src/rustc/syntax/visit.rs +++ b/src/rustc/syntax/visit.rs @@ -343,6 +343,7 @@ fn visit_expr(ex: @expr, e: E, v: vt) { visit_expr_opt(eo, e, v); } expr_while(x, b) { v.visit_expr(x, e, v); v.visit_block(b, e, v); } + expr_loop(b) { v.visit_block(b, e, v); } expr_for(dcl, x, b) { v.visit_local(dcl, e, v); v.visit_expr(x, e, v); diff --git a/src/rustdoc/markdown_writer.rs b/src/rustdoc/markdown_writer.rs index 809fd24f9e8..7f84c8393b5 100644 --- a/src/rustdoc/markdown_writer.rs +++ b/src/rustdoc/markdown_writer.rs @@ -289,7 +289,7 @@ fn future_writer() -> (writer, future::future) { }; let future = future::from_fn {|| let res = ""; - while true { + loop { alt comm::recv(port) { write(s) { res += s } done { break } diff --git a/src/rustdoc/page_pass.rs b/src/rustdoc/page_pass.rs index e3f2c4235e7..d86eecc9699 100644 --- a/src/rustdoc/page_pass.rs +++ b/src/rustdoc/page_pass.rs @@ -43,7 +43,7 @@ type page_chan = comm::chan>; fn make_doc_from_pages(page_port: page_port) -> doc::doc { let mut pages = []; - while true { + loop { let val = comm::recv(page_port); if option::is_some(val) { pages += [option::unwrap(val)]; diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 8105b019de4..29b821a75d7 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -60,7 +60,7 @@ fn parse_opts(argv: [str]) -> config { fn stress_task(&&id: int) { let i = 0; - while true { + loop { let n = 15; assert (fib(n) == fib(n)); i += 1; diff --git a/src/test/bench/task-perf-word-count-generic.rs b/src/test/bench/task-perf-word-count-generic.rs index 338a494ad16..938e0013dd5 100644 --- a/src/test/bench/task-perf-word-count-generic.rs +++ b/src/test/bench/task-perf-word-count-generic.rs @@ -34,7 +34,7 @@ import comm::send; fn map(&&filename: [u8], emit: map_reduce::putter<[u8], int>) { let f = io::file_reader(str::from_bytes(filename)); - while true { + loop { alt read_word(f) { some(w) { emit(str::bytes(w), 1); } none { break; } @@ -45,7 +45,7 @@ fn map(&&filename: [u8], emit: map_reduce::putter<[u8], int>) { fn reduce(&&_word: [u8], get: map_reduce::getter) { let count = 0; - while true { alt get() { some(_) { count += 1; } none { break; } } } + loop { alt get() { some(_) { count += 1; } none { break; } } } } mod map_reduce { diff --git a/src/test/bench/task-perf-word-count.rs b/src/test/bench/task-perf-word-count.rs index d800b5e9a64..cce242d195e 100644 --- a/src/test/bench/task-perf-word-count.rs +++ b/src/test/bench/task-perf-word-count.rs @@ -25,7 +25,7 @@ fn map(input: str, emit: map_reduce::putter) { let f = io::str_reader(input); - while true { + loop { alt read_word(f) { some(w) { emit(w, 1); } none { break; } } } } @@ -33,7 +33,7 @@ fn map(input: str, emit: map_reduce::putter) { fn reduce(_word: str, get: map_reduce::getter) { let count = 0; - while true { alt get() { some(_) { count += 1; } none { break; } } } + loop { alt get() { some(_) { count += 1; } none { break; } } } } mod map_reduce { diff --git a/src/test/compile-fail/block-must-not-have-result-while.rs b/src/test/compile-fail/block-must-not-have-result-while.rs index 7f172998c28..da006921267 100644 --- a/src/test/compile-fail/block-must-not-have-result-while.rs +++ b/src/test/compile-fail/block-must-not-have-result-while.rs @@ -1,7 +1,7 @@ // error-pattern:mismatched types: expected `()` but found `bool` fn main() { - while true { + loop { true } } \ No newline at end of file diff --git a/src/test/compile-fail/while-bypass.rs b/src/test/compile-fail/while-bypass.rs index e70090dd59e..231fb299898 100644 --- a/src/test/compile-fail/while-bypass.rs +++ b/src/test/compile-fail/while-bypass.rs @@ -1,5 +1,5 @@ // error-pattern: precondition constraint -fn f() -> int { let x: int; while true { x = 10; } ret x; } +fn f() -> int { let x: int; while 1 == 1 { x = 10; } ret x; } fn main() { f(); } diff --git a/src/test/compile-fail/while-loop-constraints.rs b/src/test/compile-fail/while-loop-constraints.rs index 58757c8bfdd..38c1d471593 100644 --- a/src/test/compile-fail/while-loop-constraints.rs +++ b/src/test/compile-fail/while-loop-constraints.rs @@ -3,11 +3,11 @@ fn main() { let y: int = 42; let x: int; - while true { + loop { log(debug, y); - while true { - while true { - while true { x <- y; } + loop { + loop { + loop { x <- y; } } } } diff --git a/src/test/compile-fail/while-loop-pred-constraints.rs b/src/test/compile-fail/while-loop-pred-constraints.rs index ea58c8377e0..abc73c86b60 100644 --- a/src/test/compile-fail/while-loop-pred-constraints.rs +++ b/src/test/compile-fail/while-loop-pred-constraints.rs @@ -9,8 +9,8 @@ fn main() { let y: int = 42; let x: int = 1; check (even(y)); - while true { + loop { print_even(y); - while true { while true { while true { y += x; } } } + loop { loop { loop { y += x; } } } } } diff --git a/src/test/run-pass/acyclic-unwind.rs b/src/test/run-pass/acyclic-unwind.rs index 0954d68ad33..21fb2f174bd 100644 --- a/src/test/run-pass/acyclic-unwind.rs +++ b/src/test/run-pass/acyclic-unwind.rs @@ -15,7 +15,7 @@ fn f(c: comm::_chan) { comm::send(c, 1); - while true { + loop { // spin waiting for the parent to kill us. #debug("child waiting to die..."); diff --git a/src/test/run-pass/break-value.rs b/src/test/run-pass/break-value.rs index 764d03bdf22..3aaadb759f7 100644 --- a/src/test/run-pass/break-value.rs +++ b/src/test/run-pass/break-value.rs @@ -1,3 +1,3 @@ fn int_id(x: int) -> int { ret x; } -fn main() { while true { int_id(break); } } +fn main() { loop { int_id(break); } } diff --git a/src/test/run-pass/infinite-loops.rs b/src/test/run-pass/infinite-loops.rs index 4eae0601d03..82b751b3b0b 100644 --- a/src/test/run-pass/infinite-loops.rs +++ b/src/test/run-pass/infinite-loops.rs @@ -14,7 +14,7 @@ fn loop(n: int) { if n > 0 { t1 = spawn loop(n - 1); t2 = spawn loop(n - 1); } - while true { } + loop { } } fn main() { let t: task = spawn loop(5); join(t); } \ No newline at end of file diff --git a/src/test/run-pass/issue-687.rs b/src/test/run-pass/issue-687.rs index f0926afe759..1bb4f69fb02 100644 --- a/src/test/run-pass/issue-687.rs +++ b/src/test/run-pass/issue-687.rs @@ -18,7 +18,7 @@ fn producer(c: chan<[u8]>) { fn packager(cb: chan>, msg: chan) { let p: port<[u8]> = port(); send(cb, chan(p)); - while true { + loop { #debug("waiting for bytes"); let data = recv(p); #debug("got bytes"); @@ -46,7 +46,7 @@ fn main() { let source_chan: chan<[u8]> = recv(recv_reader); let prod = task::spawn {|| producer(source_chan); }; - while true { + loop { let msg = recv(p); alt msg { closed { #debug("Got close message"); break; } diff --git a/src/test/run-pass/last-use-corner-cases.rs b/src/test/run-pass/last-use-corner-cases.rs index 68a230f52a0..dea4e2031a5 100644 --- a/src/test/run-pass/last-use-corner-cases.rs +++ b/src/test/run-pass/last-use-corner-cases.rs @@ -17,7 +17,7 @@ fn main() { // Check that no false positives are found in loops. let q = ~40, p = 10; - while true { + loop { let i = q; p += *i; if p > 100 { break; } diff --git a/src/test/run-pass/last-use-in-block.rs b/src/test/run-pass/last-use-in-block.rs index d0593853e1d..6915c35b2f6 100644 --- a/src/test/run-pass/last-use-in-block.rs +++ b/src/test/run-pass/last-use-in-block.rs @@ -1,6 +1,6 @@ // Issue #1818 -fn loop(s: str, f: fn(str) -> T) -> T { +fn lp(s: str, f: fn(str) -> T) -> T { while false { let r = f(s); ret r; diff --git a/src/test/run-pass/preempt.rs b/src/test/run-pass/preempt.rs index 5511225086d..3b538644976 100644 --- a/src/test/run-pass/preempt.rs +++ b/src/test/run-pass/preempt.rs @@ -6,7 +6,7 @@ fn starve_main(alive: chan) { alive <| 1; #debug("starving main"); let i: int = 0; - while true { i += 1; } + loop { i += 1; } } fn main() { diff --git a/src/test/run-pass/send-iloop.rs b/src/test/run-pass/send-iloop.rs index ece3dc4ce64..4aa058700b6 100644 --- a/src/test/run-pass/send-iloop.rs +++ b/src/test/run-pass/send-iloop.rs @@ -12,7 +12,7 @@ fn iloop() { task::spawn {|| die(); }; let p = comm::port::<()>(); let c = comm::chan(p); - while true { + loop { // Sending and receiving here because these actions yield, // at which point our child can kill us comm::send(c, ()); diff --git a/src/test/run-pass/terminate-in-initializer.rs b/src/test/run-pass/terminate-in-initializer.rs index 9b722a947c0..11e5ca3f645 100644 --- a/src/test/run-pass/terminate-in-initializer.rs +++ b/src/test/run-pass/terminate-in-initializer.rs @@ -4,7 +4,7 @@ use std; -fn test_break() { while true { let x: @int = break; } } +fn test_break() { loop { let x: @int = break; } } fn test_cont() { let i = 0; while i < 1 { i += 1; let x: @int = cont; } } diff --git a/src/test/run-pass/unreachable-code.rs b/src/test/run-pass/unreachable-code.rs index d5f896d36d3..d229448ce02 100644 --- a/src/test/run-pass/unreachable-code.rs +++ b/src/test/run-pass/unreachable-code.rs @@ -23,7 +23,7 @@ fn log_fail() { log(error, fail); } fn log_ret() { log(error, ret); } -fn log_break() { while true { log(error, break); } } +fn log_break() { loop { log(error, break); } } fn log_cont() { do { log(error, cont); } while false } diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index 4093a311b09..af942417ae8 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -55,7 +55,7 @@ fn canttouchthis() -> uint { } fn angrydome() { - while true { if break { } } + loop { if break { } } let i = 0; do { i += 1; if i == 1 { alt cont { _ { } } } } while false }