ruby / rbs

Type Signature for Ruby
Other
1.91k stars 201 forks source link

rbs/test: stack level too deep when calling super from prepend #1710

Open larskanis opened 6 months ago

larskanis commented 6 months ago

Similar issue to #478 .

Example:

# test-attach.rb
class TestAttach
  def attach
    puts "attach 2"
  end

  module RegisterAttach
    def attach
      puts "attach 1"
      super
    end
  end
  prepend RegisterAttach
end

TestAttach.new.attach
# sig/test-attach.rbs
class TestAttach
  def attach: () -> String
end

Run without rbs/test is OK:

$ ruby test-attach.rb 
attach 1
attach 2

Run with rbs/test fails with stack level too deep:

$ RBS_TEST_TARGET='TestAttach' ruby -r rbs/test/setup test-attach.rb 
[...]
attach 1
attach 1
/home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/type_check.rb:60:in `method_call': stack level too deep (SystemStackError)
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/type_check.rb:26:in `block in overloaded_call'
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/type_check.rb:25:in `map'
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/type_check.rb:25:in `overloaded_call'
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/tester.rb:152:in `call'
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/observer.rb:10:in `notify'
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/hook.rb:178:in `ensure in attach__with__RBS_TEST_16c021_404c48f8'
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/hook.rb:178:in `attach__with__RBS_TEST_16c021_404c48f8'
    from test-attach.rb:9:in `attach'
     ... 7697 levels...
    from test-attach.rb:9:in `attach'
    from /home/lars/.rvm/gems/ruby-3.3.0/gems/rbs-3.4.1/lib/rbs/test/hook.rb:146:in `attach__with__RBS_TEST_16c021_404c48f8'
    from test-attach.rb:9:in `attach'
    from test-attach.rb:15:in `<main>'
ksss commented 5 months ago

To simplify the problem, it appears that the hook is adding methods as follows, resulting in an infinite loop.

# test-attach.rb
class TestAttach
  def attach
    puts "attach 2"
  end

  module RegisterAttach
    def attach
      puts "attach 1"
      super
    end
  end
  prepend RegisterAttach

  # append by hook
  def with_attach
    send(:without_attach)
  end
  alias without_attach attach
  alias attach with_attach
end

TestAttach.new.attach

To solve the problem, the structure of the hook may need to be changed.