diff --git a/spec/compiler/codegen/struct_spec.cr b/spec/compiler/codegen/struct_spec.cr new file mode 100644 index 0000000000000000000000000000000000000000..bfd87dabac17b7de6604f4f1bc51de5263af873d --- /dev/null +++ b/spec/compiler/codegen/struct_spec.cr @@ -0,0 +1,279 @@ +#!/usr/bin/env bin/crystal --run +require "../../spec_helper" + +describe "Code gen: struct" do + it "creates structs" do + run(" + struct Foo + end + + f = Foo.allocate + 1 + ").to_i.should eq(1) + end + + it "creates structs with instance var" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + end + + f = Foo.new(1) + f.x + ").to_i.should eq(1) + end + + it "assigning a struct makes a copy (1)" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + + def x=(@x) + end + end + + f = Foo.new(1) + + g = f + g.x = 2 + + g.x + ").to_i.should eq(2) + end + + it "assigning a struct makes a copy (2)" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + + def x=(@x) + end + end + + f = Foo.new(1) + + g = f + g.x = 2 + + f.x + ").to_i.should eq(1) + end + + it "passes a struct as a parameter makes a copy" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + + def x=(@x) + end + end + + def foo(f) + f.x = 2 + end + + f = Foo.new(1) + + foo(f) + + f.x + ").to_i.should eq(1) + end + + it "passes a generic struct as a parameter makes a copy" do + run(" + struct Foo(T) + def initialize(@x) + end + + def x + @x + end + + def x=(@x) + end + end + + def foo(f) + f.x = 2 + end + + f = Foo(Int32).new(1) + + foo(f) + + f.x + ").to_i.should eq(1) + end + + it "returns struct as a copy" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + + def x=(@x) + end + end + + def foo(f) + f.x = 2 + f + end + + f = Foo.new(1) + + g = foo(f) + g.x + ").to_i.should eq(2) + end + + it "creates struct in def" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + end + + def foo + Foo.new(1) + end + + foo.x + ").to_i.should eq(1) + end + + it "declares const struct" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + end + + FOO = Foo.new(1) + + FOO.x + ").to_i.should eq(1) + end + + it "uses struct in if" do + run(" + struct Foo + def initialize(@x) + end + + def x + @x + end + end + + FOO = Foo.new(1) + + if 1 == 2 + $foo = Foo.new(1) + else + $foo = FOO + end + $foo.x + ").to_i.should eq(1) + end + + it "uses nilable struct" do + run(" + class Nil + def nil? + true + end + end + + class Value + def nil? + false + end + end + + struct Foo + end + + f = Foo.new || nil + f.nil? ? 1 : 2 + ").to_i.should eq(2) + end + + it "returns self" do + run(" + struct Foo + def initialize(@x) + end + + def foo + @x = 2 + return self + end + + def x + @x + end + end + + f = Foo.new(1) + g = f.foo + g.x + ").to_i.should eq(2) + end + + it "returns self with block" do + run(" + struct Foo + def initialize(@x) + end + + def foo + @x = 2 + yield 1 + self + end + + def x + @x + end + end + + f = Foo.new(1) + g = f.foo { } + g.x + ").to_i.should eq(2) + end +end diff --git a/spec/compiler/type_inference/struct_spec.cr b/spec/compiler/type_inference/struct_spec.cr new file mode 100644 index 0000000000000000000000000000000000000000..c9b843dd52778ceaaaa791ec95718b96091498c0 --- /dev/null +++ b/spec/compiler/type_inference/struct_spec.cr @@ -0,0 +1,85 @@ +#!/usr/bin/env bin/crystal --run +require "../../spec_helper" + +describe "Type inference: struct" do + it "types struct declaration" do + assert_type(" + struct Foo + end + Foo + ") do + str = types["Foo"] as NonGenericClassType + str.struct?.should be_true + str.metaclass + end + end + + it "types generic struct declaration" do + assert_type(" + struct Foo(T) + end + Foo(Int32) + ") do + str = types["Foo"] as GenericClassType + str.struct?.should be_true + + str_inst = str.instantiate([int32] of Type | ASTNode ) + str_inst.struct?.should be_true + str_inst.metaclass + end + end + + it "doesn't allow struct to participate in hierarchy" do + assert_type(" + struct Foo + end + + struct Bar < Foo + end + + Foo.new || Bar.new + ") do + union_of(types["Foo"], types["Bar"]) + end + end + + it "can't be nilable" do + assert_type(" + struct Foo + end + + Foo.new || nil + ") do | mod| + type = union_of(types["Foo"], mod.nil) + type.is_a?(NilableType).should be_false + type + end + end + + it "can't extend struct from class" do + assert_error " + struct Foo < Reference + end + ", "can't make struct 'Foo' inherit class 'Reference'" + end + + it "can't extend class from struct" do + assert_error " + struct Foo + end + + class Bar < Foo + end + ", "can't make class 'Bar' inherit struct 'Foo'" + end + + it "can't reopen as different type" do + assert_error " + struct Foo + end + + class Foo + end + ", "Foo is not a class, it's a struct" + end +end