ruby-changes:44470
From: nobu <ko1@a...>
Date: Wed, 2 Nov 2016 07:34:35 +0900 (JST)
Subject: [ruby-changes:44470] nobu:r56543 (trunk): numeric.c: bit op with non-integer
nobu 2016-11-02 07:34:30 +0900 (Wed, 02 Nov 2016) New Revision: 56543 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=56543 Log: numeric.c: bit op with non-integer * numeric.c (rb_num_coerce_bit): enable bit operations with coercing by non-integer object. [ruby-core:77783] [Bug #12875] Modified files: trunk/ChangeLog trunk/numeric.c trunk/test/ruby/test_integer.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 56542) +++ ChangeLog (revision 56543) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Wed Nov 2 07:34:27 2016 Nobuyoshi Nakada <nobu@r...> + + * numeric.c (rb_num_coerce_bit): enable bit operations with + coercing by non-integer object. [ruby-core:77783] [Bug #12875] + Tue Nov 1 01:31:09 2016 Nobuyoshi Nakada <nobu@r...> * configure.in (ac_cv_func_round): round(3) in x86_64-w64-mingw32 Index: numeric.c =================================================================== --- numeric.c (revision 56542) +++ numeric.c (revision 56543) @@ -293,21 +293,27 @@ num_funcall0(VALUE x, ID func) https://github.com/ruby/ruby/blob/trunk/numeric.c#L293 return rb_exec_recursive(num_funcall_op_0, x, (VALUE)func); } +static void +num_funcall_op_1_recursion(VALUE x, ID func, VALUE y) +{ + const char *name = rb_id2name(func); + if (ISALNUM(name[0])) { + rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE"(%"PRIsVALUE")", + x, ID2SYM(func), y); + } + else { + rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE"%"PRIsVALUE, + x, ID2SYM(func), y); + } +} + static VALUE num_funcall_op_1(VALUE y, VALUE arg, int recursive) { ID func = (ID)((VALUE *)arg)[0]; VALUE x = ((VALUE *)arg)[1]; if (recursive) { - const char *name = rb_id2name(func); - if (ISALNUM(name[0])) { - rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE"(%"PRIsVALUE")", - x, ID2SYM(func), y); - } - else { - rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE"%"PRIsVALUE, - x, ID2SYM(func), y); - } + num_funcall_op_1_recursion(x, func, y); } return rb_funcall(x, func, 1, y); } @@ -4128,24 +4134,33 @@ int_comp(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L4134 return Qnil; } -static int -bit_coerce(VALUE *x, VALUE *y) +static VALUE +num_funcall_bit_1(VALUE y, VALUE arg, int recursive) { - if (!RB_INTEGER_TYPE_P(*y)) { - VALUE orig = *x; - do_coerce(x, y, TRUE); - if (!RB_INTEGER_TYPE_P(*x) && !RB_INTEGER_TYPE_P(*y)) { - coerce_failed(orig, *y); - } + ID func = (ID)((VALUE *)arg)[0]; + VALUE x = ((VALUE *)arg)[1]; + if (recursive) { + num_funcall_op_1_recursion(x, func, y); } - return TRUE; + return rb_check_funcall(x, func, 1, &y); } VALUE rb_num_coerce_bit(VALUE x, VALUE y, ID func) { - bit_coerce(&x, &y); - return num_funcall1(x, func, y); + VALUE ret, args[3]; + + args[0] = (VALUE)func; + args[1] = x; + args[2] = y; + do_coerce(&args[1], &args[2], TRUE); + ret = rb_exec_recursive_paired(num_funcall_bit_1, + args[2], args[1], (VALUE)args); + if (ret == Qundef) { + /* show the original object, not coerced object */ + coerce_failed(x, y); + } + return ret; } /* Index: test/ruby/test_integer.rb =================================================================== --- test/ruby/test_integer.rb (revision 56542) +++ test/ruby/test_integer.rb (revision 56543) @@ -302,6 +302,42 @@ class TestInteger < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_integer.rb#L302 assert_equal(3 ^ 10, 3 ^ obj) end + module CoercionToSelf + def coerce(other) + [self.class.new(other), self] + end + end + + def test_bitwise_and_with_integer_coercion + obj = Struct.new(:value) do + include(CoercionToSelf) + def &(other) + self.value & other.value + end + end.new(10) + assert_equal(3 & 10, 3 & obj) + end + + def test_bitwise_or_with_integer_coercion + obj = Struct.new(:value) do + include(CoercionToSelf) + def |(other) + self.value | other.value + end + end.new(10) + assert_equal(3 | 10, 3 | obj) + end + + def test_bitwise_xor_with_integer_coercion + obj = Struct.new(:value) do + include(CoercionToSelf) + def ^(other) + self.value ^ other.value + end + end.new(10) + assert_equal(3 ^ 10, 3 ^ obj) + end + def test_bit_length assert_equal(13, (-2**12-1).bit_length) assert_equal(12, (-2**12).bit_length) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/