From d50f9ca2dd416d92152cd958b5f39496088481b0 Mon Sep 17 00:00:00 2001 From: Shugo Maeda Date: Tue, 27 Feb 2024 14:19:15 +0900 Subject: [PATCH] [Bug #20302] Multiple refinements cannot be applied to the same module In the following code, the iclass tree of refinements in cref should be -> -> Kernel. However, the iclass tree was broken because of code for included modules of refinements in rb_using_refinement(). Refinement#include is now removed, so this commit removes such unnecessary code. ```ruby module M1 refine(Kernel) do def f1 = :f1 end end module M2 refine(Kernel) do def f2 = :f2 end end class Foo using M1 using M2 def test p f2 #=> :f2 p f1 # expected => :f1 # actual => undefined local variable or method 'f1' for an instance of Foo end end Foo.new.test ``` --- eval.c | 6 ------ test/ruby/test_refinement.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/eval.c b/eval.c index a330b9c8bc..0d74de483a 100644 --- a/eval.c +++ b/eval.c @@ -1276,12 +1276,6 @@ rb_using_refinement(rb_cref_t *cref, VALUE klass, VALUE module) RCLASS_M_TBL(c) = RCLASS_M_TBL(module); - module = RCLASS_SUPER(module); - while (module && module != klass) { - c = RCLASS_SET_SUPER(c, rb_include_class_new(module, RCLASS_SUPER(c))); - RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass); - module = RCLASS_SUPER(module); - } rb_hash_aset(CREF_REFINEMENTS(cref), klass, iclass); } diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index 826616eb09..cb55627e2c 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -2672,6 +2672,35 @@ class TestRefinement < Test::Unit::TestCase assert_equal(:v2, obj.cached_foo_callsite) end + # [Bug #20302] + def test_multiple_refinements_for_same_module + assert_in_out_err([], <<-INPUT, %w(:f2 :f1), []) + module M1 + refine(Kernel) do + def f1 = :f1 + end + end + + module M2 + refine(Kernel) do + def f2 = :f2 + end + end + + class Foo + using M1 + using M2 + + def test + p f2 + p f1 + end + end + + Foo.new.test + INPUT + end + private def eval_using(mod, s)