Visit the expressions of args and check their conformity with the corresponding type in signature

The point of this method is to handle varargs correctly Note: The signature must be correctly adapted

Property definitions

nitc $ TypeVisitor :: check_signature
	# Visit the expressions of args and check their conformity with the corresponding type in signature
	# The point of this method is to handle varargs correctly
	# Note: The signature must be correctly adapted
	fun check_signature(node: ANode, args: Array[AExpr], mproperty: MProperty, msignature: MSignature): nullable SignatureMap
	do
		var vararg_rank = msignature.vararg_rank
		if vararg_rank >= 0 then
			if args.length < msignature.arity then
				modelbuilder.error(node, "Error: expected at least {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
				return null
			end
		else if args.length != msignature.arity then
			# Too much argument
			if args.length > msignature.arity then
				modelbuilder.error(node, "Error: expected {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
				return null
			end
			# Other cases are managed later
		end

		#debug("CALL {unsafe_type}.{msignature}")

		# Associate each parameter to a position in the arguments
		var map = new SignatureMap

		# Special case for the isolated last argument
		# TODO: reify this method characteristics (where? the param, the signature, the method?)
		var last_is_padded = mproperty.name.chars.last == '='
		var nbargs = args.length
		if last_is_padded then
			nbargs -= 1
			assert not args.last isa ANamedargExpr
			map.map[msignature.arity - 1] = args.length - 1
			self.visit_expr_subtype(args.last, msignature.mparameters.last.mtype)
		end

		# First, handle named arguments
		for i in [0..args.length[ do
			var e = args[i]
			if not e isa ANamedargExpr then continue
			var name = e.n_id.text
			var param = msignature.mparameter_by_name(name)
			if param == null then
				modelbuilder.error(e.n_id, "Error: no parameter `{name}` for `{mproperty}{msignature}`.")
				return null
			end
			var idx = msignature.mparameters.index_of(param)
			var prev = map.map.get_or_null(idx)
			if prev != null then
				modelbuilder.error(e, "Error: parameter `{name}` already associated with argument #{prev} for `{mproperty}{msignature}`.")
				return null
			end
			map.map[idx] = i
			e.mtype = self.visit_expr_subtype(e.n_expr, param.mtype)
		end

		# Number of minimum mandatory remaining parameters
		var min_arity = 0

		# Second, associate remaining parameters
		var vararg_decl = args.length - msignature.arity
		var j = 0
		for i in [0..msignature.arity[ do
			# Skip parameters associated by name
			if map.map.has_key(i) then continue

			var param = msignature.mparameters[i]

			# Search the next free argument: skip named arguments since they are already associated
			while j < nbargs and args[j] isa ANamedargExpr do j += 1
			if j >= nbargs then
				if not param.mtype isa MNullableType then
					min_arity = j + 1
				end
				j += 1
				continue
			end
			var arg = args[j]
			map.map[i] = j
			j += 1

			if i == vararg_rank then
				j += vararg_decl
				continue # skip the vararg
			end

			if not param.is_vararg then
				var paramtype = param.mtype
				self.visit_expr_subtype(arg, paramtype)
			else
				check_one_vararg(arg, param)
			end
		end

		if min_arity > 0 then
			if last_is_padded then min_arity += 1
			if min_arity < msignature.arity then
				modelbuilder.error(node, "Error: expected at least {min_arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
			else
				modelbuilder.error(node, "Error: expected {min_arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
			end
			return null
		end

		# Third, check varargs
		if vararg_rank >= 0 then
			var paramtype = msignature.mparameters[vararg_rank].mtype
			var first = args[vararg_rank]
			if vararg_decl == 0 then
				if not check_one_vararg(first, msignature.mparameters[vararg_rank]) then return null
			else
				first.vararg_decl = vararg_decl + 1
				for i in [vararg_rank..vararg_rank+vararg_decl] do
					self.visit_expr_subtype(args[i], paramtype)
				end
			end
		end

		return map
	end
src/semantize/typing.nit:441,2--560,4