int arg_count; // actual argument count
type_T **arg_types; // list of argument types
int arg_idx; // current argument index (first arg is zero)
+ cctx_T *arg_cctx;
} argcontext_T;
// A function to check one argument type. The first argument is the type to
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
typedef int (*argcheck_T)(type_T *, argcontext_T *);
+/*
+ * Call need_type() to check an argument type.
+ */
+ static int
+check_arg_type(
+ type_T *expected,
+ type_T *actual,
+ argcontext_T *context)
+{
+ // TODO: would be useful to know if "actual" is a constant and pass it to
+ // need_type() to get a compile time error if possible.
+ return need_type(actual, expected,
+ context->arg_idx - context->arg_count, context->arg_idx + 1,
+ context->arg_cctx, FALSE, FALSE);
+}
+
/*
* Check "type" is a float or a number.
*/
static int
arg_number(type_T *type, argcontext_T *context)
{
- return check_arg_type(&t_number, type, context->arg_idx + 1);
+ return check_arg_type(&t_number, type, context);
}
/*
static int
arg_string(type_T *type, argcontext_T *context)
{
- return check_arg_type(&t_string, type, context->arg_idx + 1);
+ return check_arg_type(&t_string, type, context);
}
/*
{
type_T *prev_type = context->arg_types[context->arg_idx - 1];
- return check_arg_type(prev_type, type, context->arg_idx + 1);
+ return check_arg_type(prev_type, type, context);
}
/*
type_T *prev_type = context->arg_types[context->arg_idx - 1];
if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
- return check_arg_type(prev_type, type, context->arg_idx + 1);
+ return check_arg_type(prev_type, type, context);
return OK;
}
// probably VAR_ANY, can't check
return OK;
- return check_arg_type(expected, type, context->arg_idx + 1);
+ return check_arg_type(expected, type, context);
}
/*
* Return FAIL and gives an error message when a type is wrong.
*/
int
-internal_func_check_arg_types(type_T **types, int idx, int argcount)
+internal_func_check_arg_types(
+ type_T **types,
+ int idx,
+ int argcount,
+ cctx_T *cctx)
{
argcheck_T *argchecks = global_functions[idx].f_argcheck;
int i;
context.arg_count = argcount;
context.arg_types = types;
+ context.arg_cctx = cctx;
for (i = 0; i < argcount; ++i)
if (argchecks[i] != NULL)
{
* If "actual_is_const" is TRUE then the type won't change at runtime, do not
* generate a TYPECHECK.
*/
- static int
+ int
need_type(
type_T *actual,
type_T *expected,
int offset,
+ int arg_idx,
cctx_T *cctx,
int silent,
int actual_is_const)
return OK;
}
- if (check_type(expected, actual, FALSE, 0) == OK)
+ if (check_type(expected, actual, FALSE, arg_idx) == OK)
return OK;
// If the actual type can be the expected type add a runtime check.
}
if (!silent)
- type_mismatch(expected, actual);
+ arg_type_mismatch(expected, actual, arg_idx);
return FAIL;
}
// This requires a runtime type check.
return generate_COND2BOOL(cctx);
- return need_type(type, &t_bool, -1, cctx, FALSE, FALSE);
+ return need_type(type, &t_bool, -1, 0, cctx, FALSE, FALSE);
}
/*
{
// Check the types of the arguments.
argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
- if (internal_func_check_arg_types(argtypes, func_idx, argcount) == FAIL)
+ if (internal_func_check_arg_types(argtypes, func_idx, argcount,
+ cctx) == FAIL)
return FAIL;
if (internal_func_is_map(func_idx))
maptype = *argtypes;
list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
expected = list_type->tt_member;
- if (need_type(item_type, expected, -1, cctx, FALSE, FALSE) == FAIL)
+ if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
// Caller already checked that blob_type is a blob.
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
- if (need_type(item_type, &t_number, -1, cctx, FALSE, FALSE) == FAIL)
+ if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
else
expected = ufunc->uf_va_type->tt_member;
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
- if (need_type(actual, expected, -argcount + i, cctx,
+ if (need_type(actual, expected, -argcount + i, 0, cctx,
TRUE, FALSE) == FAIL)
{
arg_type_mismatch(expected, actual, i + 1);
type->tt_argcount - 1]->tt_member;
else
expected = type->tt_args[i];
- if (need_type(actual, expected, offset,
+ if (need_type(actual, expected, offset, 0,
cctx, TRUE, FALSE) == FAIL)
{
arg_type_mismatch(expected, actual, i + 1);
{
type_T *keytype = ((type_T **)stack->ga_data)
[stack->ga_len - 1];
- if (need_type(keytype, &t_string, -1, cctx,
+ if (need_type(keytype, &t_string, -1, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
vtype = VAR_DICT;
if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
{
- if (need_type(valtype, &t_number, -1, cctx,
+ if (need_type(valtype, &t_number, -1, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
if (is_slice)
{
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
- if (need_type(valtype, &t_number, -2, cctx,
+ if (need_type(valtype, &t_number, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
}
else
{
- if (need_type(*typep, &t_dict_any, -2, cctx,
+ if (need_type(*typep, &t_dict_any, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
*typep = &t_any;
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (check_type(want_type, actual, FALSE, 0) == FAIL)
{
- if (need_type(actual, want_type, -1, cctx, FALSE, FALSE) == FAIL)
+ if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
}
}
return NULL;
}
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
- cctx, FALSE, FALSE) == FAIL)
+ 0, cctx, FALSE, FALSE) == FAIL)
return NULL;
}
}
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
// now we can properly check the type
if (lhs->lhs_type->tt_member != NULL && rhs_type != &t_void
- && need_type(rhs_type, lhs->lhs_type->tt_member, -2, cctx,
+ && need_type(rhs_type, lhs->lhs_type->tt_member, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
emsg(_(e_cannot_use_void_value));
goto theend;
}
- if (need_type(stacktype, &t_list_any, -1, cctx,
+ if (need_type(stacktype, &t_list_any, -1, 0, cctx,
FALSE, FALSE) == FAIL)
goto theend;
// TODO: check the length of a constant list here
// without operator check type here, otherwise below
if (lhs.lhs_has_index)
use_type = lhs.lhs_member_type;
- if (need_type(rhs_type, use_type, -1, cctx,
+ if (need_type(rhs_type, use_type, -1, 0, cctx,
FALSE, is_const) == FAIL)
goto theend;
}
}
else if (*p != '=' && need_type(rhs_type, lhs.lhs_member_type,
- -1, cctx, FALSE, FALSE) == FAIL)
+ -1, 0, cctx, FALSE, FALSE) == FAIL)
goto theend;
}
else if (cmdidx == CMD_final)
// If variable is float operation with number is OK.
!(expected == &t_float && stacktype == &t_number) &&
#endif
- need_type(stacktype, expected, -1, cctx,
+ need_type(stacktype, expected, -1, 0, cctx,
FALSE, FALSE) == FAIL)
goto theend;
// Now that we know the type of "var", check that it is a list, now or at
// runtime.
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
- if (need_type(vartype, &t_list_any, -1, cctx, FALSE, FALSE) == FAIL)
+ if (need_type(vartype, &t_list_any, -1, 0, cctx, FALSE, FALSE) == FAIL)
{
drop_scope(cctx);
return NULL;