From edc3f60ff094f6844134e193eb3c8bda5bc2beb5 Mon Sep 17 00:00:00 2001
From: Ary Borenszweig <aborenszweig@manas.com.ar>
Date: Mon, 1 Dec 2014 09:21:25 -0300
Subject: [PATCH] Fixed another const initialization issue

---
 spec/compiler/codegen/const_spec.cr     | 27 +++++++++++++++++++++++++
 src/compiler/crystal/codegen/codegen.cr | 22 +++++++++++---------
 2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/spec/compiler/codegen/const_spec.cr b/spec/compiler/codegen/const_spec.cr
index 5df31097a6..aafc10b165 100644
--- a/spec/compiler/codegen/const_spec.cr
+++ b/spec/compiler/codegen/const_spec.cr
@@ -243,4 +243,31 @@ describe "Codegen: const" do
       Foo::Y.value
       )).to_i.should eq(1)
   end
+
+  it "codegens constant that is declared later because of virtual dispatch" do
+    run(%(
+      class Base
+        def base
+        end
+      end
+
+      class Base2 < Base
+        def base
+        end
+      end
+
+      b = Base.new || Base2.new
+      b.base
+
+      class MyBase < Base
+        CONST = 1
+
+        def base
+          CONST
+        end
+      end
+
+      MyBase.new.base
+      )).to_i.should eq(1)
+  end
 end
diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr
index 86434a7004..84378eb59d 100644
--- a/src/compiler/crystal/codegen/codegen.cr
+++ b/src/compiler/crystal/codegen/codegen.cr
@@ -159,8 +159,8 @@ module Crystal
 
       alloca_vars @mod.vars, @mod
 
-      declare_const(@mod.types["ARGC_UNSAFE"] as Const)
-      declare_const(@mod.types["ARGV_UNSAFE"] as Const)
+      initialize_const(@mod.types["ARGC_UNSAFE"] as Const)
+      initialize_const(@mod.types["ARGV_UNSAFE"] as Const)
     end
 
     def wrap_builder(builder)
@@ -479,7 +479,7 @@ module Crystal
 
     def visit(node : EnumDef)
       node.enum_type.try &.types.each_value do |type|
-        declare_const(type as Const)
+        initialize_const(type as Const)
       end
       @last = llvm_nil
       false
@@ -642,7 +642,7 @@ module Crystal
       # Initialize constants if they are used
       if target.is_a?(Path)
         const = target.target_const.not_nil!
-        declare_const const
+        initialize_const const
         @last = llvm_nil
         return false
       end
@@ -878,11 +878,7 @@ module Crystal
           @last = initializer
         else
           global_name = const.llvm_name
-
-          global = @main_mod.globals[global_name]?
-          unless global
-            node.raise "Bug: global not found for #{const}"
-          end
+          global = declare_const(const, global_name)
 
           if @llvm_mod != @main_mod
             global = @llvm_mod.globals[global_name]?
@@ -908,9 +904,15 @@ module Crystal
     end
 
     def declare_const(const, global_name = const.llvm_name)
+      @main_mod.globals[global_name]? ||
+        @main_mod.globals.add(llvm_type(const.value.type), global_name)
+    end
+
+    def initialize_const(const, global_name = const.llvm_name)
       return unless const.used
 
-      global = @main_mod.globals.add(llvm_type(const.value.type), global_name)
+      # It might be that the constant is already declared by not initialized
+      global = declare_const(const, global_name)
 
       in_const_block(const.container) do
         alloca_vars const.vars
-- 
GitLab