nitc :: TypeVisitor :: check_signature
The point of this method is to handle varargs correctly Note: The signature must be correctly adapted
# 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