commit 36f113885eed8c58f5008399b297049b68bc4c53 Author: Akinori MUSHA Date: Tue Sep 1 14:48:33 2015 +0900 * vm_eval.c (rb_f_loop): When a loop is stopped by a StopIteration exception, return what the enumerator has returned instead of nil. diff --git a/ChangeLog b/ChangeLog index 77779a5..d8af4f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Tue Sep 1 14:49:27 2015 Akinori MUSHA + + * vm_eval.c (rb_f_loop): When a loop is stopped by a StopIteration + exception, return what the enumerator has returned instead of + nil. + Mon Aug 31 17:04:45 2015 Koichi Sasada * class.c (move_refined_method): should insert a write barrier diff --git a/NEWS b/NEWS index 1803ed9..f29358c 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,11 @@ with all sufficient information, see the ChangeLog file. this parameter is bitwise-ORed to oflags generated by normal mode argument. [Feature #11253] +* Kernel + + * Kernel#loop, when stopped by a StopIteration exception, returns + what the enumerator has returned instead of nil. + * Module * Module#deprecate_constant [Feature #11398] diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index b5ced3b..85e8c48 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -46,6 +46,14 @@ class TestEnumerator < Test::Unit::TestCase } end + def test_loop_return_value + assert_equal nil, loop { break } + assert_equal 42, loop { break 42 } + + e = Enumerator.new { |y| y << 1; y << 2; :stopped } + assert_equal :stopped, loop { e.next while true } + end + def test_nested_iteration def (o = Object.new).each yield :ok1 diff --git a/vm_eval.c b/vm_eval.c index 00b47e5..a08e211 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -24,7 +24,7 @@ static void vm_set_eval_stack(rb_thread_t * th, const rb_iseq_t *iseq, const rb_ static int vm_collect_local_variables_in_heap(rb_thread_t *th, const VALUE *dfp, const struct local_var_list *vars); static VALUE rb_eUncaughtThrow; -static ID id_tag, id_value; +static ID id_result, id_tag, id_value; #define id_mesg idMesg /* vm_backtrace.c */ @@ -1067,6 +1067,12 @@ loop_i(void) } static VALUE +loop_stop(VALUE dummy, VALUE exc) +{ + return rb_attr_get(exc, id_result); +} + +static VALUE rb_f_loop_size(VALUE self, VALUE args, VALUE eobj) { return DBL2NUM(INFINITY); @@ -1095,8 +1101,7 @@ static VALUE rb_f_loop(VALUE self) { RETURN_SIZED_ENUMERATOR(self, 0, 0, rb_f_loop_size); - rb_rescue2(loop_i, (VALUE)0, 0, 0, rb_eStopIteration, (VALUE)0); - return Qnil; /* dummy */ + return rb_rescue2(loop_i, (VALUE)0, loop_stop, (VALUE)0, rb_eStopIteration, (VALUE)0); } #if VMDEBUG @@ -2172,6 +2177,7 @@ Init_vm_eval(void) rb_define_method(rb_eUncaughtThrow, "value", uncaught_throw_value, 0); rb_define_method(rb_eUncaughtThrow, "to_s", uncaught_throw_to_s, 0); + id_result = rb_intern_const("result"); id_tag = rb_intern_const("tag"); id_value = rb_intern_const("value"); }