Skip to content

Commit

Permalink
Allow returning Procs from top-level funs (#14917)
Browse files Browse the repository at this point in the history
  • Loading branch information
HertzDevil committed Aug 22, 2024
1 parent 0f906a4 commit eb01f2a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
53 changes: 53 additions & 0 deletions spec/compiler/codegen/proc_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,59 @@ describe "Code gen: proc" do
))
end

it "returns proc as function pointer inside top-level fun (#14691)" do
run(<<-CRYSTAL, Int32).should eq(8)
def raise(msg)
while true
end
end
fun add : Int32, Int32 -> Int32
->(x : Int32, y : Int32) { x &+ y }
end
add.call(3, 5)
CRYSTAL
end

it "returns ProcPointer inside top-level fun (#14691)" do
run(<<-CRYSTAL, Int32).should eq(8)
def raise(msg)
while true
end
end
fun foo(x : Int32) : Int32
x &+ 5
end
fun bar : Int32 -> Int32
->foo(Int32)
end
bar.call(3)
CRYSTAL
end

it "raises if returning closure from top-level fun (#14691)" do
run(<<-CRYSTAL).to_b.should be_true
require "prelude"
@[Raises]
fun foo(x : Int32) : -> Int32
-> { x }
end
begin
foo(1)
rescue
true
else
false
end
CRYSTAL
end

it "closures var on ->var.call (#8584)" do
run(%(
def bar(x)
Expand Down
13 changes: 9 additions & 4 deletions src/compiler/crystal/codegen/fun.cr
Original file line number Diff line number Diff line change
Expand Up @@ -236,17 +236,22 @@ class Crystal::CodeGenVisitor
# Check if this def must use the C calling convention and the return
# value must be either casted or passed by sret
if target_def.c_calling_convention? && target_def.abi_info?
return_type = target_def.body.type
if return_type.proc?
@last = check_proc_is_not_closure(@last, return_type)
end

abi_info = abi_info(target_def)
ret_type = abi_info.return_type
if cast = ret_type.cast
abi_ret_type = abi_info.return_type
if cast = abi_ret_type.cast
casted_last = pointer_cast @last, cast.pointer
last = load cast, casted_last
ret last
return
end

if (attr = ret_type.attr) && attr == LLVM::Attribute::StructRet
store load(llvm_type(target_def.body.type), @last), context.fun.params[0]
if (attr = abi_ret_type.attr) && attr == LLVM::Attribute::StructRet
store load(llvm_type(return_type), @last), context.fun.params[0]
ret
return
end
Expand Down

0 comments on commit eb01f2a

Please sign in to comment.