Generate a polymorphic send for the method m and the arguments args

Property definitions

nitc $ AbstractCompilerVisitor :: send
	#  Generate a polymorphic send for the method `m` and the arguments `args`
	fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
src/compiler/abstract_compiler.nit:1512,2--1513,89

nitc $ SeparateCompilerVisitor :: send
	redef fun send(mmethod, arguments)
	do
		if arguments.first.mcasttype.is_c_primitive then
			# In order to shortcut the primitive, we need to find the most specific method
			# Howverr, because of performance (no flattening), we always work on the realmainmodule
			var m = self.compiler.mainmodule
			self.compiler.mainmodule = self.compiler.realmainmodule
			var res = self.monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
			self.compiler.mainmodule = m
			return res
		end

		return table_send(mmethod, arguments, mmethod)
	end
src/compiler/separate_compiler.nit:1462,2--1475,4

nitc $ GlobalCompilerVisitor :: send
	redef fun send(m, args)
	do
		var types = self.collect_types(args.first)

		var res: nullable RuntimeVariable
		var ret = m.intro.msignature.return_mtype
		if ret == null then
			res = null
		else
			ret = self.resolve_for(ret, args.first)
			res = self.new_var(ret)
		end

		self.add("/* send {m} on {args.first.inspect} */")
		if args.first.mtype.is_c_primitive then
			var mclasstype = args.first.mtype.as(MClassType)
			if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
				self.add("/* skip, dead class {mclasstype} */")
				return res
			end
			if not mclasstype.has_mproperty(self.compiler.mainmodule, m) then
				self.add("/* skip, no method {m} */")
				return res
			end
			var propdef = m.lookup_first_definition(self.compiler.mainmodule, mclasstype)
			var res2 = self.call(propdef, mclasstype, args)
			if res != null then self.assign(res, res2.as(not null))
			return res
		end
		var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or m.name == "==" or m.name == "!="
		if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
			# The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
			self.add("if ({args.first} == NULL) \{ /* Special null case */")
			if m.name == "==" or m.name == "is_same_instance" then
				assert res != null
				if args[1].mcasttype isa MNullableType then
					self.add("{res} = ({args[1]} == NULL);")
				else if args[1].mcasttype isa MNullType then
					self.add("{res} = 1; /* is null */")
				else
					self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
				end
			else if m.name == "!=" then
				assert res != null
				if args[1].mcasttype isa MNullableType then
					self.add("{res} = ({args[1]} != NULL);")
				else if args[1].mcasttype isa MNullType then
					self.add("{res} = 0; /* is null */")
				else
					self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
				end
			else
				self.add_abort("Receiver is null")
			end
			self.add "\} else"
		end
		if types.is_empty then
			self.add("\{")
			self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
			self.bugtype(args.first)
			self.add("\}")
			return res
		end

		self.add("switch({args.first}->classid) \{")
		var last = types.last
		var defaultpropdef: nullable MMethodDef = null
		for t in types do
			var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
			if propdef.mclassdef.mclass.name == "Object" and not t.is_c_primitive then
				defaultpropdef = propdef
				continue
			end
			if not self.compiler.hardening and t == last and defaultpropdef == null then
				self.add("default: /* test {t} */")
			else
				self.add("case {self.compiler.classid(t)}: /* test {t} */")
			end
			var res2 = self.call(propdef, t, args)
			if res != null then self.assign(res, res2.as(not null))
			self.add "break;"
		end
		if defaultpropdef != null then
			self.add("default: /* default is Object */")
			var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
			if res != null then self.assign(res, res2.as(not null))
		else if self.compiler.hardening then
			self.add("default: /* bug */")
			self.bugtype(args.first)
		end
		self.add("\}")
		return res
	end
src/compiler/global_compiler.nit:513,2--605,4