Repository: ruby/rbs (Ruby)

Issue:
RBS::InvalidOverloadMethodError caused when the super method is defined by an extended module
Since rbs v3.0.3, `rbs validate` causes RBS::InvalidOverloadMethodError with the following code.

```rbs
# test.rbs
module M
  def f: () -> void
end

class C1
  extend M
  def self.f: () -> void | ...
end
```



```console
$ rbs _3.0.3_ -I . validate --silent
/Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:716:in `define_method': test.rbs:7:2...7:30: Invalid method overloading: ::C1#f (RBS::InvalidOverloadMethodError)
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:580:in `block in import_methods'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder/method_builder.rb:56:in `block in each'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/3.3.0+0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/3.3.0+0/tsort.rb:431:in `each_strongly_connected_component_from'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/3.3.0+0/tsort.rb:349:in `block in each_strongly_connected_component'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder/method_builder.rb:73:in `each_value'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder/method_builder.rb:73:in `tsort_each_node'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/3.3.0+0/tsort.rb:347:in `call'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/3.3.0+0/tsort.rb:347:in `each_strongly_connected_component'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/3.3.0+0/tsort.rb:316:in `each_strongly_connected_component'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder/method_builder.rb:51:in `each'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:579:in `import_methods'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:248:in `block (2 levels) in build_singleton0'
	from <internal:kernel>:90:in `tap'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:225:in `block in build_singleton0'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:751:in `try_cache'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:218:in `build_singleton0'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:302:in `block (2 levels) in build_singleton'
	from <internal:kernel>:90:in `tap'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:301:in `block in build_singleton'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:751:in `try_cache'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/definition_builder.rb:294:in `build_singleton'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/cli.rb:453:in `block in run_validate'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/cli.rb:448:in `each'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/cli.rb:448:in `run_validate'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/lib/rbs/cli.rb:135:in `run'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/rbs-3.0.3/exe/rbs:7:in `<top (required)>'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/bin/rbs:25:in `load'
	from /Users/kuwabara.masataka/.rbenv/versions/trunk/bin/rbs:25:in `<main>'
```


I've confirmed the following code does not raise the error.

```rbs
module M
  def f: () -> void
end

# Overload included instance method
class C2
  include M
  def f: () -> void | ...
end

class Parent
  def self.f: () -> Integer
  def f: () -> Integer
end

# Overload superclass's singleton method
class C3 < Parent
  def self.f: () -> void | ...
end

# Overload superclass's instance method.
class C4 < Parent
  def f: () -> void | ...
end
```

And I also confirmed this problem occurs on rbs v3.0.3 but not on v3.0.2.



I got this problem on ActiveJob and ActiveRecord.
https://github.com/ruby/gem_rbs_collection/blob/6751bcb8010ea20e2a7838e92264a122e1d42c79/gems/activejob/6.0/activejob.rbs#L12
https://github.com/ruby/gem_rbs_collection/blob/6751bcb8010ea20e2a7838e92264a122e1d42c79/gems/activerecord/6.0/activerecord.rbs#L56C6-L59



Discussion:

Patch:
diff --git a/lib/rbs/definition_builder.rb b/lib/rbs/definition_builder.rb
index 255a9077c..44f572141 100644
--- a/lib/rbs/definition_builder.rb
+++ b/lib/rbs/definition_builder.rb
@@ -239,14 +239,6 @@ def build_singleton0(type_name)
             definition.class_variables.merge!(defn.class_variables)
           end
 
-          all_interfaces = one_ancestors.each_extended_interface.flat_map do |interface|
-            other_interfaces = ancestor_builder.interface_ancestors(interface.name).ancestors #: Array[Definition::Ancestor::Instance]
-            other_interfaces = other_interfaces.select {|ancestor| ancestor.source }
-            [interface, *other_interfaces]
-          end
-          interface_methods = interface_methods(all_interfaces)
-          import_methods(definition, type_name, methods, interface_methods, Substitution.new)
-
           one_ancestors.each_extended_module do |mod|
             mod.args.each do |arg|
               validate_type_presence(arg)
@@ -256,7 +248,12 @@ def build_singleton0(type_name)
             define_instance(definition, mod.name, subst)
           end
 
-          interface_methods = interface_methods(one_ancestors.each_extended_interface.to_a)
+          all_interfaces = one_ancestors.each_extended_interface.flat_map do |interface|
+            other_interfaces = ancestor_builder.interface_ancestors(interface.name).ancestors #: Array[Definition::Ancestor::Instance]
+            other_interfaces = other_interfaces.select {|ancestor| ancestor.source }
+            [interface, *other_interfaces]
+          end
+          interface_methods = interface_methods(all_interfaces)
           import_methods(definition, type_name, methods, interface_methods, Substitution.new)
 
           entry.decls.each do |d|


Test patch:
diff --git a/test/rbs/definition_builder_test.rb b/test/rbs/definition_builder_test.rb
index 89483b58a..b6f42ae7d 100644
--- a/test/rbs/definition_builder_test.rb
+++ b/test/rbs/definition_builder_test.rb
@@ -2566,4 +2566,31 @@ def __id__: () -> void
       end
     end
   end
+
+  def test_extend_overload
+    SignatureManager.new do |manager|
+      manager.files[Pathname("foo.rbs")] = <<~EOF
+        module M
+          def f: () -> Integer
+        end
+        class A
+          extend M
+          def self.f: () -> String | ...
+        end
+      EOF
+
+      manager.build do |env|
+        builder = DefinitionBuilder.new(env: env)
+
+        builder.build_singleton(type_name("::A")).tap do |definition|
+          assert_instance_of Definition, definition
+
+          definition.methods[:f].tap do |method|
+            assert_equal [TypeName("::A"), TypeName("::M")], method.defs.map(&:defined_in)
+            assert_equal [TypeName("::A"), TypeName("::A")], method.defs.map(&:implemented_in)
+          end
+        end
+      end
+    end
+  end
 end