steep icon indicating copy to clipboard operation
steep copied to clipboard

Use of `Symbol#to_proc` leads to confusing errors.

Open myronmarston opened this issue 3 years ago • 0 comments

Consider this ruby file:

class MyClass
  def using_symbol_to_proc(array)
    array.map(&:foo)
  end

  def using_a_block(array)
    array.map { |e| e.foo }
  end
end

...paired with this rbs file:

class MyClass
  def using_symbol_to_proc: (::Array[::String]) -> void
  def using_a_block: (::Array[::String]) -> void
end

When I run steep, it gives me different errors for the two usages of foo:

lib/my_class.rb:3:4: [error] Cannot find compatible overloading of method `map` of type `::Array[::String]`
│ Method types:
│   def map: [U] () { (::String) -> U } -> ::Array[U]
│          | () -> ::Enumerator[::String, ::Array[untyped]]
│
│ Diagnostic ID: Ruby::UnresolvedOverloading
│
└     array.map(&:foo)
      ~~~~~~~~~~~~~~~~

lib/my_class.rb:7:22: [error] Type `::String` does not have method `foo`
│ Diagnostic ID: Ruby::NoMethod
│
└     array.map { |e| e.foo }
                        ~~~

Detected 2 problems from 1 file

The second one is very clear: String doesn't have a foo method.

The first error is quite confusing: it makes it sound like Array#map isn't properly defined in RBS or something. It's not at all clear that the problem is that String lacks a foo method.

Symbol#to_proc is a very common idiom in Ruby, particularly for Enumerable#map, etc, and steep would be friendlier to use if it provided the same error in this situation. Conceptually, I think of some_method(&:foo) and some_method { |e| e.foo } as being equivalent, so it's quite unexpected that steep treats them differently.

myronmarston avatar Oct 05 '22 22:10 myronmarston