diff --git a/spec/compiler/interpreter/lib_spec.cr b/spec/compiler/interpreter/lib_spec.cr index bbf6367ee6df..3b30350135e5 100644 --- a/spec/compiler/interpreter/lib_spec.cr +++ b/spec/compiler/interpreter/lib_spec.cr @@ -91,4 +91,27 @@ describe Crystal::Repl::Interpreter do CRYSTAL end end + + context "proc pointer" do + it "calls extern fun" do + interpret(<<-CRYSTAL).should eq 6 + @[Link(ldflags: #{ldflags_with_backtick.inspect})] + lib LibSum + fun simple_sum_int(a : Int32, b : Int32) : Int32 + end + + class Foo + def initialize(@method : Proc(Int32, Int32, Int32)) + end + + def call(a, b) + @method.call(a, b) + end + end + + foo = Foo.new(->LibSum.simple_sum_int) + foo.call(1, 5) + CRYSTAL + end + end end diff --git a/src/compiler/crystal/interpreter/compiler.cr b/src/compiler/crystal/interpreter/compiler.cr index d59a1aae4cbb..d75d3b2b3ef2 100644 --- a/src/compiler/crystal/interpreter/compiler.cr +++ b/src/compiler/crystal/interpreter/compiler.cr @@ -2925,6 +2925,28 @@ class Crystal::Repl::Compiler < Crystal::Visitor false end + def visit(node : ProcPointer) + target_def = node.call.target_def + + unless target_def.owner.is_a?(LibType) + # LLVM codegen supports more cases like closure data and obj/self + # target, but I can't trigger them — does LiteralExpander expand + # these cases into ProcLiteral? + raise "BUG: missing interpret for ProcPointer to non Lib fun" + end + + # find or build a compiled_def + proc_type = node.type.as(ProcInstanceType) + symbol = @context.c_function(target_def.as(External).real_name) + compiled_def = @context.extern_proc_wrapper(proc_type, symbol) + + # push compiled_def to stack + no closure data (null pointer) + put_i64 compiled_def.object_id.to_i64!, node: node + put_i64 0, node: node + + false + end + def visit(node : Break) exp = node.exp