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

cdhash_cmp: can take rational literals

Rational literals are those integers suffixed with `r`.  They tend to
be a part of more complex expressions like `123/456r`, but in theory
they can live alone.  When such "bare" rational literals are passed to
case-when branch, we have to take care of them.  Fixes [Bug #17854]
This commit is contained in:
卜部昌平 2021-05-07 10:04:08 +09:00
parent 773c690f25
commit 2bc293e899
Notes: git 2021-05-12 10:31:14 +09:00
5 changed files with 26 additions and 3 deletions

View file

@ -2807,6 +2807,7 @@ compile.$(OBJEXT): $(top_srcdir)/internal/hash.h
compile.$(OBJEXT): $(top_srcdir)/internal/imemo.h
compile.$(OBJEXT): $(top_srcdir)/internal/numeric.h
compile.$(OBJEXT): $(top_srcdir)/internal/object.h
compile.$(OBJEXT): $(top_srcdir)/internal/rational.h
compile.$(OBJEXT): $(top_srcdir)/internal/re.h
compile.$(OBJEXT): $(top_srcdir)/internal/serial.h
compile.$(OBJEXT): $(top_srcdir)/internal/static_assert.h

View file

@ -28,6 +28,7 @@
#include "internal/hash.h"
#include "internal/numeric.h"
#include "internal/object.h"
#include "internal/rational.h"
#include "internal/re.h"
#include "internal/symbol.h"
#include "internal/thread.h"
@ -2004,6 +2005,10 @@ cdhash_cmp(VALUE val, VALUE lit)
else if (tlit == T_FLOAT) {
return rb_float_cmp(lit, val);
}
else if (tlit == T_RATIONAL) {
/* Rational literals don't have fractions. */
return cdhash_cmp(val, rb_rational_num(lit));
}
else {
UNREACHABLE_RETURN(-1);
}
@ -2022,6 +2027,8 @@ cdhash_hash(VALUE a)
return FIX2LONG(rb_big_hash(a));
case T_FLOAT:
return rb_dbl_long_hash(RFLOAT_VALUE(a));
case T_RATIONAL:
return rb_rational_hash(a);
default:
UNREACHABLE_RETURN(0);
}

View file

@ -33,6 +33,7 @@ VALUE rb_rational_div(VALUE self, VALUE other);
VALUE rb_lcm(VALUE x, VALUE y);
VALUE rb_rational_reciprocal(VALUE x);
VALUE rb_cstr_to_rat(const char *, int);
VALUE rb_rational_hash(VALUE self);
VALUE rb_rational_abs(VALUE self);
VALUE rb_rational_cmp(VALUE self, VALUE other);
VALUE rb_rational_pow(VALUE self, VALUE other);

View file

@ -1742,8 +1742,8 @@ nurat_rationalize(int argc, VALUE *argv, VALUE self)
}
/* :nodoc: */
static VALUE
nurat_hash(VALUE self)
st_index_t
rb_rational_hash(VALUE self)
{
st_index_t v, h[2];
VALUE n;
@ -1754,9 +1754,16 @@ nurat_hash(VALUE self)
n = rb_hash(dat->den);
h[1] = NUM2LONG(n);
v = rb_memhash(h, sizeof(h));
return ST2FIX(v);
return v;
}
static VALUE
nurat_hash(VALUE self)
{
return ST2FIX(rb_rational_hash(self));
}
static VALUE
f_format(VALUE self, VALUE (*func)(VALUE))
{

View file

@ -830,6 +830,13 @@ class Rational_Test < Test::Unit::TestCase
assert_raise(ZeroDivisionError) {Rational("1/0")}
end
def test_cdhash
assert_separately([], <<-RUBY)
n = case 1 when 2r then false else true end
assert_equal(n, true, '[ruby-core:103759] [Bug #17854]')
RUBY
end
def test_Rational_with_invalid_exception
assert_raise(ArgumentError) {
Rational("1/1", exception: 1)