Search code examples
rubyrbssteep

Ruby types and singleton methods


I'm seeing some unexpected behaviour setting up RBS types on an existing Ruby project. A minimal example:

# lib/a.rb
class A
  def self.foo
    new
  end
end

class B < A
  def self.foo
    super
  end
end

puts A.foo.inspect
puts B.foo.inspect

Output

#<A:0x000055f7cfb03908>
#<B:0x000055f7cfb037f0>

Signature

# lib/a.rbs
class A
  def self.foo: () -> A
end

class B < A
  def self.foo: () -> B
end

but the steep type-checker gives me errors

lib/a.rb:8:11: [error] Cannot allow method body have type `::A` because declared as type `::B`
│   ::A <: ::B
│     ::Object <: ::B
│       ::BasicObject <: ::B
│
│ Diagnostic ID: Ruby::MethodBodyTypeMismatch
│
└   def self.foo
             ~~~

Is this an issue with steep or (more likely) my understanding of the Ruby typing syntax?


Solution

  • Is this an issue with steep or (more likely) my understanding of the Ruby typing syntax?

    I believe it is neither.

    Your syntax is perfectly fine (otherwise steep would not even be able to parse the RBS file and give you a syntax error) and I also don't see any problem with steep here. The code you have is genuinely type-unsafe according to the types you have declared:

    • B::foo is declared to return an instance of B
    • B::foo returns super
    • super is A::foo
    • A::foo is declared to return an instance of A
    • ergo, B::foo is declared to return an instance of B but it actually returns an instance of A.

    Since A is not convertible to B, this is not type-safe.