1

I wanted to start using Steep for one of my projects, but I keep getting errors that I don't know how to fix. This is one example extracted from my code that I am struggling with. I removed all the complexity except for the relevant bits:

Setup

# lib/a/b.rb
module A
  class B
    C = [[''], ['2', '2\''], ['\'', '3', '’']].freeze
    D = (['0'] + C.map(&:first)).freeze

    def initialize(v)
      @v = v
    end

    def <=>(other)
      @v <=> other.v
    end
  end
end

My signatures look like this:

# sig/a/b.rbs
module A
  class B
    C: ::Array[::Array[::String]]
    D: ::Array[::String]

    @v: ::Integer

    def initialize: (::Integer v) -> untyped

    attr_reader v: ::Integer

    def <=>: (self other) -> ::Integer
  end
end

Steepfile:

target :lib do
  signature 'sig'

  check 'lib'
end

Steep now says:

lib/a/b.rb:4:4: IncompatibleAssignment: lhs_type=::Array[::String], rhs_type=::Array[(::String | nil)] (D = (['0'] + C.map(&:first)).freeze)
  ::Array[(::String | nil)] <: ::Array[::String]
   (::String | nil) <: ::String
    nil <: ::String
==> nil <: ::String does not hold
lib/a/b.rb:10:4: MethodBodyTypeMismatch: method=<=>, expected=::Integer, actual=(::Integer | nil) (def <=>(other))
  (::Integer | nil) <: ::Integer
   nil <: ::Integer
==> nil <: ::Integer does not hold

Problem

I think I understand the complaint. In general Array#first returns either a value from that array or nil. However, my Array was just defined one line above and so I know that it's not nil in this particular case.

Same thing for <=>. It could return nil in some cases, but given that I typed the argument other as self, I know other.value is an Integer and a <=> b where a and b are integers returns an integer. I.e. I know that it's not nil here.

But how do I tell steep that? Can I cast this to non-nil somehow?

E_net4
  • 27,810
  • 13
  • 101
  • 139
Lykos
  • 1,039
  • 6
  • 25

0 Answers0