steep icon indicating copy to clipboard operation
steep copied to clipboard

More support for record type

Open ksss opened this issue 3 years ago • 1 comments

Problem

class RecordWithHint
  type record = { foo: String, bar: Integer?, baz: Symbol? }
  def test_send: () -> record
  def test_csend: () -> record?
  def test_block: () -> record
  def test_numblock: () -> record
  def test_begin: () -> record
  def test_in_block: () -> Array[record]
end
class RecordWithHint
  def test_send
    { foo: "hello", bar: 42, baz: nil }.itself
  end
  def test_csend
    { foo: "hello", bar: 42, baz: nil }&.itself
  end
  def test_block
    { foo: "hello", bar: 42, baz: nil }.tap{}
  end
  def test_numblock
    { foo: "hello", bar: 42, baz: nil }.tap{_1}
  end
  def test_begin
    a = { foo: "hello", bar: 42, baz: nil }
    a
  end
  def test_in_block
    [1].map { { foo: "hello", bar: 42, baz: nil } }
  end
end

Currently all methods are Ruby::MethodBodyTypeMismatch. It appears that steep has lost the record type information and is interpreting it as a Hash type (::Hash[::Symbol, (::String | ::Integer | nil)]).

Expect

I hope all or some of the patterns do not result in errors.

Research

From what I have looked into, it seems difficult to support test_begin and test_in_block. Could the other patterns be supported by giving a type hint?

ksss avatar Mar 09 '22 03:03 ksss

This is related to the limitation of literal/tuple/record typing.

Steep type checks these special types, not Integer, Record, nor Hash, based on the context (== variable type declaration here), but the context is lost by method calls.

# @type const x: 1
x = 1             # OK
x = 1.freeze      # Error

One idea is to support method calls returning self type.

soutaro avatar Jun 11 '22 06:06 soutaro

Duplication of https://github.com/soutaro/steep/issues/363

soutaro avatar May 17 '23 07:05 soutaro