diff --git a/CHANGELOG.md b/CHANGELOG.md index 1664fdb3f15c..3b52914a836e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Compatibility: * Add `Refinement#refined_class` (#3039, @itarato). * Add `rb_hash_new_capa` function (#3039, @itarato). * Fix `Encoding::Converter#primitive_convert` and raise `FrozenError` when a destination buffer argument is frozen (@andrykonchin). +* Add `Module#undefined_instance_methods` (#3039, @itarato). Performance: diff --git a/spec/tags/truffle/methods_tags.txt b/spec/tags/truffle/methods_tags.txt index dac19aba2b88..2d3a11d9a73d 100644 --- a/spec/tags/truffle/methods_tags.txt +++ b/spec/tags/truffle/methods_tags.txt @@ -115,3 +115,4 @@ fails:Public methods on UnboundMethod should include protected? fails:Public methods on UnboundMethod should include public? fails:Public methods on String should not include bytesplice fails:Public methods on Module should not include refinements +fails:Public methods on Module should not include undefined_instance_methods diff --git a/spec/truffleruby.next-specs b/spec/truffleruby.next-specs index e51e875c3aa5..6f7252673827 100644 --- a/spec/truffleruby.next-specs +++ b/spec/truffleruby.next-specs @@ -31,6 +31,7 @@ spec/ruby/core/sizedqueue/pop_spec.rb spec/ruby/core/sizedqueue/shift_spec.rb spec/ruby/core/module/refinements_spec.rb +spec/ruby/core/module/undefined_instance_methods_spec.rb spec/ruby/core/refinement/refined_class_spec.rb spec/ruby/core/module/used_refinements_spec.rb spec/ruby/optional/capi/hash_spec.rb diff --git a/src/main/java/org/truffleruby/core/module/ModuleNodes.java b/src/main/java/org/truffleruby/core/module/ModuleNodes.java index 8fb01d3bba8d..fb6bfe78c728 100644 --- a/src/main/java/org/truffleruby/core/module/ModuleNodes.java +++ b/src/main/java/org/truffleruby/core/module/ModuleNodes.java @@ -2356,4 +2356,22 @@ protected Object doClass(RubyClass rubyClass) { return rubyClass.isSingleton; } } + + @CoreMethod(names = "undefined_instance_methods") + public abstract static class UndefinedInstanceMethodsNode extends CoreMethodArrayArgumentsNode { + + @Specialization + @TruffleBoundary + protected RubyArray undefinedInstanceMethods(RubyModule module) { + List methodNames = new ArrayList<>(); + + for (InternalMethod methodEntry : module.fields.getMethods()) { + if (methodEntry.isUndefined()) { + methodNames.add(getLanguage().getSymbol(methodEntry.getName())); + } + } + + return createArray(methodNames.toArray()); + } + } } diff --git a/test/mri/tests/ruby/test_module.rb b/test/mri/tests/ruby/test_module.rb index cfea4de879b2..4439d2410b04 100644 --- a/test/mri/tests/ruby/test_module.rb +++ b/test/mri/tests/ruby/test_module.rb @@ -955,6 +955,15 @@ def test_public_instance_methods assert_equal([:bClass1], BClass.public_instance_methods(false)) end + def test_undefined_instance_methods + assert_equal([], AClass.undefined_instance_methods) + assert_equal([], BClass.undefined_instance_methods) + c = Class.new(AClass) {undef aClass} + assert_equal([:aClass], c.undefined_instance_methods) + c = Class.new(c) + assert_equal([], c.undefined_instance_methods) + end + def test_s_public o = (c = Class.new(AClass)).new assert_raise(NoMethodError, /private method/) {o.aClass1}