Skip to content

Commit

Permalink
Compiler: fixed wrong codegen for virtual structs. Fixes #2551
Browse files Browse the repository at this point in the history
Ary Borenszweig committed May 3, 2016

Verified

This commit was signed with the committer’s verified signature.
rasendubi Oleksii Shmalko
1 parent 9c7f351 commit a90921c
Showing 3 changed files with 144 additions and 3 deletions.
129 changes: 129 additions & 0 deletions spec/compiler/codegen/struct_spec.cr
Original file line number Diff line number Diff line change
@@ -381,4 +381,133 @@ describe "Code gen: struct" do
ptr.value.x
)).to_i.should eq(1)
end

it "codegens virtual struct metaclass (#2551) (1)" do
run(%(
abstract struct Foo
def initialize
@x = 21
end
def x
a = @x
a
end
end
struct Bar < Foo
def initialize
@x = 42
end
end
struct Baz < Foo
end
(Bar.new as Foo).x
# (Bar || Baz).new.x
)).to_i.should eq(42)
end

it "codegens virtual struct metaclass (#2551) (2)" do
run(%(
abstract struct Foo
def initialize
@x = 21
end
end
struct Bar < Foo
def initialize
@x = 42
end
end
struct Baz < Foo
end
(Bar.new as Foo).@x
)).to_i.should eq(42)
end

it "codegens virtual struct metaclass (#2551) (3)" do
run(%(
abstract struct Foo
def initialize
@x = 21
end
def x
@x
end
end
struct Bar < Foo
def initialize
@x = 42
end
end
struct Baz < Foo
end
(Bar.new as Foo).x
)).to_i.should eq(42)
end

it "codegens virtual struct metaclass (#2551) (4)" do
run(%(
abstract struct Foo
def initialize
@x = 21
end
def x
a = @x
a
end
end
struct Bar < Foo
def initialize
@x = 42
end
end
struct Baz < Foo
end
(Bar || Baz).new.x
)).to_i.should eq(42)
end

it "mutates a virtual struct" do
run(%(
abstract struct Foo
def initialize
@x = 21
end
def x=(@x)
end
def x
@x
end
end
struct Bar < Foo
def initialize
@x = 42
end
end
struct Baz < Foo
end
foo = Bar.new as Foo
foo.x = 84
foo.x
)).to_i.should eq(84)
end
end
16 changes: 14 additions & 2 deletions src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
@@ -1462,7 +1462,13 @@ module Crystal
def llvm_self_ptr
type = context.type
if type.is_a?(VirtualType)
cast_to llvm_self, type.base_type
if type.struct?
# A virtual struct doesn't need a cast to a more generic pointer
# (it's the union already)
llvm_self
else
cast_to llvm_self, type.base_type
end
else
llvm_self
end
@@ -1832,7 +1838,13 @@ module Crystal
end

if type.is_a?(VirtualType)
pointer = cast_to pointer, type.base_type
if type.struct?
# For a struct we need to cast the second part of the union to the base type
value_ptr = gep(pointer, 0, 1)
pointer = bit_cast value_ptr, llvm_type(type.base_type).pointer
else
pointer = cast_to pointer, type.base_type
end
end

aggregate_index pointer, index
2 changes: 1 addition & 1 deletion src/compiler/crystal/codegen/primitives.cr
Original file line number Diff line number Diff line change
@@ -414,7 +414,7 @@ class Crystal::CodeGenVisitor
end

if type.is_a?(VirtualType)
@last = cast_to @last, type
@last = upcast(@last, type, base_type)
end

@last

0 comments on commit a90921c

Please sign in to comment.