Crystal: Can't use class vars in generic types

Created on 17 Dec 2016  路  2Comments  路  Source: crystal-lang/crystal

class Base
  @@current : self?
  property prev : self?
  def push_self_to_current
    @prev = @@current
    @@current = self
  end
end

class Gen(T) < Base
end

Gen(Int32).new.push_self_to_current

result in compiler error

cast from Crystal::GenericClassInstanceType to Crystal::ClassVarContainer failed, at /home/firejox/develop/crystal/src/compiler/crystal/semantic/semantic_visitor.cr:436
0x74d7a7: *CallStack::unwind:Array(Pointer(Void)) at ??
0x74d73a: *CallStack#initialize:Array(Pointer(Void)) at ??
0x74d70a: *CallStack::new:CallStack at ??
0x73fa0e: *raise<TypeCastError>:NoReturn at ??
0x1131bf5: ??? at ??
0x11318ad: *Crystal::MainVisitor#lookup_class_var<Crystal::ClassVar>:Crystal::MetaTypeVar at ??
0x11339ed: *Crystal::MainVisitor#visit_class_var<Crystal::ClassVar>:Crystal::MetaTypeVar at ??
0x113c990: *Crystal::MainVisitor#visit<Crystal::ClassVar>:Bool at ??
0xb97d03: *Crystal::ASTNode+ at ??
0x113d50d: *Crystal::MainVisitor#type_assign<Crystal::InstanceVar, Crystal::ASTNode+, Crystal::Assign>:Nil at ??
0x113cd26: *Crystal::MainVisitor#visit<Crystal::Assign>:Bool at ??
0xb97d65: *Crystal::ASTNode+ at ??
0xc0cd59: *Crystal::Expressions#accept_children<Crystal::MainVisitor>:Array(Crystal::ASTNode+) at ??
0xb9a01e: *Crystal::ASTNode+ at ??
0xf04e18: *Crystal::Call#instantiate<Crystal::Matches, Crystal::Type+, Nil, (Array(Crystal::NamedArgumentType) | Nil)>:Array(Crystal::Def+) at ??
0xeff6dc: *Crystal::Call#lookup_matches_in_type<Crystal::Type+, Array(Crystal::Type+), (Array(Crystal::NamedArgumentType) | Nil), Nil, String, Bool>:Array(Crystal::Def+) at ??
0xefdb6d: *Crystal::Call#lookup_matches_in<Crystal::Type+, Array(Crystal::Type+), (Array(Crystal::NamedArgumentType) | Nil), Nil, String, Bool>:Array(Crystal::Def+) at ??
0xf0598a: *Crystal::Call#lookup_matches_in<Crystal::Type+, Array(Crystal::Type+), (Array(Crystal::NamedArgumentType) | Nil)>:Array(Crystal::Def+) at ??
0xee3f66: *Crystal::Call#lookup_matches_without_splat<Array(Crystal::Type+), (Array(Crystal::NamedArgumentType) | Nil)>:Array(Crystal::Def+) at ??
0xee33d2: *Crystal::Call#lookup_matches:Array(Crystal::Def+) at ??
0xec585f: *Crystal::Call#recalculate:(Array(Crystal::ASTNode+) | Array(Crystal::Def+) | Nil) at ??
0x1134d2c: *Crystal::MainVisitor#visit<Crystal::Call>:Bool at ??
0xb97f51: *Crystal::ASTNode+ at ??
0xc0cd59: *Crystal::Expressions#accept_children<Crystal::MainVisitor>:Array(Crystal::ASTNode+) at ??
0xb9a01e: *Crystal::ASTNode+ at ??
0x885f4b: *Crystal::Program#visit_main<Crystal::ASTNode+, Crystal::MainVisitor, Bool>:Crystal::ASTNode+ at ??
0x885efe: *Crystal::Program#visit_main:process_finished_hooks<Crystal::ASTNode+, Bool>:Crystal::ASTNode+ at ??
0x87b179: *Crystal::Program#semantic<Crystal::ASTNode+, Bool>:Crystal::ASTNode+ at ??
0xfccea4: *Crystal::Compiler#compile<Array(Crystal::Compiler::Source), String>:Crystal::Compiler::Result at ??
0xfd3ab9: *Crystal::Command::CompilerConfig#compile<String>:Crystal::Compiler::Result at ??
0x8530ed: *Crystal::Command#run_command<Bool>:Nil at ??
0x84f1e1: *Crystal::Command#run:(Array(Crystal::ImplementationTrace) | Array(Crystal::Init::View+:Class) | Array(String) | Bool | Crystal::Compiler::Result | Hash(String, String) | IO::FileDescriptor | Nil) at ??
0x84e8db: *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) at ??
0x84e899: *Crystal::Command::run:(Array(Crystal::ImplementationTrace) | Array(Crystal::Init::View+:Class) | Array(String) | Bool | Crystal::Compiler::Result | Hash(String, String) | IO::FileDescriptor | Nil) at ??
0x72af79: ??? at ??
0x739a99: main at ??
0x7f7b69018291: __libc_start_main at ??
0x72a0fa: _start at ??
0x0: ??? at ??

Crystal version

Crystal 0.20.1+55 [60bf3cd] (2016-12-16)
https://play.crystal-lang.org#/r/1ghv

bug compiler

Most helpful comment

Hmmm.. Right now one can't use class variables in generic types:

class Foo(T)
  @@bar = 1 # Error: can't use class variables in generic types
end

This is probably why it explodes in the above case, the variable is being inherited by generic types.

I think the correct solution to this is to allow class variables in generic types, and every generic instance will share the same value. Then the above example will start to work.

All 2 comments

Hmmm.. Right now one can't use class variables in generic types:

class Foo(T)
  @@bar = 1 # Error: can't use class variables in generic types
end

This is probably why it explodes in the above case, the variable is being inherited by generic types.

I think the correct solution to this is to allow class variables in generic types, and every generic instance will share the same value. Then the above example will start to work.

Next code is parsed normally when there is nor eference to #new:

class Dummy(T)
  @@counter = 0
  def self.new
    @@counter += 1
    super
  end
end

But with:

it { Dummy(Bool).new.should_not be_nil }

It fails with:

Error in line 1: while requiring "./spec/simple.cr": cast from Crystal::GenericClassInstanceType to Crystal::ClassVarContainer failed, at /crystal/src/compiler/crystal/semantic/semantic_visitor.cr:464:5:464

So it looks to be still broken :(


Crystal 0.24.2 [4f9ed8d03] (2018-03-08)

LLVM: 4.0.0
Default target: x86_64-unknown-linux-gnu

Was this page helpful?
0 / 5 - 0 ratings

Related issues

farleyknight picture farleyknight  路  64Comments

benoist picture benoist  路  59Comments

asterite picture asterite  路  70Comments

chocolateboy picture chocolateboy  路  87Comments

akzhan picture akzhan  路  67Comments