require "../../spec_helper" describe "Code gen: sizeof" do it "gets sizeof int" do run("sizeof(Int32)").to_i.should eq(4) end it "gets sizeof struct" do run(<<-CRYSTAL).to_i.should eq(12) struct Foo def initialize(@x : Int32, @y : Int32, @z : Int32) end end Foo.new(1, 2, 3) sizeof(Foo) CRYSTAL end it "gets sizeof class" do # A class is represented as a pointer to its data run(<<-CRYSTAL).to_i.should eq(sizeof(Void*)) class Foo def initialize(@x : Int32, @y : Int32, @z : Int32) end end Foo.new(1, 2, 3) sizeof(Foo) CRYSTAL end it "gets sizeof union" do size = run(<<-CRYSTAL).to_i sizeof(Int32 | Float64) CRYSTAL # This union is represented as: # # struct { # 4 bytes, # for the type id # 8 bytes, # for the largest size between Int32 and Float64 # } # # But in 64 bits structs are aligned to 8 bytes, so it'll actually # be struct { 8 bytes, 8 bytes }. # # In 32 bits structs are aligned to 4 bytes, so it remains the same. {% if flag?(:bits64) %} size.should eq(16) {% else %} size.should eq(12) {% end %} end it "gets instance_sizeof class" do run(<<-CRYSTAL).to_i.should eq(16) class Foo def initialize(@x : Int32, @y : Int32, @z : Int32) end end Foo.new(1, 2, 3) instance_sizeof(Foo) CRYSTAL end it "gets instance_sizeof a generic type with type vars" do run(<<-CRYSTAL).to_i.should eq(8) class Foo(T) def initialize(@x : T) end end instance_sizeof(Foo(Int32)) CRYSTAL end it "gets sizeof Void" do # Same as the size of a byte, because doing # `Pointer(Void).malloc` must work like `Pointer(UInt8).malloc` run("sizeof(Void)").to_i.should eq(1) end it "gets sizeof NoReturn" do # NoReturn can't hold anything run("sizeof(NoReturn)").to_i.should eq(0) end it "gets sizeof Nil (#7644)" do # Nil can't hold anything run("sizeof(Nil)").to_i.should eq(0) end it "gets sizeof Bool (#8272)" do run("sizeof(Bool)").to_i.should eq(1) end it "can use sizeof in type argument (1)" do run(<<-CRYSTAL).to_i.should eq(4) struct StaticArray def size N end end x = uninitialized UInt8[sizeof(Int32)] x.size CRYSTAL end it "can use sizeof in type argument (2)" do run(<<-CRYSTAL).to_i.should eq(8) struct StaticArray def size N end end x = uninitialized UInt8[sizeof(Float64)] x.size CRYSTAL end it "can use sizeof of virtual type" do size = run(<<-CRYSTAL).to_i class Foo @x = 1 end class Bar < Foo @y = 2 end foo = Bar.new.as(Foo) sizeof(typeof(foo)) CRYSTAL {% if flag?(:bits64) %} size.should eq(8) {% else %} size.should eq(4) {% end %} end it "can use instance_sizeof of virtual type" do run(<<-CRYSTAL).to_i.should eq(12) class Foo @x = 1 end class Bar < Foo @y = 2 end class Baz < Bar @z = 2 end bar = Baz.new.as(Bar) instance_sizeof(typeof(bar)) CRYSTAL end it "can use instance_sizeof in type argument" do run(<<-CRYSTAL).to_i.should eq(12) struct StaticArray def size N end end class Foo def initialize @x = 1 @y = 1 end end x = uninitialized UInt8[instance_sizeof(Foo)] x.size CRYSTAL end it "returns correct sizeof for abstract struct (#4319)" do size = run(<<-CRYSTAL).to_i abstract struct Entry end struct FooEntry < Entry def initialize @uid = "" end end struct BarEntry < Entry def initialize @uid = "" end end sizeof(Entry) CRYSTAL size.should eq(16) end it "doesn't precompute sizeof of abstract struct (#7741)" do run(<<-CRYSTAL).to_i.should eq(16) abstract struct Base end struct Foo(T) < Base def initialize(@x : T) end end z = sizeof(Base) Foo({Int32, Int32, Int32, Int32}) z CRYSTAL end it "doesn't precompute sizeof of module (#7741)" do run(<<-CRYSTAL).to_i.should eq(16) module Base end struct Foo(T) include Base def initialize(@x : T) end end z = sizeof(Base) Foo({Int32, Int32, Int32, Int32}) z CRYSTAL end describe "alignof" do it "gets alignof primitive types" do run("alignof(Int32)").to_i.should eq(4) run("alignof(Void)").to_i.should eq(1) run("alignof(NoReturn)").to_i.should eq(1) run("alignof(Nil)").to_i.should eq(1) run("alignof(Bool)").to_i.should eq(1) end it "gets alignof struct" do run(<<-CRYSTAL).to_i.should eq(4) struct Foo def initialize(@x : Int8, @y : Int32, @z : Int16) end end Foo.new(1, 2, 3) alignof(Foo) CRYSTAL end it "gets alignof class" do # pointer size and alignment should be identical run(<<-CRYSTAL).to_i.should eq(sizeof(Void*)) class Foo def initialize(@x : Int8, @y : Int32, @z : Int16) end end Foo.new(1, 2, 3) alignof(Foo) CRYSTAL end it "gets alignof union" do run("alignof(Int32 | Int8)").to_i.should eq(8) run("alignof(Int32 | Int64)").to_i.should eq(8) end it "alignof mixed union is not less than alignof its variant types" do # NOTE: `alignof(Int128) == 16` is not guaranteed run("alignof(Int32 | Int128) >= alignof(Int128)").to_b.should be_true end end describe "instance_alignof" do it "gets instance_alignof class" do run(<<-CRYSTAL).to_i.should eq(4) class Foo def initialize(@x : Int8, @y : Int32, @z : Int16) end end Foo.new(1, 2, 3) instance_alignof(Foo) CRYSTAL run(<<-CRYSTAL).to_i.should eq(8) class Foo def initialize(@x : Int8, @y : Int64, @z : Int16) end end Foo.new(1, 2, 3) instance_alignof(Foo) CRYSTAL run(<<-CRYSTAL).to_i.should eq(4) class Foo end Foo.new instance_alignof(Foo) CRYSTAL end it "gets instance_alignof a generic type with type vars" do run(<<-CRYSTAL).to_i.should eq(4) class Foo(T) def initialize(@x : T) end end instance_alignof(Foo(Int32)) CRYSTAL run(<<-CRYSTAL).to_i.should eq(8) class Foo(T) def initialize(@x : T) end end instance_alignof(Foo(Int64)) CRYSTAL run(<<-CRYSTAL).to_i.should eq(4) class Foo(T) def initialize(@x : T) end end instance_alignof(Foo(Int8)) CRYSTAL end end end