Skip to content

Commit

Permalink
Compiler: evaluate instance var initializers at the metaclass level (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored and RX14 committed Jul 30, 2018
1 parent 1318e05 commit 3de4c52
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 8 deletions.
38 changes: 37 additions & 1 deletion spec/compiler/codegen/class_spec.cr
Expand Up @@ -654,7 +654,7 @@ describe "Code gen: class" do
it "doesn't crash on instance variable assigned a proc, and never instantiated (#923)" do
codegen(%(
class Klass
def f(arg)
def self.f(arg)
end
@a : Proc(String, Nil) = ->f(String)
Expand Down Expand Up @@ -1039,4 +1039,40 @@ describe "Code gen: class" do
foo.x
), inject_primitives: false).to_i.should eq(1)
end

it "runs instance variable initializer at the class level" do
run(%(
class Foo
@x : Int32 = bar
def self.bar
42
end
def x
@x
end
end
Foo.new.x
)).to_i.should eq(42)
end

it "runs instance variable initializer at the class level, for generic type" do
run(%(
class Foo(T)
@x : T = bar
def self.bar
42
end
def x
@x
end
end
Foo(Int32).new.x
)).to_i.should eq(42)
end
end
2 changes: 1 addition & 1 deletion spec/compiler/codegen/proc_spec.cr
Expand Up @@ -724,7 +724,7 @@ describe "Code gen: proc" do
class Foo
@f : -> Int32 = ->foo
def foo
def self.foo
42
end
Expand Down
2 changes: 1 addition & 1 deletion spec/compiler/semantic/class_spec.cr
Expand Up @@ -822,7 +822,7 @@ describe "Semantic: class" do
it "doesn't crash on instance variable assigned a proc, and never instantiated (#923)" do
assert_type(%(
class Klass
def f(arg)
def self.f(arg)
end
@a : Proc(String, Nil) = ->f(String)
Expand Down
67 changes: 67 additions & 0 deletions spec/compiler/semantic/instance_var_spec.cr
Expand Up @@ -5066,4 +5066,71 @@ describe "Semantic: instance var" do
Second.new.hash
)) { hash_of(hash_of(int32, int32).virtual_type, int32).virtual_type }
end

it "doesn't solve instance var initializer in instance context (1) (#5876)" do
assert_error %(
class Foo
@x : Int32 = bar
def bar
1
end
end
Foo.new
),
"undefined local variable or method 'bar'"
end

it "doesn't solve instance var initializer in instance context (2) (#5876)" do
assert_error %(
class Foo(T)
@x : T = bar
def bar
1
end
end
Foo(Int32).new
),
"undefined local variable or method 'bar'"
end

it "doesn't solve instance var initializer in instance context (3) (#5876)" do
assert_error %(
module Moo(T)
@x : T = bar
def bar
1
end
end
class Foo
include Moo(Int32)
end
Foo.new
),
"undefined local variable or method 'bar'"
end

it "solves instance var initializer in metaclass context (#5876)" do
assert_type(%(
class Foo
@x : Int32 = bar
def self.bar
1
end
def x
@x
end
end
Foo.new.x
)) { int32 }
end
end
3 changes: 1 addition & 2 deletions src/compiler/crystal/codegen/codegen.cr
Expand Up @@ -1833,9 +1833,8 @@ module Crystal
with_cloned_context do
# Instance var initializers must run with "self"
# properly set up to the type being allocated
context.type = real_type
context.type = real_type.metaclass
context.vars = LLVMVars.new
context.vars["self"] = LLVMVar.new(type_ptr, real_type)
alloca_vars init.meta_vars

accept init.value
Expand Down
Expand Up @@ -103,7 +103,7 @@ class Crystal::InstanceVarsInitializerVisitor < Crystal::SemanticVisitor
end

ivar_visitor = MainVisitor.new(program, meta_vars: i.meta_vars)
ivar_visitor.scope = scope
ivar_visitor.scope = scope.metaclass
value.accept ivar_visitor
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/crystal/types.cr
Expand Up @@ -992,7 +992,7 @@ module Crystal
if !meta_vars && !self.is_a?(GenericType)
meta_vars = MetaVars.new
visitor = MainVisitor.new(program, vars: meta_vars, meta_vars: meta_vars)
visitor.scope = self
visitor.scope = self.metaclass
value = value.clone
value.accept visitor
end
Expand Down Expand Up @@ -1507,7 +1507,7 @@ module Crystal
def run_instance_var_initializer(initializer, instance : GenericClassInstanceType | NonGenericClassType)
meta_vars = MetaVars.new
visitor = MainVisitor.new(program, vars: meta_vars, meta_vars: meta_vars)
visitor.scope = instance
visitor.scope = instance.metaclass
value = initializer.value.clone
value.accept visitor
instance_var = instance.lookup_instance_var(initializer.name)
Expand Down

0 comments on commit 3de4c52

Please sign in to comment.