Array(Int32) is not considered Enumerable(Int32)

Hi there I hope someone can help explain this to me. I’ve searched for the error in the forum and on github but I’m struggling to find an explanation. As far as I can tell it seems to be a bug in the compiler because arrays are enumerable in my experiments with simple functions. Compiling the below code on crystal v1.0.0 results in a error:

22 | @processor.call(@default, values)
                                ^-----
Error: type must be Enumerable(Int32), not Array(Int32)
class A(T)
  @processor : (T, Enumerable(T)) -> T

  def self.first
    ->(default : T, list : Enumerable(T)) {
      list.first || default
    }
  end

  def initialize(@default : T, @processor = self.class.first())
  end

  def call(values : Array(T))
    @processor.call(@default, values)
  end
end

A(Int32).new(0).call([1,2,3])

I’m still learning crystal and haven’t read all of the handbook so any help would be great!

Ah looks like I was able to solve it using as:

@processor.call(@default, values.as(Enumerable(T)))

But I’m still curious as to why the compiler fails

1 Like

This surely looks unexpected to me. Reduced reproduction:

->(list : Enumerable(Int32)){}.call([1])

Or, generalized:

module Foo(T)
end

class Bar(T)
  include Foo(T)
end

->(list : Foo(Int32)){}.call(Bar(Int32).new) # Error: type must be Foo(Int32), not Bar(Int32)

It works with class inheritance, though:

class Foo(T)
end

class Bar(T) < Foo(T)
end

->(list : Foo(Int32)){}.call(Bar(Int32).new)

This is fixed on master by Replace Crystal::Type#covariant? with #implements? by HertzDevil · Pull Request #10507 · crystal-lang/crystal · GitHub.

7 Likes