Skip to content

Commit 4b36a59

Browse files
committed
Fix setting method visibility for a refinement without an origin class
If a class has been refined but does not have an origin class, there is a single method entry marked with VM_METHOD_TYPE_REFINED, but it contains the original method entry. If the original method entry is present, we shouldn't skip the method when searching even when skipping refined methods. Fixes [Bug #17519]
1 parent cb78aae commit 4b36a59

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

test/ruby/test_module.rb

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2294,7 +2294,7 @@ def /(other)
22942294
assert_equal(0, 1 / 2)
22952295
end
22962296

2297-
def test_visibility_after_refine_and_visibility_change
2297+
def test_visibility_after_refine_and_visibility_change_with_origin_class
22982298
m = Module.new
22992299
c = Class.new do
23002300
def x; :x end
@@ -2317,6 +2317,114 @@ def x; :y end
23172317
assert_equal(:x, o2.public_send(:x))
23182318
end
23192319

2320+
def test_visibility_after_multiple_refine_and_visibility_change_with_origin_class
2321+
m = Module.new
2322+
c = Class.new do
2323+
def x; :x end
2324+
end
2325+
c.prepend(m)
2326+
Module.new do
2327+
refine c do
2328+
def x; :y end
2329+
end
2330+
end
2331+
Module.new do
2332+
refine c do
2333+
def x; :z end
2334+
end
2335+
end
2336+
2337+
o1 = c.new
2338+
o2 = c.new
2339+
assert_equal(:x, o1.public_send(:x))
2340+
assert_equal(:x, o2.public_send(:x))
2341+
o1.singleton_class.send(:private, :x)
2342+
o2.singleton_class.send(:public, :x)
2343+
2344+
assert_raise(NoMethodError) { o1.public_send(:x) }
2345+
assert_equal(:x, o2.public_send(:x))
2346+
end
2347+
2348+
def test_visibility_after_refine_and_visibility_change_without_origin_class
2349+
c = Class.new do
2350+
def x; :x end
2351+
end
2352+
Module.new do
2353+
refine c do
2354+
def x; :y end
2355+
end
2356+
end
2357+
o1 = c.new
2358+
o2 = c.new
2359+
o1.singleton_class.send(:private, :x)
2360+
o2.singleton_class.send(:public, :x)
2361+
assert_raise(NoMethodError) { o1.public_send(:x) }
2362+
assert_equal(:x, o2.public_send(:x))
2363+
end
2364+
2365+
def test_visibility_after_multiple_refine_and_visibility_change_without_origin_class
2366+
c = Class.new do
2367+
def x; :x end
2368+
end
2369+
Module.new do
2370+
refine c do
2371+
def x; :y end
2372+
end
2373+
end
2374+
Module.new do
2375+
refine c do
2376+
def x; :z end
2377+
end
2378+
end
2379+
o1 = c.new
2380+
o2 = c.new
2381+
o1.singleton_class.send(:private, :x)
2382+
o2.singleton_class.send(:public, :x)
2383+
assert_raise(NoMethodError) { o1.public_send(:x) }
2384+
assert_equal(:x, o2.public_send(:x))
2385+
end
2386+
2387+
def test_visibility_after_refine_and_visibility_change_with_superclass
2388+
c = Class.new do
2389+
def x; :x end
2390+
end
2391+
sc = Class.new(c)
2392+
Module.new do
2393+
refine sc do
2394+
def x; :y end
2395+
end
2396+
end
2397+
o1 = sc.new
2398+
o2 = sc.new
2399+
o1.singleton_class.send(:private, :x)
2400+
o2.singleton_class.send(:public, :x)
2401+
assert_raise(NoMethodError) { o1.public_send(:x) }
2402+
assert_equal(:x, o2.public_send(:x))
2403+
end
2404+
2405+
def test_visibility_after_multiple_refine_and_visibility_change_with_superclass
2406+
c = Class.new do
2407+
def x; :x end
2408+
end
2409+
sc = Class.new(c)
2410+
Module.new do
2411+
refine sc do
2412+
def x; :y end
2413+
end
2414+
end
2415+
Module.new do
2416+
refine sc do
2417+
def x; :z end
2418+
end
2419+
end
2420+
o1 = sc.new
2421+
o2 = sc.new
2422+
o1.singleton_class.send(:private, :x)
2423+
o2.singleton_class.send(:public, :x)
2424+
assert_raise(NoMethodError) { o1.public_send(:x) }
2425+
assert_equal(:x, o2.public_send(:x))
2426+
end
2427+
23202428
def test_prepend_visibility
23212429
bug8005 = '[ruby-core:53106] [Bug #8005]'
23222430
c = Class.new do

vm_method.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,8 @@ search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined)
977977
for (; klass; klass = RCLASS_SUPER(klass)) {
978978
RB_DEBUG_COUNTER_INC(mc_search_super);
979979
if ((me = lookup_method_table(klass, id)) != 0) {
980-
if (!skip_refined || me->def->type != VM_METHOD_TYPE_REFINED) {
980+
if (!skip_refined || me->def->type != VM_METHOD_TYPE_REFINED ||
981+
me->def->body.refined.orig_me) {
981982
break;
982983
}
983984
}

0 commit comments

Comments
 (0)