Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion spec/compiler/codegen/class_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion spec/compiler/codegen/proc_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ describe "Code gen: proc" do
class Foo
@f : -> Int32 = ->foo

def foo
def self.foo
42
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/compiler/semantic/class_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
67 changes: 67 additions & 0 deletions spec/compiler/semantic/instance_var_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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'"
Copy link
Copy Markdown
Member

@RX14 RX14 Jul 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we detect this and emit a specialized "did you mean" error message? I suspect it wouldn't be easy but worth asking in case it is.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's possible, if a lookup fails, see if there's a method with that name in the class scope... but I don't feel like implement that right now (someone else can try it, though)

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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down