Crystal: Compiler crashes due to recursive alias without a base case

Created on 30 Dec 2016  路  5Comments  路  Source: crystal-lang/crystal

Inserting an element into a recursively typed Hash will cause the compiler to crash due to what looks like stack corruption:

alias RecHash = Hash( String, String | RecHash )

x = {} of String => String | RecHash
y = {} of String => String | RecHash
x["y"] = y

Compiler output:

Invalid memory access (signal 11) at address 0xbf151fec
[134668725] __crystal_sigfault_handler +85
[153873279] sigfault_handler +31
[-1217295360] ???
[151857938] ???
[138754615] ???
[138732613] ???
[151856008] ???
[151856650] ???
[151852676] ???
[138714919] ???
[138752655] ???
[138732613] ???
[151856008] ???
[151856650] ???
[151852676] ???
[138714919] ???
<keeps going>

Crystal compiler version: Crystal 0.20.1 [18e7617] (2016-12-05), OS: Ubuntu 15.10.

bug compiler

All 5 comments

Workaround (might also help narrowing down the bug):

class RecHash
  def initialize
    @inner = {} of String => String | RecHash
  end

  def []( key )
    @inner[key]
  end

  def []=( key, value )
    @inner[key] = value
  end
end

x = RecHash.new
y = RecHash.new
x["y"] = y

May be unrelated, but I got some additional results while playing around with this issue.

This gives me an error message I wasn't expecting. What I expected was a warning that you can't instantiate union types.

alias RecHash = String | Hash(String, RecHash)
puts RecHash.new

Output:

Error in crystal-3804.cr:2: undefined method 'new' for RecHash:Class

puts RecHash.new
             ^~~

The following gives me the correct warning:

alias Foo = String | Hash(String, Int32)
puts Foo.new

Output:

Error in crystal-3804.cr:2: instantiating '(Hash(String, Int32) | String):Class#new()'

puts Foo.new
         ^~~

in /usr/local/Cellar/crystal-lang/0.20.3/src/union.cr:19: can't create instance of a union type

struct Union
^

Edit: Crystal version Crystal 0.20.3 (2016-12-23) on macOS Sierra 10.12.2

Looks like it can be closed?

Checked in Crystal 0.31.1 on MacOS. It does not crash anymore. It now shows an error:

$ crystal test.cr
Showing last frame. Use --error-trace for full trace.

In /usr/local/Cellar/crystal/0.31.1/src/hash.cr:1825:46

 1825 | def initialize(@hash : UInt32, @key : K, @value : V)
                                                 ^-----
Error: instance variable '@value' of Hash::Entry(String, Hash(String, RecHash | String) | String) must be (Hash(String, RecHash | String) | String), not Hash(String, Hash(String, RecHash | String) | String)
$ crystal --version
Crystal 0.31.1 (2019-10-02)

LLVM: 8.0.1
Default target: x86_64-apple-macosx

Yes, it seems we made some changes to alias and now this correctly doesn't compile.

I would still like the compiler to give a better error message for recursive aliases without a case base. Or otherwise remove recursive aliases.

I'd be fine removing recursive aliases actually, since we can always re-add them after 1.0.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nabeelomer picture nabeelomer  路  3Comments

ArthurZ picture ArthurZ  路  3Comments

jhass picture jhass  路  3Comments

asterite picture asterite  路  3Comments

will picture will  路  3Comments