Crystal: Module validation failed: Call parameter type does not match function signature!

Created on 27 Mar 2018  路  6Comments  路  Source: crystal-lang/crystal

Looked through opened & closed issues, this doesn't seem to be reported yet, but I'm pretty unfamiliar with these kinds of errors.

class Foo
  def bar
    puts "works"
  end

  @callbacks : Array(Proc(Nil)) = [
    ->{ bar }
  ]
end

Foo.new
Module validation failed: Call parameter type does not match function signature!
i32 138
 %Foo*  call void @"*Foo#bar:Nil"(i32 138)

???
???
???
???
???
__crystal_main
main
__libc_start_main
_start
???



md5-7cc5350b6fdabc27a18ab1d45d696e2a



Crystal 0.24.1 (2017-12-20)                             

LLVM: 5.0.0                                             
Default target: x86_64-unknown-linux-gnu

https://carc.in/#/r/3s96

bug compiler

Most helpful comment

I just checked this with other languages: Java evaluates instance var initializers at the instance level. But C# does it at the class (static) level, which makes much more sense to me. I'll change it to behave like in C#.

All 6 comments

Array is not essential:

class Foo
  def bar
    puts "foo"
  end

  @callbacks : Proc(Nil) = ->{ bar }
end

Foo.new

The interesting thing is that typeof(bar) is Nil and typeof(-> { bar }) is Proc(Nil) so it should work.
Replacing puts "foo" with plain nil compiles.

It also compiles if bar is not an instance method:

def bar
  puts "works"
end
class Foo
  @callback : Proc(Nil) = ->{ bar }
end

Foo.new

It compiles if you wrap the @callback inside an init.

class Foo
  @callback : Proc(Nil)

  def initialize
    @callback = ->{ bar }
  end

  def bar
    puts "works"
  end
end

Foo.new

Working example with array:

class Foo
  @callbacks : Array(Proc(Nil))

  def initialize
    @callbacks = [->{ bar }, ->{ bar; bar }]
  end

  def bar
    puts "foo"
  end

  def call
    @callbacks.each do |callback|
      callback.call
    end
  end
end

a = Foo.new
a.call

@Virtual-Machine Yeah, that's what I was doing originally. Good to point out though!

I basically had a variable in a superclass that I was trying to give a specific default value to in a subclass by overriding super's initialize. My library is a layer over another library, so if the super initialize changed, problems arose, so I tried a few ways to see if I could do it without redefining the method, and came across this issue in the process.

I did end up finding a much better way anyway :smile:

Note that I'll fix this by making the initialization of an instance variable run at the class level, not at the instance level.

The bug is basically that this compiles:

class Foo
  @bar : Int32 = bar

  def bar
    1
  end
end

It's a bit confusing that bar is found, given that's an instance method, and we are in the process of initializing an instance variable... that makes little sense.

So the above will give an error, but this will work:

class Foo
  @bar : Int32 = bar # OK, refers to the class method

  def self.bar
    1
  end
end

Of course you can always do:

class Foo
  @bar : Int32

  def initialize
    @bar = bar
  end

  def bar
    1
  end
end

and problem solved, but there at least a few checks are made to make sure you don't access self or some other instance var before assigning it to @bar.

I just checked this with other languages: Java evaluates instance var initializers at the instance level. But C# does it at the class (static) level, which makes much more sense to me. I'll change it to behave like in C#.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

costajob picture costajob  路  3Comments

RX14 picture RX14  路  3Comments

asterite picture asterite  路  3Comments

will picture will  路  3Comments

ArthurZ picture ArthurZ  路  3Comments