Call the underlying referenced function

Property definitions

nitc $ AbstractCompilerVisitor :: routine_ref_call
	# Call the underlying referenced function
	fun routine_ref_call(mmethoddef: MMethodDef, args: Array[RuntimeVariable]) is abstract
src/compiler/abstract_compiler.nit:1374,2--1375,87

nitc $ SeparateCompilerVisitor :: routine_ref_call
	redef fun routine_ref_call(mmethoddef, arguments)
	do
		#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
	end
src/compiler/separate_compiler.nit:2293,2--2352,4

nitc $ GlobalCompilerVisitor :: routine_ref_call
        redef fun routine_ref_call(mmethoddef, arguments)
        do
                var routine = arguments.first
                var routine_type = routine.mtype.as(MClassType)
                var routine_class = routine_type.mclass
                var underlying_recv = "((struct {routine.mcasttype.c_name}*){routine})->recv"
                var underlying_method = "((struct {routine.mcasttype.c_name}*){routine})->method"
                adapt_signature(mmethoddef, arguments)
                arguments.shift
                var ss = "{underlying_recv}"
                if arguments.length > 0 then
                        ss = "{ss}, {arguments.join(", ")}"
                end
                arguments.unshift routine

                var ret_mtype = mmethoddef.msignature.return_mtype

                if ret_mtype != null then
                        ret_mtype = resolve_for(ret_mtype, routine)
                end
                var callsite = "{underlying_method}({ss})"
                if ret_mtype != null then
                        var subres = new_expr("{callsite}", ret_mtype)
                        ret(subres)
                else
                        add("{callsite};")
		end
        end
src/compiler/global_compiler.nit:484,9--511,11