diff --git a/lib/crystal/codegen.rb b/lib/crystal/codegen.rb
index 1fc202d99072bdcde6c62ffd83520ef28208d979..95fb1f8d131d4502b3503d8edc9311b3c8cc7136 100644
--- a/lib/crystal/codegen.rb
+++ b/lib/crystal/codegen.rb
@@ -256,7 +256,7 @@ module Crystal
     end
 
     def visit_fun_call(node)
-      @last = @builder.call @fun.params[0], *@fun.params.to_a[1 .. -1]
+      @last = @builder.call @call_args[0], *@call_args[1 .. -1]
     end
 
     def visit_external_var(node)
@@ -609,11 +609,11 @@ module Crystal
 
     def visit_pointer_malloc(node)
       llvm_type = llvm_embedded_type(node.type.var.type)
-      @last = @builder.array_malloc(llvm_type, @vars['size'][:ptr])
+      @last = @builder.array_malloc(llvm_type, @call_args[1])
     end
 
     def visit_pointer_new(node)
-      @last = @builder.int2ptr(@vars["address"][:ptr], llvm_type(node.type))
+      @last = @builder.int2ptr(@call_args[1], llvm_type(node.type))
     end
 
     def visit_pointer_null(node)
@@ -621,8 +621,8 @@ module Crystal
     end
 
     def visit_pointer_realloc(node)
-      casted_ptr = cast_to_void_pointer(llvm_self)
-      size = @vars['size'][:ptr]
+      casted_ptr = cast_to_void_pointer(@call_args[0])
+      size = @call_args[1]
       size = @builder.mul size, LLVM::Int64.from_i(@type.var.type.llvm_size)
       reallocated_ptr = realloc casted_ptr, size
       @last = cast_to_pointer reallocated_ptr, @type.var.type
@@ -630,46 +630,46 @@ module Crystal
 
     def visit_pointer_get_value(node)
       if @type.var.type.union? || @type.var.type.c_struct? || @type.var.type.c_union?
-        @last = llvm_self
+        @last = @call_args[0]
       else
-        @last = @builder.load llvm_self
+        @last = @builder.load @call_args[0]
       end
     end
 
     def visit_pointer_set_value(node)
-      value = @fun.params[1]
+      value = @call_args[1]
 
       if node.type.c_struct? || node.type.c_union?
         loaded_value = @builder.load value
-        @builder.store loaded_value, @fun.params[0]
+        @builder.store loaded_value, @call_args[0]
         @last = value
         return
       end
 
       if node.type.union?
         value = @builder.alloca llvm_type(node.type)
-        target = @fun.params[1]
+        target = @call_args[1]
         target = @builder.load(target) if node.type.passed_by_val?
         @builder.store target, value
       end
 
-      codegen_assign llvm_self, @type.var.type, node.type, value
+      codegen_assign @call_args[0], @type.var.type, node.type, value
       @last = value
     end
 
     def visit_pointer_add(node)
-      @last = gep(llvm_self, @fun.params[1])
+      @last = gep(@call_args[0], @call_args[1])
     end
 
     def visit_pointer_diff(node)
-      p0 = @builder.ptr2int(@fun.params[0], LLVM::UInt64)
-      p1 = @builder.ptr2int(@fun.params[1], LLVM::UInt64)
+      p0 = @builder.ptr2int(@call_args[0], LLVM::UInt64)
+      p1 = @builder.ptr2int(@call_args[1], LLVM::UInt64)
       sub = @builder.sub p0, p1
-      @last = @builder.exact_sdiv sub, @builder.ptr2int(gep(llvm_self.type.null, LLVM::Int(1)), LLVM::UInt64)
+      @last = @builder.exact_sdiv sub, @builder.ptr2int(gep(@call_args[0].type.null, LLVM::Int(1)), LLVM::UInt64)
     end
 
     def visit_pointer_cast(node)
-      @last = cast_to @fun.params[0], node.type
+      @last = cast_to @call_args[0], node.type
     end
 
     def visit_simple_or(node)
@@ -849,7 +849,7 @@ module Crystal
     end
 
     def visit_primitive_body(node)
-      @last = node.block.call(@builder, @fun, @llvm_mod, @type)
+      @last = node.block.call(@builder, @call_args, @llvm_mod, @type)
     end
 
     def visit_allocate(node)
@@ -875,16 +875,16 @@ module Crystal
       var = @type.vars[node.name.to_s]
       index = @type.index_of_var(node.name)
       if var.type.c_struct? || var.type.c_union?
-        @last = gep llvm_self, 0, index
+        @last = gep @call_args[0], 0, index
       else
-        struct = @builder.load llvm_self
+        struct = @builder.load @call_args[0]
         @last = @builder.extract_value struct, index, node.name
       end
     end
 
     def visit_struct_set(node)
-      ptr = gep llvm_self, 0, @type.index_of_var(node.name)
-      @last = @vars['value'][:ptr]
+      ptr = gep @call_args[0], 0, @type.index_of_var(node.name)
+      @last = @call_args[1]
       value = @last
       value = @builder.load @last if node.type.c_struct? || node.type.c_union?
       @builder.store value, ptr
@@ -897,8 +897,8 @@ module Crystal
 
     def visit_lib_set(node)
       var = declare_lib_var node
-      @builder.store @fun.params[0], var
-      @last = @fun.params[0]
+      @builder.store @call_args[0], var
+      @last = @call_args[0]
     end
 
     def declare_lib_var(node)
@@ -919,7 +919,7 @@ module Crystal
 
     def visit_union_get(node)
       var = @type.vars[node.name.to_s]
-      ptr = gep llvm_self, 0, 0
+      ptr = gep @call_args[0], 0, 0
       if var.type.c_struct? || var.type.c_union?
         @last = @builder.bit_cast(ptr, LLVM::Pointer(llvm_struct_type(var.type)))
       else
@@ -930,9 +930,9 @@ module Crystal
 
     def visit_union_set(node)
       var = @type.vars[node.name.to_s]
-      ptr = gep llvm_self, 0, 0
+      ptr = gep @call_args[0], 0, 0
       casted_value = cast_to_pointer ptr, var.type
-      @last = @vars['value'][:ptr]
+      @last = @call_args[1]
       @builder.store @last, casted_value
     end
 
@@ -1312,6 +1312,19 @@ module Crystal
 
     def codegen_call(node, self_type, call_args)
       target_def = node.target_def
+
+      if target_def.body.is_a?(Primitive)
+        old_type = @type
+        @type = self_type
+        @call_args = call_args
+
+        target_def.body.accept self
+
+        @type = old_type
+
+        return
+      end
+
       fun = target_def_fun(target_def, self_type)
 
       # Check for struct out arguments: alloca before the call, then copy to the pointer value after the call.
diff --git a/lib/crystal/primitives.rb b/lib/crystal/primitives.rb
index e67ce3b3f078b776143e37eecd87364bececc382..08cee9905602365e276466c1964069008b8b6ccf 100644
--- a/lib/crystal/primitives.rb
+++ b/lib/crystal/primitives.rb
@@ -17,7 +17,7 @@ module Crystal
       define_number_operations
       define_math_primitives
 
-      singleton(self, 'debugger', {}, void) do |b, f, llvm_mod|
+      singleton(self, 'debugger', {}, void) do |b, args, llvm_mod|
         int3_type = LLVM::Type.function([], LLVM.Void)
         b.call LLVM::C.const_inline_asm int3_type, "int3", "", 1, 0
       end
@@ -29,29 +29,29 @@ module Crystal
     end
 
     def define_reference_primitives
-      a_def = no_args_primitive(reference, 'object_id', uint64) do |b, f, llvm_mod, self_type|
+      a_def = no_args_primitive(reference, 'object_id', uint64) do |b, args, llvm_mod, self_type|
         if self_type.hierarchy?
-          obj = b.load(b.gep(f.params[0], [LLVM::Int(0), LLVM::Int(1)]))
+          obj = b.load(b.gep(args[0], [LLVM::Int(0), LLVM::Int(1)]))
           b.ptr2int(obj, LLVM::UInt64)
         else
-          b.ptr2int(f.params[0], LLVM::UInt64)
+          b.ptr2int(args[0], LLVM::UInt64)
         end
       end
 
-      a_def = no_args_primitive(reference, 'crystal_type_id', int32) do |b, f, llvm_mod, self_type|
+      a_def = no_args_primitive(reference, 'crystal_type_id', int32) do |b, args, llvm_mod, self_type|
         if self_type.hierarchy?
-          id = b.load(b.gep(f.params[0], [LLVM::Int(0), LLVM::Int(0)]))
+          id = b.load(b.gep(args[0], [LLVM::Int(0), LLVM::Int(0)]))
           LLVM::Int(id)
         else
           LLVM::Int(self_type.type_id)
         end
       end
 
-      a_def = no_args_primitive(reference, 'to_cstr', char_pointer) do |b, f, llvm_mod, self_type|
+      a_def = no_args_primitive(reference, 'to_cstr', char_pointer) do |b, args, llvm_mod, self_type|
         if self_type.hierarchy?
-          obj = b.load(b.gep(f.params[0], [LLVM::Int(0), LLVM::Int(1)]))
+          obj = b.load(b.gep(args[0], [LLVM::Int(0), LLVM::Int(1)]))
         else
-          obj = f.params[0]
+          obj = args[0]
         end
         buffer = b.array_malloc(LLVM::Int8, LLVM::Int(self_type.to_s.length + 23))
         b.call sprintf(llvm_mod), buffer, b.global_string_pointer("#<#{self_type.to_s}:0x%016lx>"), obj
@@ -61,30 +61,30 @@ module Crystal
 
     def define_value_primitives
       [value, bool, char, int32, int64, float32, float64, symbol].each do |klass|
-        no_args_primitive(klass, 'nil?', bool) { |b, f| LLVM::Int1.from_i(0) }
-        no_args_primitive(klass, 'crystal_type_id', int32) { |b, f, llvm_mod, self_type| LLVM::Int(self_type.type_id) }
+        no_args_primitive(klass, 'nil?', bool) { |b, args| LLVM::Int1.from_i(0) }
+        no_args_primitive(klass, 'crystal_type_id', int32) { |b, args, llvm_mod, self_type| LLVM::Int(self_type.type_id) }
       end
     end
 
     def define_bool_primitives
-      singleton(bool, :==, {'other' => bool}, bool) { |b, f| b.icmp(:eq, f.params[0], f.params[1]) }
-      singleton(bool, :'!@', {}, bool) { |b, f| b.not(f.params[0]) }
+      singleton(bool, :==, {'other' => bool}, bool) { |b, args| b.icmp(:eq, args[0], args[1]) }
+      singleton(bool, :'!@', {}, bool) { |b, args| b.not(args[0]) }
     end
 
     def define_char_primitives
-      no_args_primitive(char, 'ord', int32) { |b, f| b.zext(f.params[0], int32.llvm_type) }
-      singleton(char, :==, {'other' => char}, bool) { |b, f| b.icmp(:eq, f.params[0], f.params[1]) }
-      singleton(char, :'!=', {'other' => char}, bool) { |b, f| b.icmp(:ne, f.params[0], f.params[1]) }
-      singleton(char, :<, {'other' => char}, bool) { |b, f| b.icmp(:ult, f.params[0], f.params[1]) }
-      singleton(char, :<=, {'other' => char}, bool) { |b, f| b.icmp(:ule, f.params[0], f.params[1]) }
-      singleton(char, :>, {'other' => char}, bool) { |b, f| b.icmp(:ugt, f.params[0], f.params[1]) }
-      singleton(char, :>=, {'other' => char}, bool) { |b, f| b.icmp(:uge, f.params[0], f.params[1]) }
+      no_args_primitive(char, 'ord', int32) { |b, args| b.zext(args[0], int32.llvm_type) }
+      singleton(char, :==, {'other' => char}, bool) { |b, args| b.icmp(:eq, args[0], args[1]) }
+      singleton(char, :'!=', {'other' => char}, bool) { |b, args| b.icmp(:ne, args[0], args[1]) }
+      singleton(char, :<, {'other' => char}, bool) { |b, args| b.icmp(:ult, args[0], args[1]) }
+      singleton(char, :<=, {'other' => char}, bool) { |b, args| b.icmp(:ule, args[0], args[1]) }
+      singleton(char, :>, {'other' => char}, bool) { |b, args| b.icmp(:ugt, args[0], args[1]) }
+      singleton(char, :>=, {'other' => char}, bool) { |b, args| b.icmp(:uge, args[0], args[1]) }
     end
 
     def define_math_primitives
       math = types['Math'].metaclass
-      singleton(math, 'sqrt', {'other' => float32}, float32) { |b, f, llvm_mod| b.call(sqrtf(llvm_mod), f.params[1]) }
-      singleton(math, 'sqrt', {'other' => float64}, float64) { |b, f, llvm_mod| b.call(sqrt(llvm_mod), f.params[1]) }
+      singleton(math, 'sqrt', {'other' => float32}, float32) { |b, args, llvm_mod| b.call(sqrtf(llvm_mod), args[1]) }
+      singleton(math, 'sqrt', {'other' => float64}, float64) { |b, args, llvm_mod| b.call(sqrt(llvm_mod), args[1]) }
     end
 
     INT_CALC_OP_MAP = { :+ => :add, :- => :sub, :* => :mul, :/ => :sdiv, :% => :srem, :<< => :shl, :>> => :ashr, :| => :or, :& => :and, :"^" => :xor }
@@ -177,15 +177,15 @@ module Crystal
         [:+, :-, :*, :/].each do |op|
           ret_type = greatest_type(type1, type2)
           if ret_type.equal?(float32) || ret_type.equal?(float64)
-            singleton(type1, op, {'other' => type2}, ret_type) do |b, f|
-              arg1 = adjust_calc_type(b, ret_type, type1, f.params[0])
-              arg2 = adjust_calc_type(b, ret_type, type2, f.params[1])
+            singleton(type1, op, {'other' => type2}, ret_type) do |b, args|
+              arg1 = adjust_calc_type(b, ret_type, type1, args[0])
+              arg2 = adjust_calc_type(b, ret_type, type2, args[1])
               build_calc_op(b, ret_type, op, arg1, arg2)
             end
           else
-            singleton(type1, op, {'other' => type2}, type1) do |b, f|
-              arg1 = adjust_calc_type(b, ret_type, type1, f.params[0])
-              arg2 = adjust_calc_type(b, ret_type, type2, f.params[1])
+            singleton(type1, op, {'other' => type2}, type1) do |b, args|
+              arg1 = adjust_calc_type(b, ret_type, type1, args[0])
+              arg2 = adjust_calc_type(b, ret_type, type2, args[1])
               ret = build_calc_op(b, ret_type, op, arg1, arg2)
               cast_back(b, type1, ret_type, ret)
             end
@@ -194,48 +194,48 @@ module Crystal
 
         [:==, :>, :>=, :<, :<=, :!=].each do |op|
           comp_type = greatest_type(type1, type2)
-          singleton(type1, op, {'other' => type2}, bool) do |b, f|
-            arg1 = adjust_calc_type(b, comp_type, type1, f.params[0])
-            arg2 = adjust_calc_type(b, comp_type, type2, f.params[1])
+          singleton(type1, op, {'other' => type2}, bool) do |b, args|
+            arg1 = adjust_calc_type(b, comp_type, type1, args[0])
+            arg2 = adjust_calc_type(b, comp_type, type2, args[1])
             build_comp_op(b, comp_type, op, arg1, arg2)
           end
         end
 
-        no_args_primitive(type1, "to_#{type2.suffix}", type2) do |b, f|
-          adjust_calc_type(b, type2, type1, f.params[0])
+        no_args_primitive(type1, "to_#{type2.suffix}", type2) do |b, args|
+          adjust_calc_type(b, type2, type1, args[0])
         end
       end
 
       [uint8, uint16, uint32, uint64, int8, int16, int32, int64, float32, float64].each do |type|
-        no_args_primitive(type, "to_i", int32) do |b, f|
-          adjust_calc_type(b, int32, type, f.params[0])
+        no_args_primitive(type, "to_i", int32) do |b, args|
+          adjust_calc_type(b, int32, type, args[0])
         end
 
-        no_args_primitive(type, "to_f", float64) do |b, f|
-          adjust_calc_type(b, float64, type, f.params[0])
+        no_args_primitive(type, "to_f", float64) do |b, args|
+          adjust_calc_type(b, float64, type, args[0])
         end
 
-        no_args_primitive(type, "to_f64", float64) do |b, f|
-          adjust_calc_type(b, float64, type, f.params[0])
+        no_args_primitive(type, "to_f64", float64) do |b, args|
+          adjust_calc_type(b, float64, type, args[0])
         end
 
-        no_args_primitive(type, "to_f32", float32) do |b, f|
-          adjust_calc_type(b, float32, type, f.params[0])
+        no_args_primitive(type, "to_f32", float32) do |b, args|
+          adjust_calc_type(b, float32, type, args[0])
         end
       end
 
       [uint8, uint16, uint32, uint64, int8, int16, int32, int64].each do |type|
-        no_args_primitive(type, "chr", char) do |b, f|
-          adjust_calc_type(b, int8, type, f.params[0])
+        no_args_primitive(type, "chr", char) do |b, args|
+          adjust_calc_type(b, int8, type, args[0])
         end
       end
 
       [uint8, uint16, uint32, uint64, int8, int16, int32, int64].repeated_permutation(2) do |type1, type2|
         [:%, :<<, :>>, :|, :&, :"^"].each do |op|
           ret_type = greatest_type(type1, type2)
-          singleton(type1, op, {'other' => type2}, type1) do |b, f|
-            arg1 = adjust_calc_type(b, ret_type, type1, f.params[0])
-            arg2 = adjust_calc_type(b, ret_type, type2, f.params[1])
+          singleton(type1, op, {'other' => type2}, type1) do |b, args|
+            arg1 = adjust_calc_type(b, ret_type, type1, args[0])
+            arg2 = adjust_calc_type(b, ret_type, type2, args[1])
             ret = build_calc_op(b, ret_type, op, arg1, arg2)
             cast_back(b, type1, ret_type, ret)
           end
@@ -244,18 +244,18 @@ module Crystal
     end
 
     def define_float32_primitives
-      singleton(float32, :**, {'other' => float32}, float32) { |b, f, llvm_mod| b.call(powf(llvm_mod), f.params[0], f.params[1]) }
+      singleton(float32, :**, {'other' => float32}, float32) { |b, args, llvm_mod| b.call(powf(llvm_mod), args[0], args[1]) }
     end
 
     def define_float64_primitives
-      singleton(float64, :**, {'other' => float64}, float64) { |b, f, llvm_mod| b.call(pow(llvm_mod), f.params[0], f.params[1]) }
+      singleton(float64, :**, {'other' => float64}, float64) { |b, args, llvm_mod| b.call(pow(llvm_mod), args[0], args[1]) }
     end
 
     def define_symbol_primitives
-      singleton(symbol, :==, {'other' => symbol}, bool) { |b, f| b.icmp(:eq, f.params[0], f.params[1]) }
-      singleton(symbol, 'hash', {}, int32) { |b, f| f.params[0] }
-      no_args_primitive(symbol, 'to_s', string) do |b, f, llvm_mod|
-        b.load(b.gep llvm_mod.globals['symbol_table'], [LLVM::Int(0), f.params[0]])
+      singleton(symbol, :==, {'other' => symbol}, bool) { |b, args| b.icmp(:eq, args[0], args[1]) }
+      singleton(symbol, 'hash', {}, int32) { |b, args| args[0] }
+      no_args_primitive(symbol, 'to_s', string) do |b, args, llvm_mod|
+        b.load(b.gep llvm_mod.globals['symbol_table'], [LLVM::Int(0), args[0]])
       end
     end
 
@@ -269,8 +269,8 @@ module Crystal
       pointer.add_def Def.new(:+, [Arg.new_with_restriction('offset', Ident.new(["Int64"], true))], PointerAdd.new)
       pointer.add_def Def.new(:-, [Arg.new_with_restriction('other', SelfType.instance)], PointerDiff.new)
       pointer.add_def Def.new('as', [Arg.new('type')], PointerCast.new)
-      shared_singleton(pointer, 'address', uint64) do |b, f, llvm_mod, self_type|
-        b.ptr2int(f.params[0], LLVM::UInt64)
+      shared_singleton(pointer, 'address', uint64) do |b, args, llvm_mod, self_type|
+        b.ptr2int(args[0], LLVM::UInt64)
       end
     end
 
@@ -291,7 +291,7 @@ module Crystal
     end
 
     def self_primitive(owner, name)
-      no_args_primitive(owner, name, owner) { |b, f| f.params[0] }
+      no_args_primitive(owner, name, owner) { |b, args| args[0] }
     end
 
     def singleton(owner, name, args, return_type, &block)
diff --git a/lib/crystal/type_inference.rb b/lib/crystal/type_inference.rb
index 93a93556663fb473d2b95e0179842e2d29b6eed7..066d211b2e921c90495b6c4d2df81c431987fdb8 100644
--- a/lib/crystal/type_inference.rb
+++ b/lib/crystal/type_inference.rb
@@ -443,7 +443,10 @@ module Crystal
     end
 
     def visit_var(node)
-      var = lookup_var node.name
+      var = @vars[node.name]
+      var.used = true
+
+      # var = lookup_var node.name
       filter = build_var_filter var
       node.bind_to(filter || var)
       node.type_filters = and_type_filters({node.name => NotNilFilter}, var.type_filters)
diff --git a/lib/crystal/type_inference/after_type_inference_transformer.rb b/lib/crystal/type_inference/after_type_inference_transformer.rb
index a55fce2beb8086f7c63c9c41170b87724f8ef1ea..e603c909be0b890b701819e68682eb9c1b0c1b28 100644
--- a/lib/crystal/type_inference/after_type_inference_transformer.rb
+++ b/lib/crystal/type_inference/after_type_inference_transformer.rb
@@ -28,6 +28,16 @@ module Crystal
   end
 
   class AfterTypeInferenceTransformer < Transformer
+    @@removed_assigns = 0
+    @@removed_no_effect = 0
+    @@removed_temps = 0
+
+    at_exit do
+      puts "Removed assigns: #{@@removed_assigns}"
+      puts "Removed no effect: #{@@removed_no_effect}"
+      puts "Removed temps: #{@@removed_temps}"
+    end
+
     def initialize(program)
       @program = program
       @transformed = {}
@@ -49,9 +59,15 @@ module Crystal
       exps = []
 
       found_no_return = false
-      node.expressions.each do |exp|
+      length = node.expressions.length
+      node.expressions.each_with_index do |exp, i|
         new_exp = exp.transform(self)
         if new_exp
+          if i < length - 1 && (new_exp.is_a?(Var) || new_exp.is_a?(NilLiteral) || new_exp.is_a?(NumberLiteral))
+            @@removed_no_effect += 1
+            next
+          end
+
           if new_exp.is_a?(Expressions)
             exps.concat new_exp.expressions
           else
@@ -67,14 +83,20 @@ module Crystal
 
       case exps.length
       when 0
-        nil
+        return nil
       when 1
-        exps[0]
-      else
-        node.expressions = exps
-        rebind_node node, exps.last
-        node
+        return exps[0]
+      when 2
+        first, second = exps
+        if first.is_a?(Assign) && first.target.is_a?(Var) && second.is_a?(Var) && first.target.name == second.name
+          @@removed_temps += 1
+          return first.value
+        end
       end
+
+      node.expressions = exps
+      rebind_node node, exps.last
+      node
     end
 
     def transform_assign(node)
@@ -85,6 +107,13 @@ module Crystal
         return node.value
       end
 
+      if node.target.is_a?(Var) && node.target.type
+        unless node.target.dependencies[0].used
+          @@removed_assigns += 1
+          return node.value
+        end
+      end
+
       node
     end
 
@@ -140,14 +169,14 @@ module Crystal
     end
 
     def check_comparison_of_unsigned_integer_with_zero_or_negative_literal(node)
-      if (node.name == :< || node.name == :<=) && node.obj.type.integer? && node.obj.type.unsigned?
+      if (node.name == :< || node.name == :<=) && node.obj && node.obj.type && node.obj.type.integer? && node.obj.type.unsigned?
         arg = node.args[0]
         if arg.is_a?(NumberLiteral) && arg.integer? && arg.value.to_i <= 0
           node.raise "'#{node.name}' comparison of unsigned integer with zero or negative literal will always be false"
         end
       end
 
-      if (node.name == :> || node.name == :>=) && node.obj.is_a?(NumberLiteral) && node.obj.integer? && node.obj.value.to_i <= 0
+      if (node.name == :> || node.name == :>=) && node.obj && node.obj.type && node.obj.is_a?(NumberLiteral) && node.obj.integer? && node.obj.value.to_i <= 0
         arg = node.args[0]
         if arg.type.integer? && arg.type.unsigned?
           node.raise "'#{node.name}' comparison of unsigned integer with zero or negative literal will always be false"
diff --git a/lib/crystal/type_inference/ast.rb b/lib/crystal/type_inference/ast.rb
index f8ec7bbb316bf41aae4f3a15c57469ba5a370548..901127db142851489c2ab4c61074d6aa293183b7 100644
--- a/lib/crystal/type_inference/ast.rb
+++ b/lib/crystal/type_inference/ast.rb
@@ -6,6 +6,8 @@ module Crystal
   end
 
   class Var
+    attr_accessor :used
+
     def out?
       out
     end