require "spec" require "../support/interpreted" private abstract class Base end private class Foo < Base getter i : Int64 getter str = "abc" def initialize(@i) end def initialize(@str, @i) end end private class Bar < Base getter x : UInt8[128] def initialize(@x) end end private struct Inner end private class Outer @x = Inner.new end describe "Primitives: reference" do describe ".allocate" do it "doesn't fail on complex ivar initializer if value is discarded (#14325)" do Outer.allocate 1 end end describe ".pre_initialize" do it "doesn't fail on complex ivar initializer if value is discarded (#14325)" do bar_buffer = GC.malloc(instance_sizeof(Outer)) Outer.pre_initialize(bar_buffer) 1 end it "zeroes the instance data" do bar_buffer = GC.malloc(instance_sizeof(Bar)) Slice.new(bar_buffer.as(UInt8*), instance_sizeof(Bar)).fill(0xFF) bar = Bar.pre_initialize(bar_buffer) bar.x.all?(&.zero?).should be_true end it "sets type ID" do foo_buffer = GC.malloc(instance_sizeof(Foo)) base = Foo.pre_initialize(foo_buffer).as(Base) base.should be_a(Foo) base.as(typeof(Foo.crystal_instance_type_id)*).value.should eq(Foo.crystal_instance_type_id) {% unless flag?(:interpreted) %} # FIXME: `Object#crystal_type_id` is incorrect for virtual types in the interpreter (#14967) base.crystal_type_id.should eq(Foo.crystal_instance_type_id) {% end %} end it "runs inline instance initializers" do foo_buffer = GC.malloc(instance_sizeof(Foo)) foo = Foo.pre_initialize(foo_buffer) foo.str.should eq("abc") end it "works when address is on the stack" do foo_buffer = uninitialized ReferenceStorage(Foo) foo = Foo.pre_initialize(pointerof(foo_buffer)) pointerof(foo_buffer).as(typeof(Foo.crystal_instance_type_id)*).value.should eq(Foo.crystal_instance_type_id) foo.str.should eq("abc") end # see notes in `Reference.pre_initialize` {% if compare_versions(Crystal::VERSION, "1.2.0") >= 0 %} it "works with virtual type" do foo_buffer = GC.malloc(instance_sizeof(Foo)) foo = Foo.as(Base.class).pre_initialize(foo_buffer).should be_a(Foo) foo.str.should eq("abc") end {% else %} pending! "works with virtual type" {% end %} it "raises on abstract virtual type" do expect_raises(Exception, "Can't pre-initialize abstract class Base") do Base.as(Base.class).pre_initialize(Pointer(Void).null) end end end describe ".unsafe_construct" do it "constructs an object in-place" do foo_buffer = GC.malloc(instance_sizeof(Foo)) foo = Foo.unsafe_construct(foo_buffer, 123_i64) foo.i.should eq(123) foo.str.should eq("abc") str = String.build &.<< "def" foo = Foo.unsafe_construct(foo_buffer, str, 789_i64) foo.i.should eq(789) foo.str.should be(str) end end end