aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2020-07-19 12:16:37 +0900
committernagachika <nagachika@ruby-lang.org>2020-07-19 12:16:37 +0900
commitd24cce8e7f48b0b45f726f5f1ac7ff796f46ba72 (patch)
tree5a67996530467f025a19091036980d293277d356
parentf43b8c4f7304ebea91cd01d5606e13273d0fd755 (diff)
downloadruby-d24cce8e7f48b0b45f726f5f1ac7ff796f46ba72.tar.gz
merge revision(s) bf1a6771f305ea286a3ae575676924551c03e857,c1463625555b061a2b94c3b6c5581730b482a285: [Backport #17012] [Backport #17014]
Fix non-numeric exclusive Range#minmax bug The implementation of Range#minmax added in d5c60214c45 causes the following incorrect behaviour: ('a'...'c').minmax => ["a", ["a", "b"]] instead of ('a'...'c').minmax => ["a", "b"] This is because the C implementation of Range#minmax (range_minmax) directly delegates to the C implementation of Range#min (range_min) and Range#max (range_max), without changing the execution context. Range#max's C implementation (range_max), when given a non-numeric exclusive range, delegates to super, which is meant to call Enumerable#max. However, because range_max is called directly by range_minmax, super calls Enumerable#minmax instead, causing the incorrect nesting. Perhaps it is possible to change the execution context in an optimized manner, but the simplest solution seems to be to just explicitly delegate from Range#minmax to Range#min and Range#max. Use static variables in Range#minmax
-rw-r--r--range.c7
-rw-r--r--test/ruby/test_range.rb3
-rw-r--r--version.h2
3 files changed, 10 insertions, 2 deletions
diff --git a/range.c b/range.c
index bf14c0c7a7..2deb495712 100644
--- a/range.c
+++ b/range.c
@@ -22,6 +22,8 @@ VALUE rb_cRange;
static ID id_beg, id_end, id_excl;
#define id_cmp idCmp
#define id_succ idSucc
+#define id_min idMin
+#define id_max idMax
static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
@@ -1236,7 +1238,10 @@ range_minmax(VALUE range)
if (rb_block_given_p()) {
return rb_call_super(0, NULL);
}
- return rb_assoc_new(range_min(0, NULL, range), range_max(0, NULL, range));
+ return rb_assoc_new(
+ rb_funcall(range, id_min, 0),
+ rb_funcall(range, id_max, 0)
+ );
}
int
diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb
index b37dbbc433..3953b3ecc2 100644
--- a/test/ruby/test_range.rb
+++ b/test/ruby/test_range.rb
@@ -146,6 +146,9 @@ class TestRange < Test::Unit::TestCase
assert_equal([nil, nil], (0...0).minmax)
assert_equal([2, 1], (1..2).minmax{|a, b| b <=> a})
+
+ assert_equal(['a', 'c'], ('a'..'c').minmax)
+ assert_equal(['a', 'b'], ('a'...'c').minmax)
end
def test_initialize_twice
diff --git a/version.h b/version.h
index ad01425605..f7f94bfe72 100644
--- a/version.h
+++ b/version.h
@@ -2,7 +2,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 96
+#define RUBY_PATCHLEVEL 97
#define RUBY_RELEASE_YEAR 2020
#define RUBY_RELEASE_MONTH 7