1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* numeric.c (do_coerce): Add a warning when an exception is raised

or an invalid value is returned in #coerce called by
  numeric comparison operators and the exception
  thrown by the caller has no information on the failure.
  In the next release such exception should not be rescued or
  should be the cause of the caller exception. nil is accepted
  as the "no possible coercion" return value. See #7688.
* test/ruby/test_numeric.rb: Add corresponding test.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46375 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
eregon 2014-06-07 13:16:01 +00:00
parent ea7ce3096e
commit a21ac07f69
3 changed files with 44 additions and 1 deletions

View file

@ -1,3 +1,15 @@
Sat Jun 7 22:13:42 2014 Benoit Daloze <eregontp@gmail.com>
* numeric.c (do_coerce): Add a warning when an exception is raised
or an invalid value is returned in #coerce called by
numeric comparison operators and the exception
thrown by the caller has no information on the failure.
In the next release such exception should not be rescued or
should be the cause of the caller exception. nil is accepted
as the "no possible coercion" return value. See #7688.
* test/ruby/test_numeric.rb: Add corresponding test.
Sat Jun 7 18:15:33 2014 Benoit Daloze <eregontp@gmail.com> Sat Jun 7 18:15:33 2014 Benoit Daloze <eregontp@gmail.com>
* numeric.c (bit_coerce): remove constant parameter `err' * numeric.c (bit_coerce): remove constant parameter `err'

View file

@ -251,6 +251,12 @@ coerce_rescue(VALUE *x)
return Qnil; /* dummy */ return Qnil; /* dummy */
} }
static VALUE
coerce_rescue_quiet(VALUE *x)
{
return Qundef;
}
static int static int
do_coerce(VALUE *x, VALUE *y, int err) do_coerce(VALUE *x, VALUE *y, int err)
{ {
@ -266,10 +272,18 @@ do_coerce(VALUE *x, VALUE *y, int err)
return FALSE; return FALSE;
} }
ary = rb_rescue(coerce_body, (VALUE)a, err ? coerce_rescue : 0, (VALUE)a); ary = rb_rescue(coerce_body, (VALUE)a, err ? coerce_rescue : coerce_rescue_quiet, (VALUE)a);
if (ary == Qundef) {
rb_warn("Numerical comparison operators will no more rescue exceptions of #coerce");
rb_warn("in the next release. Return nil in #coerce if the coercion is impossible.");
return FALSE;
}
if (!RB_TYPE_P(ary, T_ARRAY) || RARRAY_LEN(ary) != 2) { if (!RB_TYPE_P(ary, T_ARRAY) || RARRAY_LEN(ary) != 2) {
if (err) { if (err) {
rb_raise(rb_eTypeError, "coerce must return [x, y]"); rb_raise(rb_eTypeError, "coerce must return [x, y]");
} else if (!NIL_P(ary)) {
rb_warn("Bad return value for #coerce, called by numerical comparison operators.");
rb_warn("#coerce must return [x, y]. The next release will raise an error for this.");
} }
return FALSE; return FALSE;
} }

View file

@ -59,6 +59,23 @@ class TestNumeric < Test::Unit::TestCase
end end
assert_equal(-1, -a) assert_equal(-1, -a)
bug7688 = '[ruby-core:51389] [Bug #7688]'
DummyNumeric.class_eval do
remove_method :coerce
def coerce(x); raise StandardError; end
end
assert_raise_with_message(TypeError, /can't be coerced into /) { 1 + a }
warn = /will no more rescue exceptions of #coerce.+ in the next release/m
assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } }
DummyNumeric.class_eval do
remove_method :coerce
def coerce(x); :bad_return_value; end
end
assert_raise_with_message(TypeError, "coerce must return [x, y]") { 1 + a }
warn = /Bad return value for #coerce.+next release will raise an error/m
assert_warn(warn, bug7688) { assert_raise(ArgumentError) { 1 < a } }
ensure ensure
DummyNumeric.class_eval do DummyNumeric.class_eval do
remove_method :coerce remove_method :coerce