Feels like this should have come up before but I couldn't find anything.
struct A
end
struct B
end
a = A.new
b = B.new
obj = rand == 0 ? a : b
obj.as(B)
ary = rand == 0 ? [a] : [b]
ary.as(Array(B))
ptr = rand == 0 ? pointerof(a) : pointerof(b)
ptr.as(B*)
Error: can't cast (Pointer(A) | Pointer(B)) to Pointer(B)
What am I missing? What makes the last case different than the other two?
You can cast any reference type to pointer. But you can't cast a struct to a pointer. Im pretty sure we never though about casting a union of pointers to a pointer and the compiler is complaining because that's not a reference type.
It should be easy to fix.
I'm not sure I fully follow. A and B are both structs, obj is a union of both of them, yet the cast works?
This is the relevant code:
In the language you can do:
class A
end
A.new.as(Void*)
A.new.as(Int8*)
You can basically cast any reference type to a pointer, because a reference is represented as a pointer. This is useful for some low level things.
You can't do that with structs. The compiler will complain.
You can then cast a pointer to another pointer.
But we forgot about being able to cast a union of pointers to a pointer. That use case or scenario never came to our minds.
Is that more clear?
Most helpful comment
This is the relevant code:
https://github.com/crystal-lang/crystal/blob/35c1f41f05144d9645c7bba83cd1b1deaea68fb0/src/compiler/crystal/semantic/cleanup_transformer.cr#L728-L734
In the language you can do:
You can basically cast any reference type to a pointer, because a reference is represented as a pointer. This is useful for some low level things.
You can't do that with structs. The compiler will complain.
You can then cast a pointer to another pointer.
But we forgot about being able to cast a union of pointers to a pointer. That use case or scenario never came to our minds.
Is that more clear?