Crystal: Compiler crash when using instance variable inside instance variable initializer

Created on 17 Jun 2016  路  5Comments  路  Source: crystal-lang/crystal

Input Source Code

class Manager
  @cache = Hash(Int32, String).new do |h, k|
     h[k] = @dir.path
  end

  def initialize(path : String)
    @dir = Dir.new path
  end

  def [](i : Int)
    @cache[i]
  end
end

Manager.new(".")[1]

Compiler output

Nil assertion failed
[10407223] *CallStack::unwind:Array(Pointer(Void)) +87
[10407114] *CallStack#initialize<CallStack>:Array(Pointer(Void)) +10
[10407066] *CallStack::new:CallStack +42
[10268056] *raise<Exception>:NoReturn +24
[10268030] ???
[10689120] *Nil#not_nil!<Nil>:NoReturn +16
[11714405] ???
[26306664] *Crystal::CodeGenVisitor#read_instance_var<Crystal::CodeGenVisitor, Crystal::Type+, Crystal::Type+, String, LLVM::Value>:Bool +344
[26306299] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::InstanceVar>:Bool +107
[13658275] *Crystal::ASTNode+ +4419
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26354172] *Crystal::CodeGenVisitor#prepare_call_args_non_external<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Def+, Crystal::Type+>:{Array(LLVM::Value), Bool} +172
[26345677] *Crystal::CodeGenVisitor#prepare_call_args<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Type+>:{Array(LLVM::Value), Bool} +141
[26339698] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Call>:Bool +418
[13659384] *Crystal::ASTNode+ +5528
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26356437] *Crystal::CodeGenVisitor#prepare_call_args_non_external<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Def+, Crystal::Type+>:{Array(LLVM::Value), Bool} +2437
[26345677] *Crystal::CodeGenVisitor#prepare_call_args<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Type+>:{Array(LLVM::Value), Bool} +141
[26339698] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Call>:Bool +418
[13659384] *Crystal::ASTNode+ +5528
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26247510] *Crystal::CodeGenVisitor#codegen_fun<Crystal::CodeGenVisitor, String, Crystal::Def+, Crystal::Type+, Bool, LLVM::Module, Bool, Bool>:LLVM::Function +2230
[26245263] *Crystal::CodeGenVisitor#codegen_fun:fun_module:is_fun_literal:is_closure<Crystal::CodeGenVisitor, String, Crystal::Def+, Crystal::Type+, LLVM::Module, Bool, Bool>:LLVM::Function +111
[26243403] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::ProcLiteral>:Bool +235
[13655396] *Crystal::ASTNode+ +1540
[26358599] *Crystal::CodeGenVisitor#codegen_call_with_block_as_fun_literal<Crystal::CodeGenVisitor, Crystal::Call, Crystal::ASTNode+, Crystal::Type+, Array(LLVM::Value)>:LLVM::Value +87
[26339950] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Call>:Bool +670
[13659384] *Crystal::ASTNode+ +5528
[26402434] *Crystal::CodeGenVisitor#run_instance_vars_initializers_non_recursive<Crystal::CodeGenVisitor, Crystal::Type+, Crystal::ClassType+, LLVM::Value>:Array(Crystal::InstanceVarInitializerContainer::InstanceVarInitializer)? +1106
[26401319] *Crystal::CodeGenVisitor#run_instance_vars_initializers<Crystal::CodeGenVisitor, Crystal::Type+, (Crystal::ClassType+ | Crystal::GenericClassType+), LLVM::Value>:Array(Crystal::InstanceVarInitializerContainer::InstanceVarInitializer)? +487
[26399294] *Crystal::CodeGenVisitor#allocate_aggregate<Crystal::CodeGenVisitor, Crystal::Type+>:LLVM::Value +958
[26397901] *Crystal::CodeGenVisitor#codegen_primitive_allocate<Crystal::CodeGenVisitor, Crystal::Primitive+, Crystal::Def+, Array(LLVM::Value)>:LLVM::Value +125
[26373564] *Crystal::CodeGenVisitor#codegen_primitive<Crystal::CodeGenVisitor, Crystal::Primitive+, Crystal::Def+, Array(LLVM::Value)>:LLVM::Value +412
[26371404] *Crystal::CodeGenVisitor#codegen_call<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Def+, Crystal::Type+, Array(LLVM::Value)>:(Bool | LLVM::Value | Nil) +220
[26339894] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Call>:Bool +614
[13659384] *Crystal::ASTNode+ +5528
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26265074] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Assign>:Bool? +818
[13657663] *Crystal::ASTNode+ +3807
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26261738] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Expressions>:Bool +266
[13655592] *Crystal::ASTNode+ +1736
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26247510] *Crystal::CodeGenVisitor#codegen_fun<Crystal::CodeGenVisitor, String, Crystal::Def+, Crystal::Type+, Bool, LLVM::Module, Bool, Bool>:LLVM::Function +2230
[26261313] *Crystal::CodeGenVisitor#codegen_fun<Crystal::CodeGenVisitor, String, Crystal::Def+, Crystal::Type+>:LLVM::Function +113
[26260356] *Crystal::CodeGenVisitor#target_def_fun<Crystal::CodeGenVisitor, Crystal::Def+, Crystal::Type+>:LLVM::Function +388
[26371507] *Crystal::CodeGenVisitor#codegen_call<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Def+, Crystal::Type+, Array(LLVM::Value)>:(Bool | LLVM::Value | Nil) +323
[26339894] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Call>:Bool +614
[13659384] *Crystal::ASTNode+ +5528
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26354172] *Crystal::CodeGenVisitor#prepare_call_args_non_external<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Def+, Crystal::Type+>:{Array(LLVM::Value), Bool} +172
[26345677] *Crystal::CodeGenVisitor#prepare_call_args<Crystal::CodeGenVisitor, Crystal::Call, Crystal::Type+>:{Array(LLVM::Value), Bool} +141
[26339698] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Call>:Bool +418
[13659384] *Crystal::ASTNode+ +5528
[26206801] *Crystal::CodeGenVisitor#accept<Crystal::CodeGenVisitor, Crystal::ASTNode+>:Nil +17
[26261738] *Crystal::CodeGenVisitor#visit<Crystal::CodeGenVisitor, Crystal::Expressions>:Bool +266
[14167381] *Crystal::Expressions +37
[11539180] *Crystal::Program#codegen<Crystal::Program, Crystal::Expressions, (Array(String) | Bool | Nil), Bool, LLVM::Module, Bool>:Hash(String, LLVM::Module) +124
[11539046] *Crystal::Program#codegen:debug:single_module:expose_crystal_main<Crystal::Program, Crystal::Expressions, Bool, (Array(String) | Bool | Nil), Bool>:Hash(String, LLVM::Module) +118
[20703827] *Crystal::Compiler#codegen<Crystal::Compiler, Crystal::Program, Crystal::Expressions, Array(Crystal::Compiler::Source), String>:Array(String)? +1347
[20697703] *Crystal::Compiler#compile<Crystal::Compiler, Array(Crystal::Compiler::Source), String>:Crystal::Compiler::Result +183
[20713642] *Crystal::Command::CompilerConfig#compile<Crystal::Command::CompilerConfig, String>:Crystal::Compiler::Result +58
[11172054] *Crystal::Command#run_command<Crystal::Command, Bool>:Nil +406
[11158779] *Crystal::Command#run<Crystal::Command>:(Array(Crystal::ImplementationTrace) | Array(Crystal::Init::View+:Class) | Array(String) | Bool | Crystal::Compiler::Result | Hash(String, String) | IO::FileDescriptor+ | Nil) +2107
[11156364] *Crystal::Command::run<Array(String)>:(Array(Crystal::ImplementationTrace) | Array(Crystal::Init::View+:Class) | Array(String) | Bool | Crystal::Compiler::Result | Hash(String, String) | IO::FileDescriptor+ | Nil) +44
[11156234] *Crystal::Command::run:(Array(Crystal::ImplementationTrace) | Array(Crystal::Init::View+:Class) | Array(String) | Bool | Crystal::Compiler::Result | Hash(String, String) | IO::FileDescriptor+ | Nil) +42
[10226273] ???
[10295412] main +52
[139960729585712] __libc_start_main +240
[10222697] _start +41
[0] ???

Error: you've found a bug in the Crystal compiler. Please open an issue, including source code that will allow us to reproduce the bug: https://github.com/crystal-lang/crystal/issues

Version: Crystal 0.18.2+41 861b5af

bug compiler

Most helpful comment

Yes, it's pretty complex to prove that. I'm thinking I'll just a give a compiler error if any other instance variable is mentioned in an initializer like that. Those initializers are meant to be simple. Otherwise you can always do them inside the initialize method, like in the above snippet.

All 5 comments

Thanks for reporting! That in the future will give a proper compile error, as you are accessing @dir before it's initialized.

Workaround:

class Manager
  def initialize(path : String)
    @dir = Dir.new path
    @cache = Hash(Int32, String).new do |h, k|
      h[k] = @dir.path
    end
  end

  def [](i : Int)
    @cache[i]
  end
end

Manager.new(".")[1]

Actually I didn't access @dir before initialization (hash block will be called only from Manager#[]) but compiler has theoretical problems with proving this

Yes, it's pretty complex to prove that. I'm thinking I'll just a give a compiler error if any other instance variable is mentioned in an initializer like that. Those initializers are meant to be simple. Otherwise you can always do them inside the initialize method, like in the above snippet.

Bump, just ran into this

This gives Error: @instance_vars are not yet allowed in metaclasses: use @@class_vars instead now, do we want to close this?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ArthurZ picture ArthurZ  路  3Comments

asterite picture asterite  路  3Comments

lgphp picture lgphp  路  3Comments

pbrusco picture pbrusco  路  3Comments

cjgajard picture cjgajard  路  3Comments