diff --git a/spec/compiler/codegen/class_spec.cr b/spec/compiler/codegen/class_spec.cr index 5b7abf38a8ac..da7ff1e7dcd5 100644 --- a/spec/compiler/codegen/class_spec.cr +++ b/spec/compiler/codegen/class_spec.cr @@ -646,7 +646,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) @@ -1031,4 +1031,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 diff --git a/spec/compiler/codegen/proc_spec.cr b/spec/compiler/codegen/proc_spec.cr index 4e08c075cb51..784f05ab2bee 100644 --- a/spec/compiler/codegen/proc_spec.cr +++ b/spec/compiler/codegen/proc_spec.cr @@ -724,7 +724,7 @@ describe "Code gen: proc" do class Foo @f : -> Int32 = ->foo - def foo + def self.foo 42 end end diff --git a/spec/compiler/semantic/class_spec.cr b/spec/compiler/semantic/class_spec.cr index 897e119a64a6..412a80769685 100644 --- a/spec/compiler/semantic/class_spec.cr +++ b/spec/compiler/semantic/class_spec.cr @@ -854,7 +854,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) diff --git a/spec/compiler/semantic/instance_var_spec.cr b/spec/compiler/semantic/instance_var_spec.cr index d7b3e0bdcfea..b54fb3aaaea0 100644 --- a/spec/compiler/semantic/instance_var_spec.cr +++ b/spec/compiler/semantic/instance_var_spec.cr @@ -5042,4 +5042,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 diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr index 236b525b48c4..57faf72ae026 100644 --- a/src/compiler/crystal/codegen/codegen.cr +++ b/src/compiler/crystal/codegen/codegen.cr @@ -1831,9 +1831,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 diff --git a/src/compiler/crystal/semantic/instance_vars_initializer_visitor.cr b/src/compiler/crystal/semantic/instance_vars_initializer_visitor.cr index 227242bd8b98..3b140b27b849 100644 --- a/src/compiler/crystal/semantic/instance_vars_initializer_visitor.cr +++ b/src/compiler/crystal/semantic/instance_vars_initializer_visitor.cr @@ -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 diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr index d77176cb1bbe..2331524cf486 100644 --- a/src/compiler/crystal/types.cr +++ b/src/compiler/crystal/types.cr @@ -945,7 +945,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 @@ -1460,7 +1460,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)