Invalid type derivation
Closed this issue · 5 comments
mperham commented
Somehow the Crystal compiler thinks that Sidekiq::Job#retry can be of type Array(Redis::RedisValue) but I clearly mark its type here. I can't figure out what is wrong. Can anyone help?
property retry : (Bool | Int64 | Nil)
def to_h : Hash(String, JSON::Type)
h = Hash(String, JSON::Type).new
h["jid"] = jid
h["args"] = args
h["queue"] = queue
h["class"] = klass
h["created_at"] = created_at.epoch_f
h["bid"] = bid if bid
h["at"] = at.not_nil!.epoch_f if at
h["failed_at"] = failed_at.not_nil!.epoch_f if failed_at
h["retried_at"] = retried_at.not_nil!.epoch_f if retried_at
h["enqueued_at"] = enqueued_at.not_nil!.epoch_f if enqueued_at
h["retry_count"] = retry_count if retry_count
h["dead"] = dead if dead
h["backtrace"] = backtrace if backtrace
h["retry"] = retry if retry
h["error_class"] = error_class if error_class
h["error_message"] = error_message if error_message
h["error_backtrace"] = error_backtrace.not_nil!.map{|x| x.as(JSON::Type)} if error_backtrace
h
end
$ crystal spec
Error in ./spec/api_spec.cr:136: instantiating 'Sidekiq::SortedEntry#add_to_queue()'
job.add_to_queue
^~~~~~~~~~~~
in ./src/sidekiq/api.cr:370: instantiating 'remove_job()'
remove_job do |message|
^~~~~~~~~~
in ./src/sidekiq/api.cr:407: instantiating 'Sidekiq:Module#redis()'
Sidekiq.redis do |conn|
^~~~~
in ./src/sidekiq.cr:15: instantiating 'Sidekiq::Pool#redis()'
Sidekiq::Client.default_context.pool.redis do |conn|
^~~~~
in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'
@pool.connection do |conn|
^~~~~~~~~~
in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'
@pool.connection do |conn|
^~~~~~~~~~
in ./src/sidekiq.cr:15: instantiating 'Sidekiq::Pool#redis()'
Sidekiq::Client.default_context.pool.redis do |conn|
^~~~~
in ./src/sidekiq/api.cr:407: instantiating 'Sidekiq:Module#redis()'
Sidekiq.redis do |conn|
^~~~~
in ./src/sidekiq/api.cr:370: instantiating 'remove_job()'
remove_job do |message|
^~~~~~~~~~
in ./src/sidekiq/api.cr:374: instantiating 'Sidekiq::Client#push(Sidekiq::Job)'
Sidekiq::Client.new.push(job)
^~~~
in ./src/sidekiq/client.cr:100: instantiating 'raw_push(Array(Sidekiq::Job+))'
raw_push([job])
^~~~~~~~
in ./src/sidekiq/client.cr:135: instantiating 'Sidekiq::Pool#redis()'
@ctx.pool.redis do |conn|
^~~~~
in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'
@pool.connection do |conn|
^~~~~~~~~~
in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'
@pool.connection do |conn|
^~~~~~~~~~
in ./src/sidekiq/client.cr:135: instantiating 'Sidekiq::Pool#redis()'
@ctx.pool.redis do |conn|
^~~~~
in ./src/sidekiq/client.cr:136: instantiating 'Redis#multi()'
conn.multi do |multi|
^~~~~
in ./src/sidekiq/client.cr:136: instantiating 'Redis#multi()'
conn.multi do |multi|
^~~~~
in ./src/sidekiq/client.cr:137: instantiating 'atomic_push(Redis::TransactionApi, Array(Sidekiq::Job+))'
atomic_push(multi, payloads)
^~~~~~~~~~~
in ./src/sidekiq/client.cr:146: instantiating 'Array(Sidekiq::Job+)#each()'
payloads.each do |hash|
^~~~
in /usr/local/Cellar/crystal-lang/0.17.4/src/array.cr:813: instantiating 'each_index()'
each_index do |i|
^~~~~~~~~~
in /usr/local/Cellar/crystal-lang/0.17.4/src/array.cr:813: instantiating 'each_index()'
each_index do |i|
^~~~~~~~~~
in ./src/sidekiq/client.cr:146: instantiating 'Array(Sidekiq::Job+)#each()'
payloads.each do |hash|
^~~~
in ./src/sidekiq/client.cr:149: instantiating 'Sidekiq::Job+#to_json()'
all << hash.to_json
^~~~~~~
in ./src/sidekiq/job.cr:68: instantiating 'to_h()'
to_h.to_json
^~~~
in ./src/sidekiq/job.cr:60: no overload matches 'Hash(String, JSON::Type)#[]=' with types String, (Array(Redis::RedisValue) | Bool | Int64 | Nil)
Overloads are:
- Hash(K, V)#[]=(key : K, value : V)
Couldn't find overloads for these types:
- Hash(String, JSON::Type)#[]=(key : String, value : Array(Redis::RedisValue))
h["retry"] = retry if retry
^
mperham commented
asterite commented
Sidekiq::JobProxy#retry
returns this
asterite commented
I'm thinking of ways to improve the error message, but it's hard. Basically retry
got that type from that method and it was passed to a method. Traces are already very long.
The way I found the error was:
- The compiler seems to believe
retry
has a type I didn't expect - Is
retry
redefined inJob
, or any subclass ofJob
redefines this method? - Found
Sidekiq::JobProxy#retry
returning the result of aneach
method.
mperham commented
Thanks, that was it. Now I seem to have an infinite loop. Is it possible to dump a current backtrace when running crystal spec
?
mperham commented
crystal spec -v
gave me the hint I needed.