steep icon indicating copy to clipboard operation
steep copied to clipboard

`steep check` uses wrong context for `#define_method` in a singleton

Open skryukov opened this issue 4 years ago • 2 comments

Here is example:

# storage.rb
class Storage
  attr_reader :store

  def initialize
    @store = {}
  end

  class << self
    def dynamic_attr(name)
      define_method(name) do
        store[name]
      end

      define_method(:"#{name}=") do |val|
        store[name] = val
      end
    end
  end
end
# storage.rbs
class Storage
  attr_reader store: Hash[Symbol, untyped]

  def initialize: () -> void

  def self.dynamic_attr: (Symbol name) -> void
end
❯ steep check

storage.rb:11:8: [error] Type `singleton(::Storage)` does not have method `store`
│ Diagnostic ID: Ruby::NoMethod
│
└         store[name]
          ~~~~~

storage.rb:15:8: [error] Type `singleton(::Storage)` does not have method `store`
│ Diagnostic ID: Ruby::NoMethod
│
└         store[name] = val
          ~~~~~

skryukov avatar May 06 '21 13:05 skryukov

I think I'm having a similar error with Sequel:

class Game < Sequel::Model
  # other code
  
  dataset_module do
    def current
      where(status: 'init').first
    end
  end
end

And no matter how I try to define dataset_module, I get this error:

lib/models.rb:22:6: [error] Type `::Game` does not have method `where`
│ Diagnostic ID: Ruby::NoMethod
│
└       where(status: 'init').first
        ~~~~~

art-solopov avatar Apr 13 '24 15:04 art-solopov

Thank you for reporting the problem. Will take a look at the context setup if it can be supported.

A workaround is using @type self: Storage annotation inside the block given to define_method. I'm not sure what the self is inside dataset_module, but @type self: T or @implements annotation might help you...

soutaro avatar Apr 15 '24 04:04 soutaro