Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interpreter: cast proc call arguments to proc arg types #12375

Merged
merged 7 commits into from
Aug 19, 2022
30 changes: 30 additions & 0 deletions spec/compiler/interpreter/procs_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,34 @@ describe Crystal::Repl::Interpreter do
CODE
end
end

it "casts proc call arguments to proc arg types (#12350)" do
interpret(<<-CODE).should eq(42)
abstract struct Base
end

struct Foo < Base
def initialize(@x : Int32)
end

def x
@x
end
end

struct Bar < Base
end

proc = ->(base : Base) {
if base.is_a?(Foo)
base.x
else
0
end
}

bar = Foo.new(42)
proc.call(bar)
CODE
end
end
2 changes: 1 addition & 1 deletion src/compiler/crystal/interpreter/compiler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1796,7 +1796,7 @@ class Crystal::Repl::Compiler < Crystal::Visitor

body = target_def.body
if body.is_a?(Primitive)
visit_primitive(node, body)
visit_primitive(node, body, target_def)
return false
end

Expand Down
16 changes: 14 additions & 2 deletions src/compiler/crystal/interpreter/primitives.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require "./compiler"
# (for example `caller`, or doing a fiber context switch.)

class Crystal::Repl::Compiler
private def visit_primitive(node, body, wants_struct_pointer = false)
private def visit_primitive(node, body, target_def)
obj = node.obj

case body.name
Expand Down Expand Up @@ -254,7 +254,19 @@ class Crystal::Repl::Compiler

pointer_address(node: node)
when "proc_call"
node.args.each { |arg| request_value(arg) }
proc_type = (obj.try(&.type) || scope).as(ProcInstanceType)

node.args.each_with_index do |arg, arg_index|
request_value(arg)

# Cast call argument to proc's type
# (this same logic is done in codegen/primtiives.cr)
asterite marked this conversation as resolved.
Show resolved Hide resolved
proc_arg_type = proc_type.arg_types[arg_index]
target_def_arg_type = target_def.args[arg_index].type
if proc_arg_type != target_def_arg_type
upcast(arg, target_def_arg_type, proc_arg_type)
end
end

obj ? request_value(obj) : put_self(node: node)

Expand Down