Crystal: llvm assertion failed

Created on 3 May 2016  Â·  11Comments  Â·  Source: crystal-lang/crystal

On https://github.com/will/crystal-pg/tree/cafe2be546ecf566b3c99210025f5f42e875ff87 using crystal head 9c7f351

crystal-pg ➤ bcrystal spec
Using compiled compiler at .build/crystal
Assertion failed: (castIsValid(op, S, Ty) && "Invalid cast!"), function Create, file /tmp/llvm20151214-69554-hagc7s/llvm-3.6.2.src/lib/IR/Instructions.cpp, line 2408.
[1]    55157 abort      /Users/will/code/crystal/bin/crystal spec
bug compiler

All 11 comments

I tried removing my cache build directory but it is still the same error

Thanks, I'll take a look. It might be because of the change to structs. I'll fix it before the release.

I do have a struct that inherits from an abstract struct that inherits from an abstract struct, but that appears to work

abstract struct A
end

abstract struct B < A
end

struct C < B
end

p C.new
/tmp ➤ bcrystal s.cr
Using compiled compiler at .build/crystal
C()

Reduced:

abstract struct Foo
end

struct Bar < Foo
end

struct Baz < Foo
end

instance = (Bar || Baz).new

I knew I forgot something, struct classes should also have a special treatment. It's good that you found this :-)

Please explain if you get a chance (Bar || Baz).new . Wouldn’t that always simplify down to Bar.new ? How does that trigger different behavior?

Oh, the || isn't optimized by the compiler for trivial cases (yet). Right now it's rewritten to:

if Bar
  Bar
else
  Baz
end

Maybe it's better if I use rand < 0.5 ? Bar : Baz, but of course || is shorter and we use it in specs to quickly create a union type.

So the final type of that expression would be Bar:Class | Baz:Class. However, similar to instance types, a union of two types under the same hierarchy gives a virtual type. So the type of the above is actually Foo+:Class... so a virtual type.

Before a few commits, virtual types were always reference types. Now they can be structs, so the codegen must be updated for this. The thing is, when you later do new on a Foo:Class+, the final result, before the structs change, would be a pointer... but now that's not true anymore. The buggy line is this one, which blindly casts the value to a pointer.

The reason why there's a virtual type for metaclass is because of this:

foo_plus = rand < 0.5 ? Bar.new :  Baz.new
typeof(foo_plus) # Foo+
foo_plus.class # what's the type of this? ... Foo+:Class

Anyway, that's the technical explanation... I'm usually not good at explaining this, but little by little I'm adding more comments in the compiler.

Also know that we will _probably_ stop generating virtual types for union types. So Bar.new || Baz.new will be of type Bar | Baz in the future. Only when assigning it to a variable of type Foo+ they will get casted to this virtual type. This is probably more intuitive than what we have right now, but we'll have to test it.

Thanks!

@will It should be working now, I checked out that branch and run ccrystal spec with head and all specs pass :-)

It's so good that you reported this: the compiler and standard library don't use struct inheritance and the current specs were very poor. The handling of virtual structs was missing in a few places, and with crystal-pg working I think they are all covered now (I also checked all uses of VirtualType in the codegen).

Confirm, things look good now

I see your alias is ccrystal instead of my bcrystal for bin/crystal

Yeah, first thing that came to my mind... the first c doesn't mean anything, I just double tap it to use the next compiler :-)

Was this page helpful?
0 / 5 - 0 ratings