+ #debug "ENTER ref_call"
+ compiler.modelbuilder.nb_invok_by_tables += 1
+ if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_tables++;")
+ var nclasses = mmodule.model.get_mclasses_by_name("RoutineRef").as(not null)
+ var nclass = nclasses.first
+ var runtime_function = mmethoddef.virtual_runtime_function
+
+ # Save the current receiver since adapt_signature will autobox
+ # the routine receiver which is not the underlying receiver.
+ # The underlying receiver has already been adapted in the
+ # `routine_ref_instance` method. Here we just want to adapt the
+ # rest of the signature, but it's easier to pass the wrong
+ # receiver in adapt_signature then discards it with `shift`.
+ #
+ # ~~~~nitish
+ # class A; def toto do print "toto"; end
+ # var a = new A
+ # var f = &a.toto # `a` is the underlying receiver
+ # f.call # here `f` is the routine receiver
+ # ~~~~
+ var routine = arguments.first
+
+ # Retrieve the concrete routine type
+ var original_recv_c = "(((struct instance_{nclass.c_name}*){arguments[0]})->recv)"
+ var nitmethod = "(({runtime_function.c_funptrtype})(((struct instance_{nclass.c_name}*){arguments[0]})->method))"
+ if arguments.length > 1 then
+ adapt_signature(mmethoddef, arguments)
+ end
+
+ var ret_mtype = runtime_function.called_signature.return_mtype
+
+ if ret_mtype != null then
+ # `ret` is actually always nullable Object. When invoking
+ # a callref, we don't have the original callsite information.
+ # Thus, we need to recompute the return type of the callsite.
+ ret_mtype = resolve_for(ret_mtype, routine)
+ end
+
+ # remove the routine's receiver
+ arguments.shift
+ var ss = arguments.join(", ")
+ # replace the receiver with the original one
+ if arguments.length > 0 then
+ ss = "{original_recv_c}, {ss}"
+ else
+ ss = original_recv_c
+ end
+
+ arguments.unshift routine # put back the routine ref receiver
+ add "/* {mmethoddef.mproperty} on {arguments.first.inspect}*/"
+ var callsite = "{nitmethod}({ss})"
+ if ret_mtype != null then
+ var subres = new_expr("{callsite}", ret_mtype)
+ ret(subres)
+ else
+ add("{callsite};")
+ end