From 209aee25acfae532451be67d44b6f9aeab651f84 Mon Sep 17 00:00:00 2001
From: Ary Borenszweig <aborenszweig@manas.com.ar>
Date: Sat, 18 Jan 2014 22:31:25 -0300
Subject: [PATCH] Make primitive types that extend from Value be structs, and
 some errors when extending a struct from a class, etc.

---
 spec/compiler/codegen/and_spec.cr             | 18 ++++-----
 spec/compiler/codegen/block_spec.cr           | 10 ++---
 spec/compiler/codegen/case_spec.cr            |  2 +-
 spec/compiler/codegen/def_spec.cr             |  4 +-
 spec/compiler/codegen/hierarchy_spec.cr       |  2 +-
 spec/compiler/codegen/is_a_spec.cr            |  6 +--
 spec/compiler/codegen/or_spec.cr              | 18 ++++-----
 spec/compiler/codegen/primitives_spec.cr      |  2 +-
 spec/compiler/codegen/responds_to_spec.cr     |  2 +-
 spec/compiler/codegen/return_spec.cr          |  6 +--
 spec/compiler/codegen/struct_spec.cr          |  4 +-
 spec/compiler/codegen/union_type_spec.cr      |  2 +-
 spec/compiler/interpreter/interpreter_spec.cr |  2 +-
 spec/compiler/parser/parser_spec.cr           |  4 +-
 spec/compiler/type_inference/block_spec.cr    |  2 +-
 spec/compiler/type_inference/class_spec.cr    |  2 +-
 spec/compiler/type_inference/const_spec.cr    |  2 +-
 spec/compiler/type_inference/def_spec.cr      |  4 +-
 spec/compiler/type_inference/if_spec.cr       |  2 +-
 spec/compiler/type_inference/is_a_spec.cr     |  4 +-
 spec/compiler/type_inference/module_spec.cr   |  2 +-
 spec/compiler/type_inference/union_spec.cr    |  6 +--
 src/bool.cr                                   |  2 +-
 src/char.cr                                   |  2 +-
 src/compiler/crystal/codegen.cr               | 40 +++++++++----------
 src/compiler/crystal/lexer.cr                 |  2 +-
 .../type_inference/type_visitor_helper.cr     | 16 +++++++-
 src/compiler/crystal/types.cr                 | 24 ++++++++++-
 src/float.cr                                  |  6 +--
 src/int.cr                                    | 18 ++++-----
 src/nil.cr                                    |  2 +-
 src/number.cr                                 |  2 +-
 src/symbol.cr                                 |  4 +-
 src/value.cr                                  |  2 +-
 34 files changed, 131 insertions(+), 95 deletions(-)

diff --git a/spec/compiler/codegen/and_spec.cr b/spec/compiler/codegen/and_spec.cr
index d1467ecd6a..9bf16460fe 100755
--- a/spec/compiler/codegen/and_spec.cr
+++ b/spec/compiler/codegen/and_spec.cr
@@ -19,11 +19,11 @@ describe "Code gen: and" do
   end
 
   it "codegens and with bool and int 1" do
-    run("class Bool; def to_i; 0; end; end; (false && 2).to_i").to_i.should eq(0)
+    run("struct Bool; def to_i; 0; end; end; (false && 2).to_i").to_i.should eq(0)
   end
 
   it "codegens and with bool and int 2" do
-    run("class Bool; def to_i; 0; end; end; (true && 2).to_i").to_i.should eq(2)
+    run("struct Bool; def to_i; 0; end; end; (true && 2).to_i").to_i.should eq(2)
   end
 
   it "codegens and with primitive type other than bool" do
@@ -85,7 +85,7 @@ describe "Code gen: and" do
 
   it "codegens and with bool union as left node 1" do
     run("
-      class Bool; def to_i; 0; end; end
+      struct Bool; def to_i; 0; end; end
       a = false
       a = 1
       (a && 2).to_i
@@ -94,7 +94,7 @@ describe "Code gen: and" do
 
   it "codegens and with bool union as left node 2" do
     run("
-      class Bool; def to_i; 0; end; end
+      struct Bool; def to_i; 0; end; end
       a = 1
       a = false
       (a && 2).to_i
@@ -103,7 +103,7 @@ describe "Code gen: and" do
 
   it "codegens and with bool union as left node 3" do
     run("
-      class Bool; def to_i; 0; end; end
+      struct Bool; def to_i; 0; end; end
       a = 1
       a = true
       (a && 2).to_i
@@ -113,7 +113,7 @@ describe "Code gen: and" do
   it "codegens and with bool union as left node 1" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = false
       a = nil
       a = 2
@@ -124,7 +124,7 @@ describe "Code gen: and" do
   it "codegens and with bool union as left node 2" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = nil
       a = 2
       a = false
@@ -135,7 +135,7 @@ describe "Code gen: and" do
   it "codegens and with bool union as left node 3" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = nil
       a = 2
       a = true
@@ -146,7 +146,7 @@ describe "Code gen: and" do
   it "codegens and with bool union as left node 4" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = 2
       a = true
       a = nil
diff --git a/spec/compiler/codegen/block_spec.cr b/spec/compiler/codegen/block_spec.cr
index 8e830df922..744da7f178 100755
--- a/spec/compiler/codegen/block_spec.cr
+++ b/spec/compiler/codegen/block_spec.cr
@@ -40,7 +40,7 @@ describe "Code gen: block" do
 
   it "pass self to yielder function" do
     run("
-      class Int
+      struct Int
         def foo
           yield self
         end
@@ -54,7 +54,7 @@ describe "Code gen: block" do
 
   it "pass self and arguments to yielder function" do
     run("
-      class Int
+      struct Int
         def foo(i)
           yield self, i
         end
@@ -550,7 +550,7 @@ describe "Code gen: block" do
       end
 
 
-      class Int
+      struct Int
         def foo
           x = Foo.new
           x = Bar.new
@@ -708,7 +708,7 @@ describe "Code gen: block" do
 
   it "allows yields with less arguments than in block" do
     run("
-      class Nil
+      struct Nil
         def to_i
           0
         end
@@ -812,7 +812,7 @@ describe "Code gen: block" do
 
   it "codegens block with union arg" do
     run("
-      class Number
+      struct Number
         def abs
           self
         end
diff --git a/spec/compiler/codegen/case_spec.cr b/spec/compiler/codegen/case_spec.cr
index de1b9fd2a9..f37c6794c5 100644
--- a/spec/compiler/codegen/case_spec.cr
+++ b/spec/compiler/codegen/case_spec.cr
@@ -55,7 +55,7 @@ describe "Code gen: case" do
   it "codegens case with class" do
     run("
       require \"nil\"
-      class Int32
+      struct Int32
         def foo
           self
         end
diff --git a/spec/compiler/codegen/def_spec.cr b/spec/compiler/codegen/def_spec.cr
index 55f66bcb48..01d9a336be 100755
--- a/spec/compiler/codegen/def_spec.cr
+++ b/spec/compiler/codegen/def_spec.cr
@@ -23,7 +23,7 @@ describe "Code gen: def" do
   end
 
   it "uses self" do
-    run("class Int; def foo; self + 1; end; end; 3.foo").to_i.should eq(4)
+    run("struct Int; def foo; self + 1; end; end; 3.foo").to_i.should eq(4)
   end
 
   it "uses var after external" do
@@ -138,7 +138,7 @@ describe "Code gen: def" do
     run("
       require \"prelude\"
 
-      class Int
+      struct Int
         def baz(x)
         end
       end
diff --git a/spec/compiler/codegen/hierarchy_spec.cr b/spec/compiler/codegen/hierarchy_spec.cr
index 0a852658dd..4142036ee5 100755
--- a/spec/compiler/codegen/hierarchy_spec.cr
+++ b/spec/compiler/codegen/hierarchy_spec.cr
@@ -243,7 +243,7 @@ describe "Code gen: hierarchy type" do
       class Bar < Foo
       end
 
-      class Nil
+      struct Nil
         def foo
           2
         end
diff --git a/spec/compiler/codegen/is_a_spec.cr b/spec/compiler/codegen/is_a_spec.cr
index baa72bd459..f0e1db89c3 100755
--- a/spec/compiler/codegen/is_a_spec.cr
+++ b/spec/compiler/codegen/is_a_spec.cr
@@ -70,7 +70,7 @@ describe "Codegen: is_a?" do
 
   it "evaluate method on filtered type nilable type nil" do
     run("
-      class Nil
+      struct Nil
         def foo
           1
         end
@@ -251,13 +251,13 @@ describe "Codegen: is_a?" do
 
   it "restricts union with union" do
     run("
-      class Char
+      struct Char
         def +(other : Int32)
           other
         end
       end
 
-      class Bool
+      struct Bool
         def foo
           2
         end
diff --git a/spec/compiler/codegen/or_spec.cr b/spec/compiler/codegen/or_spec.cr
index 93ec441565..e3d8119c17 100755
--- a/spec/compiler/codegen/or_spec.cr
+++ b/spec/compiler/codegen/or_spec.cr
@@ -19,11 +19,11 @@ describe "Code gen: or" do
   end
 
   it "codegens or with bool and int 1" do
-    run("class Bool; def to_i; 0; end; end; (false || 2).to_i").to_i.should eq(2)
+    run("struct Bool; def to_i; 0; end; end; (false || 2).to_i").to_i.should eq(2)
   end
 
   it "codegens or with bool and int 2" do
-    run("class Bool; def to_i; 0; end; end; (true || 2).to_i").to_i.should eq(0)
+    run("struct Bool; def to_i; 0; end; end; (true || 2).to_i").to_i.should eq(0)
   end
 
   it "codegens or with primitive type other than bool" do
@@ -85,7 +85,7 @@ describe "Code gen: or" do
 
   it "codegens or with bool union as left node 1" do
     run("
-      class Bool; def to_i; 0; end; end
+      struct Bool; def to_i; 0; end; end
       a = false
       a = 1
       (a || 2).to_i
@@ -94,7 +94,7 @@ describe "Code gen: or" do
 
   it "codegens or with bool union as left node 2" do
     run("
-      class Bool; def to_i; 0; end; end
+      struct Bool; def to_i; 0; end; end
       a = 1
       a = false
       (a || 2).to_i
@@ -103,7 +103,7 @@ describe "Code gen: or" do
 
   it "codegens or with bool union as left node 3" do
     run("
-      class Bool; def to_i; 0; end; end
+      struct Bool; def to_i; 0; end; end
       a = 1
       a = true
       (a || 2).to_i
@@ -113,7 +113,7 @@ describe "Code gen: or" do
   it "codegens or with bool union as left node 1" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = false
       a = nil
       a = 2
@@ -124,7 +124,7 @@ describe "Code gen: or" do
   it "codegens or with bool union as left node 2" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = nil
       a = 2
       a = false
@@ -135,7 +135,7 @@ describe "Code gen: or" do
   it "codegens or with bool union as left node 3" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = nil
       a = 2
       a = true
@@ -146,7 +146,7 @@ describe "Code gen: or" do
   it "codegens or with bool union as left node 4" do
     run("
       require \"nil\"
-      class Bool; def to_i; 1; end; end
+      struct Bool; def to_i; 1; end; end
       a = 2
       a = true
       a = nil
diff --git a/spec/compiler/codegen/primitives_spec.cr b/spec/compiler/codegen/primitives_spec.cr
index 469fb64c28..617da12390 100755
--- a/spec/compiler/codegen/primitives_spec.cr
+++ b/spec/compiler/codegen/primitives_spec.cr
@@ -49,7 +49,7 @@ describe "Code gen: primitives" do
 
   it "defined method that calls primitive (bug)" do
     run("
-      class Int64
+      struct Int64
         def foo
           to_u64
         end
diff --git a/spec/compiler/codegen/responds_to_spec.cr b/spec/compiler/codegen/responds_to_spec.cr
index df49a7c3fa..6c49004d8d 100644
--- a/spec/compiler/codegen/responds_to_spec.cr
+++ b/spec/compiler/codegen/responds_to_spec.cr
@@ -19,7 +19,7 @@ describe "Codegen: responds_to?" do
   end
 
   it "codegens is_a? with nilable gives true" do
-    run("class Nil; def foo; end; end; (1 == 1 ? nil : Reference.new).responds_to?(:foo)").to_b.should be_true
+    run("struct Nil; def foo; end; end; (1 == 1 ? nil : Reference.new).responds_to?(:foo)").to_b.should be_true
   end
 
   it "codegens is_a? with nilable gives false becuase other type 1" do
diff --git a/spec/compiler/codegen/return_spec.cr b/spec/compiler/codegen/return_spec.cr
index 75430d8037..dbaa22aa8e 100644
--- a/spec/compiler/codegen/return_spec.cr
+++ b/spec/compiler/codegen/return_spec.cr
@@ -15,11 +15,11 @@ describe "Code gen: return" do
   end
 
   it "return from function with union type" do
-    run("class Char; def to_i; 2; end; end; def foo; return 1 if 1 == 1; 'a'; end; foo.to_i").to_i.should eq(1)
+    run("struct Char; def to_i; 2; end; end; def foo; return 1 if 1 == 1; 'a'; end; foo.to_i").to_i.should eq(1)
   end
 
   it "return union" do
-    run("class Char; def to_i; 2; end; end; def foo; 1 == 2 ? return 1 : return 'a'; end; foo.to_i").to_i.should eq(2)
+    run("struct Char; def to_i; 2; end; end; def foo; 1 == 2 ? return 1 : return 'a'; end; foo.to_i").to_i.should eq(2)
   end
 
   it "return from function with nilable type" do
@@ -32,7 +32,7 @@ describe "Code gen: return" do
 
   it "returns empty from function" do
     run("
-      class Nil; def to_i; 0; end; end
+      struct Nil; def to_i; 0; end; end
       def foo(x)
         return if x == 1
         1
diff --git a/spec/compiler/codegen/struct_spec.cr b/spec/compiler/codegen/struct_spec.cr
index bfd87dabac..04b7391efc 100644
--- a/spec/compiler/codegen/struct_spec.cr
+++ b/spec/compiler/codegen/struct_spec.cr
@@ -212,13 +212,13 @@ describe "Code gen: struct" do
 
   it "uses nilable struct" do
     run("
-      class Nil
+      struct Nil
         def nil?
           true
         end
       end
 
-      class Value
+      struct Value
         def nil?
           false
         end
diff --git a/spec/compiler/codegen/union_type_spec.cr b/spec/compiler/codegen/union_type_spec.cr
index b36fa95cdd..01e518b75a 100644
--- a/spec/compiler/codegen/union_type_spec.cr
+++ b/spec/compiler/codegen/union_type_spec.cr
@@ -68,7 +68,7 @@ describe "Code gen: union type" do
     run("
       require \"prelude\"
 
-      class Char
+      struct Char
         def to_i
           ord
         end
diff --git a/spec/compiler/interpreter/interpreter_spec.cr b/spec/compiler/interpreter/interpreter_spec.cr
index b5e8f44429..28ec0e8be7 100644
--- a/spec/compiler/interpreter/interpreter_spec.cr
+++ b/spec/compiler/interpreter/interpreter_spec.cr
@@ -65,7 +65,7 @@ describe "Interpreter" do
   end
 
   it "interprets a def and a call with self" do
-    assert_interpret_primitive "class Int32; def foo; self; end; end; 1.foo", 1, &.int32
+    assert_interpret_primitive "struct Int32; def foo; self; end; end; 1.foo", 1, &.int32
   end
 
   it "interprets primitive +" do
diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr
index 4b5b75e87c..ef8dcb1e55 100755
--- a/spec/compiler/parser/parser_spec.cr
+++ b/spec/compiler/parser/parser_spec.cr
@@ -1,7 +1,7 @@
 #!/usr/bin/env crystal --run
 require "../../spec_helper"
 
-class Number
+struct Number
   def int32
     NumberLiteral.new to_s, :i32
   end
@@ -19,7 +19,7 @@ class Number
   end
 end
 
-class Bool
+struct Bool
   def bool
     BoolLiteral.new self
   end
diff --git a/spec/compiler/type_inference/block_spec.cr b/spec/compiler/type_inference/block_spec.cr
index bdf31757c1..c437d8d5ed 100755
--- a/spec/compiler/type_inference/block_spec.cr
+++ b/spec/compiler/type_inference/block_spec.cr
@@ -93,7 +93,7 @@ describe "Block inference" do
 
   it "infers type of block before call" do
     result = assert_type("
-      class Int32
+      struct Int32
         def foo
           10.5
         end
diff --git a/spec/compiler/type_inference/class_spec.cr b/spec/compiler/type_inference/class_spec.cr
index 4de1978ed8..8cc69a90fd 100755
--- a/spec/compiler/type_inference/class_spec.cr
+++ b/spec/compiler/type_inference/class_spec.cr
@@ -245,7 +245,7 @@ describe "Type inference: class" do
   end
 
   it "reports undefined method when method inside a class" do
-    assert_error "class Int; def foo; 1; end; end; foo",
+    assert_error "struct Int; def foo; 1; end; end; foo",
       "undefined local variable or method 'foo'"
   end
 
diff --git a/spec/compiler/type_inference/const_spec.cr b/spec/compiler/type_inference/const_spec.cr
index 6dfc4740b5..1c06102542 100755
--- a/spec/compiler/type_inference/const_spec.cr
+++ b/spec/compiler/type_inference/const_spec.cr
@@ -104,7 +104,7 @@ describe "Type inference: const" do
 
   it "finds const from restriction" do
     assert_type("
-      class Int32
+      struct Int32
         FOO = 'a'
       end
 
diff --git a/spec/compiler/type_inference/def_spec.cr b/spec/compiler/type_inference/def_spec.cr
index 2b80ec4188..6789b2d221 100755
--- a/spec/compiler/type_inference/def_spec.cr
+++ b/spec/compiler/type_inference/def_spec.cr
@@ -65,7 +65,7 @@ describe "Type inference: def" do
   end
 
   it "assigns def owner" do
-    input = parse "class Int; def foo; 2.5; end; end; 1.foo"
+    input = parse "struct Int; def foo; 2.5; end; end; 1.foo"
     result = infer_type input
     mod, input = result.program, result.node as Expressions
     (input.last as Call).target_def.owner.should eq(mod.int32)
@@ -116,7 +116,7 @@ describe "Type inference: def" do
   end
 
   it "defines class method with self" do
-    assert_type("class Int; def self.foo; 2.5; end; end; Int.foo") { float64 }
+    assert_type("struct Int; def self.foo; 2.5; end; end; Int.foo") { float64 }
   end
 
   it "calls with default argument" do
diff --git a/spec/compiler/type_inference/if_spec.cr b/spec/compiler/type_inference/if_spec.cr
index cd3eaedf89..0e1ee77a49 100755
--- a/spec/compiler/type_inference/if_spec.cr
+++ b/spec/compiler/type_inference/if_spec.cr
@@ -16,7 +16,7 @@ describe "Type inference: if" do
 
   it "types and if with and and assignment" do
     assert_type("
-      class Number
+      struct Number
         def abs
           self
         end
diff --git a/spec/compiler/type_inference/is_a_spec.cr b/spec/compiler/type_inference/is_a_spec.cr
index cb3eeffb20..a74c2e2d7d 100755
--- a/spec/compiler/type_inference/is_a_spec.cr
+++ b/spec/compiler/type_inference/is_a_spec.cr
@@ -135,13 +135,13 @@ describe "Type inference: is_a?" do
 
   it "checks union with union" do
     assert_type("
-      class Char
+      struct Char
         def +(other : Int32)
           self
         end
       end
 
-      class Bool
+      struct Bool
         def foo
           2
         end
diff --git a/spec/compiler/type_inference/module_spec.cr b/spec/compiler/type_inference/module_spec.cr
index ff3973f0c4..1010a93045 100755
--- a/spec/compiler/type_inference/module_spec.cr
+++ b/spec/compiler/type_inference/module_spec.cr
@@ -205,7 +205,7 @@ describe "Type inference: module" do
     assert_type("
       require \"prelude\"
 
-      class Int32
+      struct Int32
         include Enumerable(Int32)
 
         def each
diff --git a/spec/compiler/type_inference/union_spec.cr b/spec/compiler/type_inference/union_spec.cr
index 3098473891..89eb32e69f 100755
--- a/spec/compiler/type_inference/union_spec.cr
+++ b/spec/compiler/type_inference/union_spec.cr
@@ -3,15 +3,15 @@ require "../../spec_helper"
 
 describe "Type inference: union" do
   it "types union when obj is union" do
-    assert_type("class Char; def +(other); self; end; end; a = 1 || 'a'; a + 1") { union_of(int32, char) }
+    assert_type("struct Char; def +(other); self; end; end; a = 1 || 'a'; a + 1") { union_of(int32, char) }
   end
 
   it "types union when arg is union" do
-    assert_type("class Int; def +(x : Char); x; end; end; a = 1 || 'a'; 1 + a") { union_of(int32, char) }
+    assert_type("struct Int; def +(x : Char); x; end; end; a = 1 || 'a'; 1 + a") { union_of(int32, char) }
   end
 
   it "types union when both obj and arg are union" do
-    assert_type("class Char; def +(other); self; end; end; class Int; def +(x : Char); x; end; end; a = 1 || 'a'; a + a") { union_of(int32, char) }
+    assert_type("struct Char; def +(other); self; end; end; struct Int; def +(x : Char); x; end; end; a = 1 || 'a'; a + a") { union_of(int32, char) }
   end
 
   it "types union of classes" do
diff --git a/src/bool.cr b/src/bool.cr
index 2061f4d1f2..1e4d45f727 100644
--- a/src/bool.cr
+++ b/src/bool.cr
@@ -1,4 +1,4 @@
-class Bool
+struct Bool
   def !@
     self ? false : true
   end
diff --git a/src/char.cr b/src/char.cr
index 01f4028b03..fea93a38aa 100644
--- a/src/char.cr
+++ b/src/char.cr
@@ -1,4 +1,4 @@
-class Char
+struct Char
   def ==(other : Int)
     ord == other
   end
diff --git a/src/compiler/crystal/codegen.cr b/src/compiler/crystal/codegen.cr
index d57b295e6b..6569c58eb1 100644
--- a/src/compiler/crystal/codegen.cr
+++ b/src/compiler/crystal/codegen.cr
@@ -445,7 +445,7 @@ module Crystal
     def codegen_primitive_pointer_get(node, target_def, call_args)
       type = @type as PointerInstanceType
       @last = call_args[0]
-      @last = @builder.load(@last) unless type.var.type.union? || type.var.type.value_like?
+      @last = @builder.load(@last) unless type.var.type.union? || type.var.type.struct_like?
       @last
     end
 
@@ -494,7 +494,7 @@ module Crystal
       @last = call_args[1]
 
       value = @last
-      value = @builder.load value if node.type.value_like?
+      value = @builder.load value if node.type.struct_like?
 
       ptr = struct_field_ptr(type, name, call_args[0])
       @builder.store value, ptr
@@ -508,7 +508,7 @@ module Crystal
       name = target_def.name
 
       @last = struct_field_ptr(type, name, call_args[0])
-      @last = @builder.load(@last) unless node.type.value_like?
+      @last = @builder.load(@last) unless node.type.struct_like?
       @last
     end
 
@@ -534,7 +534,7 @@ module Crystal
       name = target_def.name[0 .. -2]
 
       @last = call_args[1]
-      @last = @builder.load @last if node.type.value_like?
+      @last = @builder.load @last if node.type.struct_like?
 
       ptr = union_field_ptr(node, call_args[0])
       @builder.store @last, ptr
@@ -547,7 +547,7 @@ module Crystal
       name = target_def.name
 
       @last = union_field_ptr(node, call_args[0])
-      @last = @builder.load(@last) unless node.type.value_like?
+      @last = @builder.load(@last) unless node.type.struct_like?
       @last
     end
 
@@ -807,7 +807,7 @@ module Crystal
           ret @last
         end
       else
-        @last = @builder.load @last if return_type.value_like?
+        @last = @builder.load @last if return_type.struct_like?
         ret @last
       end
     end
@@ -1075,7 +1075,7 @@ module Crystal
         if @node.type.nilable? && LLVM.type_kind_of(LLVM.type_of value) == LibLLVM::TypeKind::Integer
           @phi_table.add block, @codegen.builder.int2ptr(value, @codegen.llvm_type(node.type))
         else
-          value = @codegen.builder.load value if type.value_like?
+          value = @codegen.builder.load value if type.struct_like?
           @phi_table.add block, value
         end
         @count += 1
@@ -1212,7 +1212,7 @@ module Crystal
 
     def codegen_assign(pointer, target_type, value_type, value, load_struct_and_union = true)
       if target_type == value_type
-        value = @builder.load value if target_type.union? || (load_struct_and_union && target_type.value_like?)
+        value = @builder.load value if target_type.union? || (load_struct_and_union && target_type.struct_like?)
         @builder.store value, pointer
       elsif target_type.is_a?(HierarchyTypeMetaclass) && value_type.is_a?(Metaclass)
         @builder.store value, pointer
@@ -1281,7 +1281,7 @@ module Crystal
 
         unless type == @mod.void
           casted_value_ptr = cast_to_pointer value_ptr, type
-          value = @builder.load value if type.value_like?
+          value = @builder.load value if type.struct_like?
           @builder.store value, casted_value_ptr
         end
       end
@@ -1308,7 +1308,7 @@ module Crystal
       if var_type == @mod.void
         # Nothing to do
       elsif var_type == node.type
-        @last = @builder.load(@last) unless var.treated_as_pointer || var_type.union? || var_type.value_like?
+        @last = @builder.load(@last) unless var.treated_as_pointer || var_type.union? || var_type.struct_like?
       elsif var_type.is_a?(NilableType)
         if node.type.nil_type?
           @last = null_pointer?(@last)
@@ -1355,7 +1355,7 @@ module Crystal
       else
         value_ptr = union_value(@last)
         @last = cast_to_pointer value_ptr, to_type
-        @last = @builder.load(@last) unless to_type.value_like?
+        @last = @builder.load(@last) unless to_type.struct_like?
       end
     end
 
@@ -1389,7 +1389,7 @@ module Crystal
 
     def read_global(name, type)
       @last = get_global name, type
-      @last = @builder.load @last unless type.union? || type.value_like?
+      @last = @builder.load @last unless type.union? || type.struct_like?
       @last
     end
 
@@ -1399,7 +1399,7 @@ module Crystal
       ivar = type.lookup_instance_var(node.name)
       @last = instance_var_ptr type, node.name, llvm_self_ptr
 
-      if ivar.type.union? || ivar.type.value_like?
+      if ivar.type.union? || ivar.type.struct_like?
         unless node.type == ivar.type
           if node.type.union?
             @last = cast_to_pointer @last, node.type
@@ -1568,7 +1568,7 @@ module Crystal
                 LLVM.set_initializer global, @last
                 LLVM.set_global_constant global, true
               else
-                if const.value.type.value_like?
+                if const.value.type.struct_like?
                   @last = @builder.load @last
                   LLVM.set_initializer global, LLVM.undef(llvm_type(const.value.type))
                 else
@@ -1594,7 +1594,7 @@ module Crystal
         end
 
         @last = global
-        @last = @builder.load @last unless const.value.type.value_like?
+        @last = @builder.load @last unless const.value.type.struct_like?
       elsif replacement = node.syntax_replacement
         replacement.accept self
       else
@@ -1770,7 +1770,7 @@ module Crystal
       ptr = visit_indirect(node)
       ptr = cast_to_pointer ptr, node.type
 
-      if node.type.value_like?
+      if node.type.struct_like?
         @last = ptr
       else
         @last = @builder.load ptr
@@ -1785,7 +1785,7 @@ module Crystal
 
       node.value.accept self
 
-      if node.value.type.value_like?
+      if node.value.type.struct_like?
         @last = @builder.load @last
       end
 
@@ -1924,7 +1924,7 @@ module Crystal
         return_block = @return_block = new_block "return"
         return_block_table = @return_block_table = LLVM::PhiTable.new
         return_type = @return_type = node.type
-        if return_type.union? || return_type.value_like?
+        if return_type.union? || return_type.struct_like?
           @return_union = alloca(llvm_type(node.type), "return")
         else
           @return_union = nil
@@ -2136,7 +2136,7 @@ module Crystal
         @builder.unreachable
       end
 
-      if type.union? || type.value_like?
+      if type.union? || type.struct_like?
         union = alloca llvm_type(type)
         @builder.store @last, union
         @last = union
@@ -2322,7 +2322,7 @@ module Crystal
 
         if return_type == @mod.void
           ret
-        elsif return_type.value_like?
+        elsif return_type.struct_like?
           ret(@builder.load(@last))
         else
           ret(@last)
diff --git a/src/compiler/crystal/lexer.cr b/src/compiler/crystal/lexer.cr
index 53ecac276d..a94bb29d62 100644
--- a/src/compiler/crystal/lexer.cr
+++ b/src/compiler/crystal/lexer.cr
@@ -2,7 +2,7 @@ require "token"
 require "exception"
 require "char_reader"
 
-class Char
+struct Char
   def ident_start?
     alpha? || self == '_'
   end
diff --git a/src/compiler/crystal/type_inference/type_visitor_helper.cr b/src/compiler/crystal/type_inference/type_visitor_helper.cr
index 9b3ff0bcb9..d2318e2782 100644
--- a/src/compiler/crystal/type_inference/type_visitor_helper.cr
+++ b/src/compiler/crystal/type_inference/type_visitor_helper.cr
@@ -20,8 +20,22 @@ module Crystal
       end
 
       type = scope.types[name]?
+
+      if !type && superclass
+        if (!!node.struct) != (!!superclass.struct?)
+          node.raise "can't make #{node.struct ? "struct" : "class"} '#{node.name}' inherit #{superclass.type_desc} '#{superclass.to_s}'"
+        end
+      end
+
       if type
-        node.raise "#{name} is not a class, it's a #{type.type_desc}" unless type.is_a?(ClassType)
+        unless type.is_a?(ClassType)
+          node.raise "#{name} is not a #{node.struct ? "struct" : "class"}, it's a #{type.type_desc}"
+        end
+
+        if (!!node.struct) != (!!type.struct?)
+          node.raise "#{name} is not a #{node.struct ? "struct" : "class"}, it's a #{type.type_desc}"
+        end
+
         if node.superclass && type.superclass != superclass
           node.raise "superclass mismatch for class #{type} (#{superclass} for #{type.superclass})"
         end
diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr
index 994640d82b..22ca98ec75 100644
--- a/src/compiler/crystal/types.cr
+++ b/src/compiler/crystal/types.cr
@@ -97,7 +97,7 @@ module Crystal
       false
     end
 
-    def value_like?
+    def struct_like?
       c_struct? || c_union? || struct?
     end
 
@@ -924,6 +924,7 @@ module Crystal
 
     def initialize(program, container, name, superclass, @llvm_type, @llvm_size)
       super(program, container, name, superclass)
+      self.struct = true
     end
 
     def llvm_name
@@ -938,6 +939,14 @@ module Crystal
       true
     end
 
+    def struct_like?
+      false
+    end
+
+    def passed_by_val?
+      false
+    end
+
     def allocated
       true
     end
@@ -1020,9 +1029,22 @@ module Crystal
   end
 
   class ValueType < NonGenericClassType
+    def initialize(program, container, name, superclass, add_subclass = true)
+      super
+      self.struct = true
+    end
+
     def value?
       true
     end
+
+    def struct_like?
+      false
+    end
+
+    def passed_by_val?
+      false
+    end
   end
 
   module GenericType
diff --git a/src/float.cr b/src/float.cr
index 26fd473885..eb2a6a045b 100644
--- a/src/float.cr
+++ b/src/float.cr
@@ -1,4 +1,4 @@
-class Float
+struct Float
   def +@
     self
   end
@@ -16,7 +16,7 @@ class Float
   end
 end
 
-class Float32
+struct Float32
   MIN = -INFINITY
   MAX =  INFINITY
 
@@ -33,7 +33,7 @@ class Float32
   end
 end
 
-class Float64
+struct Float64
   MIN = -INFINITY
   MAX =  INFINITY
 
diff --git a/src/int.cr b/src/int.cr
index bd638297db..a205dbe5ee 100644
--- a/src/int.cr
+++ b/src/int.cr
@@ -1,4 +1,4 @@
-class Int
+struct Int
   def ==(other : Char)
     self == other.ord
   end
@@ -91,7 +91,7 @@ class Int
   end
 end
 
-class Int8
+struct Int8
   MIN = -128_i8
   MAX =  127_i8
 
@@ -106,7 +106,7 @@ class Int8
   end
 end
 
-class Int16
+struct Int16
   MIN = -32768_i16
   MAX =  32767_i16
 
@@ -121,7 +121,7 @@ class Int16
   end
 end
 
-class Int32
+struct Int32
   MIN = -2147483648_i32
   MAX =  2147483647_i32
 
@@ -136,7 +136,7 @@ class Int32
   end
 end
 
-class Int64
+struct Int64
   MIN = -9223372036854775808_i64
   MAX =  9223372036854775807_i64
 
@@ -151,7 +151,7 @@ class Int64
   end
 end
 
-class UInt8
+struct UInt8
   MIN = 0_u8
   MAX = 255_u8
 
@@ -162,7 +162,7 @@ class UInt8
   end
 end
 
-class UInt16
+struct UInt16
   MIN = 0_u16
   MAX = 65535_u16
 
@@ -173,7 +173,7 @@ class UInt16
   end
 end
 
-class UInt32
+struct UInt32
   MIN = 0_u32
   MAX = 4294967295_u32
 
@@ -184,7 +184,7 @@ class UInt32
   end
 end
 
-class UInt64
+struct UInt64
   MIN = 0_u64
   MAX = 18446744073709551615_u64
 
diff --git a/src/nil.cr b/src/nil.cr
index 9b9755d504..35a37d13d6 100644
--- a/src/nil.cr
+++ b/src/nil.cr
@@ -1,4 +1,4 @@
-class Nil
+struct Nil
   def object_id
     0_u64
   end
diff --git a/src/number.cr b/src/number.cr
index af55d01496..31e301dd55 100644
--- a/src/number.cr
+++ b/src/number.cr
@@ -1,4 +1,4 @@
-class Number
+struct Number
   def ==(other)
     false
   end
diff --git a/src/symbol.cr b/src/symbol.cr
index 6100a7ba7a..8bb8eedb0f 100644
--- a/src/symbol.cr
+++ b/src/symbol.cr
@@ -1,4 +1,4 @@
-class Symbol
+struct Symbol
   def ==(other)
     false
   end
@@ -6,4 +6,4 @@ class Symbol
   def inspect
     ":#{to_s}"
   end
-end
\ No newline at end of file
+end
diff --git a/src/value.cr b/src/value.cr
index 5d93ece072..3142681517 100644
--- a/src/value.cr
+++ b/src/value.cr
@@ -1,4 +1,4 @@
-class Value
+struct Value
   def !@
     false
   end
-- 
GitLab