[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]