Error in macro ?
hutou opened this issue ยท 13 comments
Given the following code:
require "debug"
Debug.enabled = true
class Test(T)
def initialize(@sources : Enumerable(T))
@count = @sources.size
end
end
t = Test.new([1, 2, 3])
with p! t
, I get # => #<Test(Int32):0x7f83d3425e70 @sources=[1, 2, 3], @count=3>
, which is expected, but with debug!(t)
, an error occurs :
In zzz.cr:7:23
7 | @count = @sources.size
^---
Error: Can't calculate size of an open range
The full trace is in the attached zip file:
zzz.trace.zip
Thanks for this shard I find very useful.
Just an hint:
If I add a different type (String, Float, ...) in the array, no error !
t = Test.new([1, 2, "A", 4])
debug! t => DEBUG -- test_sija.cr:12 -- t = #<Test(Int32 | String):0x7f6800ea6e10 @count=4, @sources=[1, 2, "A", 4]> (Test(Int32 | String))
There are some strange things goin' on in here... ๐ค
Your example code stops working immediately after the open ended Range
is somewhere in the code - without the debug.cr involved at all:
class Test(T)
def initialize(@sources : Enumerable(T))
@count = @sources.size
end
end
p! 0..
p! Test.new([1, 2, 3])
This raises the same error (https://carc.in/#/r/elfa)
Interestingly, the begin-less Range
(..10
) or the infinite one (..
) doesn't trigger the error ๐ค
I'm sensing this might be a Crystal compiler error...
/cc @asterite @HertzDevil
The open range instantiates Range(Int32, Nil)
which means its #size
implementation will be taken into account as an override of Enumerable#size
. And Range(Int32, Nil)#size
raises at compile time which effectively makes this method undefined for Range(Int32, Nil)
.
I think that's an error in stdlib.
@straight-shoota Yeah, that's more or less expected. What's weird is outlined in my last comment.
Ah you mean the part that the begin-less or infinite range are unaffected?
That's because Range(B, E)
is an Enumerable(B)
, so only the type of the begin value counts. Thus those two are Enumerable(Nil)
.
The problem I described above appears because 0..
is Enumerable(Int32)
and thus the same as [1, 2, 3]
. The type of @sources
is Enumerable(Int32)
and thus the call @sources.size
finds implementations in Array#size
and Range(Int32, Nil)#size
.
@straight-shoota Oh, I see, that makes sense, thanks for the explanation. One thing that kinda bothers me is that the error only happens, when there's a reference to the type-matching Range
- which causes these confusing hard-to-identify-and-debug kind of errors - not mentioning that the stack trace and the error message are not helping either.
Yes, I think there are two things to do here:
Range#size
should not raise at compile time.- Provide more context for compile time error messages. In this case it would've helped if the error message stated that it's raised while instantiating
Range(Int32, Nil)#size
as an implementation ofEnumerable(Int32)#size
.
@straight-shoota Should I create a ticket for that?
Sure, go ahead if you like. Otherwise I'll take care of that in the next days.
Should be two separate issues.
@straight-shoota Actually, I'd leave it to you if you don't mind, since I'm out of time for next days. Just wanted to ensure it will be reported.
I'm gonna keep it open as a reminder for the issues raised.
I created crystal-lang/crystal#13121 and crystal-lang/crystal#13123 to track the raised issues.
This can probably be closed then.