diff options
author | nagachika <nagachika@ruby-lang.org> | 2022-10-01 13:39:47 +0900 |
---|---|---|
committer | nagachika <nagachika@ruby-lang.org> | 2022-10-01 15:32:44 +0900 |
commit | 9e739022ded433f189a575017d3936b79541f229 (patch) | |
tree | cfb987600d99acf60ab1959873e1cbf51028f8f7 /test | |
parent | e46532feafadef252682794c941180df72483c19 (diff) |
merge revision(s) 94cea3e4d0a60326bd95be762819eed8ccd59ca6,aa53d69aa21c4dfa2a78a1cec5cb34e9697b3d30,6b7d32a5e54088b6b4014529bbf2b4b8c1a96029,c6319026caa6c8f0f569f80011e8502349a04b14,aa490f9442c32cd0e1e449ac817f410bd5924c8b: [Backport #18435]
Fix {Method,UnboundMethod}#super_method for zsuper methods
* We need to resolve the zsuper method first, and then look the super
method of that.
---
proc.c | 25 ++++++++++++-----------
spec/ruby/core/method/super_method_spec.rb | 15 +++-----------
spec/ruby/core/unboundmethod/super_method_spec.rb | 16 ++++++---------
3 files changed, 22 insertions(+), 34 deletions(-)
Add specs for {Method,UnboundMethod}#owner of a zsuper method
---
spec/ruby/core/method/owner_spec.rb | 6 ++++++
spec/ruby/core/unboundmethod/owner_spec.rb | 7 +++++++
2 files changed, 13 insertions(+)
Resolve zsuper method during lookup but preserve owner separately
* See https://bugs.ruby-lang.org/issues/18729#note-34
* See [Bug #18729]
---
proc.c | 109 +++++++++++++++++++++++++----------------------
test/ruby/test_method.rb | 66 +++++++++++++++++++++++-----
2 files changed, 114 insertions(+), 61 deletions(-)
Extend tests for a zsuper method of which the method it resolved to
has been removed
---
test/ruby/test_method.rb | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
Reduce diff to proc.c @ b0b9f7201acab05c2a3ad92c3043a1f01df3e17f
* So it's easy to review https://github.com/ruby/ruby/pull/6242 +
https://github.com/ruby/ruby/pull/6467 and there are less changes
overall.
---
proc.c | 76 ++++++++++++++++++------------------------------
test/ruby/test_method.rb | 7 +++--
2 files changed, 34 insertions(+), 49 deletions(-)
Diffstat (limited to 'test')
-rw-r--r-- | test/ruby/test_method.rb | 112 |
1 files changed, 100 insertions, 12 deletions
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index f1522890e5..ac50a9d0b0 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -1052,7 +1052,7 @@ class TestMethod < Test::Unit::TestCase c1.class_eval {undef foo} m = c3.instance_method(:foo) m = assert_nothing_raised(NameError, Feature9781) {break m.super_method} - assert_equal c2, m.owner + assert_nil(m, Feature9781) end def test_super_method_removed_regular @@ -1064,19 +1064,26 @@ class TestMethod < Test::Unit::TestCase end def test_prepended_public_zsuper - mod = EnvUtil.labeled_module("Mod") {private def foo; :ok end} + mod = EnvUtil.labeled_module("Mod") {private def foo; [:ok] end} obj = Object.new.extend(mod) - mods = [obj.singleton_class] + class << obj public :foo end - 2.times do |i| - mods.unshift(mod = EnvUtil.labeled_module("Mod#{i}") {def foo; end}) - obj.singleton_class.prepend(mod) - end + + mod1 = EnvUtil.labeled_module("Mod1") {def foo; [:mod1] + super end} + obj.singleton_class.prepend(mod1) + + mod2 = EnvUtil.labeled_module("Mod2") {def foo; [:mod2] + super end} + obj.singleton_class.prepend(mod2) + m = obj.method(:foo) - assert_equal(mods, mods.map {m.owner.tap {m = m.super_method}}) - assert_nil(m.super_method) + assert_equal mod2, m.owner + assert_equal mod1, m.super_method.owner + assert_equal obj.singleton_class, m.super_method.super_method.owner + assert_equal nil, m.super_method.super_method.super_method + + assert_equal [:mod2, :mod1, :ok], obj.foo end def test_super_method_with_prepended_module @@ -1242,11 +1249,92 @@ class TestMethod < Test::Unit::TestCase a.remove_method(:foo) - assert_equal [[:rest]], unbound.parameters - assert_equal "#<UnboundMethod: B#foo(*)>", unbound.inspect + assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect + assert_equal [[:opt, :arg]], unbound.parameters obj = b.new - assert_raise_with_message(NoMethodError, /super: no superclass method `foo'/) { unbound.bind_call(obj) } + assert_equal 1, unbound.bind_call(obj) + + assert_include b.instance_methods(false), :foo + link = 'https://github.com/ruby/ruby/pull/6467#issuecomment-1262159088' + assert_raise(NameError, link) { b.instance_method(:foo) } + # For #test_method_list below, otherwise we get the same error as just above + b.remove_method(:foo) + end + + def test_zsuper_method_removed_higher_method + a0 = EnvUtil.labeled_class('A0') do + def foo(arg1 = nil, arg2 = nil) + 0 + end + end + line0 = __LINE__ - 4 + a0_foo = a0.instance_method(:foo) + + a = EnvUtil.labeled_class('A', a0) do + private + def foo(arg = nil) + 1 + end + end + line = __LINE__ - 4 + + b = EnvUtil.labeled_class('B', a) do + public :foo + end + + unbound = b.instance_method(:foo) + + assert_equal a0_foo, unbound.super_method + + a.remove_method(:foo) + + assert_equal "#<UnboundMethod: B(A)#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect + assert_equal [[:opt, :arg]], unbound.parameters + assert_equal a0_foo, unbound.super_method + + obj = b.new + assert_equal 1, unbound.bind_call(obj) + + assert_include b.instance_methods(false), :foo + assert_equal "#<UnboundMethod: B(A0)#foo(arg1=..., arg2=...) #{__FILE__}:#{line0}>", b.instance_method(:foo).inspect + end + + def test_zsuper_method_redefined_bind_call + c0 = EnvUtil.labeled_class('C0') do + def foo + [:foo] + end + end + + c1 = EnvUtil.labeled_class('C1', c0) do + def foo + super + [:bar] + end + end + m1 = c1.instance_method(:foo) + + c2 = EnvUtil.labeled_class('C2', c1) do + private :foo + end + + assert_equal [:foo], c2.private_instance_methods(false) + m2 = c2.instance_method(:foo) + + c1.class_exec do + def foo + [:bar2] + end + end + + m3 = c2.instance_method(:foo) + c = c2.new + assert_equal [:foo, :bar], m1.bind_call(c) + assert_equal c1, m1.owner + assert_equal [:foo, :bar], m2.bind_call(c) + assert_equal c2, m2.owner + assert_equal [:bar2], m3.bind_call(c) + assert_equal c2, m3.owner end # Bug #18751 |