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