The issue happens when the variable, that the array was built from, was a nil initially.
y = (1..2).map do
v = nil
v = 1
v
end
p y # => [1, 1]
p y.class # => Array(Int32)
p y.sum # => 2
When v stops being nil on a condition, that is potentially computational and not solvable while compiling:
z = (1..2).map do
v = nil
v = 1 if true
v
end
p z # [1, 1]
p z.class # => Array(Nil | Int32)
The array gets more complex type, that isn't compatible with current sum implementation, so p z.sum causes compile time error:
undefined method 'zero' for Nil:Class (compile-time type is (Nil | Int32):Class)
def sum(initial = T.zero)
^~~~
How am I supposed to fight this properly?
Or maybe it waits for some better implementation of stdlib sum method or anything else?
UPD: inject gives the same:
p z.inject{ |i, j| i + j }
undefined method '+' for Nil (compile-time type is (Nil | Int32))
You can use
Iterator#compact_mapto select non-nil values. The compiler will be able to infer aArray(Int32)in that case.http://play.crystal-lang.org/#/r/e85
Also, notice that
typeof(Expr)andExpr.classmight lead to different results. The first is the compile time type and the later is the runtime type.