From 57bf99a1648a27ebe460bd227a05dde8d186840a Mon Sep 17 00:00:00 2001 From: Ary Borenszweig <aborenszweig@manas.com.ar> Date: Thu, 18 Sep 2014 09:25:18 -0300 Subject: [PATCH] Fixed #210: Error calling a proc with an argument of module type --- spec/compiler/codegen/fun_spec.cr | 10 +++++ spec/compiler/codegen/module_spec.cr | 43 ++++++++++++++++++++++ src/compiler/crystal/codegen/cast.cr | 4 ++ src/compiler/crystal/codegen/primitives.cr | 8 +++- 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/spec/compiler/codegen/fun_spec.cr b/spec/compiler/codegen/fun_spec.cr index 96af3f79b4..7879c04cd1 100644 --- a/spec/compiler/codegen/fun_spec.cr +++ b/spec/compiler/codegen/fun_spec.cr @@ -475,4 +475,14 @@ describe "Code gen: fun" do foo { } )).to_i.should eq(1) end + + it "codegens fun with union type that returns itself" do + run(%( + a = 1 || 1.5 + + foo = ->(x : Int32 | Float64) { x } + foo.call(a) + foo.call(a).to_i + )).to_i.should eq(1) + end end diff --git a/spec/compiler/codegen/module_spec.cr b/spec/compiler/codegen/module_spec.cr index 524833461b..0f56411381 100644 --- a/spec/compiler/codegen/module_spec.cr +++ b/spec/compiler/codegen/module_spec.cr @@ -184,4 +184,47 @@ describe "Code gen: module" do p.value.foo )).to_i.should eq(2) end + + it "declares proc with module type" do + run(%( + module Moo + def moo + 1 + end + end + + class Foo + include Moo + end + + class Bar + include Moo + end + + foo = ->(x : Moo) { x.moo } + foo.call(Bar.new) + )).to_i.should eq(1) + end + + it "declares proc with module type and invoke it with two different types that return themselves" do + build(%( + module Moo + def moo + 1 + end + end + + class Foo + include Moo + end + + struct Bar + include Moo + end + + foo = ->(x : Moo) { x } + foo.call(Foo.new) + foo.call(Bar.new) + )) + end end diff --git a/src/compiler/crystal/codegen/cast.cr b/src/compiler/crystal/codegen/cast.cr index 0907b97628..8cb604aa41 100644 --- a/src/compiler/crystal/codegen/cast.cr +++ b/src/compiler/crystal/codegen/cast.cr @@ -344,6 +344,10 @@ class Crystal::CodeGenVisitor < Crystal::Visitor value end + def upcast_distinct(value, to_type : NonGenericModuleType, from_type : Type) + upcast_distinct value, to_type.including_types.not_nil!, from_type + end + def upcast_distinct(value, to_type : Type, from_type : Type) raise "Bug: trying to upcast #{to_type} <- #{from_type}" end diff --git a/src/compiler/crystal/codegen/primitives.cr b/src/compiler/crystal/codegen/primitives.cr index eef4e420c6..c48f66bfa3 100644 --- a/src/compiler/crystal/codegen/primitives.cr +++ b/src/compiler/crystal/codegen/primitives.cr @@ -434,7 +434,10 @@ class Crystal::CodeGenVisitor < Crystal::Visitor ctx_is_null = equal? ctx_ptr, LLVM.null(LLVM::VoidPointer) cond ctx_is_null, ctx_is_null_block, ctx_is_not_null_block - Phi.open(self, node, true) do |phi| + old_needs_value = @needs_value + @needs_value = true + + phi_value = Phi.open(self, node, @needs_value) do |phi| position_at_end ctx_is_null_block real_fun_ptr = bit_cast fun_ptr, llvm_fun_type(context.type) value = codegen_call_or_invoke(node, target_def, nil, real_fun_ptr, args, true, target_def.type, false, fun_type) @@ -446,6 +449,9 @@ class Crystal::CodeGenVisitor < Crystal::Visitor value = codegen_call_or_invoke(node, target_def, nil, real_fun_ptr, args, true, target_def.type, true, fun_type) phi.add value, node.type, true end + + old_needs_value = @needs_value + phi_value end def codegen_primitive_fun_closure(node, target_def, call_args) -- GitLab