patch 9.0.0419: the :defer command does not check the function arguments
Problem: The :defer command does not check the function argument count and
types.
Solution: Check the function arguments when adding a deferred function.
diff --git a/src/vim9instr.c b/src/vim9instr.c
index 34d4ae3..6a387fa 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -1329,6 +1329,65 @@
return OK;
}
+/*
+ * Check "argount" arguments and their types on the type stack.
+ * Give an error and return FAIL if something is wrong.
+ * When "method_call" is NULL no code is generated.
+ */
+ int
+check_internal_func_args(
+ cctx_T *cctx,
+ int func_idx,
+ int argcount,
+ int method_call,
+ type2_T **argtypes,
+ type2_T *shuffled_argtypes)
+{
+ garray_T *stack = &cctx->ctx_type_stack;
+ int argoff = check_internal_func(func_idx, argcount);
+
+ if (argoff < 0)
+ return FAIL;
+
+ if (method_call && argoff > 1)
+ {
+ isn_T *isn = generate_instr(cctx, ISN_SHUFFLE);
+
+ if (isn == NULL)
+ return FAIL;
+ isn->isn_arg.shuffle.shfl_item = argcount;
+ isn->isn_arg.shuffle.shfl_up = argoff - 1;
+ }
+
+ if (argcount > 0)
+ {
+ type2_T *typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount;
+
+ // Check the types of the arguments.
+ if (method_call && argoff > 1)
+ {
+ int i;
+
+ for (i = 0; i < argcount; ++i)
+ shuffled_argtypes[i] = (i < argoff - 1)
+ ? typep[i + 1]
+ : (i == argoff - 1) ? typep[0] : typep[i];
+ *argtypes = shuffled_argtypes;
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < argcount; ++i)
+ shuffled_argtypes[i] = typep[i];
+ *argtypes = shuffled_argtypes;
+ }
+ if (internal_func_check_arg_types(*argtypes, func_idx, argcount,
+ cctx) == FAIL)
+ return FAIL;
+ }
+ return OK;
+}
/*
* Generate an ISN_BCALL instruction.
@@ -1340,8 +1399,6 @@
{
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
- int argoff;
- type2_T *typep;
type2_T *argtypes = NULL;
type2_T shuffled_argtypes[MAX_FUNC_ARGS];
type2_T *maptype = NULL;
@@ -1349,46 +1406,13 @@
type_T *decl_type;
RETURN_OK_IF_SKIP(cctx);
- argoff = check_internal_func(func_idx, argcount);
- if (argoff < 0)
+
+ if (check_internal_func_args(cctx, func_idx, argcount, method_call,
+ &argtypes, shuffled_argtypes) == FAIL)
return FAIL;
- if (method_call && argoff > 1)
- {
- if ((isn = generate_instr(cctx, ISN_SHUFFLE)) == NULL)
- return FAIL;
- isn->isn_arg.shuffle.shfl_item = argcount;
- isn->isn_arg.shuffle.shfl_up = argoff - 1;
- }
-
- if (argcount > 0)
- {
- // Check the types of the arguments.
- typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount;
- if (method_call && argoff > 1)
- {
- int i;
-
- for (i = 0; i < argcount; ++i)
- shuffled_argtypes[i] = (i < argoff - 1)
- ? typep[i + 1]
- : (i == argoff - 1) ? typep[0] : typep[i];
- argtypes = shuffled_argtypes;
- }
- else
- {
- int i;
-
- for (i = 0; i < argcount; ++i)
- shuffled_argtypes[i] = typep[i];
- argtypes = shuffled_argtypes;
- }
- if (internal_func_check_arg_types(argtypes, func_idx, argcount,
- cctx) == FAIL)
- return FAIL;
- if (internal_func_is_map(func_idx))
- maptype = argtypes;
- }
+ if (internal_func_is_map(func_idx))
+ maptype = argtypes;
if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
return FAIL;
@@ -1578,6 +1602,61 @@
}
/*
+ * Check the arguments of function "type" against the types on the stack.
+ * Returns OK or FAIL;
+ */
+ int
+check_func_args_from_type(
+ cctx_T *cctx,
+ type_T *type,
+ int argcount,
+ int at_top,
+ char_u *name)
+{
+ if (type->tt_argcount != -1)
+ {
+ int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
+
+ if (argcount < type->tt_min_argcount - varargs)
+ {
+ emsg_funcname(e_not_enough_arguments_for_function_str, name);
+ return FAIL;
+ }
+ if (!varargs && argcount > type->tt_argcount)
+ {
+ emsg_funcname(e_too_many_arguments_for_function_str, name);
+ return FAIL;
+ }
+ if (type->tt_args != NULL)
+ {
+ int i;
+
+ for (i = 0; i < argcount; ++i)
+ {
+ int offset = -argcount + i - (at_top ? 0 : 1);
+ type_T *actual = get_type_on_stack(cctx, -1 - offset);
+ type_T *expected;
+
+ if (varargs && i >= type->tt_argcount - 1)
+ expected = type->tt_args[type->tt_argcount - 1]->tt_member;
+ else if (i >= type->tt_min_argcount
+ && actual->tt_type == VAR_SPECIAL)
+ expected = &t_any;
+ else
+ expected = type->tt_args[i];
+ if (need_type(actual, expected, offset, i + 1,
+ cctx, TRUE, FALSE) == FAIL)
+ {
+ arg_type_mismatch(expected, actual, i + 1);
+ return FAIL;
+ }
+ }
+ }
+ }
+
+ return OK;
+}
+/*
* Generate an ISN_PCALL instruction.
* "type" is the type of the FuncRef.
*/
@@ -1598,47 +1677,9 @@
ret_type = &t_any;
else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
{
- if (type->tt_argcount != -1)
- {
- int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
+ if (check_func_args_from_type(cctx, type, argcount, at_top, name) == FAIL)
+ return FAIL;
- if (argcount < type->tt_min_argcount - varargs)
- {
- emsg_funcname(e_not_enough_arguments_for_function_str, name);
- return FAIL;
- }
- if (!varargs && argcount > type->tt_argcount)
- {
- emsg_funcname(e_too_many_arguments_for_function_str, name);
- return FAIL;
- }
- if (type->tt_args != NULL)
- {
- int i;
-
- for (i = 0; i < argcount; ++i)
- {
- int offset = -argcount + i - (at_top ? 0 : 1);
- type_T *actual = get_type_on_stack(cctx, -1 - offset);
- type_T *expected;
-
- if (varargs && i >= type->tt_argcount - 1)
- expected = type->tt_args[
- type->tt_argcount - 1]->tt_member;
- else if (i >= type->tt_min_argcount
- && actual->tt_type == VAR_SPECIAL)
- expected = &t_any;
- else
- expected = type->tt_args[i];
- if (need_type(actual, expected, offset, i + 1,
- cctx, TRUE, FALSE) == FAIL)
- {
- arg_type_mismatch(expected, actual, i + 1);
- return FAIL;
- }
- }
- }
- }
ret_type = type->tt_member;
if (ret_type == &t_unknown)
// return type not known yet, use a runtime check