ruby-changes:66154
From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Wed, 12 May 2021 10:31:08 +0900 (JST)
Subject: [ruby-changes:66154] 2bc293e899 (master): cdhash_cmp: can take rational literals
https://git.ruby-lang.org/ruby.git/commit/?id=2bc293e899 From 2bc293e899c9d32dcd794a73de8925c49ecf8f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= <shyouhei@r...> Date: Fri, 7 May 2021 10:04:08 +0900 Subject: 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] --- common.mk | 1 + compile.c | 7 +++++++ internal/rational.h | 1 + rational.c | 13 ++++++++++--- test/ruby/test_rational.rb | 7 +++++++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/common.mk b/common.mk index f3aa284..5310173 100644 --- a/common.mk +++ b/common.mk @@ -2807,6 +2807,7 @@ compile.$(OBJEXT): $(top_srcdir)/internal/hash.h https://github.com/ruby/ruby/blob/trunk/common.mk#L2807 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 diff --git a/compile.c b/compile.c index a3a828f..9001fd1 100644 --- a/compile.c +++ b/compile.c @@ -28,6 +28,7 @@ https://github.com/ruby/ruby/blob/trunk/compile.c#L28 #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) https://github.com/ruby/ruby/blob/trunk/compile.c#L2005 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) https://github.com/ruby/ruby/blob/trunk/compile.c#L2027 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); } diff --git a/internal/rational.h b/internal/rational.h index e53ee7b..6bbd2a9 100644 --- a/internal/rational.h +++ b/internal/rational.h @@ -33,6 +33,7 @@ VALUE rb_rational_div(VALUE self, VALUE other); https://github.com/ruby/ruby/blob/trunk/internal/rational.h#L33 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); diff --git a/rational.c b/rational.c index c7437df..846e8bd 100644 --- a/rational.c +++ b/rational.c @@ -1742,8 +1742,8 @@ nurat_rationalize(int argc, VALUE *argv, VALUE self) https://github.com/ruby/ruby/blob/trunk/rational.c#L1742 } /* :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) https://github.com/ruby/ruby/blob/trunk/rational.c#L1754 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)) { diff --git a/test/ruby/test_rational.rb b/test/ruby/test_rational.rb index fe9de64..d7f4961 100644 --- a/test/ruby/test_rational.rb +++ b/test/ruby/test_rational.rb @@ -830,6 +830,13 @@ class Rational_Test < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_rational.rb#L830 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) -- cgit v1.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/